Preučujemo VoIP motor Mediastreamer2. Del 5

Materijal u članku preuzet je sa mog zen kanala.

Odkritelj tončnega signala

V prejšnjem članku Ustvarili smo merilnik jakosti signala. V tem članku se bomo naučili odkrivati tončni signal.

Preučujemo VoIP motor Mediastreamer2. Del 5

V starih časih, ko v vsaki družini ni bilo televizorja in pri polovici njih so kanale menjavali s kleščami, se je v tujih tehničnih revijah pojavila zanimiva novica, da je eden od proizvajalcev televizorjev opremil svoje naprave z brezžičnim daljinskim upravljalnikom. Iz podrobnosti je bilo znano, da daljinec deluje brez baterij zaradi posebnega pristopa — daljinec je bil mehanski in je bil hibrid glasbenega instrumenta — metalofona in revolverja. V bobnu revolverja so bili kovinski valji, različni po dolžini, in ko je udarec zadel enega od njih, je valj začel zvoniti na svoji lastni frekvenci. Predvideva se, da na ultrazvočni ravni. Elektronika v televizorju je slišala ta signal in na podlagi njegove frekvence izvedla ustrezno dejanje — preklopila kanal, spremenila glasnost, izklopila televizor.

Danes bomo poskušali rekonstruirati ta sistem prenašanja ukazov, pri čemer bomo izkoristili naše znanje o medijskem strežniku.

Za posnemanje daljinca bomo uporabili besedilo našega primera tončnega generatorja. Dodali bomo nadzor frekvence generatorja s pritiski na tipkovnico in sprejemnik z dekoderjem, ki bo izpisal sprejete ukaze v konzolo. Po spremembi bo generator oddajal tončne signale 6 frekvenc, s katerimi bomo kodirali ukaze za povečanje/zmanjšanje glasnosti, menjavo kanala, vklop/izklop televizorja. Za nastavitev detektorja bo uporabljena struktura:

struct _MSToneDetectorDef{  
     char tone_name[8];     
     int frequency; ;/*Očekivana frekvenca tona*/*/ 
     int min_duration; ;/*Min trajanje tona v milisekundah*/*/ 
     float min_amplitude; ;/*Minimalna amplituda tona; 1.0 ustreza normalizirani ravni 0dbm*/*/
};

typedef struct _MSToneDetectorDef MSToneDetectorDef;

Detektorju lahko posredujemo 10 takih struktur, s čimer lahko en detektor nastavimo za odkrivanje desetih dvotonalnih signalov. Toda mi bomo uporabili le šest enotonalnih signalov. Za prenos nastavitev detektorju se uporablja metoda MS_TONE_DETECTOR_ADD_SCAN.

Da bi detektor mogao da nas obavesti kada na njegov ulaz stigne signal sa traženim frekvencijskim komponentama, moramo mu obezbediti funkciju povratnog poziva koju će pokrenuti u tom slučaju. To se realizuje pomoću funkcije ms_filter_set_notify_callback(). Kao argumente, ona prima pokazivač na filter, pokazivač na funkciju povratnog poziva i pokazivač na podatke koje želimo da prosledimo funkciji povratnog poziva (korisnički podaci).

Kada se detektor aktivira, funkcija povratnog poziva će primiti korisničke podatke, pokazivač na filter detektora, identifikator događaja i strukturu koja opisuje događaj:


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

Strukturni dijagram obrade signala prikazan je na uvodnoj slici.

Sada ćemo prikazati sam kod programa sa komentarima.

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

Kompajliramo i pokrećemo program. Ako sve radi ispravno, trebali bismo dobiti otprilike ovakvo ponašanje programa:

$ ./mstest4
ALSA lib conf.c:4738:(snd_config_expand) Nepoznata svojstva 0
ALSA lib control.c:954:(snd_ctl_open_noupdate) Nevalidan CTL default:0
ortp-warning- Nije moguće povezati mikser sa karticom: Nevalidna argumentacija
ALSA lib conf.c:4738:(snd_config_expand) Nepoznata svojstva 0
ALSA lib pcm.c:2266:(snd_pcm_open_noupdate) Nepoznata PCM default:0
ALSA lib conf.c:4738:(snd_config_expand) Nepoznata svojstva 0
ALSA lib pcm.c:2266:(snd_pcm_open_noupdate) Nepoznata PCM default:0
ortp-warning-Čudno, zvučna kartica Intel 82801AA-ICH se čini da nije sposobna za bilo šta, ponovo pokušavamo sa plughw...
Pritisnite dugme komande, a zatim Enter.
Za završetak programa unesite 0.
ortp-warning-alsa_set_params: periodsize:256 Koristi 256
ortp-warning-alsa_set_params: period:8 Koristi 8

Pritiskom na bilo koju tasteru od "1" do "6", potvrđujući tasterom "Enter", trebalo bi da dobijemo otprilike ovakav ispis:


2
Poslata komanda: 2
                      Primljena komanda: V-
1
Poslata komanda: 1
                      Primljena komanda: V+
3
Poslata komanda: 3
                      Primljena komanda: C+
4
Poslata komanda: 4
                      Primljena komanda: C-
0
$

Vidimo da komande tonova uspešno šalju i detektor ih otkriva.

U sledećem članku bavićemo se prenosa zvučnog signala preko Ethernet mreže pomoću RTP protokola i odmah ćemo ga primeniti u našem daljinskom upravljaču.

Izvor: habr.com

Kupite zanesljivo gostovanje za spletne strani z zaščito pred DDoS, VPS VDS strežniki 🔥 Kupite zanesljivo gostovanje za spletne strani z zaščito pred DDoS, VPS VDS strežniki | ProHoster