Омӯзиши муҳаррики Mediastreamer2 VoIP. Қисми 9

Материали макола аз ман гирифта шудааст канали zen.

Домофони дуплекс

Омӯзиши муҳаррики Mediastreamer2 VoIP. Қисми 9

Дар охир мақола домофони дуплекс эълон карда шуд ва дар ин до мо онро месозем.

Диаграмма дар расми сарлавҳа нишон дода шудааст. Занҷири поёнии филтрҳо роҳи интиқолро ташкил медиҳад, ки аз корти садоӣ оғоз мешавад. Он намунаҳои сигналро аз микрофон медиҳад. Бо нобаёнӣ, ин бо суръати 8000 намуна дар як сония рух медиҳад. Амиқии бит маълумоте, ки филтрҳои аудиоии медиа истифода мебаранд 16 бит аст (ин муҳим нест; агар шумо хоҳед, шумо метавонед филтрҳоеро нависед, ки бо умқи бит баландтар кор мекунанд). Маълумот ба блокҳои 160 намуна гурӯҳбандӣ карда шудааст. Ҳамин тариқ, ҳар як блок 320 байт аст. Баъдан, мо маълумотро ба вуруди генератор медиҳем, ки ҳангоми хомӯш кардани он ба додаҳо "шаффоф" аст. Ман онро илова кардам, агар шумо ҳангоми ислоҳи хатогӣ бо микрофон хаста шавед - шумо метавонед генераторро барои "паррондан" роҳ бо сигнали оҳанг истифода баред.

Пас аз генератор, сигнал ба рамзгузор меравад, ки намунаҳои 16-битии моро мувофиқи қонуни µ-қонун (стандарти G.711) ба ҳашт-бит табдил медиҳад. Дар баромади рамзгузор, мо аллакай як блоки маълумотро ба андозаи нисфи андоза дорем. Умуман, мо метавонем маълумотро бидуни фишурда интиқол диҳем, агар ба мо сарфа кардани трафик лозим набошад. Аммо дар ин ҷо истифодаи рамзгузор муфид аст, зеро Wireshark метавонад аудиоро аз ҷараёни RTP танҳо ҳангоми фишурдани он мувофиқи қонун ё қонун дубора тавлид кунад.

Пас аз рамзгузор, блокҳои сабуктари додаҳо ба филтри rtpsend фиристода мешаванд, ки онҳоро дар бастаи RTP ҷойгир мекунад, парчамҳои заруриро муқаррар мекунад ва онҳоро барои интиқол тавассути шабака дар шакли пакети UDP ба медиа-стример медиҳад.

Занҷири болоии филтрҳо роҳи қабулкуниро ташкил медиҳад; Бастаҳои RTP, ки стримери медиа аз шабака гирифтааст, ба филтри rtprecv дохил мешаванд, ки дар баромади онҳо дар шакли блокҳои додаҳо пайдо мешаванд, ки ҳар кадоме ба як бастаи қабулшуда мувофиқат мекунанд. Блок танҳо маълумоти боркашониро дар бар мегирад; дар мақолаи қаблӣ онҳо дар расм бо ранги сабз нишон дода шудаанд.

Баъдан, блокҳо ба филтри декодер фиристода мешаванд, ки намунаҳои якбайти дар онҳо мавҷудбударо ба 16-битии хатӣ табдил медиҳанд. Онро аллакай тавассути филтрҳои стримери медиа коркард кардан мумкин аст. Дар ҳолати мо, мо онҳоро танҳо ба корти садоӣ барои бозӣ дар баландгӯякҳои гӯшмонаки шумо мефиристем.

Акнун биёед ба татбиқи нармафзор гузарем. Барои ин, мо файлҳои қабулкунанда ва интиқолдиҳандаро, ки қаблан ҷудо карда будем, якҷоя мекунем. Пеш аз ин, мо барои портҳо ва суроғаҳо танзимоти собит истифода мебурдем, аммо ҳоло ба мо лозим аст, ки барнома тавонист танзимоти ҳангоми оғозёбиро истифода барад. Барои ин, мо функсияҳоро барои коркарди далелҳои сатри фармон илова мекунем. Пас аз он мо метавонем суроғаи IP ва порти интеркомро, ки бо он пайвастшавӣ барқарор кардан мехоҳем, таъин кунем.

Аввалан, биёед ба барнома сохторе илова кунем, ки танзимоти онро нигоҳ медорад:

struct _app_vars
{
  int  local_port;              /* Локальный порт. */
  int  remote_port;             /* Порт переговорного устройства на удаленном компьютере. */
  char remote_addr[128];        /* IP-адрес удаленного компьютера. */
  MSDtmfGenCustomTone dtmf_cfg; /* Настройки тестового сигнала генератора. */
};

typedef struct _app_vars app_vars;

Барнома сохтори чунин намудро эълон мекунад, ки vars ном дорад.
Минбаъд, биёед функсияеро барои таҳлили аргументҳои сатри фармон илова кунем:

/* Функция преобразования аргументов командной строки в
* настройки программы. */
void  scan_args(int argc, char *argv[], app_vars *v)
{
    char i;
    for (i=0; i<argc; i++)
    {
        if (!strcmp(argv[i], "--help"))
        {
            char *p=argv[0]; p=p + 2;
            printf("  %s walkie talkienn", p);
            printf("--help      List of options.n");
            printf("--version   Version of application.n");
            printf("--addr      Remote abonent IP address string.n");
            printf("--port      Remote abonent port number.n");
            printf("--lport     Local port number.n");
            printf("--gen       Generator frequency.n");
            exit(0);
        }

        if (!strcmp(argv[i], "--version"))
        {
            printf("0.1n");
            exit(0);
        }

        if (!strcmp(argv[i], "--addr"))
        {
            strncpy(v->remote_addr, argv[i+1], 16);
            v->remote_addr[16]=0;
            printf("remote addr: %sn", v->remote_addr);
        }

        if (!strcmp(argv[i], "--port"))
        {
            v->remote_port=atoi(argv[i+1]);
            printf("remote port: %in", v->remote_port);
        }

        if (!strcmp(argv[i], "--lport"))
        {
            v->local_port=atoi(argv[i+1]);
            printf("local port : %in", v->local_port);
        }

        if (!strcmp(argv[i], "--gen"))
        {
            v -> dtmf_cfg.frequencies[0] = atoi(argv[i+1]);
                printf("gen freq : %in", v -> dtmf_cfg.frequencies[0]);
        }
    }
}

Дар натиҷаи таҳлил, аргументҳои сатри фармон дар майдонҳои сохтори vars ҷойгир карда мешаванд. Вазифаи асосии барнома ҷамъоварии роҳҳои интиқол ва қабул аз филтрҳо хоҳад буд; пас аз пайваст кардани тикер, назорат ба як ҳалқаи беохир интиқол дода мешавад, ки агар басомади генератор ба сифр муқаррар карда шуда бошад, генератори санҷиширо аз нав оғоз мекунад, то беист кор мекунад.

Генератор аз сабаби тарҳрезии худ ин дубора оғозёбиро талаб мекунад; бо баъзе сабабҳо он сигналеро, ки зиёда аз 16 сония давом мекунад, тавлид карда наметавонад. Бояд қайд кард, ки давомнокии он бо рақами 32-бит муайян карда мешавад.

Тамоми барнома чунин хоҳад буд:

/* Файл mstest8.c Имитатор переговорного устройства. */

#include <mediastreamer2/mssndcard.h>
#include <mediastreamer2/dtmfgen.h>
#include <mediastreamer2/msrtp.h>

/* Подключаем файл общих функций. */
#include "mstest_common.c"

/*----------------------------------------------------------*/
struct _app_vars
{
    int  local_port;              /* Локальный порт. */
    int  remote_port;             /* Порт переговорного устройства на удаленном компьютере. */
    char remote_addr[128];        /* IP-адрес удаленного компьютера. */
    MSDtmfGenCustomTone dtmf_cfg; /* Настройки тестового сигнала генератора. */
};

typedef struct _app_vars app_vars;

/*----------------------------------------------------------*/
/* Создаем дуплексную RTP-сессию. */
RtpSession* create_duplex_rtp_session(app_vars v)
{
    RtpSession *session = create_rtpsession (v.local_port, v.local_port + 1, FALSE, RTP_SESSION_SENDRECV);
    rtp_session_set_remote_addr_and_port(session, v.remote_addr, v.remote_port, v.remote_port + 1);
    rtp_session_set_send_payload_type(session, PCMU);
    return session;
}

/*----------------------------------------------------------*/
/* Функция преобразования аргументов командной строки в
* настройки программы. */
void  scan_args(int argc, char *argv[], app_vars *v)
{
    char i;
    for (i=0; i<argc; i++)
    {
        if (!strcmp(argv[i], "--help"))
        {
            char *p=argv[0]; p=p + 2;
            printf("  %s walkie talkienn", p);
            printf("--help      List of options.n");
            printf("--version   Version of application.n");
            printf("--addr      Remote abonent IP address string.n");
            printf("--port      Remote abonent port number.n");
            printf("--lport     Local port number.n");
            printf("--gen       Generator frequency.n");
            exit(0);
        }

        if (!strcmp(argv[i], "--version"))
        {
            printf("0.1n");
            exit(0);
        }

        if (!strcmp(argv[i], "--addr"))
        {
            strncpy(v->remote_addr, argv[i+1], 16);
            v->remote_addr[16]=0;
            printf("remote addr: %sn", v->remote_addr);
        }

        if (!strcmp(argv[i], "--port"))
        {
            v->remote_port=atoi(argv[i+1]);
            printf("remote port: %in", v->remote_port);
        }

        if (!strcmp(argv[i], "--lport"))
        {
            v->local_port=atoi(argv[i+1]);
            printf("local port : %in", v->local_port);
        }

        if (!strcmp(argv[i], "--gen"))
        {
            v -> dtmf_cfg.frequencies[0] = atoi(argv[i+1]);
                printf("gen freq : %in", v -> dtmf_cfg.frequencies[0]);
        }
    }
}

/*----------------------------------------------------------*/
int main(int argc, char *argv[])
{
    /* Устанавливаем настройки по умолчанию. */
    app_vars vars={5004, 7010, "127.0.0.1", {0}};

    /* Устанавливаем настройки настройки программы в
     * соответствии с аргументами командной строки. */
    scan_args(argc, argv, &vars);

    ms_init();

    /* Создаем экземпляры фильтров передающего тракта. */
    MSSndCard *snd_card =
        ms_snd_card_manager_get_default_card(ms_snd_card_manager_get());
    MSFilter *snd_card_read = ms_snd_card_create_reader(snd_card);
    MSFilter *dtmfgen = ms_filter_new(MS_DTMF_GEN_ID);
    MSFilter *rtpsend = ms_filter_new(MS_RTP_SEND_ID);

    /* Создаем фильтр кодера. */
    MSFilter *encoder = ms_filter_create_encoder("PCMU");

    /* Регистрируем типы нагрузки. */
    register_payloads();

    /* Создаем дуплексную RTP-сессию. */
    RtpSession* rtp_session= create_duplex_rtp_session(vars);
    ms_filter_call_method(rtpsend, MS_RTP_SEND_SET_SESSION, rtp_session);

    /* Соединяем фильтры передатчика. */
    ms_filter_link(snd_card_read, 0, dtmfgen, 0);
    ms_filter_link(dtmfgen, 0, encoder, 0);
    ms_filter_link(encoder, 0, rtpsend, 0);

    /* Создаем фильтры приемного тракта. */
    MSFilter *rtprecv = ms_filter_new(MS_RTP_RECV_ID);
    ms_filter_call_method(rtprecv, MS_RTP_RECV_SET_SESSION, rtp_session);

    /* Создаем фильтр декодера, */
    MSFilter *decoder=ms_filter_create_decoder("PCMU");

    /* Создаем фильтр звуковой карты. */
    MSFilter *snd_card_write = ms_snd_card_create_writer(snd_card);

    /* Соединяем фильтры приёмного тракта. */
    ms_filter_link(rtprecv, 0, decoder, 0);
    ms_filter_link(decoder, 0,  snd_card_write, 0);

    /* Создаем источник тактов - тикер. */
    MSTicker *ticker = ms_ticker_new();

    /* Подключаем источник тактов. */
    ms_ticker_attach(ticker, snd_card_read);
    ms_ticker_attach(ticker, rtprecv);

    /* Если настройка частоты генератора отлична от нуля, то запускаем генератор. */   
    if (vars.dtmf_cfg.frequencies[0])
    {
        /* Настраиваем структуру, управляющую выходным сигналом генератора. */
        vars.dtmf_cfg.duration = 10000;
        vars.dtmf_cfg.amplitude = 1.0;
    }

    /* Организуем цикл перезапуска генератора. */
    while(TRUE)
    {
        if(vars.dtmf_cfg.frequencies[0])
        {
            /* Включаем звуковой генератор. */
            ms_filter_call_method(dtmfgen, MS_DTMF_GEN_PLAY_CUSTOM,
                    (void*)&vars.dtmf_cfg);
        }
        /* Укладываем тред в спячку на 20мс, чтобы другие треды
         * приложения получили время на работу. */
        ms_usleep(20000);
    }
}

Биёед тартиб диҳем. Пас барномаро дар ду компютер иҷро кардан мумкин аст. Ё дар як, чунон ки ман ҳоло мекунам. Мо TShark-ро бо далелҳои зерин оғоз мекунем:

$ sudo tshark -i lo -f "udp dst port 7010" -P -V -O RTP -o rtp.heuristic_rtp:TRUE -x

Агар майдони оғозёбӣ дар консол танҳо паёмро дар бораи оғози забт нишон диҳад, пас ин аломати хуб аст - ин маънои онро дорад, ки бандари мо эҳтимолан барномаҳои дигарро ишғол накардааст. Дар терминали дигар, мо як мисоли барномаро оғоз мекунем, ки бо нишон додани ин рақами порт ба интеркоми "дурдаст" тақлид мекунад:

$ ./mstest8 --port 9010 --lport 7010

Тавре ки аз матни барнома дида мешавад, суроғаи IP-и пешфарз 127.0.0.1 (бозгашти маҳаллӣ) мебошад.

Дар терминали дигар, мо як нусхаи дуюми барномаро оғоз мекунем, ки дастгоҳи маҳаллиро тақлид мекунад. Мо як далели иловагӣ истифода мебарем, ки имкон медиҳад генератори дарунсохт кор кунад:

$ ./mstest8  --port 7010 --lport 9010 --gen 440

Дар айни замон, пакетҳое, ки ба дастгоҳи "дурдаст" интиқол дода мешаванд, бояд дар консол бо TShark дурахш кунанд ва аз баландгӯяки компютер оҳанги муттасил шунида мешавад.

Агар ҳама чиз тавре навишта шуда бошад, пас мо нусхаи дуюми барномаро аз нав оғоз мекунем, аммо бидуни калид ва аргументи "-gen 440". Шумо ҳоло нақши генераторро мебозед. Пас аз ин, шумо метавонед дар микрофон садо эҷод кунед; шумо бояд садои мувофиқро дар баландгӯяк ё гӯшмонак бишнавед. Ҳатто худидоракунии акустикӣ метавонад ба амал ояд; садои баландгӯякро паст кунед ва эффект аз байн меравад.

Агар шумо онро дар ду компютер иҷро кунед ва дар бораи суроғаҳои IP ошуфта нашавед, пас шуморо ҳамон натиҷа интизор аст - алоқаи дуҷонибаи рақамии сифат.

Дар мақолаи навбатӣ мо меомӯзем, ки чӣ гуна филтрҳои худамон - плагинҳоро нависед, ба шарофати ин маҳорат шумо метавонед стримери медиаро на танҳо барои аудио ва видео, балки дар дигар соҳаҳои мушаххас низ истифода баред.

Манбаъ: will.com

Илова Эзоҳ