Ukuphonononga injini yeMediastreamer2 VoIP. Icandelo 9

Izinto zenqaku zithathwe kum zen channel.

Duplex intercom

Ukuphonononga injini yeMediastreamer2 VoIP. Icandelo 9

Ekugqibeleni nqaku kwabhengezwa i-duplex intercom, kwaye kule siza kuyenza.

Umzobo uboniswe kumfanekiso wesihloko. Ikhonkco elisezantsi lezihluzi lenza indlela yothumelo, eqala kwikhadi lesandi. Inika iisampulu zomqondiso ukusuka kwimakrofoni. Ngokungagqibekanga, oku kwenzeka ngesantya seesampuli ezingama-8000 ngomzuzwana. Ubunzulu besuntswana ledatha olusetyenziswa zizihluzi zeaudio zemidiya yemidiya ngamasuntswana ali-16 (oku akubalulekanga; ukuba uyanqwenela, ungabhala izihluzo eziya kusebenza ngobunzulu obuphezulu besuntswana). Idatha ihlanganiswe kwiibhloko zeesampuli ze-160. Ngaloo ndlela, ibhloko nganye yi-320 bytes ngobukhulu. Emva koko, sondla idatha kwigalelo le-generator, ethi, xa ivaliwe, "icacile" kwidatha. Ndongeze ukuba udinwe kukuthetha kwimakrofoni ngexesha lokulungisa ingxaki - ungasebenzisa ijeneretha "ukudubula" indlela ngethoni yesiginali.

Emva kwejenereyitha, umqondiso uya kwi-encoder, ethi iguqule iisampulu zethu ze-16-bit ngokomthetho weµ (G.711 standard) zibe ziibhithi ezisibhozo. Kwimveliso ye-encoder, sele sinayo ibhloko yedatha yesiqingatha sobukhulu. Ngokubanzi, sinokuhambisa idatha ngaphandle koxinzelelo ukuba asidingi kugcina i-traffic. Kodwa apha kuluncedo ukusebenzisa i-encoder, kuba iWireshark inokuvelisa kwakhona iaudio kwiRTP umsinga kuphela xa icinezelwe ngokomthetho µ okanye umthetho.

Emva kwe-encoder, iibhloko ezikhanyayo zedatha zithunyelwa kwifayile ye-rtpsend, eya kubafaka kwipakethi ye-RTP, ibeke iiflegi eziyimfuneko kwaye ibanike i-media streamer yokudluliselwa kwinethiwekhi ngendlela yepakethi ye-UDP.

Ikhonkco eliphezulu lezihluzi zenza indlela yokufumana; Iipakethi ze-RTP ezifunyenwe ngumsasazi weendaba kwinethiwekhi zingena kwisihluzo se-rtprecv, ekuphumeni kwayo kubonakala ngendlela yeebhloko zedatha, nganye ehambelana nepakethi enye efunyenweyo. Ibhloko iqulethe idatha yokuhlawula kuphela; kwinqaku elidlulileyo baboniswe eluhlaza kumfanekiso.

Emva koko, iibhloko zithunyelwa kwisihluzo se-decoder, esiguqula iisampulu zebhayithi enye equlethwe kuzo zibe yimida, i-16-bit. Esele iqhutywe zizihluzo zemidiya yemidiya. Kwimeko yethu, sizithumela ngokulula kwikhadi lesandi ukuze udlale kwakhona kwizithethi ze-headset yakho.

Ngoku makhe siqhubele phambili ekuphunyezweni kwesoftware. Ukwenza oku, siya kudibanisa umamkeli kunye neefayile zokuhambisa esizihlule ngaphambili. Ngaphambi koku, sasebenzisa izicwangciso ezisisigxina zamachweba kunye needilesi, kodwa ngoku sifuna inkqubo ukuze ikwazi ukusebenzisa izicwangciso esizichazayo ekuqaleni. Ukwenza oku, siyakongeza umsebenzi wokuqhubekekisa iingxoxo zomgca womyalelo. Emva koko siya kukwazi ukuseta idilesi ye-IP kunye nechweba le-intercom esifuna ukuseka uqhagamshelo.

Okokuqala, masenze ulwakhiwo kwinkqubo eya kugcina useto lwayo:

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

typedef struct _app_vars app_vars;

Inkqubo iya kubhengeza ubume bolu hlobo olubizwa ngokuba zii-vars.
Okulandelayo, masenze umsebenzi wokwahlulahlula iingxoxo zomgca womyalelo:

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

Njengesiphumo sokwahlulahlula, iingxoxo zomgca womyalelo ziya kubekwa kwimimandla yesakhiwo se-vars. Umsebenzi ophambili wesicelo iya kuba kukuqokelela iindlela zokuhambisa kunye nokufumana ukusuka kwizihluzi; emva kokudibanisa inqaku, ulawulo luya kudluliselwa kwiluphu engapheliyo apho, ukuba i-frequency yejenereyitha isetelwe kwi-non-zero, iya kuphinda iqalise ijenereyitha yovavanyo ukuze isebenza ngaphandle kokuyeka.

Ijenereyitha iya kufuna oku kuqaliswa kwakhona ngenxa yoyilo lwayo; ngesizathu esithile ayikwazi ukuvelisa uphawu oluhlala ngaphezu kwemizuzwana ye-16. Kufuneka kuqatshelwe ukuba ubude bayo buchazwe ngenani le-32-bit.

Yonke inkqubo iya kujongeka ngolu hlobo:

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

Masiqokelele. Emva koko inkqubo inokuqhutywa kwiikhompyuter ezimbini. Okanye kwelinye, njengoko ndiza kwenza ngoku. Siphehlelela i-TShark ngezi ngxoxo zilandelayo:

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

Ukuba ibala lokuphehlelelwa kwikhonsoli libonisa kuphela umyalezo malunga nokuqala kokubamba, ke olu luphawu olulungileyo - oko kuthetha ukuba izibuko lethu alinakuhlala ezinye iinkqubo. Kwesinye i-terminal, siqalisa umzekelo wenkqubo oza kulinganisa i-intercom "ekude" ngokuchaza le nombolo yezibuko:

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

Njengoko kunokubonwa kumbhalo weprogram, idilesi ye-IP engagqibekanga ngu-127.0.0.1 (i-loopback yendawo).

Kwesinye i-terminal, siqalisa umzekelo wesibini wenkqubo, elinganisa isixhobo sasekhaya. Sisebenzisa ingxabano eyongezelelweyo evumela ukuba ijenereyitha yovavanyo eyakhelwe-ngaphakathi isebenze:

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

Ngeli xesha, iipakethi ezithunyelwa kwisixhobo "esikude" kufuneka ziqale ukudanyaza kwikhonsoli nge TShark, kwaye ithoni eqhubekayo iya kuviwa kwisithethi sekhompyuter.

Ukuba yonke into yenzeka njengoko kubhaliwe, ngoko siqala kwakhona ikopi yesibini yeprogram, kodwa ngaphandle kwesitshixo kunye nengxabano "-gen 440". Ngoku uya kudlala indima yejenereyitha. Emva koku, unokwenza ingxolo kwi-microphone; kufuneka uve isandi esihambelanayo kwisithethi okanye kwi-headphones. I-acoustic self-excitation inokwenzeka; yehlisa ivolyum yesithethi kwaye umphumo uya kunyamalala.

Ukuba uqhube kwiikhomputha ezimbini kwaye awuzange udideke malunga needilesi ze-IP, ngoko umphumo ofanayo ulindele wena-unxibelelwano lwezwi lwedijithali oluneendlela ezimbini.

Kwinqaku elilandelayo siza kufunda indlela yokubhala ezethu izihluzi - iiplagi, ngenxa yolu buchule uya kukwazi ukusebenzisa i-media streamer kungekuphela nje kwi-audio kunye nevidiyo, kodwa nakwenye indawo ethile.

umthombo: www.habr.com

Yongeza izimvo