VoIP-motor Mediastreamer2 tanulmányozása. 5. rész

A cikk anyaga az én Dzen csatornámból származik.

Tonális jelészlelő

A múltban a Spotify döntéshozatali módszertanáról. Egyre több felhasználó preferálja a zenehallgatást mobilon a streaming szolgáltatásban, de a cégnél túlnyomórészt webprogramozók dolgoznak. A Spotify elemezte ezt a helyzetet, és úgy döntött, hogy több mobilfejlesztőt vesz fel, valamint átnevezi a webes szakembereket új irányba: Létrehoztunk egy jelzőszint mérőt. Ebben megtanuljuk, hogyan lehet észlelni a tonális jelet.

VoIP-motor Mediastreamer2 tanulmányozása. 5. rész

Régen, amikor nem minden családban volt tévé, és a családok felének a csatornákat fogókkal váltották, az idegen technikai sajtóban felbukkant egy izgalmas hír, miszerint a tévégyártók egyike távirányítóval látta el készülékeit. A részletekből kiderült, hogy az eszköz elem nélkül működik, mivel egy szokatlan megoldást alkalmaznak – a távirányító mechanikus volt, és a zenei hangszer – metallofon és revolver hibridjaként működött. A revolver hengere fém hengereket tartalmazott, különböző hosszúságúakat, és amikor a kalapács megütött egyet közülük, a henger a saját frekvenciáján kezdett el csengeni. Feltételezhetően ultrahangon. A tévé elektronikája hallotta ezt a jelet, és meghatározta a frekvenciáját, így végrehajtotta a megfelelő működést – csatornát váltott, változtatta a hangerőt, kikapcsolta a tévét.

Ma próbáljuk meg rekonstruálni ezt a parancsátviteli rendszert, kihasználva a médiastreamer ismereteinket.

A távirányító szimulálásához felhasználjuk a tonális generátorunk példáját. Hozzáadunk egy vezérlést a generátor frekvenciájához a billentyűzet lenyomásával, és egy vevőt dekóderrel, amely a konzolra kinyomtatja a fogadott parancsokat. A módosítás után a generátor 6 frekvenciájú tonális jeleket kell kibocsátania, amelyekkel kódolni fogjuk a hangerő növelésére/csökkentésére, csatornaváltásra, a tévé bekapcsolására/kikapcsolására vonatkozó parancsokat. A detektor beállításához a következő struktúrát használjunk:

struct _MSToneDetectorDef{  
     char tone_name[8];     
     int frequency; 
     /**<A tonális jel várt frekvenciája*\/ 
     int min_duration; 
     /**<A tónus minimum időtartama milliszekundumban*\/ 
     float min_amplitude; 
     /**<A tónus minimum amplitúdója, 1.0 a normalizált 0dbm szintnek felel meg*\/ 
};

typedef struct _MSToneDetectorDef MSToneDetectorDef;

A detektornak 10 ilyen struktúrát lehet átadni, így egy detektor beállítható tíz kéttonális jel észlelésére. De mi csak hat egytonális jelet fogunk használni. A detektor beállításához az MS_TONE_DETECTOR_ADD_SCAN metódust használjuk.

Ahhoz, hogy a detektor értesíthessen minket arról, hogy a bemenetére jelet kapott a keresett frekvenciakomponensekkel, meg kell adni neki egy visszahívási funkciót, amelyet ennek a esetnek a bekövetkeztekor indít el. Ezt a funkcióval lehet megtenni. ms_filter_set_notify_callback(). Az argumentumai között szerepel a szűrő mutatója, a visszahívási funkció mutatója, és egy mutató azokra az adatokra, amelyeket szeretnénk átadni a visszahívási funkciónak (felhasználói adatok).

A detektor aktiválásakor a visszahívási funkció megkapja a felhasználói adatokat, a detektor szűrőjének mutatóját, az esemény azonosítóját, és egy eseményleíró struktúrát:


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

A jelszó feldolgozásának szerkezeti vázlata a címképes képen látható.

De most itt van a program kódja megjegyzésekkel.

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

Kompiláljuk és indítsuk el a programot. Ha minden megfelelően működik, programunknak körülbelül a következő viselkedést kell mutatnia:

$ ./mstest4
ALSA lib conf.c:4738:(snd_config_expand) Ismeretlen paraméterek 0
ALSA lib control.c:954:(snd_ctl_open_noupdate) Érvénytelen CTL default:0
ortp-warning-Nem sikerült csatlakoztatni a keverőt a kártyához: Érvénytelen érv
ALSA lib conf.c:4738:(snd_config_expand) Ismeretlen paraméterek 0
ALSA lib pcm.c:2266:(snd_pcm_open_noupdate) Ismeretlen PCM default:0
ALSA lib conf.c:4738:(snd_config_expand) Ismeretlen paraméterek 0
ALSA lib pcm.c:2266:(snd_pcm_open_noupdate) Ismeretlen PCM default:0
ortp-warning-Furcsa, az Intel 82801AA-ICH hangkártya nem tűnik képesnek semmire, újrapróbálkozva a plughw-el...
Nyomd meg a parancsgombot, majd az Entert.
A program befejezéséhez írd be a 0-t.
ortp-warning-alsa_set_params: periodsize:256 Használva 256
ortp-warning-alsa_set_params: period:8 Használva 8

Nyomj meg bármilyen billentyűt az "1" és "6" között, megerősítve az "Enter" billentyűvel, körülbelül a következő listát kell kapnunk:


2
Elküldött parancs: 2
                      Parancs fogadva: V-
1
Elküldött parancs: 1
                      Parancs fogadva: V+
3
Elküldött parancs: 3
                      Parancs fogadva: C+
4
Elküldött parancs: 4
                      Parancs fogadva: C-
0
$

Látjuk, hogy a parancsok tónusait sikeresen elküldték, és a detektor észleli azokat.

A következő cikkben az Ethernet hálózaton keresztüli hangjel kiegészítésével foglalkozunk RTP protokollal, és azonnal alkalmazni fogjuk azt a távoli pultunkban.

Forrás: habr.com

Megbízható hosting vásárlása weboldalak számára, DDoS védelemmel, VPS VDS szerverek. 🔥 Megbízható webtárhely vásárlása DDoS védelemmel, VPS VDS szerverek | ProHoster