Esplorare il motore VoIP di Mediastreamer2. Parte 2

Il materiale dell'articolo è tratto dal mio canale zen.

Esplorare il motore VoIP di Mediastreamer2. Parte 2

Creazione di un generatore di suoni

Nel precedente Articolo Abbiamo installato la libreria di streaming multimediale, gli strumenti di sviluppo e ne abbiamo testato la funzionalità creando un'applicazione di prova.

Oggi creeremo un'applicazione in grado di generare un segnale sonoro su una scheda audio. Per risolvere questo problema dobbiamo collegare i filtri al circuito del generatore sonoro mostrato di seguito:

Esplorare il motore VoIP di Mediastreamer2. Parte 2

Leggiamo il diagramma da sinistra a destra, questa è la direzione in cui si muove il nostro flusso di dati. Anche le frecce lo suggeriscono. I rettangoli indicano filtri che elaborano blocchi di dati e restituiscono il risultato. All'interno del rettangolo è indicato il suo ruolo e il tipo di filtro è indicato in maiuscolo appena sotto. Le frecce che collegano i rettangoli sono code di dati attraverso le quali i blocchi di dati vengono consegnati da un filtro all'altro. In generale, un filtro può avere molti ingressi e uscite.

Tutto inizia con la sorgente clock, che imposta il tempo con cui i dati vengono calcolati nei filtri. Ogni filtro elabora in base al suo ciclo di clock tutti i blocchi di dati che si trovano al suo ingresso. E mette in coda i blocchi con il risultato. Innanzitutto, il filtro più vicino alla sorgente del clock esegue i calcoli, quindi i filtri collegati alle sue uscite (possono esserci molte uscite) e così via. Una volta terminata l'elaborazione dell'ultimo filtro nella catena, l'esecuzione si interrompe fino all'arrivo di un nuovo orologio. Per impostazione predefinita, i battiti seguono un intervallo di 10 millisecondi.

Torniamo al nostro diagramma. I cicli di clock arrivano all'ingresso della sorgente di silenzio; questa è un filtro, che è impegnato a generare un blocco di dati contenente zeri in uscita per ogni ciclo di clock. Se consideriamo questo blocco come un blocco di campioni sonori, questo non è altro che silenzio. A prima vista, sembra strano generare blocchi di dati con il silenzio - dopo tutto, non si sente, ma questi blocchi sono necessari per il funzionamento del generatore di segnali sonori. Il generatore utilizza questi blocchi come un foglio di carta bianco, registrandovi campioni sonori. Nel suo stato normale, il generatore è spento e inoltra semplicemente i blocchi di input all'output. Così, i blocchi di silenzio percorrono inalterati l'intero circuito da sinistra a destra, finendo nella scheda audio. Che prende silenziosamente i blocchi dalla coda connessa al suo input.

Ma tutto cambia se al generatore viene dato il comando di riprodurre il suono, inizia a generare campioni sonori e li sostituisce con campioni nei blocchi di input e inserisce i blocchi modificati in output. La scheda audio inizia a riprodurre l'audio. Di seguito è riportato un programma che implementa lo schema di lavoro sopra descritto:

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

Dopo aver inizializzato il media streamer, vengono creati tre filtri: voidsource, dtmfgen, snd_card_write. Viene creata una sorgente di clock.

Quindi è necessario collegare i filtri secondo il nostro circuito e la sorgente dell'orologio deve essere collegata per ultima, poiché dopodiché il circuito inizierà immediatamente a funzionare. Se si collega una sorgente di clock a un circuito incompleto, può accadere che il media streamer si blocchi se rileva almeno un filtro nella catena con tutti gli ingressi o tutte le uscite “sospesi in aria” (non collegati).

Il collegamento dei filtri viene effettuato utilizzando la funzione

ms_filter_link(src, src_out, dst, dst_in)

dove il primo argomento è un puntatore al filtro sorgente, il secondo argomento è il numero dell'output sorgente (nota che input e output sono numerati a partire da zero). Il terzo argomento è un puntatore al filtro del ricevitore, il quarto è il numero di input del ricevitore.

Tutti i filtri sono collegati e la sorgente orologio viene collegata per ultima (d'ora in avanti la chiameremo semplicemente ticker). Dopodiché il nostro circuito audio inizia a funzionare, ma non si sente ancora nulla negli altoparlanti del computer: il generatore di suoni è spento e passa semplicemente attraverso i blocchi di dati di input in silenzio. Per iniziare a generare un tono, è necessario eseguire il metodo del filtro del generatore.

Genereremo un segnale bitonale (DTMF) corrispondente alla pressione del pulsante "1" sul telefono. Per fare ciò utilizziamo la funzione ms_filter_call_method() Chiamiamo il metodo MS_DTMF_GEN_PLAY, passandogli come argomento un puntatore al codice a cui dovrebbe corrispondere il segnale di riproduzione.

Non resta che compilare il programma:

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

E corri:

$ ./mstest2

Dopo aver avviato il programma, sentirai un breve segnale acustico composto da due toni nell'altoparlante del computer.

Abbiamo costruito e lanciato il nostro primo circuito audio. Abbiamo visto come creare istanze di filtro, come collegarle e come richiamare i loro metodi. Anche se siamo soddisfatti del nostro successo iniziale, dobbiamo comunque prestare attenzione al fatto che il nostro programma non libera la memoria allocata prima di uscire. Nel prossimo Articolo impareremo a ripulire noi stessi.

Fonte: habr.com

Aggiungi un commento