De Mediastreamer2 VoIP-engine verkennen. Deel 5

Het materiaal van het artikel is afkomstig uit mijn zen-kanaal.

Toonsignaaldetector

In het verleden ΡΡ‚Π°Ρ‚ΡŒΠ΅ We hebben een signaalniveaumeter gemaakt. In deze les leren we hoe we een toonsignaal kunnen detecteren.

De Mediastreamer2 VoIP-engine verkennen. Deel 5

Vroeger, toen nog niet elk gezin een televisie had en de helft van de gezinnen met een tang van zender wisselde, verschenen er interessante berichten in recensies van buitenlandse vakbladen over een van de fabrikanten van televisies die zijn apparaten had uitgerust met een draadloze afstandsbediening. Uit de details bleek dat de afstandsbediening zonder batterijen werkte. Dat kwam door een ongebruikelijke aanpak: de afstandsbediening was mechanisch en leek een kruising tussen een muziekinstrument, een metallofoon, en een revolver. In de trommel van de revolver zaten metalen cilinders van verschillende lengtes. Wanneer de slagpin er een raakte, begon de cilinder op zijn eigen frequentie te rinkelen. Waarschijnlijk op echo. De elektronica in de televisie heeft dit signaal opgevangen en, nadat de frequentie ervan was vastgesteld, de juiste actie ondernomen: van kanaal wisselen, volume aanpassen en de televisie uitzetten.

Vandaag gaan we proberen dit commando-overdrachtsysteem te reconstrueren met behulp van onze kennis van de mediastreamer.

Om de afstandsbediening te simuleren, gebruiken we de tekst uit ons voorbeeld van de toongenerator. We voegen hier de besturing van de generatorfrequentie via toetsaanslagen aan toe en een ontvanger met een decoder die de ontvangen opdrachten naar de console stuurt. Na de aanpassing zou de generator toonsignalen met 6 frequenties moeten produceren. Deze gebruiken we om opdrachten te coderen voor het verhogen/verlagen van het volume, het veranderen van het kanaal en het aan/uitzetten van de televisie. Om de detector te configureren, wordt de volgende structuur gebruikt:

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;

De detector kan tien van dergelijke structuren voeden. EΓ©n detector kan dus worden geconfigureerd om tien tweekleurige signalen te detecteren. Maar we gebruiken alleen zes enkeltoonsignalen. Om instellingen naar de detector over te brengen, wordt de MS_TONE_DETECTOR_ADD_SCAN-methode gebruikt.

Om de detector te laten weten dat een signaal met de gewenste frequentiecomponenten bij de ingang is aangekomen, moeten we hem voorzien van een callback-functie die hij in zo'n geval start. Dit gebeurt met behulp van de functie ms_filter_set_notify_callback(). Als argumenten ontvangt het een pointer naar het filter, een pointer naar de callback-functie en een pointer naar de gegevens die we willen doorgeven aan de callback-functie (gebruikersgegevens).

Wanneer de detector wordt geactiveerd, ontvangt de callback-functie gebruikersgegevens, een aanwijzer naar het detectorfilter, een gebeurtenis-ID en een structuur die de gebeurtenis beschrijft:


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

Het structuurdiagram van de signaalverwerking wordt weergegeven in de titelafbeelding.

Nou, nu de programmacode zelf met commentaar.

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

Wij compileren en voeren het programma uit. Als alles goed werkt, zouden we na de lancering ongeveer het volgende programmagedrag moeten zien:

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

Druk op een van de toetsen van "1" tot "6" en bevestig met de "Enter"-toets. U zou dan zoiets als dit moeten krijgen:


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

We zien dat de commandotonen succesvol worden verzonden en dat de detector ze detecteert.

In het volgende artikel gaan we in op het verzenden van audio via Ethernet met behulp van het RTP-protocol en hoe we dit direct toepassen op onze afstandsbediening.

Bron: www.habr.com

Koop betrouwbare hosting voor sites met DDoS-bescherming, VPS VDS-servers πŸ”₯ Koop betrouwbare websitehosting met DDoS-bescherming, VPS- en VDS-servers | ProHoster