Archwilio peiriant VoIP Mediastreamer2. Rhan 9

Mae deunydd yr erthygl yn cael ei gymryd o fy sianel zen.

Intercom deublyg

Archwilio peiriant VoIP Mediastreamer2. Rhan 9

Yn yr olaf Erthygl cyhoeddwyd intercom deublyg, ac yn yr un hwn byddwn yn ei wneud.

Mae'r diagram yn cael ei ddangos yn y ffigwr teitl. Mae'r gadwyn isaf o hidlwyr yn ffurfio'r llwybr trosglwyddo, sy'n cychwyn o'r cerdyn sain. Mae'n darparu samplau signal o'r meicroffon. Yn ddiofyn, mae hyn yn digwydd ar gyfradd o 8000 sampl yr eiliad. Y dyfnder did data y mae hidlwyr sain ffrydio cyfryngau yn ei ddefnyddio yw 16 did (nid yw hyn yn bwysig; os dymunwch, gallwch ysgrifennu hidlwyr a fydd yn gweithio gyda dyfnder did uwch). Mae'r data wedi'i grwpio'n flociau o 160 o samplau. Felly, maint pob bloc yw 320 beit. Nesaf, rydym yn bwydo'r data i fewnbwn y generadur, sydd, o'i ddiffodd, yn "dryloyw" i'r data. Fe wnes i ei ychwanegu rhag ofn y byddwch chi'n blino siarad yn y meicroffon yn ystod dadfygio - gallwch chi ddefnyddio'r generadur i “saethu” y llwybr gyda signal tôn.

Ar ôl y generadur, mae'r signal yn mynd i'r amgodiwr, sy'n trosi ein samplau 16-did yn ôl y gyfraith µ (safon G.711) yn rhai wyth did. Ar allbwn yr amgodiwr, mae gennym eisoes bloc data hanner y maint. Yn gyffredinol, gallwn drosglwyddo data heb gywasgu os nad oes angen i ni arbed traffig. Ond yma mae'n ddefnyddiol defnyddio amgodiwr, gan mai dim ond pan fydd wedi'i gywasgu yn unol â'r µ-law neu gyfraith y gall Wireshark atgynhyrchu sain o ffrwd CTRh.

Ar ôl yr amgodiwr, anfonir y blociau data ysgafnach i'r hidlydd rtpsend, a fydd yn eu rhoi mewn pecyn CTRh, yn gosod y baneri angenrheidiol ac yn eu rhoi i'r ffrwdiwr cyfryngau i'w trosglwyddo dros y rhwydwaith ar ffurf pecyn CDU.

Mae'r gadwyn uchaf o hidlwyr yn ffurfio'r llwybr derbyn; Mae pecynnau CTRh a dderbynnir gan y ffrwdiwr cyfryngau o'r rhwydwaith yn mynd i mewn i'r hidlydd rtprecv, y maent yn ymddangos ar ffurf blociau data ar yr allbwn, ac mae pob un ohonynt yn cyfateb i un pecyn a dderbyniwyd. Mae'r bloc yn cynnwys data llwyth tâl yn unig; yn yr erthygl flaenorol fe'u dangoswyd mewn gwyrdd yn y llun.

Nesaf, anfonir y blociau i'r hidlydd datgodiwr, sy'n trosi'r samplau un beit sydd ynddynt yn rhai llinol, 16-did. Pa rai y gellir eu prosesu eisoes gan hidlwyr ffrydio cyfryngau. Yn ein hachos ni, rydym yn syml yn eu hanfon at y cerdyn sain i'w chwarae ar siaradwyr eich clustffonau.

Nawr, gadewch i ni symud ymlaen at weithredu meddalwedd. I wneud hyn, byddwn yn cyfuno'r ffeiliau derbynnydd a throsglwyddydd y gwnaethom wahanu o'r blaen. Cyn hyn, fe wnaethon ni ddefnyddio gosodiadau sefydlog ar gyfer porthladdoedd a chyfeiriadau, ond nawr mae angen i'r rhaglen allu defnyddio'r gosodiadau rydyn ni'n eu nodi wrth gychwyn. I wneud hyn, byddem yn ychwanegu ymarferoldeb ar gyfer prosesu dadleuon llinell orchymyn. Ar ôl hynny byddwn yn gallu gosod y cyfeiriad IP a phorthladd yr intercom yr ydym am sefydlu cysylltiad ag ef.

Yn gyntaf, gadewch i ni ychwanegu strwythur at y rhaglen a fydd yn storio ei osodiadau:

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

typedef struct _app_vars app_vars;

Bydd y rhaglen yn datgan strwythur o'r math hwn o'r enw vars.
Nesaf, gadewch i ni ychwanegu swyddogaeth i ddosrannu dadleuon llinell orchymyn:

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

O ganlyniad i ddosrannu, bydd y dadleuon llinell orchymyn yn cael eu gosod ym meysydd strwythur vars. Prif swyddogaeth y cymhwysiad fydd casglu llwybrau trosglwyddo a derbyn o hidlwyr; ar ôl cysylltu'r ticiwr, bydd rheolaeth yn cael ei drosglwyddo i ddolen anfeidrol a fydd, pe bai amledd y generadur wedi'i osod i nad yw'n sero, yn ailgychwyn y generadur prawf fel bod mae'n gweithio heb stopio.

Bydd angen yr ailddechrau hyn ar y generadur oherwydd ei ddyluniad; am ryw reswm ni all gynhyrchu signal sy'n para mwy nag 16 eiliad. Dylid nodi bod ei hyd wedi'i nodi gan rif 32-bit.

Bydd y rhaglen gyfan yn edrych fel hyn:

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

Gadewch i ni lunio. Yna gellir rhedeg y rhaglen ar ddau gyfrifiadur. Neu ar un, fel y gwnaf yn awr. Rydym yn lansio TShark gyda'r dadleuon canlynol:

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

Os mai dim ond neges am ddechrau'r cipio y mae'r maes lansio yn y consol yn ei ddangos, yna mae hyn yn arwydd da - mae'n golygu nad yw ein porthladd yn fwyaf tebygol o gael ei feddiannu gan raglenni eraill. Mewn terfynell arall, rydym yn lansio enghraifft rhaglen a fydd yn efelychu intercom “o bell” trwy nodi'r rhif porthladd hwn:

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

Fel y gwelir o destun y rhaglen, y cyfeiriad IP rhagosodedig yw 127.0.0.1 (dolen leol).

Mewn terfynell arall, rydym yn lansio ail enghraifft o'r rhaglen, sy'n efelychu dyfais leol. Rydym yn defnyddio dadl ychwanegol sy'n caniatáu i'r generadur prawf adeiledig weithio:

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

Ar hyn o bryd, dylai pecynnau a drosglwyddir tuag at y ddyfais “o bell” ddechrau fflachio yn y consol gyda TShark, a bydd naws barhaus i'w chlywed gan siaradwr y cyfrifiadur.

Os digwyddodd popeth fel y'i hysgrifennwyd, yna rydym yn ailgychwyn ail gopi o'r rhaglen, ond heb yr allwedd a'r ddadl “—gen 440”. Byddwch nawr yn chwarae rôl generadur. Ar ôl hyn, gallwch chi wneud sŵn i'r meicroffon; dylech chi glywed y sain cyfatebol yn y siaradwr neu'r clustffonau. Gall hunan-gyffroi acwstig hyd yn oed ddigwydd; trowch i lawr cyfaint y siaradwr a bydd yr effaith yn diflannu.

Os gwnaethoch ei redeg ar ddau gyfrifiadur a heb ddrysu am y cyfeiriadau IP, yna mae'r un canlyniad yn aros amdanoch chi - cyfathrebu llais o ansawdd digidol dwy ffordd.

Yn yr erthygl nesaf byddwn yn dysgu sut i ysgrifennu ein hidlwyr ein hunain - ategion, diolch i'r sgil hon byddwch yn gallu defnyddio'r ffrwdwr cyfryngau nid yn unig ar gyfer sain a fideo, ond hefyd mewn maes penodol arall.

Ffynhonnell: hab.com

Ychwanegu sylw