Erforschung des VoIP-Engines Mediastreamer2. Teil 5

Der Inhalt dieses Artikels stammt von meinem Zen-Kanal.

Tonsignalsensor

Im letzten Artikel Wir haben einen Signalpegelmesser entwickelt. In diesem Abschnitt lernen wir, wie man ein Tonsignal erkennt.

Erforschung des VoIP-Engines Mediastreamer2. Teil 5

In früheren Zeiten, als nicht jede Familie einen Fernseher hatte und viele von ihnen die Kanäle mit einer Zange umschalteten, erschien in den Berichten ausländischer Fachzeitschriften eine faszinierende Nachricht: Einer der Fernseher-Hersteller stattete seine Geräte mit einer fernbedienbaren drahtlosen Steuerung aus. Aus den Einzelheiten war bekannt, dass die Fernbedienung ohne Batterien funktioniert, dank eines ungewöhnlichen Ansatzes — die Fernbedienung war mechanisch und stellte eine Hybridform eines Musikinstruments — eines Xylophons — und eines Revolvers dar. Im Zylinder des Revolvers befanden sich Metallzylinder, die unterschiedlich lang waren, und als der Hammer einen von ihnen traf, begann der Zylinder mit seiner eigenen Frequenz zu klingen, möglicherweise im Ultraschallbereich. Die Elektronik im Fernseher hörte dieses Signal und führte, nachdem sie die Frequenz bestimmt hatte, die entsprechende Aktion aus — den Kanal wechseln, die Lautstärke ändern oder den Fernseher ausschalten.

Heute werden wir versuchen, dieses System zur Übertragung von Kommandos mithilfe unseres Wissens über Media-Streaming neu zu gestalten.

Um die Fernbedienung zu simulieren, verwenden wir den Text unseres Beispiels für einen Tönungsgenerator. Wir werden die Frequenzsteuerung des Generators über Tastatureingaben hinzufügen und einen Empfänger mit Decoder, der die empfangenen Kommandos in der Konsole ausgibt. Nach der Änderung sollte der Generator Ton.signale mit 6 Frequenzen erzeugen, die wir zum Kodieren von Kommandos zur Lautstärkeregelung, zum Wechseln des Kanals sowie zum Ein- und Ausschalten des Fernsehers verwenden. Für die Einstellung des Detektors wird folgende Struktur verwendet:

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 normalisierten 0dbm Niveau */
};

typedef struct _MSToneDetectorDef MSToneDetectorDef;

An den Detektor können 10 solcher Strukturen übergeben werden, wodurch ein Detektor auf die Erkennung von zehn zweitonalen Signalen eingestellt werden kann. Wir werden jedoch 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, wenn ein Signal mit den gewünschten Frequenzkomponenten an seinem Eingang ankommt, müssen wir ihm eine Callback-Funktion bereitstellen, die in diesem Fall ausgelöst wird. Dies geschieht durch die Funktion ms_filter_set_notify_callback(). Sie erhält als Argumente einen Zeiger auf den Filter, einen Zeiger auf die Callback-Funktion und einen Zeiger auf die Daten, die wir der Callback-Funktion übergeben möchten (Benutzerdaten).

Wenn der Detektor aktiviert wird, erhält die Callback-Funktion die Benutzerdaten, einen Zeiger auf den Detektorfilter, die Ereignis-ID 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 strukturelle Schema der Signalverarbeitung ist im Titelbild dargestellt.

Nun folgt der Programmcode 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 führen das Programm aus. Wenn alles richtig funktioniert, sollten wir nach dem Start ungefähr dieses Verhalten des Programms erhalten:

$ ./mstest4
ALSA-Bibliothek conf.c:4738:(snd_config_expand) Unbekannte Parameter 0
ALSA-Bibliothek control.c:954:(snd_ctl_open_noupdate) Ungültiger CTL default:0
ortp-Warnung-Konnte Mixer nicht an Karte anhängen: Ungültiges Argument
ALSA-Bibliothek conf.c:4738:(snd_config_expand) Unbekannte Parameter 0
ALSA-Bibliothek pcm.c:2266:(snd_pcm_open_noupdate) Unbekannte PCM default:0
ALSA-Bibliothek conf.c:4738:(snd_config_expand) Unbekannte Parameter 0
ALSA-Bibliothek pcm.c:2266:(snd_pcm_open_noupdate) Unbekannte PCM default:0
ortp-Warnung-Komisch, Soundkarte Intel 82801AA-ICH scheint nichts zu können, versuche es mit plughw erneut...
Drücken Sie die Befehlstaste, gefolgt von Enter.
Geben Sie 0 ein, um das Programm zu beenden.
ortp-Warnung-alsa_set_params: periodsize:256 Verwende 256
ortp-Warnung-alsa_set_params: period:8 Verwende 8

Drücken Sie eine beliebige Taste von "1" bis "6", bestätigen Sie mit der Taste "Enter", das sollte ungefähr diese Liste ergeben:


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 befassen wir uns mit der Übertragung von Audiosignalen über das Ethernet-Netzwerk mithilfe des RTP-Protokolls und wenden es direkt in unserer Fernbedienung an.

Quelle: habr.com

Zuverlässiges Webhosting mit DDoS-Schutz, VPS- und VDS-Server kaufen 🔥 Zuverlässiges Webhosting mit DDoS-Schutz, VPS- und VDS-Server kaufen | ProHoster