Ny fitaovan'ny lahatsoratra dia nalaina avy amin'ny ahy
Duplex intercom
Amin'ny farany
Ny kisary dia aseho amin'ny sarin'ny lohateny. Ny rojo sivana ambany dia mamorona ny lalan'ny fifindrana, izay manomboka amin'ny karatra fanamafisam-peo. Izy io dia manome santionany famantarana avy amin'ny mikrΓ΄. Amin'ny alΓ lan'ny default, izany dia mitranga amin'ny tahan'ny santionany 8000 isan-tsegondra. Ny halalin'ny angon-drakitra ampiasain'ny sivana audio streamer dia 16 bits (tsy zava-dehibe izany, raha tianao dia azonao atao ny manoratra sivana izay hiasa amin'ny halalin'ny kely kokoa). Ny angon-drakitra dia navondrona ho blocs misy santionany 160. Noho izany, ny bloc tsirairay dia 320 bytes ny habeny. Manaraka, mamahana ny angon-drakitra amin'ny fampidirana ny mpamokatra, izay, rehefa tapaka, dia "mangarahara" amin'ny data. Nampiako izany raha toa ka reraky ny miresaka amin'ny mikrΓ΄ ianao mandritra ny debugging - azonao atao ny mampiasa ny gropy mba "hitifitra" ny lalana miaraka amin'ny mari-pamantarana feo.
Aorian'ny famokarana, ny famantarana dia mankany amin'ny encoder, izay mamadika ny santionany 16-bit araka ny lalΓ na Β΅ (G.711 standard) ho lasa valo-bit. Amin'ny fivoahan'ny encoder dia efa manana sakana angon-drakitra ny antsasaky ny habeny. Amin'ny ankapobeny, afaka mamindra angona tsy misy famoretana isika raha tsy mila mitsitsy fifamoivoizana. Fa eto dia ilaina ny mampiasa encoder, satria Wireshark dia afaka mamerina feo avy amin'ny RTP stream raha tsy rehefa voatsindry araka ny Β΅-lalΓ na na a-lalΓ na.
Aorian'ny encoder dia alefa any amin'ny sivana rtpsend ireo sakana maivana kokoa, izay hametraka azy ireo ao anaty fonosana RTP, mametraka ny saina ilaina ary manome azy ireo amin'ny streamer media ho an'ny fampitana amin'ny tambajotra amin'ny endrika fonosana UDP.
Ny rojo sivana ambony dia mamorona ny lalana fandraisana; Ny fonosana RTP noraisin'ny media streamer avy amin'ny tambajotra dia miditra amin'ny sivana rtprecv, amin'ny famoahana azy ireo amin'ny endrika sakana data, izay mifanaraka amin'ny fonosana iray voaray. Ny sakana dia tsy misy afa-tsy angon-drakitra momba ny karama; tao amin'ny lahatsoratra teo aloha dia naseho tamin'ny maitso izy ireo tamin'ny sary.
Avy eo dia alefa any amin'ny sivana decoder ireo sakana, izay mamadika ireo santionany tokana misy ao aminy ho lasa tsipika, 16-bit. Izay efa azo karakarain'ny sivana streamer media. Amin'ny tranga misy anay, alefanay any amin'ny karatra fanamafisam-peo fotsiny izy ireo mba hamerenana amin'ny fanamafisam-peo amin'ny headset.
Andeha isika hiroso amin'ny fampiharana rindrambaiko. Mba hanaovana izany, dia hanambatra ny fisie mpandray sy mpandefa izay nosarahanay taloha. Talohan'izay dia nampiasa rindrankajy raikitra ho an'ny seranan-tsambo sy adiresy izahay, fa ankehitriny dia mila ny programa izahay mba hahafahana mampiasa ny toe-javatra voafaritra amin'ny fanombohana. Mba hanaovana izany, dia hanampy fampiasa amin'ny fanodinana ny tohan-kevitra andalana baiko. Aorian'izay dia ho afaka hametraka ny adiresy IP sy ny seranan-tsambon'ny intercom izay tiantsika hanorina fifandraisana.
Voalohany, andeha isika hanampy rafitra iray amin'ny programa izay hitahiry ny firafiny:
struct _app_vars
{
int local_port; /* ΠΠΎΠΊΠ°Π»ΡΠ½ΡΠΉ ΠΏΠΎΡΡ. */
int remote_port; /* ΠΠΎΡΡ ΠΏΠ΅ΡΠ΅Π³ΠΎΠ²ΠΎΡΠ½ΠΎΠ³ΠΎ ΡΡΡΡΠΎΠΉΡΡΠ²Π° Π½Π° ΡΠ΄Π°Π»Π΅Π½Π½ΠΎΠΌ ΠΊΠΎΠΌΠΏΡΡΡΠ΅ΡΠ΅. */
char remote_addr[128]; /* IP-Π°Π΄ΡΠ΅Ρ ΡΠ΄Π°Π»Π΅Π½Π½ΠΎΠ³ΠΎ ΠΊΠΎΠΌΠΏΡΡΡΠ΅ΡΠ°. */
MSDtmfGenCustomTone dtmf_cfg; /* ΠΠ°ΡΡΡΠΎΠΉΠΊΠΈ ΡΠ΅ΡΡΠΎΠ²ΠΎΠ³ΠΎ ΡΠΈΠ³Π½Π°Π»Π° Π³Π΅Π½Π΅ΡΠ°ΡΠΎΡΠ°. */
};
typedef struct _app_vars app_vars;
Ny programa dia hanambara rafitra iray amin'ity karazana antsoina hoe vars.
Manaraka, ndao ampio asa iray handinihana ny arguments command line:
/* Π€ΡΠ½ΠΊΡΠΈΡ ΠΏΡΠ΅ΠΎΠ±ΡΠ°Π·ΠΎΠ²Π°Π½ΠΈΡ Π°ΡΠ³ΡΠΌΠ΅Π½ΡΠΎΠ² ΠΊΠΎΠΌΠ°Π½Π΄Π½ΠΎΠΉ ΡΡΡΠΎΠΊΠΈ Π²
* Π½Π°ΡΡΡΠΎΠΉΠΊΠΈ ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΌΡ. */
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]);
}
}
}
Vokatry ny famakafakana dia hapetraka ao amin'ny sahan'ny firafitry ny vars ny tohan-kevitra andalana baiko. Ny tena anjara asan'ny fampiharana dia ny hanangona ny fampitana sy ny fandraisana lalana avy amin'ny sivana; aorian'ny fampifandraisana ny ticker, ny fanaraha-maso dia hafindra amin'ny loop tsy manam-petra izay, raha toa ka napetraka amin'ny tsy aotra ny fatran'ny mpamokatra, dia hamerina indray ny mpamokatra fitsapana ka miasa tsy miato.
Ny mpamokatra dia mila ireo famerenana ireo noho ny famolavolana azy; noho ny antony tsy ahafahany mamoaka famantarana maharitra mihoatra ny 16 segondra. Tsara homarihina fa ny faharetany dia voafaritra amin'ny isa 32-bit.
Ny fandaharana manontolo dia ho toy izao:
/* Π€Π°ΠΉΠ» 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);
}
}
Andao hanangona. Avy eo dia azo atao amin'ny ordinatera roa ny programa. Na amin'ny iray, toy ny hataoko izao. Manomboka TShark miaraka amin'ireto hevitra manaraka ireto izahay:
$ sudo tshark -i lo -f "udp dst port 7010" -P -V -O RTP -o rtp.heuristic_rtp:TRUE -x
Raha ny sahan'ny fanombohana ao amin'ny console ihany no mampiseho hafatra momba ny fanombohan'ny fisamborana, dia famantarana tsara izany - midika izany fa ny seranan-tsambontsika dia azo inoana fa tsy misy programa hafa. Ao amin'ny terminal iray hafa, dia manomboka programa iray izahay izay hanahaka ny intercom "lavitra" amin'ny alΓ lan'ny famaritana ity laharana seranana ity:
$ ./mstest8 --port 9010 --lport 7010
Araka ny hita amin'ny lahatsoratry ny programa, ny adiresy IP default dia 127.0.0.1 (loopback eo an-toerana).
Any amin'ny terminal iray hafa, dia manomboka ohatra faharoa amin'ny programa izahay, izay mamolavola fitaovana eo an-toerana. Mampiasa tohan-kevitra fanampiny izahay izay ahafahan'ny mpamokatra fitsapana naorina:
$ ./mstest8 --port 7010 --lport 9010 --gen 440
Amin'izao fotoana izao, ny fonosana ampitaina mankany amin'ny fitaovana "lavitra" dia tokony hanomboka hikoropaka ao amin'ny console miaraka amin'ny TShark, ary hisy feo mitohy ho re avy amin'ny mpandahateny solosaina.
Raha toa ka nitranga araka ny voasoratra ny zava-drehetra, dia averinay indray ny kopia faharoa amin'ny programa, fa tsy misy ny fanalahidy sy ny tohan-kevitra "-gen 440". Hilalao ny andraikitry ny mpamokatra ianao izao. Aorian'izany dia afaka manao tabataba amin'ny mikrΓ΄ ianao; tokony handre ny feo mifanaraka amin'izany ianao amin'ny fanamafisam-peo na headphone. Mety hitranga mihitsy aza ny fientanam-po amin'ny acoustic; ampidino ny haavon'ny mpandahateny dia hanjavona ny vokany.
Raha mihazakazaka amin'ny solosaina roa ianao ary tsy very hevitra momba ny adiresy IP, dia ny vokatra mitovy ihany no miandry anao - fifandraisana feo nomerika roa.
Ao amin'ny lahatsoratra manaraka dia hianarantsika ny fomba fanoratana ny sivana manokana - plugins, noho io fahaiza-manao io dia ho afaka hampiasa ny streamer amin'ny haino aman-jery ianao tsy ho an'ny feo sy horonan-tsary, fa amin'ny faritra hafa manokana.
Source: www.habr.com