Истраживање Медиастреамер2 ВоИП механизма. Део 5

Материјал чланка је преузет са мог зен канал.

Детектор тона

У последњих Чланак Направили смо мерач нивоа сигнала. У овом ћемо научити како да детектујемо тонски сигнал.

Истраживање Медиастреамер2 ВоИП механизма. Део 5

У стара времена, када није свака породица имала телевизор, а половина њих мењала канале помоћу клешта, у рецензијама стране техничке штампе појавиле су се интригантне вести да је један произвођач телевизора опремио своје уређаје бежичним даљинским управљачем. Из детаља се знало да је даљински управљач радио без батерија захваљујући употреби необичног приступа - даљински управљач је био механички и представљао је хибрид музичког инструмента - металофона и револвера. У бубњу револвера налазили су се метални цилиндри различите дужине, а када је ударна игла ударила у један од њих, цилиндар је почео да звони на сопственој фреквенцији. Вероватно на ултразвуку. Електроника у телевизору је чула овај сигнал и, након што је одредила његову фреквенцију, извршила одговарајућу акцију - пребаците канал, промените јачину звука, искључите ТВ.

Данас ћемо покушати да реконструишемо овај систем преноса команди, користећи наше знање о медијском стримеру.

Да бисмо симулирали даљински управљач, користићемо текст нашег примера генератора тона. Додаћемо му контролу фреквенције генератора притиском на тастере и пријемник са декодером који ће емитовати примљене команде на конзолу. Након промене, генератор треба да производи тонове од 6 фреквенција, којима ћемо кодирати команде за повећање/смањење јачине звука, промену канала, укључивање/искључивање телевизора. За конфигурисање детектора користи се следећа структура:

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;

Детектору се може дати 10 ових структура, тако да се један детектор може конфигурисати да детектује десет двотонских сигнала. Али користићемо само шест једнотонских сигнала. За пренос подешавања на детектор користи се метода МС_ТОНЕ_ДЕТЕЦТОР_АДД_СЦАН.

Да би нас детектор обавестио да је на његов улаз стигао сигнал са жељеним фреквентним компонентама, морамо му обезбедити цаллбацк функцију коју ће у овом случају покренути. Ово се ради помоћу функције мс_филтер_сет_нотифи_цаллбацк(). Као аргументе, прима показивач на филтер, показивач на функцију повратног позива и показивач на податке које желимо да проследимо функцији повратног позива (кориснички подаци).

Када се детектор активира, функција повратног позива ће примити корисничке податке, показивач на филтер детектора, идентификатор догађаја и структуру која описује догађај:


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

Блок шема обраде сигнала је приказана на насловној слици.

Па, сада сам програмски код са коментарима.

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

Састављамо и покрећемо програм. Ако све ради како треба, онда би након покретања требало да добијемо нешто попут оваквог понашања програма:

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

Притисните било који тастер од "1" до "6", потврђујући тастером "Ентер", требало би да добијете нешто попут ове листе:


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

Видимо да су командни тонови успешно послати и детектор их детектује.

У следећем чланку ћемо се окренути преносу аудио сигнала преко Етхернет мреже користећи РТП протокол и одмах га применити у нашем даљинском управљачу.

Извор: ввв.хабр.цом

Додај коментар