کاوش در موتور VoIP Mediastreamer2. قسمت 5

مطالب مقاله از من گرفته شده است کانال ذن.

ردیاب تن

در آخر مقاله ما یک سطح سیگنال سنج ایجاد کرده ایم. در این یکی یاد می گیریم که چگونه سیگنال تون را تشخیص دهیم.

کاوش در موتور VoIP Mediastreamer2. قسمت 5

در زمان‌های قدیم، زمانی که همه خانواده‌ها تلویزیون نداشتند و نیمی از آن‌ها با استفاده از انبردست کانال خود را تغییر می‌دادند، اخبار جالبی در بررسی مطبوعات فنی خارجی منتشر شد مبنی بر اینکه یکی از تولیدکنندگان تلویزیون دستگاه‌های خود را به یک کنترل از راه دور بی‌سیم مجهز کرده است. از جزئیات مشخص شد که کنترل از راه دور به لطف استفاده از یک رویکرد غیر معمول بدون باتری کار می کند - کنترل از راه دور مکانیکی بود و ترکیبی از یک آلت موسیقی - یک متالوفون و یک هفت تیر بود. طبل هفت تیر حاوی استوانه های فلزی با طول های مختلف بود و هنگامی که پین ​​شلیک به یکی از آنها برخورد کرد، سیلندر با فرکانس خودش شروع به زنگ زدن کرد. احتمالا در سونوگرافی الکترونیک در تلویزیون این سیگنال را شنید و با تعیین فرکانس آن، اقدام مناسب را انجام داد - کانال را تغییر دهید، صدا را تغییر دهید، تلویزیون را خاموش کنید.

امروز ما سعی خواهیم کرد این سیستم انتقال فرمان را با استفاده از دانش خود در مورد پخش کننده رسانه بازسازی کنیم.

برای شبیه سازی یک کنترل از راه دور، از متن مثال مولد صدا استفاده می کنیم. به آن کنترل فرکانس ژنراتور از طریق زدن کلید و یک گیرنده با رمزگشا اضافه می کنیم که دستورات دریافتی را به کنسول ارسال می کند. پس از تغییر، ژنراتور باید تن های 6 فرکانس را تولید کند، که با آن دستورات را برای افزایش / کاهش صدا، تغییر کانال، روشن / خاموش کردن تلویزیون رمزگذاری می کنیم. برای پیکربندی آشکارساز از ساختار زیر استفاده می شود:

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;

می توان 10 عدد از این ساختارها را به یک آشکارساز داد، بنابراین می توان یک آشکارساز را برای تشخیص ده سیگنال دو رنگی پیکربندی کرد. اما ما فقط از شش سیگنال تک صدایی استفاده خواهیم کرد. برای انتقال تنظیمات به آشکارساز، از روش MS_TONE_DETECTOR_ADD_SCAN استفاده می شود.

برای اینکه آشکارساز به ما اطلاع دهد که سیگنالی با اجزای فرکانس مورد نظر به ورودی خود رسیده است، باید یک تابع callback برای آن ارائه کنیم که در این حالت راه اندازی می شود. این کار با استفاده از تابع انجام می شود ms_filter_set_notify_callback(). به عنوان آرگومان، یک اشاره‌گر به فیلتر، یک اشاره‌گر به تابع callback و یک اشاره‌گر به داده‌هایی که می‌خواهیم به تابع callback ارسال کنیم (داده‌های کاربر) را دریافت می‌کند.

هنگامی که آشکارساز فعال می شود، عملکرد پاسخ به تماس داده های کاربر، یک اشاره گر به فیلتر آشکارساز، یک شناسه رویداد و ساختاری را که رویداد را توصیف می کند دریافت می کند:


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

بلوک دیاگرام پردازش سیگنال در تصویر عنوان نشان داده شده است.

خب حالا خود کد برنامه با نظرات.

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

ما برنامه را کامپایل و اجرا می کنیم. اگر همه چیز درست کار کند، پس از راه اندازی باید چیزی شبیه به این رفتار برنامه را دریافت کنیم:

$ ./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" تا "6" را فشار دهید، با تایید کلید "Enter"، باید چیزی شبیه به این لیست دریافت کنید:


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

می بینیم که آهنگ های فرمان با موفقیت ارسال می شوند و آشکارساز آنها را شناسایی می کند.

در مقاله بعدی به انتقال سیگنال صوتی از طریق شبکه اترنت با استفاده از پروتکل RTP خواهیم پرداخت و بلافاصله آن را در کنترل از راه دور اعمال می کنیم.

منبع: www.habr.com

اضافه کردن نظر