Udforskning af Mediastreamer2 VoIP-motoren. Del 5

Artiklens materiale er hentet fra min zen kanal.

Tonedetektor

I fortiden artiklen Vi har lavet en signalniveaumåler. I denne vil vi lære, hvordan man registrerer et tonesignal.

Udforskning af Mediastreamer2 VoIP-motoren. Del 5

I gamle dage, hvor ikke alle familier havde et tv, og halvdelen af ​​dem skiftede kanal ved hjælp af en tang, dukkede spændende nyheder op i anmeldelser af den udenlandske tekniske presse om, at en tv-producent udstyrede deres enheder med en trådløs fjernbetjening. Fra detaljerne vidste man, at fjernbetjeningen fungerede uden batterier takket være brugen af ​​en usædvanlig tilgang - fjernbetjeningen var mekanisk og var en hybrid af et musikinstrument - en metallofon og en revolver. Revolvertromlen indeholdt metalcylindre af forskellig længde, og da slagstiften ramte en af ​​dem, begyndte cylinderen at ringe med sin egen frekvens. Formentlig på ultralyd. Elektronikken i tv'et hørte dette signal og efter at have bestemt dets frekvens udførte den passende handling - skift kanalen, skift lydstyrken, sluk tv'et.

I dag vil vi forsøge at rekonstruere dette kommandotransmissionssystem ved at bruge vores viden om mediestreameren.

For at simulere en fjernbetjening vil vi bruge teksten i vores tonegeneratoreksempel. Vi vil tilføje kontrol af generatorens frekvens fra tastetryk og en modtager med en dekoder, der udsender modtagne kommandoer til konsollen. Efter ændringen skal generatoren producere toner på 6 frekvenser, med hvilke vi vil kode kommandoer for at øge/sænke lydstyrken, skifte kanal, tænde/slukke for tv'et. For at konfigurere detektoren bruges følgende struktur:

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;

En detektor kan få 10 af disse strukturer, så en detektor kan konfigureres til at detektere ti to-tone signaler. Men vi vil kun bruge seks enkelttonesignaler. For at overføre indstillinger til detektoren bruges metoden MS_TONE_DETECTOR_ADD_SCAN.

For at detektoren kan meddele os, at et signal med de ønskede frekvenskomponenter er ankommet til sin indgang, skal vi forsyne den med en tilbagekaldsfunktion, som den vil starte i dette tilfælde. Dette gøres ved hjælp af funktionen ms_filter_set_notify_callback(). Som argumenter modtager den en pegepind til filteret, en pegepind til tilbagekaldsfunktionen og en pegepind til de data, som vi gerne vil videregive til tilbagekaldsfunktionen (brugerdata).

Når detektoren udløses, vil tilbagekaldsfunktionen modtage brugerdata, en pointer til detektorfilteret, en hændelsesidentifikator og en struktur, der beskriver hændelsen:


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

Blokdiagrammet for signalbehandling er vist i titelbilledet.

Nå, nu selve programkoden med kommentarer.

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

Vi kompilerer og kører programmet. Hvis alt fungerer korrekt, bør vi efter lanceringen få noget som denne programadfærd:

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

Tryk på en vilkårlig tast fra "1" til "6", og bekræft med "Enter"-tasten, du skulle få noget som denne liste:


2
Отправлена команда: 2
                      Принята команда: V-
1
Отправлена команда: 1
                      Принята команда: V+
3
Отправлена команда: 3
                      Принята команда: C+
4
Отправлена команда: 4
                      Принята команда: C-
0
$

Vi ser, at kommandotonerne sendes med succes, og detektoren registrerer dem.

I den næste artikel vil vi vende os til at sende et lydsignal over et Ethernet-netværk ved hjælp af RTP-protokollen og straks anvende det i vores fjernbetjening.

Kilde: www.habr.com

Tilføj en kommentar