Artikli sisu on pärit minu .
Dupleks kõne seadmed

Eelmises osas Dupleks kõne seade on kuulutatud välja, ja selles me seda teeme.
Skeem on kujutatud pealkirja pildil. Alumine filtrite ahel moodustab saatmise tee, mis algab helikaardist. See edastab signaali mikrofoni. Vaikeväärtus on 8000 näidist sekundis. Andmete täpsus, mida helifiltrid meedia edastajas kasutavad, on 16 bit (see ei ole põhimõtteline, vajadusel on võimalik kirjutada filtreid, mis töötavad suurema täpsusega). Andmed on grupeeritud plokkideks, igaühes 160 näidist. Seega on iga ploki suurus 320 baiti. Edasi anname andmed generaatori sisendisse, mis on välja lülitatud olekus andmete jaoks "läbipaistev". Lisasin selle juhuks, kui te tahate debugimise ajal mikrofoni rääkides väsida — saate generaatorit kasutada, et "laskuda" trassi toonilise signaaliga.
Pärast generaatorit jõuab signaal kodeerijasse, mis muundab meie 16-bitised proovide µ-seaduse (G.711 standard) põhjal kaheksabitiseks. Kodeerija väljundis on meil juba andmepakett, mille suurus on poole väiksem. Üldiselt võime edastada andmeid kompressioonita, kui meil pole vajadust liiklust kokku hoida. Kuid siin on kasulik kasutada kodeerijat, kuna Wireshark suudab mängida heli RTP-voost ainult siis, kui see on komprimeeritud µ-seaduse või a-seaduse alusel.
Pärast kodeerijat suunatakse kerged andmepaketid rtpsend filtrisse, mis asetab need RTP-paketti, seadistab vajalikud lipud ja edastab need meediastrimerile edastamiseks võrgus UDP-paketi kujul.
Ülemine filtrite ahel moodustab vastuvõtu tee: RTP-paketid, mille meediastrimer võrgust saab, siseneb rtprecv filtrisse, mille väljundis ilmnevad need juba andmepakettidena, millest igaühel on oma vastuvõetud paketile vastav sisu. Paketis on ainult kasuliku koormuse andmed, mis olid eelmisel artiklis illustratsioonis kujutatud rohelise värviga.
Seejärel suunduvad blokkid dekoodri filtrisse, mis muudab neis sisalduvad ühekohalised mõõtmised lineaarseteks, 16-bitisteks. Need on juba ettevalmistatud meediastreamerite filtrite töötlemiseks. Antud juhul edastame need lihtsalt helikaardile, et need teie kõrvaklappide kõlarites mängiks.
Nüüd liigume tarkvaralise rakenduse juurde. Selleks ühendame vastuvõtja ja edastaja failid, mille oleme varem eraldanud. Varem kasutasime fikseeritud portide ja aadresside seadeid, kuid nüüd peame tagama, et programm saaks kasutada neid seadeid, mille me käivitamisel määrame. Selleks lisame käsurea argumentide töötlemise funktsionaalsuse. Pärast seda saame määrata IP-aadressi ja porti dialoogiseadmest, millega tahame ühendust luua.
Esmalt lisame programmi struktuuri, mis salvestab selle seaded:
struct _app_vars
{
int local_port; /* Kohalik pord. */
int remote_port; /* Eemalda pord. */
char remote_addr[128]; /* Eemalda arvuti IP-aadress. */
MSDtmfGenCustomTone dtmf_cfg; /* Testsignaali genereerija seaded. */
};
typedef struct _app_vars app_vars;Programmis kuulutatakse välja selle tüübi struktuur nimega vars.
Seejärel lisame käsurea argumentide eraldamise funktsiooni:
/* Функция преобразования аргументов командной строки в
* настройки программы. */
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]);
}
}
}Tulemuseks paigutatakse käsurea argumendid struktuuri vars väljadele. Rakenduse põhifunktsioon kogub filtreid edastus- ja vastuvõtuteede seadistamiseks, pärast tikri ühendamist antakse juhtimine üle lõputule tsüklile, mis, kui genereerija sagedus oli seatud mittebaasväljaks, taaskäivitab testgeneraatoreid — et see töötaks katkematult.
Need taaskäivitused on generaatori jaoks vajalikud tema ehituse eripära tõttu, kuid ta ei suuda kuidagi anda signaali, mille kestus ületaks 16 sekundit. Samuti tasub märkida, et kestus määratakse 32-bitise arvuna.
Programm näeb välja järgmine:
/* Файл 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);
}
}Kompileerime. Edasi saab programmi käivitada kahel arvutil. Või ühel, nagu ma nüüd teen. Käivitame TSharki järgmiste argumentidega:
$ sudo tshark -i lo -f "udp dst port 7010" -P -V -O RTP -o rtp.heuristic_rtp:TRUE -xKui käivituse väli konsoolis kuvab ainult sõnumi, et salvestamine on alanud, siis on see hea märk – meie port ei ole tõenäoliselt teiste programmide poolt hõivatud. Teises terminalis käivitame programmi eksemplari, mis imiteerib "kaug" suhtlusseadet, andes sellele selle porti numbri:
$ ./mstest8 --port 9010 --lport 7010Nagu programmi tekstist näha, kasutatakse vaikimisi IP-aadressi 127.0.0.1 (kohalik silmus).
Veel ühes terminalis käivitame programmi teise eksemplari, mis imiteerib kohaliku seadme. Kasutame täiendavat argumenti, mis lubab sisseehitatud testigeneraatori töötamise:
$ ./mstest8 --port 7010 --lport 9010 --gen 440Sel hetkel peaks TSharki konsoolis hakkama vilkuma paketid, mis saadetakse "kaug" seadme suunas, ja arvuti kõlarist kostub pidev tooniline signaal.
Kui kõik läks nagu ette nähtud, siis taaskäivitame teise programmi eksemplari, kuid ilma võtmeta ja argumendita "—gen 440". Nüüd täidate generaatori rolli teie. Pärast seda võite mikrofoni kaudu mürada, kõlaritest või kõrvaklappidest peaksite kuulma vastavat heli. Võimalik, et tekib isegi akustiline iseäratamine, vähendage helitugevust ja efekt kaob.
Kui olete käivitanud kahel arvutil ja ei ole IP-aadressides segadusse sattunud, siis ootab teid sama tulemus — kahepoolsed digitaalsete kvaliteediga helikõned.
Järgmises artiklis õpime kirjutama oma filtreid — pluginaid, tänu sellele oskusele suudate rakendada meediastrimmerit mitte ainult heli ja video, vaid ka mõnes muus spetsiifilises valdkonnas.
Allikas: habr.com
