A’ sgrùdadh einnsean Mediastreamer2 VoIP. Pàirt 9

Tha stuth an artaigil air a thoirt bho mo seanail zen.

Intercom dà-fhillte

A’ sgrùdadh einnsean Mediastreamer2 VoIP. Pàirt 9

Anns an àm a dh ’fhalbh artaigil chaidh intercom duplex ainmeachadh, agus anns an fhear seo nì sinn e.

Tha an diagram air a shealltainn ann am figear an tiotail. Bidh an t-sreath sìoltachain as ìsle a’ cruthachadh an t-slighe tar-chuir, a thòisicheas bhon chairt fuaim. Bidh e a’ toirt seachad sampallan chomharran bhon mhicreofon. Gu gnàthach, bidh seo a’ tachairt aig ìre 8000 sampall gach diog. Is e an doimhneachd dàta a bhios sìoltachain claisneachd sruthadh meadhanan a’ cleachdadh 16 pìosan (chan eil seo cudromach; ma thogras tu, faodaidh tu sìoltachain a sgrìobhadh a dh’ obraicheas le doimhneachd beagan nas àirde). Tha an dàta air a chruinneachadh ann am blocaichean de 160 sampall. Mar sin, tha meud gach bloc 320 bytes. An ath rud, bidh sinn a ’biathadh an dàta gu cuir a-steach a’ ghineadair, a tha, nuair a thèid a chuir dheth, “follaiseach” don dàta. Chuir mi ris air eagal ‘s gum fàs thu sgìth de bhith a’ bruidhinn a-steach don mhicreofon aig àm deasbaid - faodaidh tu an gineadair a chleachdadh gus an t-slighe a “losgadh” le comharra tòna.

Às deidh an gineadair, thèid an comharra chun a’ chòdadair, a thionndaidheas na sampallan 16-bit againn a rèir an µ-law (inbhe G.711) gu bhith nan ochd pìosan. Aig toradh an encoder, tha bloc dàta againn mu thràth leth na meud. San fharsaingeachd, is urrainn dhuinn dàta a chuir thairis gun cho-èigneachadh mura feum sinn trafaic a shàbhaladh. Ach an seo tha e feumail encoder a chleachdadh, oir chan urrainn dha Wireshark claisneachd ath-riochdachadh bho shruth RTP ach nuair a tha e air a dhlùthadh a rèir an µ-law no a-law.

Às deidh an encoder, thèid na blocaichean dàta nas aotroime a chuir chun chriathrag rtpsend, a chuireas iad ann am pasgan RTP, suidhich na brataichean riatanach agus bheir iad gu streapadair nam meadhanan airson an sgaoileadh thairis air an lìonra ann an cruth pacaid UDP.

Bidh an t-sreath àrd de shìoltachain a’ cruthachadh an t-slighe faighinn; Bidh pacaidean RTP a gheibh an sruth-meadhain bhon lìonra a’ dol a-steach don chriathrag rtprecv, aig an toradh a nochdas iad ann an cruth blocaichean dàta, agus tha gach fear dhiubh a’ freagairt ri aon phacaid a fhuaireadh. Chan eil anns a’ bhloc ach dàta pàighidh pàighidh; san artaigil roimhe chaidh an sealltainn ann an uaine san dealbh.

An uairsin, thèid na blocaichean a chuir chun chriathrag decoder, a thionndaidheas na sampallan aon-byte a tha annta gu bhith sreathach, 16-bit. A dh’ fhaodar a ghiullachd mu thràth le sìoltachain sruthadh meadhanan. Anns a ’chùis againn, bidh sinn dìreach gan cur chun chairt fuaim airson ath-chluich air luchd-labhairt an headset agad.

A-nis gluaisidh sinn air adhart gu buileachadh bathar-bog. Gus seo a dhèanamh, cuiridh sinn còmhla na faidhlichean cuidhteas agus tar-chuir a dhealaich sinn roimhe. Roimhe seo, chleachd sinn roghainnean stèidhichte airson puirt agus seòlaidhean, ach a-nis feumaidh sinn am prògram gus a bhith comasach air na roghainnean a shònraicheas sinn aig àm tòiseachaidh a chleachdadh. Gus seo a dhèanamh, chuireadh sinn comas-gnìomh airson a bhith a’ giullachd argamaidean loidhne-àithne. Às deidh sin bidh e comasach dhuinn an seòladh IP agus port an intercom a shuidheachadh leis a bheil sinn airson ceangal a stèidheachadh.

An toiseach, leig dhuinn structar a chuir ris a’ phrògram a chumas na roghainnean aige:

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

typedef struct _app_vars app_vars;

Foillsichidh am prògram structar den t-seòrsa seo ris an canar vars.
An ath rud, cuiridh sinn gnìomh gus argamaidean loidhne-àithne a pharsadh:

/* Функция преобразования аргументов командной строки в
* настройки программы. */
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]);
        }
    }
}

Mar thoradh air parsadh, thèid na h-argamaidean loidhne-àithne a chuir ann an raointean structar vars. Is e prìomh obair an tagraidh slighean tar-chuir agus faighinn bho shìoltachain a chruinneachadh; às deidh an ticker a cheangal, thèid smachd a ghluasad gu lùb gun chrìoch a bheir, ma chaidh tricead gineadair a shuidheachadh gu neo-neoni, ath-thòiseachadh an gineadair deuchainn gus an bidh e ag obair gun stad.

Feumaidh an gineadair na h-ath-thòiseachadh sin mar thoradh air an dealbhadh aige; airson adhbhar air choireigin chan urrainn dha comharra a thoirt gu buil a mhaireas barrachd air 16 diogan. Bu chòir a thoirt fa-near gu bheil an ùine aige air a shònrachadh le àireamh 32-bit.

Bidh am prògram gu lèir a’ coimhead mar seo:

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

Feuch an cuir sinn ri chèile. An uairsin faodar am prògram a ruith air dà choimpiutair. No air aon, mar a nì mi a‑nis. Bidh sinn a’ cur TShark air bhog leis na h-argamaidean a leanas:

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

Mura h-eil an raon cur air bhog anns a’ chonsail a’ nochdadh ach teachdaireachd mu thoiseach glacaidh, is e deagh shoidhne a tha seo - tha e a’ ciallachadh gu bheil e nas coltaiche nach eil prògraman eile air a’ phort againn. Ann an ceann-uidhe eile, bidh sinn a’ cur air bhog prògram prògram a nì atharrais air intercom “iomallach” le bhith a’ sònrachadh àireamh a’ phuirt seo:

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

Mar a chithear bho theacsa a’ phrògraim, is e an seòladh IP bunaiteach 127.0.0.1 (loopback ionadail).

Ann an ceann-uidhe eile, bidh sinn a 'cur air bhog dàrna eisimpleir den phrògram, a tha coltach ri inneal ionadail. Cleachdaidh sinn argamaid a bharrachd a leigeas leis a’ ghineadair deuchainn togte obrachadh:

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

Aig an àm seo, bu chòir pacaidean a thèid a ghluasad chun inneal “iomallach” tòiseachadh a ’frasadh sa chonsail le TShark, agus cluinnear tòna leantainneach bho neach-labhairt a’ choimpiutair.

Ma thachair a h-uile càil mar a chaidh a sgrìobhadh, bidh sinn ag ath-thòiseachadh an dàrna leth-bhreac den phrògram, ach às aonais an iuchair agus an argamaid “-gen 440”. Cluichidh tu a-nis pàirt gineadair. Às deidh seo, faodaidh tu fuaim a chuir a-steach don mhicreofon; bu chòir dhut am fuaim co-fhreagarrach a chluinntinn anns an neach-labhairt no na fònaichean-cluaise. Dh’ fhaodadh eadhon fèin-spèis fuaimneach tachairt; tionndaidh sìos meud an neach-labhairt agus falbhaidh a’ bhuaidh.

Ma ruith thu e air dà choimpiutair agus nach robh thu troimh-chèile mu na seòlaidhean IP, tha an aon toradh a ’feitheamh riut - conaltradh guth càileachd didseatach dà-shligheach.

Anns an ath artaigil ionnsaichidh sinn mar a sgrìobhas tu na sìoltachain againn fhèin - plugins, le taing don sgil seo bidh e comasach dhut an streamer meadhanan a chleachdadh chan ann a-mhàin airson claisneachd is bhidio, ach cuideachd ann an raon sònraichte eile.

Source: www.habr.com

Cuir beachd ann