Explorant el motor de VoIP Mediastreamer2. Part 5

El material de l'article està extret del meu canal zen.

Detector de to

En l'últim article Hem creat un mesurador de nivell de senyal. En aquest aprendrem a detectar un senyal de to.

Explorant el motor de VoIP Mediastreamer2. Part 5

Antigament, quan no totes les famílies tenien un televisor i la meitat d'elles canviaven de canal amb unes pinces, a les revisions de la premsa tècnica estrangera van aparèixer notícies intrigants que un fabricant de televisors equipava els seus dispositius amb un comandament a distància sense fil. Pels detalls se sabia que el comandament a distància funcionava sense piles gràcies a l'ús d'un enfocament inusual -el comandament a distància era mecànic i era un híbrid d'un instrument musical- un metal·lòfon i un revòlver. El tambor del revòlver contenia cilindres metàl·lics de diferents longituds, i quan el percutor va colpejar un d'ells, el cilindre va començar a sonar amb la seva pròpia freqüència. Presumiblement a l'ecografia. L'electrònica del televisor va sentir aquest senyal i, després d'haver determinat la seva freqüència, va realitzar l'acció adequada: canviar el canal, canviar el volum, apagar el televisor.

Avui intentarem reconstruir aquest sistema de transmissió d'ordres, utilitzant els nostres coneixements de la transmissió multimèdia.

Per simular un comandament a distància, utilitzarem el text del nostre exemple de generador de tons. Hi afegirem el control de la freqüència del generador a partir de les pulsacions de tecles i un receptor amb un descodificador que enviarà les ordres rebudes a la consola. Després del canvi, el generador hauria de produir tons de 6 freqüències, amb els quals codificarem ordres per augmentar/baixar el volum, canviar de canal, encendre/apagar el televisor. Per configurar el detector, s'utilitza l'estructura següent:

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;

Es pot donar a un detector 10 d'aquestes estructures, de manera que es pot configurar un detector per detectar deu senyals de dos tons. Però utilitzarem només sis senyals d'un sol to. Per transferir la configuració al detector, s'utilitza el mètode MS_TONE_DETECTOR_ADD_SCAN.

Perquè el detector ens notifique que ha arribat a la seva entrada un senyal amb els components de freqüència desitjats, hem de proporcionar-li una funció de devolució de trucada que posarà en marxa en aquest cas. Això es fa mitjançant la funció ms_filter_set_notify_callback(). Com a arguments, rep un punter al filtre, un punter a la funció de devolució de trucada i un punter a les dades que voldríem passar a la funció de devolució de trucada (dades d'usuari).

Quan s'activa el detector, la funció de devolució de trucada rebrà dades d'usuari, un punter al filtre del detector, un identificador d'esdeveniment i una estructura que descriu l'esdeveniment:


/** * 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 blocs del processament del senyal es mostra a la imatge del títol.

Bé, ara el codi del programa en si amb comentaris.

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

Compilem i executem el programa. Si tot funciona correctament, després del llançament hauríem d'obtenir alguna cosa com aquest comportament del programa:

$ ./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

Premeu qualsevol tecla de "1" a "6", confirmant amb la tecla "Enter", hauríeu d'obtenir alguna cosa com aquesta llista:


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

Veiem que els tons d'ordre s'envien correctament i el detector els detecta.

En el següent article passarem a transmetre un senyal d'àudio a través d'una xarxa Ethernet mitjançant el protocol RTP i aplicar-lo immediatament al nostre comandament a distància.

Font: www.habr.com

Afegeix comentari