Ուսումնասիրելով Mediastreamer2 VoIP շարժիչը: Մաս 5

Հոդվածի նյութը վերցված է իմ զեն ալիք.

Տոնային դետեկտոր

Անցյալում Հոդված Մենք ստեղծել ենք ազդանշանի մակարդակի չափիչ։ Այս մեկում մենք կսովորենք, թե ինչպես հայտնաբերել տոնային ազդանշանը:

Ուսումնասիրելով Mediastreamer2 VoIP շարժիչը: Մաս 5

Հին ժամանակներում, երբ ոչ բոլոր ընտանիքներն ուներ հեռուստացույց, և նրանց կեսը փոխում էր ալիքները՝ օգտագործելով տափակաբերան աքցան, արտասահմանյան տեխնիկական մամուլի ակնարկներում հետաքրքիր նորություններ հայտնվեցին այն մասին, որ հեռուստացույց արտադրողներից մեկն իր սարքերը սարքավորել է անլար հեռակառավարմամբ: Մանրամասներից հայտնի դարձավ, որ հեռակառավարման վահանակն աշխատում էր առանց մարտկոցների՝ անսովոր մոտեցման կիրառման շնորհիվ՝ հեռակառավարման վահանակը մեխանիկական էր և երաժշտական ​​գործիքի՝ մետալոֆոնի և ատրճանակի հիբրիդ էր։ Ռեւոլվերի թմբուկը պարունակում էր տարբեր երկարության մետաղական բալոններ, եւ երբ կրակակետը դիպավ դրանցից մեկին, մխոցը սկսեց զնգալ իր հաճախականությամբ։ Ենթադրաբար ուլտրաձայնի վրա։ Հեռուստացույցի էլեկտրոնիկան լսեց այս ազդանշանը և, որոշելով դրա հաճախականությունը, կատարեց համապատասխան գործողությունը՝ միացրեք ալիքը, փոխեք ձայնի ձայնը, անջատեք հեռուստացույցը:

Այսօր մենք կփորձենք վերակառուցել հրամանի փոխանցման այս համակարգը՝ օգտագործելով մեդիա հոսքի մասին մեր գիտելիքները:

Հեռակառավարման վահանակը մոդելավորելու համար մենք կօգտագործենք մեր ձայնային գեներատորի տեքստը: Մենք դրան կավելացնենք գեներատորի հաճախականության հսկողությունը ստեղնաշարի միջոցով և ապակոդավորիչով ստացող, որը ստացված հրամանները կուղարկի վահանակ: Փոփոխությունից հետո գեներատորը պետք է արտադրի 6 հաճախականության հնչերանգներ, որոնցով կկոդավորենք ձայնի բարձրացման/նվազեցման, ալիքը փոխելու, հեռուստացույցը միացնելու/անջատելու հրամաններ։ Դետեկտորը կարգավորելու համար օգտագործվում է հետևյալ կառուցվածքը.

struct _MSToneDetectorDef{  
     char tone_name[8];     
     int frequency; /**<Expected frequency of the tone*/ 
     int min_duration; /**<Min duration of the tone in milliseconds */ 
     float min_amplitude; /**<Minimum amplitude of the tone, 1.0 corresponding to the normalized 0dbm level */
};

typedef struct _MSToneDetectorDef MSToneDetectorDef;

Դետեկտորին կարող են տրվել այդ կառույցներից 10-ը, այնպես որ մեկ դետեկտորը կարող է կազմաձևվել տասը երկտոնային ազդանշան հայտնաբերելու համար: Բայց մենք կօգտագործենք միայն վեց մեկ տոնով ազդանշան: Պարամետրերը դետեկտորին փոխանցելու համար օգտագործվում է MS_TONE_DETECTOR_ADD_SCAN մեթոդը:

Որպեսզի դետեկտորը մեզ տեղեկացնի, որ ցանկալի հաճախականության բաղադրիչներով ազդանշան է ժամանել իր մուտքին, մենք պետք է նրան տրամադրենք հետ կանչի գործառույթ, որը այն կգործարկի այս դեպքում: Դա արվում է ֆունկցիայի միջոցով ms_filter_set_notify_callback(). Որպես արգումենտ, այն ստանում է ցուցիչ դեպի ֆիլտր, ցուցիչ դեպի հետադարձ կապ ֆունկցիան և ցուցիչ դեպի այն տվյալները, որոնք մենք կցանկանայինք փոխանցել հետադարձ կապի գործառույթին (օգտագործողի տվյալներ):

Երբ դետեկտորը գործարկվի, հետ կանչի գործառույթը կստանա օգտվողի տվյալներ, դետեկտորի ֆիլտրի ցուցիչ, իրադարձության նույնացուցիչ և իրադարձությունը նկարագրող կառուցվածք.


/** * Structure carried as argument of the MS_TONE_DETECTOR_EVENT**/
struct _MSToneDetectorEvent{ 
      char tone_name[8];       /* Имя тона которое мы ему назначили при настройке детектора. */
      uint64_t tone_start_time;   /* Время в миллисекундах, когда тон был обнаружен. */
};

typedef struct _MSToneDetectorEvent MSToneDetectorEvent;

Ազդանշանի մշակման բլոկային դիագրամը ներկայացված է վերնագրի նկարում:

Դե, հիմա ծրագրի կոդը ինքնին մեկնաբանություններով:

/* Файл mstest4.c Имитатор пульта управления и приемника. */
#include <mediastreamer2/msfilter.h>
#include <mediastreamer2/msticker.h>
#include <mediastreamer2/dtmfgen.h>
#include <mediastreamer2/mssndcard.h>
#include <mediastreamer2/msvolume.h>
#include <mediastreamer2/mstonedetector.h>

/* Подключаем заголовочный файл с функциями управления событиями
 * медиастримера. */
#include <mediastreamer2/mseventqueue.h>

/* Функция обратного вызова, она будет вызвана фильтром, как только он
 * обнаружит совпадение характеристик входного сигнала с заданными. */
static void tone_detected_cb(void *data, MSFilter *f, unsigned int event_id,
        MSToneDetectorEvent *ev)
{
    printf("                      Принята команда: %sn", ev->tone_name);
}

int main()
{
    ms_init();

    /* Создаем экземпляры фильтров. */
    MSFilter  *voidsource = ms_filter_new(MS_VOID_SOURCE_ID);
    MSFilter  *dtmfgen = ms_filter_new(MS_DTMF_GEN_ID);
    MSFilter  *volume = ms_filter_new(MS_VOLUME_ID);
    MSSndCard *card_playback =
        ms_snd_card_manager_get_default_card(ms_snd_card_manager_get());
    MSFilter  *snd_card_write = ms_snd_card_create_writer(card_playback);
    MSFilter  *detector = ms_filter_new(MS_TONE_DETECTOR_ID);

    /* Очищаем массив находящийся внутри детектора тонов, он описывает
     * особые приметы разыскиваемых сигналов.*/
    ms_filter_call_method(detector, MS_TONE_DETECTOR_CLEAR_SCANS, 0);

    /* Создаем источник тактов - тикер. */
    MSTicker *ticker=ms_ticker_new();

    /* Соединяем фильтры в цепочку. */
    ms_filter_link(voidsource, 0, dtmfgen, 0);
    ms_filter_link(dtmfgen, 0, volume, 0);
    ms_filter_link(volume, 0, detector, 0);
    ms_filter_link(detector, 0, snd_card_write, 0);

    /* Подключаем к фильтру функцию обратного вызова. */
    ms_filter_set_notify_callback(detector,
            (MSFilterNotifyFunc)tone_detected_cb, NULL);

    /* Подключаем источник тактов. */
    ms_ticker_attach(ticker,voidsource);

    /* Создаем массив, каждый элемент которого описывает характеристику
     * одного из тонов, который требуется обнаруживать: Текстовое имя
     * данного элемента, частота в герцах, длительность в миллисекундах,
     * минимальный уровень относительно 0,775В. */  
    MSToneDetectorDef  scan[6]=
    {
        {"V+",  440, 100, 0.1}, /* Команда "Увеличить громкость". */
        {"V-",  540, 100, 0.1}, /* Команда "Уменьшить громкость". */
        {"C+",  640, 100, 0.1}, /* Команда "Увеличить номер канала". */
        {"C-",  740, 100, 0.1}, /* Команда "Уменьшить номер канала". */
        {"ON",  840, 100, 0.1}, /* Команда "Включить телевизор". */
        {"OFF", 940, 100, 0.1}  /* Команда "Выключить телевизор". */
    };

    /* Передаем в детектор тонов приметы сигналов. */
    int i;
    for (i = 0; i < 6; i++)
    {
        ms_filter_call_method(detector, MS_TONE_DETECTOR_ADD_SCAN,
                &scan[i]);
    }

    /* Настраиваем структуру, управляющую выходным сигналом генератора.*/
    MSDtmfGenCustomTone dtmf_cfg;
    dtmf_cfg.tone_name[0] = 0;
    dtmf_cfg.duration = 1000;
    dtmf_cfg.frequencies[0] = 440;
    /* Будем генерировать один тон, частоту второго тона установим в 0.*/
    dtmf_cfg.frequencies[1] = 0;
    dtmf_cfg.amplitude = 1.0;
    dtmf_cfg.interval = 0.;
    dtmf_cfg.repeat_count = 0.;

    /* Организуем цикл сканирования нажатых клавиш. Ввод нуля завершает
     * цикл и работу программы. */
    char key='9';
    printf("Нажмите клавишу команды, затем ввод.n"
        "Для завершения программы введите 0.n");
    while(key != '0')
    {
        key = getchar();
        if ((key >= 49) && (key <= 54))
        {
                printf("Отправлена команда: %cn", key);
            /* Устанавливаем частоту генератора в соответствии с
             * кодом нажатой клавиши.*/
            dtmf_cfg.frequencies[0] = 440 + 100*(key-49);

            /* Включаем звуковой генератор c обновленной частотой. */
            ms_filter_call_method(dtmfgen, MS_DTMF_GEN_PLAY_CUSTOM,
                    (void*)&dtmf_cfg);
        }
        ms_usleep(20000);
    }
}

Մենք կազմում և գործարկում ենք ծրագիրը: Եթե ​​ամեն ինչ ճիշտ է աշխատում, ապա գործարկումից հետո մենք պետք է ստանանք այս ծրագրի վարքագիծը.

$ ./mstest4
ALSA lib conf.c:4738:(snd_config_expand) Unknown parameters 0
ALSA lib control.c:954:(snd_ctl_open_noupdate) Invalid CTL default:0
ortp-warning-Could not attach mixer to card: Invalid argument
ALSA lib conf.c:4738:(snd_config_expand) Unknown parameters 0
ALSA lib pcm.c:2266:(snd_pcm_open_noupdate) Unknown PCM default:0
ALSA lib conf.c:4738:(snd_config_expand) Unknown parameters 0
ALSA lib pcm.c:2266:(snd_pcm_open_noupdate) Unknown PCM default:0
ortp-warning-Strange, sound card Intel 82801AA-ICH does not seems to be capable of anything, retrying with plughw...
Нажмите клавишу команды, затем ввод.
Для завершения программы введите 0.
ortp-warning-alsa_set_params: periodsize:256 Using 256
ortp-warning-alsa_set_params: period:8 Using 8

Սեղմեք «1»-ից մինչև «6» ցանկացած ստեղն՝ հաստատելով «Enter» ստեղնը, դուք պետք է ստանաք այսպիսի մի բան.


2
Отправлена команда: 2
                      Принята команда: V-
1
Отправлена команда: 1
                      Принята команда: V+
3
Отправлена команда: 3
                      Принята команда: C+
4
Отправлена команда: 4
                      Принята команда: C-
0
$

Մենք տեսնում ենք, որ հրամանի ազդանշանները հաջողությամբ ուղարկվում են, և դետեկտորը հայտնաբերում է դրանք:

Հաջորդ հոդվածում մենք կանդրադառնանք ձայնային ազդանշանի փոխանցմանը Ethernet ցանցի միջոցով RTP արձանագրության միջոցով և անմիջապես կկիրառենք այն մեր հեռակառավարման վահանակում:

Source: www.habr.com

Добавить комментарий