Iniúchadh ar inneall VoIP Mediastreamer2. Cuid 9

Tógtar ábhar an ailt ó mo cainéal zen.

Idirchum déphléacsacha

Iniúchadh ar inneall VoIP Mediastreamer2. Cuid 9

Sa cheann deireanach Airteagal fógraíodh idirchum déphléacsach, agus sa cheann seo déanfaimid é.

Taispeántar an léaráid san fhigiúr teidil. Cruthaíonn slabhra níos ísle na scagairí an cosán tarchurtha, a thosaíonn ón gcárta fuaime. Soláthraíonn sé samplaí comhartha ón micreafón. De réir réamhshocraithe, tarlaíonn sé seo ag ráta 8000 sampla in aghaidh an tsoicind. Is é doimhneacht an ghiotán sonraí a úsáideann scagairí fuaime sruthaithe meán ná 16 giotán (níl sé seo tábhachtach; más mian leat, is féidir leat scagairí a scríobh a oibreoidh le doimhneacht giotán níos airde). Déantar na sonraí a ghrúpáil i mbloic de 160 sampla. Mar sin, tá gach bloc 320 bytes i méid. Ansin, cuirimid na sonraí ar fáil d'ionchur an ghineadóra, a bhíonn "trédhearcach" do na sonraí nuair a mhúchtar é. Chuir mé leis é ar eagla go n-éireoidh tú tuirseach de bheith ag caint isteach sa mhicreafón le linn dífhabhtaithe - is féidir leat an gineadóir a úsáid chun an cosán a “lámhaigh” le comhartha toin.

Tar éis an ghineadóra, téann an comhartha chuig an ionchódóir, a thiontaíonn ár samplaí 16-giotán de réir an µ-dlí (caighdeán G.711) i gceann ocht-giotán. Ag aschur an ionchódóra, tá bloc sonraí leath den mhéid againn cheana féin. Go ginearálta, is féidir linn sonraí a tharchur gan chomhbhrú mura gá dúinn trácht a shábháil. Ach anseo tá sé úsáideach ionchódóir a úsáid, toisc nach féidir le Wireshark fuaime a atáirgeadh ó shruth RTP ach amháin nuair a bhíonn sé comhbhrúite de réir an µ-dlí nó an dlí.

Tar éis an ionchódóra, seoltar na bloic sonraí níos éadroime chuig an scagaire rtpsend, a chuirfidh iad i bpaicéad RTP, socróidh siad na bratacha riachtanacha agus tabharfaidh siad chuig an sruthóir meáin iad le tarchur thar an líonra i bhfoirm paicéad UDP.

Is é an slabhra uachtair scagairí a fhoirmíonn an cosán glactha; cuireann paicéid RTP a fhaigheann an sruthóir meán ón líonra isteach an scagaire rtprecv, a bhfuil siad le feiceáil ag an aschur i bhfoirm bloic sonraí, agus comhfhreagraíonn gach ceann acu le paicéad faighte amháin. Níl sa bhloc ach sonraí pálasta; san alt roimhe seo taispeánadh i glas iad sa léaráid.

Ansin, seoltar na bloic chuig an scagaire díchódóra, a thiontaíonn na samplaí aon bheart atá iontu go cinn líneacha 16-giotán. Is féidir le scagairí streamer meáin a phróiseáil cheana féin. Inár gcás, ní dhéanaimid ach iad a sheoladh chuig an gcárta fuaime le haghaidh athsheinm ar chainteoirí do chluasáin.

Anois, a ligean ar bogadh ar aghaidh go dtí cur i bhfeidhm bogearraí. Chun seo a dhéanamh, cuirfimid na comhaid glacadóra agus tarchuradóra a scaramar roimhe seo le chéile. Roimhe seo, d'úsáideamar socruithe seasta le haghaidh calafoirt agus seoltaí, ach anois ní mór dúinn an clár a bheith in ann na socruithe a shonraíonn muid ag am tosaithe a úsáid. Chun seo a dhéanamh, chuirfimid feidhmiúlacht leis chun argóintí na n-orduithe a phróiseáil. Ina dhiaidh sin beimid in ann seoladh IP agus calafort an idirchum a shocrú lena dteastaíonn uainn nasc a bhunú.

Ar dtús, cuirimis struchtúr leis an gclár a stórálfaidh a chuid socruithe:

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

typedef struct _app_vars app_vars;

Dearbhóidh an clár struchtúr den chineál seo ar a dtugtar vars.
Ansin, cuirimis feidhm leis chun argóintí na n-orduithe a pharsáil:

/* Функция преобразования аргументов командной строки в
* настройки программы. */
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 ar pharsáil, cuirfear na hargóintí ordú i réimsí an struchtúir vars. Is í príomhfheidhm an fheidhmchláir ná cosáin tarchurtha agus glactha ó scagairí a bhailiú; tar éis an ticker a nascadh, aistreofar an rialú chuig lúb gan teorainn, agus má shocraítear minicíocht an ghineadóra go neamh-nialas, athshocróidh sé an gineadóir tástála ionas gur féidir oibríonn sé gan stad.

Beidh na hathchóirithe seo de dhíth ar an ngineadóir mar gheall ar a dhearadh; ar chúis éigin ní féidir leis comhartha a mhairfidh níos mó ná 16 soicind a tháirgeadh. Ba chóir a thabhairt faoi deara go bhfuil a ré sonraithe ag uimhir 32-giotán.

Beidh cuma mar seo ar an gclár iomlán:

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

A ligean ar a thiomsú. Ansin is féidir an clár a reáchtáil ar dhá ríomhaire. Nó ar cheann amháin, mar a dhéanfaidh mé anois. Seolaimid TShark leis na hargóintí seo a leanas:

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

Mura dtaispeánann an réimse seolta sa chonsól ach teachtaireacht faoi thús na gabhála, ansin is comhartha maith é seo - ciallaíonn sé gur dócha nach bhfuil ár gcalafort á áitiú ag cláir eile. I gcríochfort eile, seolann muid clár a insamhail idirchum “iargúlta” tríd an uimhir phoirt seo a shonrú:

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

Mar is léir ó théacs an chláir, is é an seoladh IP réamhshocraithe ná 127.0.0.1 (lobback áitiúil).

I gcríochfort eile, seolann muid an dara dul síos den chlár, a shamhlaíonn feiste áitiúil. Bainimid úsáid as argóint bhreise a ligeann don ghineadóir tástála ionsuite oibriú:

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

Ag an nóiméad seo, ba cheart go dtosódh paicéid a tharchuirtear chuig an ngléas “iargúlta” ag splancadh sa chonsól le TShark, agus cloisfear ton leanúnach ón gcainteoir ríomhaire.

Má tharla gach rud mar atá scríofa, déanaimid an dara cóip den chlár a atosú, ach gan an eochair agus an argóint “—gen 440”. Beidh ról an ghineadóra agat anois. Tar éis seo, is féidir leat torann a dhéanamh isteach sa mhicreafón; ba cheart duit an fhuaim chomhfhreagrach a chloisteáil sa chainteoir nó sna cluasáin. Is féidir fiú féin-excitation fuaimiúil tarlú; laghdaigh toirt an chainteora agus imeoidh an éifeacht.

Má rith tú é ar dhá ríomhaire agus mura raibh mearbhall ort faoi na seoltaí IP, ansin beidh an toradh céanna ag fanacht leat - cumarsáid gutha dhá bhealach ar chaighdeán digiteach.

San Airteagal seo chugainn beidh muid ag foghlaim conas a scríobh ár scagairí féin - forlíontáin, a bhuíochas leis an scil seo beidh tú in ann úsáid a bhaint as an streamer meáin, ní hamháin le haghaidh fuaime agus físe, ach freisin i réimse áirithe eile.

Foinse: will.com

Add a comment