Eksplorimi i motorit VoIP Mediastreamer2. Pjesa 5

Materiali i artikullit është marrë nga ime kanal zen.

Detektor toni

Në të fundit artikull Ne kemi krijuar një matës të nivelit të sinjalit. Në këtë do të mësojmë se si të zbulojmë një sinjal toni.

Eksplorimi i motorit VoIP Mediastreamer2. Pjesa 5

Në kohët e vjetra, kur jo çdo familje kishte një televizor dhe gjysma e tyre ndërronin kanalet duke përdorur pincë, në rishikimet e shtypit teknik të huaj u shfaqën një lajm intrigues se një prodhues i televizorit i kishte pajisur pajisjet e tyre me një telekomandë me valë. Nga detajet u bë e ditur se telekomanda funksiononte pa bateri falë përdorimit të një qasjeje të pazakontë - telekomanda ishte mekanike dhe ishte një hibrid i një instrumenti muzikor - një metalofoni dhe një revolver. Tamburi i revolverit përmbante cilindra metalikë me gjatësi të ndryshme dhe kur kunja e qitjes goditi njërin prej tyre, cilindri filloi të kumbonte me frekuencën e vet. Me sa duket në ultratinguj. Elektronika në televizor e dëgjoi këtë sinjal dhe, pasi përcaktoi frekuencën e tij, kreu veprimin e duhur - ndërroni kanalin, ndryshoni volumin, fikni televizorin.

Sot do të përpiqemi të rindërtojmë këtë sistem transmetimi komandues, duke përdorur njohuritë tona për transmetuesin e medias.

Për të simuluar një telekomandë, ne do të përdorim tekstin e shembullit të gjeneratorit tonë të tonit. Ne do t'i shtojmë atij kontrollin e frekuencës së gjeneratorit nga goditjet e tasteve dhe një marrës me një dekoder që do të nxjerrë komandat e marra në tastierë. Pas ndryshimit, gjeneratori duhet të prodhojë tone me 6 frekuenca, me të cilat do të kodojmë komandat për rritjen/uljen e volumit, ndryshimin e kanalit, ndezjen/fikjen e televizorit. Për të konfiguruar detektorin, përdoret struktura e mëposhtme:

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;

Një detektori mund t'i jepet 10 prej këtyre strukturave, kështu që një detektor mund të konfigurohet për të zbuluar dhjetë sinjale me dy ngjyra. Por ne do të përdorim vetëm gjashtë sinjale me një ton. Për të transferuar cilësimet në detektor, përdoret metoda MS_TONE_DETECTOR_ADD_SCAN.

Në mënyrë që detektori të na njoftojë se një sinjal me përbërësit e frekuencës së dëshiruar ka mbërritur në hyrjen e tij, duhet t'i sigurojmë atij një funksion kthimi të thirrjes që do të nisë në këtë rast. Kjo bëhet duke përdorur funksionin ms_filter_set_notify_callback(). Si argumente, ai merr një tregues në filtrin, një tregues për funksionin e kthimit të thirrjes dhe një tregues për të dhënat që do të donim t'i kalonim funksionit të kthimit të thirrjes (të dhënat e përdoruesit).

Kur aktivizohet detektori, funksioni i kthimit të thirrjes do të marrë të dhënat e përdoruesit, një tregues në filtrin e detektorit, një identifikues të ngjarjes dhe një strukturë që përshkruan ngjarjen:


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

Blloku i përpunimit të sinjalit tregohet në foton e titullit.

Epo, tani vetë kodi i programit me komente.

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

Ne përpilojmë dhe ekzekutojmë programin. Nëse gjithçka funksionon si duhet, atëherë pas nisjes duhet të marrim diçka si kjo sjellje e programit:

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

Shtypni çdo çelës nga "1" në "6", duke konfirmuar me tastin "Enter", duhet të merrni diçka si kjo listë:


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

Ne shohim që tonet e komandës dërgohen me sukses dhe detektori i zbulon ato.

Në artikullin tjetër do t'i drejtohemi transmetimit të një sinjali audio përmes një rrjeti Ethernet duke përdorur protokollin RTP dhe do ta zbatojmë menjëherë në telekomandën tonë.

Burimi: www.habr.com

Shto një koment