Entdecken Sie die VoIP-Engine von Mediastreamer2. Teil 2

Das Material des Artikels stammt von mir Zen-Kanal.

Entdecken Sie die VoIP-Engine von Mediastreamer2. Teil 2

Erstellen eines Tongenerators

Im vorigen Artikel Wir haben die Media-Streamer-Bibliothek und Entwicklungstools installiert und ihre Funktionalität getestet, indem wir eine Testanwendung erstellt haben.

Heute erstellen wir eine Anwendung, die ein Tonsignal auf einer Soundkarte erzeugen kann. Um dieses Problem zu lösen, müssen wir die Filter in den unten gezeigten Tongenerator-Schaltkreis einbinden:

Entdecken Sie die VoIP-Engine von Mediastreamer2. Teil 2

Wir lesen das Diagramm von links nach rechts, das ist die Richtung, in die sich unser Datenfluss bewegt. Darauf deuten auch die Pfeile hin. Rechtecke kennzeichnen Filter, die Datenblöcke verarbeiten und das Ergebnis ausgeben. Innerhalb des Rechtecks ​​ist seine Rolle angegeben und der Filtertyp ist in Großbuchstaben direkt darunter angegeben. Die Pfeile, die die Rechtecke verbinden, sind Datenwarteschlangen, über die Datenblöcke von Filter zu Filter geliefert werden. Im Allgemeinen kann ein Filter viele Ein- und Ausgänge haben.

Alles beginnt mit der Taktquelle, die das Tempo festlegt, mit dem Daten in den Filtern berechnet werden. Jeder Filter verarbeitet entsprechend seinem Taktzyklus alle Datenblöcke, die an seinem Eingang anliegen. Und stellt Blöcke mit dem Ergebnis in die Warteschlange. Zuerst führt der Filter, der der Taktquelle am nächsten liegt, Berechnungen durch, dann die an seine Ausgänge angeschlossenen Filter (es können viele Ausgänge sein) und so weiter. Nachdem der letzte Filter in der Kette die Verarbeitung beendet hat, wird die Ausführung angehalten, bis ein neuer Takt eintrifft. Beats folgen standardmäßig einem Intervall von 10 Millisekunden.

Kehren wir zu unserem Diagramm zurück. Die Taktzyklen kommen am Eingang der Ruhequelle an; dabei handelt es sich um einen Filter, der damit beschäftigt ist, an seinem Ausgang für jeden Taktzyklus einen Datenblock mit Nullen zu erzeugen. Wenn wir diesen Block als einen Block von Klangbeispielen betrachten, dann ist dies nichts anderes als Stille. Auf den ersten Blick erscheint es seltsam, Datenblöcke mit Stille zu erzeugen – schließlich ist es nicht zu hören, aber diese Blöcke sind für den Betrieb des Tonsignalgenerators notwendig. Der Generator nutzt diese Blöcke wie ein leeres Blatt Papier und zeichnet darin Klangbeispiele auf. Im Normalzustand ist der Generator ausgeschaltet und leitet Eingangsblöcke einfach an den Ausgang weiter. Somit durchlaufen Stilleblöcke unverändert den gesamten Schaltkreis von links nach rechts und landen schließlich in der Soundkarte. Der stillschweigend Blöcke aus der Warteschlange übernimmt, die mit seinem Eingang verbunden ist.

Aber alles ändert sich, wenn dem Generator der Befehl zum Abspielen von Sound gegeben wird, er beginnt, Sound-Samples zu generieren, diese durch Samples in den Eingabeblöcken zu ersetzen und die geänderten Blöcke am Ausgang abzulegen. Die Soundkarte beginnt mit der Tonwiedergabe. Nachfolgend finden Sie ein Programm, das das oben beschriebene Arbeitsschema implementiert:

/* Файл 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 Taktquelle wird erstellt.

Anschließend müssen Sie die Filter entsprechend unserer Schaltung anschließen und zuletzt die Taktquelle anschließen, da die Schaltung danach sofort in Betrieb geht. Wenn Sie eine Taktquelle an eine unvollendete Schaltung anschließen, kann es passieren, dass der Medienstreamer abstürzt, wenn er erkennt, dass mindestens ein Filter in der Kette alle Eingänge oder alle Ausgänge „in der Luft hängt“ (nicht angeschlossen).

Das Anschließen von Filtern erfolgt über die Funktion

ms_filter_link(src, src_out, dst, dst_in)

Dabei ist das erste Argument ein Zeiger auf den Quellfilter, das zweite Argument ist die Ausgangsnummer der Quelle (beachten Sie, dass Ein- und Ausgänge von Null beginnend nummeriert werden). Das dritte Argument ist ein Zeiger auf den Empfängerfilter, das vierte ist die Empfängereingangsnummer.

Alle Filter sind angeschlossen und die Taktquelle wird zuletzt angeschlossen (im Folgenden nennen wir sie einfach Ticker). Danach beginnt unser Tonkreis zu arbeiten, aber in den Computerlautsprechern ist noch nichts zu hören – der Tongenerator wird ausgeschaltet und durchläuft einfach die Eingangsdatenblöcke mit Stille. Um mit der Erzeugung eines Tons zu beginnen, müssen Sie die Generatorfiltermethode ausführen.

Wir erzeugen ein Zweitonsignal (DTMF), das dem Drücken der Taste „1“ am Telefon entspricht. Dazu nutzen wir die Funktion ms_filter_call_method() Wir rufen die Methode MS_DTMF_GEN_PLAY auf und übergeben ihr als Argument einen Zeiger auf den Code, dem das Wiedergabesignal entsprechen soll.

Jetzt muss nur noch das Programm kompiliert werden:

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

Und Renn:

$ ./mstest2

Nach dem Start des Programms hören Sie im Lautsprecher des Computers ein kurzes Tonsignal, bestehend aus zwei Tönen.

Wir haben unsere erste Tonschaltung gebaut und auf den Markt gebracht. Wir haben gesehen, wie man Filterinstanzen erstellt, wie man sie verbindet und wie man ihre Methoden aufruft. Obwohl wir mit unserem anfänglichen Erfolg zufrieden sind, müssen wir dennoch darauf achten, dass unser Programm den zugewiesenen Speicher vor dem Beenden nicht freigibt. Im nächsten Artikel Wir werden lernen, hinter uns selbst aufzuräumen.

Source: habr.com

Kommentar hinzufügen