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