Utforska Mediastreamer2 VoIP-motorn. Del 5

Materialet i artikeln är hämtat från min zen kanal.

Tondetektor

Förr artikeln Vi har skapat en signalnivåmätare. I den här kommer vi att lära oss hur man känner av en tonsignal.

Utforska Mediastreamer2 VoIP-motorn. Del 5

Förr i tiden, när inte alla familjer hade en TV, och hälften av dem bytte kanal med en tång, dök spännande nyheter upp i recensioner av den utländska tekniska pressen att en TV-tillverkare utrustade sina enheter med en trådlös fjärrkontroll. Från detaljerna var det känt att fjärrkontrollen fungerade utan batterier tack vare användningen av ett ovanligt tillvägagångssätt - fjärrkontrollen var mekanisk och var en hybrid av ett musikinstrument - en metallofon och en revolver. Revolvertrumman innehöll metallcylindrar av olika längd och när slagstiftet träffade en av dem började cylindern ringa med sin egen frekvens. Förmodligen på ultraljud. Elektroniken i TV:n hörde denna signal och, efter att ha bestämt dess frekvens, utförde den lämplig åtgärd - byt kanal, ändra volymen, stäng av TV:n.

Idag kommer vi att försöka rekonstruera detta kommandoöverföringssystem, med hjälp av vår kunskap om mediastreamern.

För att simulera en fjärrkontroll kommer vi att använda texten i vårt tongeneratorexempel. Vi kommer att lägga till kontroll över generatorns frekvens från tangenttryckningar och en mottagare med en avkodare som kommer att mata ut mottagna kommandon till konsolen. Efter ändringen bör generatorn producera toner med 6 frekvenser, med vilka vi kommer att koda kommandon för att öka/sänka volymen, byta kanal, slå på/stänga av TV:n. För att konfigurera detektorn används följande 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 ges 10 av dessa strukturer, så en detektor kan konfigureras för att detektera tio tvåtonssignaler. Men vi kommer bara att använda sex entonssignaler. För att överföra inställningar till detektorn används metoden MS_TONE_DETECTOR_ADD_SCAN.

För att detektorn ska meddela oss att en signal med önskade frekvenskomponenter har kommit till sin ingång måste vi förse den med en återuppringningsfunktion som den kommer att starta i detta fall. Detta görs med hjälp av funktionen ms_filter_set_notify_callback(). Som argument får den en pekare till filtret, en pekare till callback-funktionen och en pekare till data som vi skulle vilja skicka till callback-funktionen (användardata).

När detektorn utlöses kommer återuppringningsfunktionen att ta emot användardata, en pekare till detektorfiltret, en händelseidentifierare och en struktur som 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;

Blockschemat för signalbehandling visas i titelbilden.

Nåväl, nu själva 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 kompilerar och kör programmet. Om allt fungerar korrekt, bör vi efter lanseringen få något i stil med detta programbeteende:

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

Tryck på valfri tangent från "1" till "6", bekräfta med "Enter"-tangenten, du bör få något i stil med denna lista:


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

Vi ser att kommandotonerna skickas framgångsrikt och detektorn känner av dem.

I nästa artikel kommer vi att övergå till att överföra en ljudsignal över ett Ethernet-nätverk med hjälp av RTP-protokollet och omedelbart tillämpa det i vår fjärrkontroll.

Källa: will.com

Lägg en kommentar