Uurime VoIP mootori Mediastreamer2. Osa 5

Artikli materjal on saadud minu Dzen-kanalist.

Heli signaali tuvastaja

Eelmisel artiklis Oleme loonud signaalitaseme mõõdiku. Selles õpetuses õpime, kuidas tuvastada heli signaali.

Uurime VoIP mootori Mediastreamer2. Osa 5

Vanaajal, kui mitte igas peres ei olnud televiisorit ja pooltel neist vahetati kanaleid tangidega, ilmusid välismaise tehnikaajakirjanduse ülevaates intrigeeriv uudis, et üks televiisorite tootjatest varustas oma seadmed kaugjuhtimispuldiga. Üksikasjadest selgus, et puldil ei olnud akusid, kuna see kasutas ebatavalist lähenemist — pult oli mehaaniline ja kujutas endast muusikariista hübriidi — metallofoni ja revolvri. Revolvri rullikus olid metallist tsylinderid, erineva pikkusega, ja kui naha lõuend tabas ühte neist, hakkas tsylinder helisema omaenda sagedusel. Eeldatavasti ultrahelis. Televiisori elektroonika kuulis seda signaali ja määrates selle sageduse, sooritas vastava toimingu — vahetas kanalit, muutis helitugevust või lülitas televiisori välja.

Täna proovime rekonstrueerida seda käsu edastamise süsteemi, kasutades meie teadmisi meediastreamerist.

Puldi simuleerimiseks kasutame meie näite heli generaatori teksti. Lisame selles juhtimise generaatori sagedusele klaviatuurilt tulenevate vajutustega ja vastuvõtja dekooderiga, mis väljastab konsolisse vastuvõetud käsud. Pärast muudatust peab generaator andma kuut erinevat heli signaali, millega koodime helitugevuse suurendamise/väikese, kanalivahetuse, televisiooni sisse-/väljalülitamise käsud. Detektori seadistamiseks kasutatakse struktuuri:

struct _MSToneDetectorDef{  
     char tone_name[8];     
     int frequency; "/**<Oodatav heli sagedus*/  
     int min_duration; "/**<Heli minimaalne kestus millisekundites */  
     float min_amplitude; "/**<Heli minimaalne amplitude, 1.0 vastab normaliseeritud 0dbm tasemele */
};

typedef struct _MSToneDetectorDef MSToneDetectorDef;

Detektorile saab edastada 10 sellist struktuuri, mistõttu saab ühte detektorit häälestada kümne kahetoonilise signaali tuvastamiseks. Kuid me kasutame ainult kuut ühetoonilist signaali. Detektori seadete edastamiseks kasutatakse meetodit MS_TONE_DETECTOR_ADD_SCAN.

Kuna detektor suudab meid teavitada, et selle sisendisse on saabunud signaal soovitud sageduskomponentidega, peame talle andma tagasisidefunktsiooni, mida ta sellisel juhul käivitab. See toimub funktsiooni kaudu ms_filter_set_notify_callback(). Argumentideks on filteri näidik, tagasisidefunktsiooni näidik ja näidik andmete kohta, mida soovime tagasisidefunktsioonile edastada (kasutajaandmed).

Kui detektor aktiveerub, saab tagasisidefunktsioon kasutajaandmed, filteri näidiku, sündmuse identifikaatori ja sündmust kirjeldava struktuuri:


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

Signaali töötlemise struktuur on kujutatud pealkirja pildil.

Nüüd on käes koodi osa koos kommentaaridega.

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

Kompileerime ja käivitame programmi. Kui kõik töötab õigesti, peaksime pärast käivitamist saama umbes sellise programmi käitumise:

$ ./mstest4
ALSA lib conf.c:4738:(snd_config_expand) Tundmatud parameetrid 0
ALSA lib control.c:954:(snd_ctl_open_noupdate) Kehtetu CTL default:0
ortp-warning-Koosseisu ei õnnestunud segistiga ühendada: Kehtetu argumend
ALSA lib conf.c:4738:(snd_config_expand) Tundmatud parameetrid 0
ALSA lib pcm.c:2266:(snd_pcm_open_noupdate) Tundmatu PCM default:0
ALSA lib conf.c:4738:(snd_config_expand) Tundmatud parameetrid 0
ALSA lib pcm.c:2266:(snd_pcm_open_noupdate) Tundmatu PCM default:0
ortp-warning-Imelik, helikaart Intel 82801AA-ICH näib olevat võimetu millegiga, proovime uuesti plughw...
Vajutage käskluse klahvi ja seejärel Enter.
Programmi lõpetamiseks sisestage 0.
ortp-warning-alsa_set_params: periodsize:256 Kasutatakse 256
ortp-warning-alsa_set_params: period:8 Kasutatakse 8

Vajutage mis tahes klahve vahemikus "1" kuni "6", kinnitades klahviga "Enter", peaks saama umbes sellise väljundi:


2
Saadeti käsk: 2
                      Saadi käsk: V-
1
Saadeti käsk: 1
                      Saadi käsk: V+
3
Saadeti käsk: 3
                      Saadi käsk: C+
4
Saadeti käsk: 4
                      Saadi käsk: C-
0
$

Näeme, et käskude toone saadetakse edukalt ja detektor tuvastab need.

Järgmises artiklis käsitleme helisignaali edastamist Etherneti kaudu RTP-protokolli abil ja rakendame seda kohe meie kaugjuhtimispuldiga.

Allikas: habr.com

Osta usaldusväärne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid 🔥 Osta usaldusväärne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid | ProHoster