Mediastreamer2 VoIP 엔진 탐색. 5 부

글의 소재는 제 글에서 가져왔습니다. 젠 채널.

톤 감지기

과거에 기사 우리는 신호 레벨 미터를 만들었습니다. 이번 시간에는 톤 신호를 감지하는 방법을 알아 보겠습니다.

Mediastreamer2 VoIP 엔진 탐색. 5 부

옛날에는 모든 가족이 TV를 가지고 있지 않았고 절반이 펜치를 사용하여 채널을 전환했을 때 외국 기술 언론의 리뷰에 한 TV 제조업체가 장치에 무선 리모컨을 장착했다는 흥미로운 소식이 나타났습니다. 세부 사항에서 리모콘은 특이한 접근 방식을 사용하여 배터리 없이 작동하는 것으로 알려졌습니다. 리모콘은 기계식이었고 악기인 메탈로폰과 리볼버의 하이브리드였습니다. 리볼버 드럼에는 길이가 다른 금속 실린더가 포함되어 있으며 발사 핀이 그 중 하나에 부딪히면 실린더가 자체 주파수로 울리기 시작했습니다. 아마도 초음파에있을 것입니다. TV의 전자 장치는 이 신호를 듣고 주파수를 결정한 후 적절한 작업(채널 전환, 볼륨 변경, TV 끄기)을 수행했습니다.

오늘 우리는 미디어 스트리머에 대한 지식을 활용하여 이 명령 전송 시스템을 재구성해 보겠습니다.

리모콘을 시뮬레이션하기 위해 톤 제너레이터 예제의 텍스트를 사용하겠습니다. 여기에 키 입력을 통한 생성기 주파수 제어와 수신된 명령을 콘솔에 출력하는 디코더가 있는 수신기를 추가하겠습니다. 변경 후 생성기는 6개 주파수의 톤을 생성해야 하며, 이를 통해 볼륨 증가/감소, 채널 변경, TV 켜기/끄기 명령을 인코딩합니다. 감지기를 구성하려면 다음 구조가 사용됩니다.

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개가 제공될 수 있으므로 하나의 감지기가 XNUMX개의 XNUMX톤 신호를 감지하도록 구성할 수 있습니다. 그러나 우리는 XNUMX개의 단일 톤 신호만 사용할 것입니다. 설정을 감지기로 전송하기 위해 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 프로토콜을 사용하여 이더넷 네트워크를 통해 오디오 신호를 전송하고 이를 원격 제어에 즉시 적용하는 방법을 살펴보겠습니다.

출처 : habr.com

코멘트를 추가