Istraživanje Mediastreamer2 VoIP motora. Dio 5

Materijal članka je preuzet sa mog zen kanal.

Tonski detektor

U poslednjem članak Napravili smo mjerač nivoa signala. U ovom ćemo naučiti kako detektirati tonski signal.

Istraživanje Mediastreamer2 VoIP motora. Dio 5

U stara vremena, kada nije svaka porodica imala televizor, a polovina ih je prebacivala kanale pomoću kliješta, u recenzijama strane tehničke štampe pojavile su se intrigantne vijesti da je jedan proizvođač televizora opremio svoje uređaje bežičnim daljinskim upravljačem. Iz detalja se znalo da je daljinski upravljač radio bez baterija zahvaljujući upotrebi neobičnog pristupa - daljinski upravljač je bio mehanički i bio je hibrid muzičkog instrumenta - metalofona i revolvera. Bubanj revolvera sadržavao je metalne cilindre različite dužine, a kada je udarna igla udarila u jedan od njih, cilindar je počeo da zvoni svojom frekvencijom. Vjerovatno na ultrazvuku. Elektronika u televizoru je čula ovaj signal i, nakon što je odredila njegovu frekvenciju, izvršila odgovarajuću radnju - prebacite kanal, promijenite glasnoću, isključite TV.

Danas ćemo pokušati da rekonstruišemo ovaj sistem prenosa komandi, koristeći naše znanje o medijskom strimeru.

Da bismo simulirali daljinski upravljač, koristit ćemo tekst našeg primjera generatora tona. Dodaćemo mu kontrolu frekvencije generatora od pritiska na tastere i prijemnik sa dekoderom koji će emitovati primljene komande na konzolu. Nakon promjene, generator bi trebao proizvoditi tonove od 6 frekvencija, kojima ćemo kodirati komande za povećanje/smanjenje jačine zvuka, promjenu kanala, uključivanje/isključivanje TV-a. Za konfiguraciju detektora koristi se sljedeća struktura:

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;

Detektoru se može dati 10 ovih struktura, tako da se jedan detektor može konfigurirati da detektuje deset dvotonskih signala. Ali mi ćemo koristiti samo šest jednotonskih signala. Za prijenos postavki na detektor koristi se metoda MS_TONE_DETECTOR_ADD_SCAN.

Kako bi nas detektor obavijestio da je na njegov ulaz stigao signal sa željenim frekvencijskim komponentama, moramo mu obezbijediti callback funkciju koju će u tom slučaju pokrenuti. Ovo se radi pomoću funkcije ms_filter_set_notify_callback(). Kao argumente, prima pokazivač na filter, pokazivač na funkciju povratnog poziva i pokazivač na podatke koje bismo željeli proslijediti funkciji povratnog poziva (korisnički podaci).

Kada se detektor aktivira, funkcija povratnog poziva će primiti korisničke podatke, pokazivač na filter detektora, identifikator događaja i strukturu koja opisuje događaj:


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

Blok dijagram obrade signala prikazan je na naslovnoj slici.

Pa, sada sam programski kod s komentarima.

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

Sastavljamo i pokrećemo program. Ako sve radi kako treba, onda bi nakon pokretanja trebali dobiti nešto poput ovakvog ponašanja 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

Pritisnite bilo koju tipku od “1” do “6”, potvrđujući tipkom “Enter”, trebalo bi da dobijete nešto poput ove liste:


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

Vidimo da su tonovi naredbi uspješno poslani i detektor ih detektuje.

U sljedećem članku ćemo se okrenuti prijenosu audio signala preko Ethernet mreže koristeći RTP protokol i odmah ga primijeniti u našem daljinskom upravljaču.

izvor: www.habr.com

Dodajte komentar