Explorando el motor VoIP Mediastreamer2. Parte 2

El material del artículo fue tomado de mi canal de Zen.

Explorando el motor VoIP Mediastreamer2. Parte 2

Creando un generador tonal

En el anterior el artículo Hemos realizado la instalación de la biblioteca de MEDIAstreamer, las herramientas de desarrollo y hemos verificado su funcionamiento, creando una aplicación de prueba.

Hoy crearemos una aplicación que podrá emitir un tono a través de la tarjeta de sonido. Para resolver esta tarea, necesitamos conectar los filtros en el esquema de generador de sonido que se muestra a continuación:

Explorando el motor VoIP Mediastreamer2. Parte 2

Leemos el esquema de izquierda a derecha, esta es la dirección en la que fluye el flujo de datos. Las flechas también sugieren esto. Los rectángulos representan los filtros que procesan los bloques de datos y presentan el resultado en la salida. Dentro del rectángulo se indica su función y un poco más abajo, en letras mayúsculas, el tipo de filtro. Las flechas que conectan los rectángulos son colas de datos, a través de las cuales se entregan los bloques de datos de un filtro a otro. En general, un filtro puede tener múltiples entradas y salidas.

Todo comienza con la fuente de pulsos, que establece el ritmo en el que se procesan los datos en los filtros. Con cada pulso, cada filtro procesa todos los bloques de datos que tiene en su entrada. Y coloca los bloques de resultados en la salida — en la cola. Primero, el filtro más cercano a la fuente de pulsos realiza el procesamiento, luego los filtros conectados a sus salidas (puede haber muchas salidas) y así sucesivamente. Después de que el último filtro de la cadena termine de procesar, la ejecución se detiene hasta que llegue un nuevo pulso. Por defecto, los pulsos siguen a intervalos de 10 milisegundos.

Regresamos a nuestro esquema. Los pulsos llegan a la entrada de la fuente de silencio, que es un filtro que genera en su salida, en cada pulso, un bloque de datos que contiene ceros. Si consideramos este bloque como un bloque de muestras de sonido, no es otra cosa que silencio. A simple vista parece extraño generar bloques de datos con silencio, ya que no se puede escuchar, sin embargo, estos bloques son necesarios para el funcionamiento del generador de señales sonoras. El generador utiliza estos bloques como una hoja en blanco, grabando en ellos muestras de sonido. En su estado normal, el generador está apagado y simplemente pasa los bloques de entrada a la salida. Así, los bloques de silencio pasan sin cambios a lo largo del esquema de izquierda a derecha, llegando a la tarjeta de sonido, que silenciosamente toma los bloques de la cola conectada a su entrada.

Pero todo cambia si el generador recibe la orden de reproducir sonido; comienza a generar muestras sonoras y reemplaza las muestras en los bloques de entrada, colocando los bloques modificados en la salida. La tarjeta de sonido empieza a reproducir sonido. A continuación se presenta el programa que implementa el esquema de trabajo descrito anteriormente:

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

Después de inicializar el medio streamer, se crean tres filtros: voidsource, dtmfgen, snd_card_write. Se crea una fuente de señal de reloj.

Luego es necesario conectar los filtros de acuerdo con nuestro esquema, conectando la fuente de reloj al final, ya que después de eso, el esquema comenzará a funcionar de inmediato. Si se conecta la fuente de reloj a un esquema incompleto, puede suceder que el medio streamer finalice abruptamente si detecta en la cadena al menos un filtro cuyos todas las entradas o todas las salidas 'cuelguen en el aire' (no estén conectadas).

La conexión de los filtros se realiza mediante la función

ms_filter_link(src, src_out, dst, dst_in)

donde el primer argumento es un puntero al filtro fuente, el segundo argumento es el número de salida de la fuente (ten en cuenta que las entradas y salidas se numeran desde cero). El tercer argumento es un puntero al filtro receptor, y el cuarto es el número de entrada del receptor.

Todos los filtros están conectados y el último es la fuente de ticks (que a partir de ahora simplemente llamaremos ticker). Después de esto, nuestro esquema de sonido se activa, pero en los altavoces del ordenador todavía no se escucha nada: el generador de sonido está apagado y simplemente pasa a través de sí mismo los bloques de datos de entrada en silencio. Para iniciar la generación de una señal tonal, es necesario ejecutar el método del filtro del generador.

Vamos a generar una señal DTMF de doble tono correspondiente a la pulsación del botón "1" en el teléfono. Para ello, utilizaremos la función ms_filter_call_method() llamando al método MS_DTMF_GEN_PLAY, pasando como argumento un puntero al código que debe corresponder a la señal que se está reproduciendo.

Solo queda compilar el programa:

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

Y ejecutarlo:

$ ./mstest2

Una vez que el programa esté en funcionamiento, escuchará un corto tono sonoro en los altavoces del ordenador que consiste en dos tonos.

Hemos construido y activado nuestro primer esquema de sonido. Hemos visto cómo crear instancias de filtros, cómo conectarlos y cómo invocar sus métodos. Luego de celebrar este primer éxito, debemos prestar atención a que nuestra programa no libera la memoria asignada antes de finalizar. En la siguiente el artículo aprenderemos a limpiar detrás de nosotros.

Fuente: habr.com

Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS 🔥 Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS | ProHoster