Esplorante la Mediastreamer2 VoIP-motoron. Parto 5

La materialo de la artikolo estas prenita el mia zen kanalo.

Tondetektilo

En la lasta artikolo Ni kreis signalnivelan mezurilon. En ĉi tiu ni lernos kiel detekti tonsignalon.

Esplorante la Mediastreamer2 VoIP-motoron. Parto 5

En la malnova tempo, kiam ne ĉiu familio havis televidilon, kaj duono de ili ŝanĝis kanalojn per tenilo, en recenzoj de la eksterlanda teknika gazetaro aperis interesaj novaĵoj, ke unu televida fabrikanto ekipis siajn aparatojn per sendrata teleregilo. De la detaloj oni sciis, ke la teleregilo funkciis sen kuirilaroj danke al la uzo de nekutima aliro - la teleregilo estis mekanika kaj estis hibrido de muzika instrumento - metalofono kaj revolvero. La revolvera tamburo enhavis metalajn cilindrojn de malsamaj longoj, kaj kiam la perkulo trafis unu el ili, la cilindro komencis sonorigi laŭ sia propra frekvenco. Supozeble ĉe ultrasono. La elektroniko en la televido aŭdis ĉi tiun signalon kaj, determininte ĝian frekvencon, faris la taŭgan agon - ŝanĝi la kanalon, ŝanĝi la volumon, malŝalti la televidilon.

Hodiaŭ ni provos rekonstrui ĉi tiun komandan transmisisistemon, uzante nian scion pri la amaskomunikila streamer.

Por simuli teleregilon, ni uzos la tekston de nia ekzemplo de tongeneratoro. Ni aldonos al ĝi kontrolon de la generatora frekvenco de klavpremoj kaj ricevilon kun malĉifrilo, kiu eligos ricevitajn komandojn al la konzolo. Post la ŝanĝo, la generatoro devus produkti tonojn de 6 frekvencoj, per kiuj ni kodos komandojn por pliigi/malpliigi la volumon, ŝanĝi la kanalon, ŝalti/malŝalti la televidilon. Por agordi la detektilon, la sekva strukturo estas uzata:

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;

Detektilo povas ricevi 10 el tiuj strukturoj, tiel ke unu detektilo povas esti agordita por detekti dek du-tonajn signalojn. Sed ni uzos nur ses unutonajn signalojn. Por transdoni agordojn al la detektilo, la metodo MS_TONE_DETECTOR_ADD_SCAN estas uzata.

Por ke la detektilo sciigu al ni, ke signalo kun la dezirataj frekvencaj komponantoj alvenis al sia enigo, ni devas provizi ĝin per revokfunkcio, kiun ĝi lanĉos ĉi-kaze. Ĉi tio estas farita uzante la funkcion ms_filter_set_notify_callback (). Kiel argumentoj, ĝi ricevas montrilon al la filtrilo, montrilon al la revokfunkcio, kaj montrilon al la datumoj kiujn ni ŝatus transdoni al la revokfunkcio (uzantdatenoj).

Kiam la detektilo estas ekigita, la revokfunkcio ricevos uzantdatenojn, montrilon al la detektilfiltrilo, okazaĵidentigilon, kaj strukturon priskribantan la okazaĵon:


/** * 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;

La blokdiagramo de signal-prilaborado estas montrita en la titolbildo.

Nu, nun la programo kodo mem kun komentoj.

/* Файл 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);
    }
}

Ni kompilas kaj rulas la programon. Se ĉio funkcias ĝuste, tiam post lanĉo ni devus ricevi ion kiel ĉi tiu programkonduto:

$ ./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

Premu iujn ajn klavojn de "1" ĝis "6", konfirmante per la "Enter" klavo, vi devus ricevi ion kiel ĉi tiu listo:


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

Ni vidas, ke la komandtonoj estas sukcese senditaj kaj la detektilo ilin detektas.

En la sekva artikolo ni transdonos sonsignalon per Ethernet-reto uzante la RTP-protokolon kaj tuj aplikos ĝin en nia teleregilo.

fonto: www.habr.com

Aldoni komenton