Wir lernen den VoIP-Engine Mediastreamer2. Teil 5

Der Artikelinhalt stammt von meinem Zen-Kanal.

Tonfrequenzdetektor

Letzte Woche Artikel Wir haben einen Signalpegelmesser erstellt. In diesem Kapitel lernen wir, den Tonfrequenzsignale zu erkennen.

Wir lernen den VoIP-Engine Mediastreamer2. Teil 5

In früheren Zeiten, als nicht in jeder Familie ein Fernseher vorhanden war und die meisten von ihnen die Kanäle mit Zangen umschalteten, erschien in den Reviews der ausländischen Technikpresse eine faszinierende Nachricht, dass einer der Fernseherhersteller seine Geräte mit einer Fernbedienung ausgestattet hatte, die keinen Strom benötigte. Es war bekannt, dass die Fernbedienung durch einen ungewöhnlichen Ansatz - einen mechanischen Hybrid aus einem Musikinstrument, einem Metallophon und einem Revolver - funktionierte. In der Trommel des Revolvers befanden sich unterschiedlich lange Metallzylinder, und wenn der Schlagbolzen auf einen von ihnen traf, begann der Zylinder auf seiner eigenen Frequenz zu läuten. Vermutlich im Ultraschallbereich. Die Elektronik im Fernseher hörte dieses Signal und führte, nachdem sie dessen Frequenz festgelegt hatte, die entsprechende Aktion aus - Kanal wechseln, Lautstärke ändern, Fernseher ausschalten.

Heute werden wir versuchen, dieses System zur Übertragung von Befehlen zu rekonstruieren, indem wir unser Wissen über den Mediastreamer nutzen.

Um die Fernbedienung zu simulieren, verwenden wir den Text unseres Beispiels für den Tonfrequenzgenerator. Wir fügen die Steuerung der Frequenz des Generators durch Tasteneingaben und einen Empfänger mit Decoder hinzu, der die empfangenen Befehle auf die Konsole ausgibt. Nach der Änderung sollte der Generator Töne mit 6 Frequenzen erzeugen, mit denen wir die Befehle zur Lautstärkenerhöhung/ -verringerung, Kanalwechsel und Ein-/Ausschalten des Fernsehers kodieren werden. Zum Einstellen des Detektors verwenden wir die Struktur:

struct _MSToneDetectorDef{  
     char tone_name[8];     
     int frequency; 
     /**Erwartete Frequenz des Tons*/ 
     int min_duration; 
     /**Minimale Dauer des Tons in Millisekunden*/ 
     float min_amplitude; 
     /**Minimale Amplitude des Tons, 1.0 entspricht dem normierten 0dBm-Niveau*/
};

typedef struct _MSToneDetectorDef MSToneDetectorDef;

Dem Detektor können bis zu 10 solcher Strukturen übergeben werden, was bedeutet, dass ein Detektor auf das Erkennen von zehn zweitonalen Signalen eingestellt werden kann. Aber wir werden nur sechs einstimmige Signale verwenden. Um die Einstellungen an den Detektor zu übertragen, wird die Methode MS_TONE_DETECTOR_ADD_SCAN verwendet.

Damit der Detektor uns benachrichtigen kann, dass ein Signal mit den gewünschten Frequenzkomponenten an seinem Eingang angekommen ist, müssen wir ihm eine Rückruffunktion bereitstellen, die er in diesem Fall aufruft. Dies erfolgt mit der Funktion ms_filter_set_notify_callback(). Als Argumente erhält sie einen Zeiger auf den Filter, einen Zeiger auf die Rückruffunktion und einen Zeiger auf die Daten, die wir an die Rückruffunktion übergeben möchten (Benutzerdaten).

Wenn der Detektor ausgelöst wird, erhält die Rückruffunktion die Benutzerdaten, den Zeiger auf den Detektorfilter, die Ereignis-ID und die 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 strukturelle Schema der Signalverarbeitung ist im Titelbild dargestellt.

Nun der eigentliche Programmcodes 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 und starten das Programm. Wenn alles richtig funktioniert, sollten wir nach dem Start ein ungefähr folgendes Verhalten des Programms erhalten:

$ ./mstest4
ALSA lib conf.c:4738:(snd_config_expand) Unbekannte Parameter 0
ALSA lib control.c:954:(snd_ctl_open_noupdate) Ungültiger CTL default:0
ortp-Warnung - Mixer konnte nicht an die Karte angehängt werden: Ungültiges Argument
ALSA lib conf.c:4738:(snd_config_expand) Unbekannte Parameter 0
ALSA lib pcm.c:2266:(snd_pcm_open_noupdate) Unbekannte PCM default:0
ALSA lib conf.c:4738:(snd_config_expand) Unbekannte Parameter 0
ALSA lib pcm.c:2266:(snd_pcm_open_noupdate) Unbekannte PCM default:0
ortp-Warnung - Seltsam, die Soundkarte Intel 82801AA-ICH scheint zu nichts fähig zu sein, versuche es mit plughw erneut...
Drücken Sie die Befehlstaste und dann Eingabetaste.
Um das Programm zu beenden, geben Sie 0 ein.
ortp-Warnung - alsa_set_params: periodsize:256 Benutze 256
ortp-Warnung - alsa_set_params: period:8 Benutze 8

Drücken Sie beliebige Tasten von "1" bis "6" und bestätigen Sie mit der "Enter"-Taste; es sollte ungefähr folgende Ausgabe erscheinen:


2
Befehl gesendet: 2
                      Befehl empfangen: V-
1
Befehl gesendet: 1
                      Befehl empfangen: V+
3
Befehl gesendet: 3
                      Befehl empfangen: C+
4
Befehl gesendet: 4
                      Befehl empfangen: C-
0
$

Wir sehen, dass die Befehltöne erfolgreich gesendet werden und der Detektor sie erkennt.

Im nächsten Artikel werden wir die Übertragung von Audiosignalen über ein Ethernet-Netzwerk mithilfe des RTP-Protokolls behandeln und es sofort in unserer Fernbedienung anwenden.

Quelle: habr.com

60GB SSD 8Gb DDR4