Mediastreamer2 VoIP motorra arakatzen. 5. zatia

Artikuluaren materiala niretik hartua da zen kanala.

Tonu-detektagailua

Azkenean Artikulu Seinale maila neurgailua sortu dugu. Honetan tonu seinale bat nola detektatzen ikasiko dugu.

Mediastreamer2 VoIP motorra arakatzen. 5. zatia

Antzina, familia guztiek ez zuten telebistarik eta haietako erdiek aliketak erabiliz kanalez aldatzen zutenean, atzerriko prentsa teknikoaren berrikuspenetan albiste interesgarriak agertu ziren telebista fabrikatzaile batek hari gabeko urruneko aginte batekin hornitzen zituela gailuak. Xehetasunetatik jakin zen urrutiko agintea bateriarik gabe funtzionatzen zuela ezohiko ikuspegi baten erabilerari esker - urrutiko agintea mekanikoa zen eta musika tresna baten hibridoa zen - metalofonoa eta errebolber bat. Errebolber-danborrak luzera ezberdinetako metalezko zilindroak zituen, eta perkutak horietako bat jo zuenean, zilindroa bere maiztasunarekin jotzen hasi zen. Ustez, ultrasoinuetan. Telebistako elektronikak seinale hori entzun zuen eta, maiztasuna zehaztuta, ekintza egokia egin zuen: kanala aldatu, bolumena aldatu, telebista itzali.

Agindu transmisio sistema hau berreraikitzen saiatuko gara gaur, multimedia streamer-aren ezagutza erabiliz.

Urruneko aginte bat simulatzeko, gure tonu-sorgailuaren adibidearen testua erabiliko dugu. Sorgailuaren frekuentziaren kontrola gehituko diogu tekla sakeetatik eta jasotako komandoak kontsolara aterako dituen deskodetzaile bat duen hargailua. Aldaketaren ondoren, sorgailuak 6 maiztasuneko tonuak sortu behar ditu, eta horiekin bolumena igo/gutxitzeko aginduak kodetuko ditugu, kanala aldatu, telebista pizteko/itzaltzeko. Detektagailua konfiguratzeko, egitura hau erabiltzen da:

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;

Detektagailu bati egitura horietako 10 eman daitezke, beraz, detektagailu bat konfigura daiteke bi tonuko hamar seinale detektatzeko. Baina tonu bakarreko sei seinale baino ez ditugu erabiliko. Ezarpenak detektagailura transferitzeko, MS_TONE_DETECTOR_ADD_SCAN metodoa erabiltzen da.

Detektagailuak bere sarrerara nahi diren maiztasun-osagaiak dituen seinalea iritsi dela jakinarazteko, kasu honetan abiaraziko duen callback funtzio bat eman behar diogu. Hau funtzioa erabiliz egiten da ms_filter_set_notify_callback(). Argumentu gisa, iragazkiaren erakuslea, dei-atzera funtziorako erakuslea eta dei-atzerako funtziora (erabiltzaile-datuak) pasatu nahi ditugun datuen erakuslea jasotzen du.

Detektagailua abiarazten denean, dei-atzera funtzioak erabiltzailearen datuak, detektagailuaren iragazkirako erakuslea, gertaeren identifikatzaile bat eta gertaera deskribatzen duen egitura jasoko ditu:


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

Seinalearen prozesamenduaren bloke-diagrama izenburuko irudian agertzen da.

Beno, orain programaren kodea bera iruzkinekin.

/* Π€Π°ΠΉΠ» 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);
    }
}

Programa konpilatu eta exekutatzen dugu. Dena behar bezala funtzionatzen badu, abiarazi ondoren programaren portaera honen antzeko zerbait lortu beharko genuke:

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

Sakatu "1"tik "6ra" teklaren bat, "Sartu" teklarekin berresten baduzu, zerrenda honen antzeko zerbait lortu beharko zenuke:


2
ΠžΡ‚ΠΏΡ€Π°Π²Π»Π΅Π½Π° ΠΊΠΎΠΌΠ°Π½Π΄Π°: 2
                      ΠŸΡ€ΠΈΠ½ΡΡ‚Π° ΠΊΠΎΠΌΠ°Π½Π΄Π°: V-
1
ΠžΡ‚ΠΏΡ€Π°Π²Π»Π΅Π½Π° ΠΊΠΎΠΌΠ°Π½Π΄Π°: 1
                      ΠŸΡ€ΠΈΠ½ΡΡ‚Π° ΠΊΠΎΠΌΠ°Π½Π΄Π°: V+
3
ΠžΡ‚ΠΏΡ€Π°Π²Π»Π΅Π½Π° ΠΊΠΎΠΌΠ°Π½Π΄Π°: 3
                      ΠŸΡ€ΠΈΠ½ΡΡ‚Π° ΠΊΠΎΠΌΠ°Π½Π΄Π°: C+
4
ΠžΡ‚ΠΏΡ€Π°Π²Π»Π΅Π½Π° ΠΊΠΎΠΌΠ°Π½Π΄Π°: 4
                      ΠŸΡ€ΠΈΠ½ΡΡ‚Π° ΠΊΠΎΠΌΠ°Π½Π΄Π°: C-
0
$

Agindu-tonuak ongi bidali direla ikusten dugu eta detektagailuak detektatzen ditu.

Hurrengo artikuluan RTP protokoloa erabiliz Ethernet sare baten bidez audio-seinalea transmititzeari ekingo diogu eta berehala gure urruneko agintean aplikatuko dugu.

Iturria: www.habr.com

Gehitu iruzkin berria