استكشاف محرك Mediastreamer2 VoIP. الجزء 5

مادة المقال مأخوذة من بلدي قناة زين.

كاشف النغمات

في الماضي مقالة لقد أنشأنا مقياس مستوى الإشارة. في هذا الدرس سوف نتعلم كيفية اكتشاف إشارة النغمة.

استكشاف محرك Mediastreamer2 VoIP. الجزء 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.

لكي يخطرنا الكاشف بأن الإشارة التي تحتوي على مكونات التردد المطلوبة قد وصلت إلى مدخلها، يجب أن نزودها بوظيفة رد الاتصال التي ستطلقها في هذه الحالة. ويتم ذلك باستخدام الوظيفة ms_filter_set_notify_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

إضافة تعليق