Explorando el motor VoIP de Mediastreamer2. Parte 5

El material del artículo está tomado de mi canal zen.

detector de tono

En el pasado статье Hemos creado un medidor de nivel de señal. En este aprenderemos cómo detectar una señal de tono.

Explorando el motor VoIP de Mediastreamer2. Parte 5

En los viejos tiempos, cuando no todas las familias tenían un televisor y la mitad de ellos cambiaban de canal con unos alicates, en las reseñas de la prensa técnica extranjera aparecían noticias intrigantes de que un fabricante de televisores equipaba sus dispositivos con un control remoto inalámbrico. Por los detalles se supo que el control remoto funcionaba sin baterías gracias al uso de un enfoque inusual: el control remoto era mecánico y era un híbrido de un instrumento musical: un metalófono y un revólver. El tambor del revólver contenía cilindros metálicos de diferentes longitudes, y cuando el percutor golpeó uno de ellos, el cilindro comenzó a sonar a su propia frecuencia. Presumiblemente en ultrasonido. La electrónica del televisor escuchó esta señal y, después de determinar su frecuencia, realizó la acción adecuada: cambiar de canal, cambiar el volumen y apagar el televisor.

Hoy intentaremos reconstruir este sistema de transmisión de comandos, utilizando nuestro conocimiento del transmisor de medios.

Para simular un control remoto, usaremos el texto de nuestro ejemplo de generador de tonos. Le agregaremos el control de la frecuencia del generador mediante pulsaciones de teclas y un receptor con un decodificador que enviará los comandos recibidos a la consola. Tras el cambio, el generador debería producir tonos de 6 frecuencias, con los que codificaremos comandos para subir/bajar volumen, cambiar de canal, encender/apagar el televisor. Para configurar el detector se utiliza la siguiente estructura:

struct _MSToneDetectorDef{  
     char tone_name[8];     
     int frequency; /**<Expected frequency of the tone*/ 
     int min_duration; /**<Min duration of the tone in milliseconds */ 
     float min_amplitude; /**<Minimum amplitude of the tone, 1.0 corresponding to the normalized 0dbm level */
};

typedef struct _MSToneDetectorDef MSToneDetectorDef;

A un detector se le pueden asignar 10 de estas estructuras, por lo que se puede configurar un detector para detectar diez señales de dos tonos. Pero usaremos sólo seis señales de un solo tono. Para transferir la configuración al detector, se utiliza el método MS_TONE_DETECTOR_ADD_SCAN.

Para que el detector nos avise de que ha llegado a su entrada una señal con los componentes de frecuencia deseados, debemos dotarle de una función de devolución de llamada que lanzará en este caso. Esto se hace usando la función ms_filter_set_notify_callback(). Como argumentos, recibe un puntero al filtro, un puntero a la función de devolución de llamada y un puntero a los datos que nos gustaría pasar a la función de devolución de llamada (datos de usuario).

Cuando se activa el detector, la función de devolución de llamada recibirá datos del usuario, un puntero al filtro del detector, un identificador de evento y una estructura que describe el evento:


/** * 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;

El diagrama de bloques del procesamiento de señales se muestra en la imagen del título.

Bueno, ahora el código del programa con comentarios.

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

Compilamos y ejecutamos el programa. Si todo funciona correctamente, después del lanzamiento deberíamos obtener un comportamiento del programa similar a este:

$ ./mstest4
ALSA lib conf.c:4738:(snd_config_expand) Unknown parameters 0
ALSA lib control.c:954:(snd_ctl_open_noupdate) Invalid CTL default:0
ortp-warning-Could not attach mixer to card: Invalid argument
ALSA lib conf.c:4738:(snd_config_expand) Unknown parameters 0
ALSA lib pcm.c:2266:(snd_pcm_open_noupdate) Unknown PCM default:0
ALSA lib conf.c:4738:(snd_config_expand) Unknown parameters 0
ALSA lib pcm.c:2266:(snd_pcm_open_noupdate) Unknown PCM default:0
ortp-warning-Strange, sound card Intel 82801AA-ICH does not seems to be capable of anything, retrying with plughw...
Нажмите клавишу команды, затем ввод.
Для завершения программы введите 0.
ortp-warning-alsa_set_params: periodsize:256 Using 256
ortp-warning-alsa_set_params: period:8 Using 8

Presione cualquier tecla del “1” al “6”, confirmando con la tecla “Enter”, debería obtener algo como este listado:


2
Отправлена команда: 2
                      Принята команда: V-
1
Отправлена команда: 1
                      Принята команда: V+
3
Отправлена команда: 3
                      Принята команда: C+
4
Отправлена команда: 4
                      Принята команда: C-
0
$

Vemos que los tonos de comando se envían con éxito y el detector los detecta.

En el próximo artículo pasaremos a transmitir una señal de audio a través de una red Ethernet utilizando el protocolo RTP y lo aplicaremos inmediatamente en nuestro control remoto.

Fuente: habr.com

Añadir un comentario