Entdecken Sie die VoIP-Engine von Mediastreamer2. Teil 5

Das Material des Artikels stammt von mir Zen-Kanal.

Tondetektor

In der Vergangenheit Artikel Wir haben einen Signalpegelmesser entwickelt. In diesem erfahren Sie, wie Sie ein Tonsignal erkennen.

Entdecken Sie die VoIP-Engine von Mediastreamer2. Teil 5

Früher, als nicht jede Familie einen Fernseher hatte und die Hälfte von ihnen den Sender mit einer Zange wechselte, tauchten in Rezensionen der ausländischen Fachpresse interessante Neuigkeiten auf, dass ein TV-Hersteller seine Geräte mit einer drahtlosen Fernbedienung ausstattete. Aus den Details war bekannt, dass die Fernbedienung dank eines ungewöhnlichen Ansatzes ohne Batterien funktionierte – die Fernbedienung war mechanisch und eine Mischung aus einem Musikinstrument – ​​einem Metallophon und einem Revolver. Die Revolvertrommel enthielt Metallzylinder unterschiedlicher Länge, und als der Schlagbolzen auf einen von ihnen traf, begann der Zylinder mit seiner eigenen Frequenz zu klingeln. Vermutlich im Ultraschall. Die Elektronik im Fernseher hörte dieses Signal und führte nach Ermittlung der Frequenz die entsprechende Aktion aus: Kanal wechseln, Lautstärke ändern, Fernseher ausschalten.

Heute werden wir versuchen, dieses Befehlsübertragungssystem mithilfe unseres Wissens über den Media Streamer zu rekonstruieren.

Um eine Fernbedienung zu simulieren, verwenden wir den Text unseres Tongenerator-Beispiels. Wir werden die Steuerung der Generatorfrequenz über Tastenanschläge und einen Empfänger mit Decoder hinzufügen, der empfangene Befehle an die Konsole ausgibt. Nach der Änderung sollte der Generator Töne mit 6 Frequenzen erzeugen, mit denen wir Befehle zum Erhöhen/Verringern der Lautstärke, zum Wechseln des Kanals und zum Ein-/Ausschalten des Fernsehers kodieren. Zur Konfiguration des Melders wird folgender Aufbau verwendet:

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;

Ein Detektor kann mit 10 dieser Strukturen ausgestattet werden, sodass ein Detektor für die Erkennung von zehn Zweitonsignalen konfiguriert werden kann. Aber wir werden nur sechs Einzeltonsignale verwenden. Um Einstellungen an den Detektor zu übertragen, wird die Methode MS_TONE_DETECTOR_ADD_SCAN verwendet.

Damit uns der Detektor mitteilt, dass an seinem Eingang ein Signal mit den gewünschten Frequenzkomponenten angekommen ist, müssen wir ihm eine Callback-Funktion zur Verfügung stellen, die er in diesem Fall auslöst. Dies geschieht über die Funktion ms_filter_set_notify_callback(). Als Argumente erhält er einen Zeiger auf den Filter, einen Zeiger auf die Callback-Funktion und einen Zeiger auf die Daten, die wir an die Callback-Funktion übergeben möchten (Benutzerdaten).

Wenn der Detektor ausgelöst wird, empfängt die Rückruffunktion Benutzerdaten, einen Zeiger auf den Detektorfilter, eine Ereigniskennung und eine Struktur, die das Ereignis beschreibt:


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

Das Blockschaltbild der Signalverarbeitung ist im Titelbild dargestellt.

Nun, nun der Programmcode selbst mit Kommentaren.

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

Wir kompilieren das Programm und führen es aus. Wenn alles korrekt funktioniert, sollten wir nach dem Start etwa dieses Programmverhalten feststellen:

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

Drücken Sie eine beliebige Taste von „1“ bis „6“ und bestätigen Sie mit der „Enter“-Taste. Sie sollten etwa diese Auflistung erhalten:


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

Wir sehen, dass die Befehlstöne erfolgreich gesendet wurden und der Detektor sie erkennt.

Im nächsten Artikel wenden wir uns der Übertragung eines Audiosignals über ein Ethernet-Netzwerk mithilfe des RTP-Protokolls zu und wenden es sofort in unserer Fernbedienung an.

Source: habr.com

Kommentar hinzufügen