Mediastreamer2 VoIP mühərrikini öyrənirik. 5-ci hissə

Məqalənin materialı mənim zen-kanalımdan.

Ton siqnalını aşkar edən cihaz

Keçən dəfə makalede biz siqnal səviyyəsini ölçən cihaz yaratdıq. Bu dəfə ton siqnalını aşkar etməyi öyrənəcəyik.

Mediastreamer2 VoIP mühərrikini öyrənirik. 5-ci hissə

Keçmişdə, hər bir evdə televizor olmadığı zaman, və onların yarısında kanallar cütlənən açarlarla dəyişdirilərkən, xarici texnologiya mətbuatında bir istehsalçının televizorlarını uzaqdan idarə etmə pultu ilə təmin etdiyinə dair maraqlı bir xəbərə rast gəlinmişdi. Ətraflı məlumata görə, pult batareya olmadan işləyirdi, çünki qeyri-adi bir yanaşma istifadə olunurdu — pult mexaniki idi və musiqi aləti olan metalofonla revolverin bir hibridi kimi görünürdü. Revolverin barabanında müxtəlif uzunluqlarda metal silindrlər var idi və hamarlanan çubuq onlardan birinə vurduğunda, silindr öz frekansında zəng çalmağa başlayırdı. İddia olunurdu ki, bu, ultrasəs dalğaları ilə olur. Televizordakı elektronika bu siqnalı eşidirdi və onun frekansını müəyyən edərək uyğun hərəkəti yerinə yetirirdi — kanal dəyişdirmək, səs düzəlişi etmək, televizoru söndürmək.

Bu gün bu komanda göndərmə sisteminin bərpasını etməyə çalışacağıq, mediastreamer biliklərimizdən istifadə edərək.

Pultu imita etmək üçün ton generatorunun mətnindən istifadə edəcəyik. Biz ona klaviaturada basma ilə generatorun frekansını idarə etməyi və qəbul edicinin dekoderi ilə, qəbul edilmiş komandaları konsola çıxaracaq bir qurğu əlavə edəcəyik. Dəyişiklikdən sonra generator, səsin artırılması/azaldılması, kanal dəyişikliyi, televizoru açma/söndürmə komandalarını kodlayacağımız 6 ton siqnalı verməlidir. Detektoru tənzimləmək üçün aşağıdakı strukturu istifadə edirik:

struct _MSToneDetectorDef{  
     char tone_name[8];     
     int frequency; 
     /**<Gözlənilən tonun frekansı*\/ 
     int min_duration; 
     /**<Tonun minimum müddəti millisekundlarla *\/ 
     float min_amplitude; 
     /**<Tonun minimum amplitudu, 1.0 normalize edilmiş 0dbm səviyyəsinə müvafiqdir *\/ 
};

typedef struct _MSToneDetectorDef MSToneDetectorDef;

Detektor 10 belə strukturu qəbul edə bilər, bu da bir detektorun on iki ton siqnalını aşkar etməyə ayarlana biləcəyini bildirir. Ancaq biz yalnız altı bir tonlu siqnal istifadə edəcəyik. Detektora parametrləri ötürmək üçün MS_TONE_DETECTOR_ADD_SCAN metodundan istifadə olunur.

Detektorun bizə məsələn, girişinə uyğun frekans komponentləri olan siqnal gəldikdə xəbər verməsi üçün ona geri çağırma funksiyası təqdim etməliyik. Bu, ms_filter_set_notify_callback()funksiyası ilə edilir. Əsas arqumentlər olaraq filtrə işarə, geri çağırma funksiyasına işarə, geri çağırma funksiyasına ötürmək istədiyimiz məlumatlara işarə (istifadəçi məlumatları) təqdim olunur.

Dezaktivasiyası zamanı geri çağırma funksiyası istifadəçi məlumatlarını, detektor filtrasına göstərilən yeri, hadisə identifikatorunu və hadisəni təsvir edən strukturu alacaq.


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

Siqnal emalı üçün struktur sxemi baş şəkildə göstərilmişdir.

İndi kommentlərlə proqramın koduna baxaq.

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

Proqramı kompilyasiya edirik və işə salırıq. Bütün şeylər düzgün işlədikdə, işə saldıqdan sonra proqramın belə bir davranışını almalı oluruq:

$ ./mstest4
ALSA lib conf.c:4738:(snd_config_expand) Naməlum parametrlər 0
ALSA lib control.c:954:(snd_ctl_open_noupdate) Yanlış CTL default:0
ortp-xəbər-Birləşdirici kartı bağlamaq mümkün olmadı: Yanlış arqument
ALSA lib conf.c:4738:(snd_config_expand) Naməlum parametrlər 0
ALSA lib pcm.c:2266:(snd_pcm_open_noupdate) Naməlum PCM default:0
ALSA lib conf.c:4738:(snd_config_expand) Naməlum parametrlər 0
ALSA lib pcm.c:2266:(snd_pcm_open_noupdate) Naməlum PCM default:0
ortp-xəbər-Qeyri-adi, Intel 82801AA-ICH səs kartının heç bir şeyə qadir olmadığı görünür, plughw ilə yenidən cəhd edilir...
Əmr düyməsinə basın, sonra daxil edin.
Proqramı dayandırmaq üçün 0 daxil edin.
ortp-xəbər-alsa_set_params: periodsize:256 256-dan istifadə edərək
ortp-xəbər-alsa_set_params: period:8 8-dən istifadə edərək

1-dən 6-ya qədər olan hər hansı düyməni basırıq, "Enter" düyməsi ilə təsdiqləyirik, təxminən belə bir siyahı almalı oluruq:


2
Göndərilən əmr: 2
                      Qəbul edilən əmr: V-
1
Göndərilən əmr: 1
                      Qəbul edilən əmr: V+
3
Göndərilən əmr: 3
                      Qəbul edilən əmr: C+
4
Göndərilən əmr: 4
                      Qəbul edilən əmr: C-
0
$

Görürük ki, komanda tonları uğurla göndərilir və detektor bunları aşkar edir.

Növbəti məqalədə Ethernet şəbəkəsi üzərindən RTP protokolu ilə səs siqnalının ötürülməsinə müraciət edəcəyik və bunu uzaqdan pultumuzda tətbiq edəcəyik.

Mənbə: habr.com

DDoS qoruması olan saytlara etibarlı hosting satın alın, VPS VDS serverlər 🔥 DDoS qoruması olan saytlara etibarlı hosting satın alın, VPS VDS serverlər | ProHoster