Mediastreamer2 VoIP motorunu keşfetme. 5. Bölüm

Makalenin materyali benim zenci kanalı.

Ton dedektörü

Geçmişte Makale Bir sinyal seviyesi ölçer oluşturduk. Bu derste bir ton sinyalinin nasıl tespit edileceğini öğreneceğiz.

Mediastreamer2 VoIP motorunu keşfetme. 5. Bölüm

Her ailenin televizyonunun olmadığı ve yarısının pense kullanarak kanal değiştirdiği eski günlerde, yabancı teknik basının incelemelerinde bir TV üreticisinin cihazlarını kablosuz uzaktan kumandayla donattığına dair ilgi çekici haberler çıktı. Ayrıntılardan, alışılmadık bir yaklaşım sayesinde uzaktan kumandanın pilsiz çalıştığı biliniyordu - uzaktan kumanda mekanikti ve bir müzik enstrümanının - bir metalofon ve bir tabanca - meleziydi. Tabanca tamburu farklı uzunluklarda metal silindirler içeriyordu ve ateşleme iğnesi bunlardan birine çarptığında silindir kendi frekansında çınlamaya başladı. Muhtemelen ultrasonda. TV'deki elektronikler bu sinyali duydu ve frekansını belirledikten sonra uygun işlemi gerçekleştirdi - kanalı değiştirin, ses seviyesini değiştirin, TV'yi kapatın.

Bugün medya aktarıcı hakkındaki bilgimizi kullanarak bu komut iletim sistemini yeniden yapılandırmaya çalışacağız.

Uzaktan kumandayı simüle etmek için ton üreteci örneğimizin metnini kullanacağız. Buna, tuş vuruşlarından jeneratör frekansının kontrolünü ve alınan komutları konsola gönderecek kod çözücüye sahip bir alıcıyı ekleyeceğiz. Değişiklikten sonra jeneratör, ses seviyesini artırma/azaltma, kanalı değiştirme, TV'yi açma/kapama komutlarını kodlayacağımız 6 frekanslı tonlar üretmelidir. Dedektörü yapılandırmak için aşağıdaki yapı kullanılır:

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;

Bir dedektöre bu yapılardan 10 tanesi verilebilir, böylece bir dedektör on adet iki tonlu sinyali algılayacak şekilde yapılandırılabilir. Ancak yalnızca altı adet tek tonlu sinyal kullanacağız. Ayarları dedektöre aktarmak için MS_TONE_DETECTOR_ADD_SCAN yöntemi kullanılır.

Dedektörün girişine istenilen frekans bileşenlerine sahip bir sinyalin geldiğini bize bildirebilmesi için, bu durumda başlatacağı bir geri arama fonksiyonunu ona sağlamamız gerekir. Bu fonksiyon kullanılarak yapılır ms_filter_set_notify_callback(). Argüman olarak, filtreye bir işaretçi, geri çağırma işlevine bir işaretçi ve geri çağırma işlevine iletmek istediğimiz verilere (kullanıcı verileri) bir işaretçi alır.

Dedektör tetiklendiğinde geri arama işlevi kullanıcı verilerini, dedektör filtresine yönelik bir işaretçiyi, bir olay tanımlayıcıyı ve olayı açıklayan bir yapıyı alacaktır:


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

Sinyal işlemenin blok şeması başlık resminde gösterilmektedir.

Artık programın kendisi yorumlarla kodlanıyor.

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

Programı derleyip çalıştırıyoruz. Her şey doğru çalışıyorsa, başlattıktan sonra şu program davranışına benzer bir şey elde etmeliyiz:

$ ./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" ile "6" arasındaki tuşlardan herhangi birine basın ve "Enter" tuşuyla onaylayın, aşağıdaki listeye benzer bir şey elde etmelisiniz:


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

Komut seslerinin başarıyla gönderildiğini ve dedektörün bunları algıladığını görüyoruz.

Bir sonraki makalede, RTP protokolünü kullanarak bir Ethernet ağı üzerinden ses sinyali iletmeye ve bunu hemen uzaktan kumandamıza uygulayacağız.

Kaynak: habr.com

Yorum ekle