Raziskovanje mehanizma VoIP Mediastreamer2. 5. del

Gradivo članka je vzeto iz mojega zen kanal.

Tonski detektor

V preteklosti članek Izdelali smo merilnik nivoja signala. V tem se bomo naučili zaznati tonski signal.

Raziskovanje mehanizma VoIP Mediastreamer2. 5. del

V starih časih, ko še ni imela vsaka družina televizorja in jih je polovica preklapljala s kleščami, so se v ocenah tujega tehničnega tiska pojavile zanimive novice, da je en proizvajalec televizorjev svoje naprave opremil z brezžičnim daljinskim upravljalnikom. Iz podrobnosti je bilo znano, da je daljinski upravljalnik deloval brez baterij zahvaljujoč uporabi nenavadnega pristopa - daljinski upravljalnik je bil mehanski in je bil hibrid glasbila - metalofona in revolverja. V bobnu revolverja so bili kovinski valji različnih dolžin in ko je udarna igla zadela enega od njih, je valj začel zvoniti s svojo frekvenco. Predvidoma na ultrazvoku. Elektronika v televizorju je slišala ta signal in po določitvi njegove frekvence izvedla ustrezno dejanje - preklopila kanal, spremenila glasnost, izklopila televizor.

Danes bomo poskušali rekonstruirati ta sistem prenosa ukazov z uporabo našega znanja o medijskem pretakalniku.

Za simulacijo daljinskega upravljalnika bomo uporabili besedilo našega primera generatorja tonov. Dodali mu bomo nadzor frekvence generatorja s pritiski na tipke in sprejemnik z dekoderjem, ki bo prejete ukaze oddajal na konzolo. Po spremembi naj bi generator proizvedel tone 6 frekvenc, s katerimi bomo zakodirali ukaze za povečanje/zmanjšanje glasnosti, menjavo kanala, vklop/izklop TV-ja. Za konfiguracijo detektorja se uporablja naslednja struktura:

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;

Detektorju je mogoče dati 10 teh struktur, tako da je mogoče en detektor konfigurirati za zaznavanje desetih dvotonskih signalov. Vendar bomo uporabili samo šest enotonskih signalov. Za prenos nastavitev v detektor se uporablja metoda MS_TONE_DETECTOR_ADD_SCAN.

Da nas detektor obvesti, da je na njegov vhod prišel signal z želenimi frekvenčnimi komponentami, mu moramo zagotoviti funkcijo povratnega klica, ki jo bo v tem primeru sprožil. To se naredi s funkcijo ms_filter_set_notify_callback(). Kot argumente prejme kazalec na filter, kazalec na funkcijo povratnega klica in kazalec na podatke, ki bi jih radi posredovali funkciji povratnega klica (uporabniški podatki).

Ko se detektor sproži, bo funkcija povratnega klica prejela uporabniške podatke, kazalec na filter detektorja, identifikator dogodka in strukturo, ki opisuje dogodek:


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

Blok diagram obdelave signala je prikazan na naslovni sliki.

No, zdaj pa sama programska koda s komentarji.

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

Program sestavimo in poženemo. Če vse deluje pravilno, bi morali po zagonu dobiti nekaj podobnega temu vedenju programa:

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

Pritisnite katero koli tipko od "1" do "6", potrdite s tipko "Enter", dobili bi nekaj takega kot ta seznam:


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

Vidimo, da so ukazni toni uspešno poslani in jih detektor zazna.

V naslednjem članku se bomo posvetili prenosu zvočnega signala preko omrežja Ethernet z uporabo protokola RTP in ga takoj uporabili v našem daljinskem upravljalniku.

Vir: www.habr.com

Dodaj komentar