Wir beschäftigen uns mit dem VoIP-Engine Mediastreamer2. Teil 2

Der Artikelinhalt stammt von meinem Zen-Kanal.

Wir beschäftigen uns mit dem VoIP-Engine Mediastreamer2. Teil 2

Wir erstellen einen Tonfrequenzgenerator

Im vorherigen Artikel Wir haben die MediaStreamer-Bibliothek, Entwicklungswerkzeuge installiert und deren Funktionalität geprüft, indem wir eine Testanwendung erstellt haben.

Heute werden wir eine Anwendung erstellen, die in der Lage ist, ein Tonsignal auf der Soundkarte zu erzeugen. Um diese Aufgabe zu lösen, müssen wir die Filter in das unten gezeigte Schema des Klanggenerators einspeisen:

Wir beschäftigen uns mit dem VoIP-Engine Mediastreamer2. Teil 2

Wir lesen das Schema von links nach rechts, in dieser Richtung fließt der Datenstrom. Pfeile deuten auch darauf hin. Rechtecke stehen für Filter, die Datenblöcke verarbeiten und das Ergebnis ausgeben. Innerhalb des Rechtecks ist seine Rolle angegeben, und etwas darunter steht in Großbuchstaben der Typ des Filters. Die Pfeile, die die Rechtecke verbinden, sind Datenwarteschlangen, über die Datenblöcke von Filter zu Filter transportiert werden. Im Allgemeinen kann ein Filter viele Eingänge und Ausgänge haben.

Alles beginnt mit der Taktquelle, die das Tempo festlegt, in dem die Daten in den Filtern verarbeitet werden. Nach ihrem Takt verarbeitet jeder Filter alle Datenblöcke, die sich an seinem Eingang befinden. Es gibt die verarbeiteten Blöcke als Ergebnis aus – in die Warteschlange. Zuerst verarbeitet der Filter, der der Taktquelle am nächsten ist, dann die Filter, die mit seinen Ausgängen verbunden sind (es kann viele Ausgänge geben), und so weiter. Nachdem der letzte Filter in der Kette die Verarbeitung abgeschlossen hat, wird die Ausführung gestoppt, bis ein neuer Takt eingeht. Die Takte folgen standardmäßig in Intervallen von 10 Millisekunden.

Kehren wir zu unserem Schema zurück. Taktimpulse gelangen an den Eingang der Stillequelle, dies ist ein Filter, der damit beschäftigt ist, für jeden Takt am Ausgang einen Datenblock aus Nullen zu generieren. Wenn man diesen Block als Block von Audiodaten betrachtet, ist es nichts anderes als Stille. Auf den ersten Blick scheint es merkwürdig, Datenblöcke mit Stille zu generieren - schließlich kann man sie nicht hören, aber diese Blöcke sind notwendig für die Funktion des Audiogenerators. Der Generator nutzt diese Blöcke wie ein leeres Blatt Papier, um Audiodaten darin aufzuzeichnen. Im normalen Zustand ist der Generator ausgeschaltet und leitet einfach die Eingangsblöcke nach außen weiter. So durchlaufen die Stilleblöcke unverändert das gesamte Schema von links nach rechts und gelangen zur Soundkarte, die geräuschlos Blöcke von der an ihren Eingang angeschlossenen Warteschlange abholt.

Doch alles ändert sich, wenn der Generator ein Signal zum Abspielen von Sound erhält. Er beginnt, Audiodaten zu erzeugen und ersetzt diese in den Eingangsblöcken und gibt die veränderten Blöcke nach außen weiter. Die Soundkarte beginnt, den Sound abzuspielen. Im Folgenden ist das Programm aufgeführt, das das oben beschriebene Schema umsetzt:

/* Файл mstest2.c */
#include <mediastreamer2/msfilter.h>
#include <mediastreamer2/msticker.h>
#include <mediastreamer2/dtmfgen.h>
#include <mediastreamer2/mssndcard.h>
int main()
{
    ms_init();

    /* Создаем экземпляры фильтров. */
    MSFilter  *voidsource = ms_filter_new(MS_VOID_SOURCE_ID);
    MSFilter  *dtmfgen = ms_filter_new(MS_DTMF_GEN_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);

    /* Создаем тикер. */
    MSTicker *ticker = ms_ticker_new();

    /* Соединяем фильтры в цепочку. */
    ms_filter_link(voidsource, 0, dtmfgen, 0);
    ms_filter_link(dtmfgen, 0, snd_card_write, 0);

   /* Подключаем источник тактов. */
   ms_ticker_attach(ticker, voidsource);

   /* Включаем звуковой генератор. */
   char key='1';
   ms_filter_call_method(dtmfgen, MS_DTMF_GEN_PLAY, (void*)&key);

   /* Даем, время, чтобы все блоки данных были получены звуковой картой.*/
   ms_sleep(2);   
}

Nach der Initialisierung des Medienstreamers werden drei Filter erstellt: voidsource, dtmfgen, snd_card_write. Eine Quelle für das Taktsignal wird erstellt.

Dann muss die Verbindung der Filter gemäß unserem Schema hergestellt werden, wobei die Taktsignalquelle zuletzt angeschlossen wird, da danach sofort der Betrieb des Schemas beginnt. Wenn die Taktsignalquelle an ein unvollendetes Schema angeschlossen wird, kann es passieren, dass der Medienstreamer abstürzt, wenn er auch nur einen Filter in der Kette entdeckt, dessen Eingänge oder Ausgänge "in der Luft hängen" (nicht angeschlossen sind).

Die Verbindung der Filter erfolgt mit der Funktion

ms_filter_link(src, src_out, dst, dst_in)

wobei das erste Argument ein Zeiger auf den Quellfilter ist, das zweite Argument - die Nummer des Ausgangs des Filters (beachten Sie, dass die Eingänge und Ausgänge ab null nummeriert werden). Das dritte Argument ist ein Zeiger auf den Empfangsfilter, das vierte - die Nummer des Eingangs des Empfängers.

Alle Filter sind verbunden, und der Taktgeber (nachfolgend einfach als Ticker bezeichnet) wird zuletzt angeschlossen. Danach wird unser Audio-Schema aktiviert, jedoch ist aus den Lautsprechern des Computers zunächst nichts zu hören — der Klanggenerator ist ausgeschaltet und leitet lediglich die Eingangsdatenblöcke mit Stille weiter. Um die Erzeugung eines tonalen Signals zu starten, muss die Methode des Generators aufgerufen werden.

Wir werden ein zweitonales (DTMF) Signal generieren, das dem Drücken der Taste "1" auf dem Telefon entspricht. Dazu verwenden wir die Funktion ms_filter_call_method() rufen wir die Methode MS_DTMF_GEN_PLAY auf und übergeben ihr als Argument einen Zeiger auf den Code, dem das wiederzugebende Signal entsprechen soll.

Jetzt bleibt nur noch, das Programm zu kompilieren:

$ gcc mstest2.c -o mstest2 `pkg-config mediastreamer --libs --cflags`

Und es zu starten:

$ ./mstest2

Nach dem Start des Programms hören Sie einen kurzen Klangsignal aus den Lautsprechern des Computers, der aus zwei Tönen besteht.

Wir haben unser erstes Audio-Schema zusammengestellt und in Betrieb genommen. Wir haben gesehen, wie man Filterinstanzen erstellt, wie man sie verbindet und wie man ihre Methoden aufruft. Nach diesem ersten Erfolg sollten wir jedoch darauf achten, dass unser Programm den zugewiesenen Speicher vor dem Beenden nicht freigibt. In der nächsten Artikel werden wir lernen, aufzuräumen.

Quelle: habr.com

60GB SSD 8Gb DDR4