Ihlola injini ye-Mediastreamer2 VoIP. Ingxenye 9

Indaba ye-athikili ithathwe kweyami ishaneli zen.

I-intercom ye-Duplex

Ihlola injini ye-Mediastreamer2 VoIP. Ingxenye 9

Ekugcineni isihloko kumenyezelwe i-duplex intercom, futhi kulokhu sizoyenza.

Umdwebo uboniswa esithombeni sesihloko. Iketango eliphansi lezihlungi lakha indlela yokudlulisela, eqala ekhadini lomsindo. Inikeza amasampula esignali asuka kumakrofoni. Ngokuzenzakalelayo, lokhu kwenzeka ngenani lamasampuli angu-8000 ngomzuzwana. Ukujula kwebhithi yedatha ezisetshenziswa izihlungi zomsindo ze-media streamer zingamabhithi angu-16 (lokhu akubalulekile; uma uthanda, ungabhala izihlungi ezizosebenza ngokujula okuphezulu kakhulu). Idatha ihlelwe yaba amabhulokhi amasampula angu-160. Ngakho, ibhulokhi ngalinye lingamabhayithi angu-320 ngosayizi. Okulandelayo, sondla idatha ekufakweni kwe-generator, okuthi, lapho ivaliwe, "isobala" kudatha. Ngiyengeze uma kwenzeka ukhathala ukukhuluma kumakrofoni ngesikhathi sokulungisa iphutha - ungasebenzisa ijeneretha "ukudubula" indlela ngesignali yethoni.

Ngemva kwejeneretha, isignali iya kusishumeki sekhodi, esiguqula amasampula ethu angu-16-bit ngokuya nge-µ-law (G.711 standard) abe amabhithi ayisishiyagalombili. Ekuphumeni kwesifaki khodi, sesivele sinebhulokhi yedatha uhhafu kasayizi. Ngokuvamile, singakwazi ukudlulisa idatha ngaphandle kokucindezelwa uma singadingi ukulondoloza ithrafikhi. Kodwa lapha kuyasiza ukusebenzisa isishumeki sekhodi, njengoba i-Wireshark ingakwazi ukukhiqiza kabusha umsindo ovela ekusakazweni kwe-RTP kuphela uma icindezelwe ngokuya µ-umthetho noma umthetho.

Ngemuva kokufaka ikhodi, amabhulokhi alula wedatha athunyelwa kusihlungi se-rtpsend, esizowafaka ephaketheni le-RTP, setha amafulegi adingekayo bese uwanikeza umsakazo wemidiya ukuze adluliselwe kunethiwekhi ngendlela yephakethe le-UDP.

Iketango eliphezulu lezihlungi lakha indlela yokwamukela; Amaphakethe e-RTP atholwe umsakazi wemidiya evela kunethiwekhi afaka isihlungi se-rtprecv, ekuphumeni kwaso avela ngendlela yamabhulokhi wedatha, ngalinye elihambisana nephakethe elilodwa elitholiwe. Ibhulokhi iqukethe idatha yomthwalo okhokhelwayo kuphela; esihlokweni esedlule aboniswe ngokuluhlaza emfanekisweni.

Okulandelayo, amabhlogo athunyelwa kusihlungi se-decoder, esiguqula amasampula ebhayithi eyodwa aqukethwe kuwo abe ngomugqa, angu-16-bit. Okusengacutshungulwa kakade izihlungi ze-media streamer. Kithina, simane sizithumele ekhadini lomsindo ukuze zidlale futhi kuzipikha zamahedsethi akho.

Manje ake siqhubekele ekusetshenzisweni kwesoftware. Ukuze senze lokhu, sizohlanganisa umamukeli kanye namafayela okudlulisela esiwahlukanise ngaphambili. Ngaphambi kwalokhu, sasebenzisa izilungiselelo ezihleliwe zamachweba namakheli, kodwa manje sidinga uhlelo ukuze lukwazi ukusebenzisa izilungiselelo esizicacisa ekuqaleni. Ukuze senze lokhu, sizongeza ukusebenza kokucubungula ama-agumenti omugqa womyalo. Ngemuva kwalokho sizokwazi ukusetha ikheli le-IP kanye nechweba le-intercom esifuna ukusungula uxhumano nalo.

Okokuqala, ake sengeze isakhiwo kuhlelo oluzogcina izilungiselelo zalo:

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

typedef struct _app_vars app_vars;

Uhlelo luzomemezela isakhiwo salolu hlobo olubizwa ngokuthi ama-vars.
Okulandelayo, ake sengeze umsebenzi ukuze sihlukanise izimpikiswano zomugqa womyalo:

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

Njengomphumela wokuhlaziya, izimpikiswano zomugqa womyalo zizobekwa ezindaweni zesakhiwo se-vars. Umsebenzi oyinhloko wohlelo lokusebenza kuzoba ukuqoqa izindlela zokudlulisa nokwamukela ezihlungini; ngemuva kokuxhuma ithikha, isilawuli sizodluliselwa ku-loop engapheli okuthi, uma imvamisa ye-generator isethwe kokungeyona i-zero, izoqala kabusha ijeneretha yokuhlola ukuze isebenza ngaphandle kokuma.

Ijeneretha izodinga lokhu kuqalisa kabusha ngenxa yokwakheka kwayo; ngesizathu esithile ayikwazi ukukhiqiza isignali ehlala imizuzwana eyi-16. Kufanele kuqashelwe ukuthi ubude bayo bucaciswe inombolo ye-32-bit.

Lonke uhlelo luzobukeka kanje:

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

Ake sihlanganise. Khona-ke uhlelo lungaqhutshwa kumakhompyutha amabili. Noma kokukodwa, njengoba ngizokwenza manje. Sethula i-TShark ngezimpikiswano ezilandelayo:

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

Uma inkambu yokwethulwa kukhonsoli ibonisa kuphela umlayezo mayelana nokuqala kokuthwebula, khona-ke lokhu kuwuphawu oluhle - kusho ukuthi ichweba lethu cishe alihlali ezinye izinhlelo. Kwesinye itheminali, sethula isibonelo sohlelo esizolingisa i-intercom “ekude” ngokucacisa le nombolo yembobo:

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

Njengoba kungabonwa embhalweni wohlelo, ikheli le-IP elizenzakalelayo lithi 127.0.0.1 (i-loopback yendawo).

Kwesinye isiphetho, sethula isibonelo sesibili sohlelo, esilingisa idivayisi yendawo. Sisebenzisa i-agumenti eyengeziwe evumela ukuthi ijeneretha yokuhlola eyakhelwe ngaphakathi isebenze:

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

Ngalesi sikhathi, amaphakethe adluliselwe kudivayisi “esilawuli kude” kufanele aqale ukukhanya kukhonsoli nge-TShark, futhi ithoni eqhubekayo izozwakala kusipika sekhompyutha.

Uma konke kwenzeke njengoba kubhaliwe, bese siqala kabusha ikhophi yesibili yohlelo, kodwa ngaphandle kokhiye nengxabano “-gen 440”. Manje uzodlala indima yejeneretha. Ngemuva kwalokhu, ungenza umsindo kumakrofoni; kufanele uzwe umsindo ohambisanayo kusipika noma kuma-headphone. Ukuzithokozisa kwe-acoustic kungase kwenzeke; yehlisa ivolumu yesipika futhi umphumela uzonyamalala.

Uma uyisebenzise kumakhompuyutha amabili futhi ungazange udideke mayelana namakheli e-IP, umphumela ofanayo ulindele wena - ukuxhumana kwezwi ledijithali kwezindlela ezimbili.

Esihlokweni esilandelayo sizofunda ukuthi singabhala kanjani izihlungi zethu - ama-plugin, ngenxa yaleli khono uzokwazi ukusebenzisa i-media streamer hhayi kuphela umsindo nevidiyo, kodwa nakwenye indawo ethile.

Source: www.habr.com

Engeza amazwana