የጽሁፉ ይዘት ከኔ የተወሰደ ነው።
Duplex intercom
በመጨረሻው
ስዕሉ በርዕሱ ምስል ላይ ይታያል. የታችኛው የማጣሪያዎች ሰንሰለት የማስተላለፊያ መንገድን ይመሰርታል, ይህም ከድምጽ ካርዱ ይጀምራል. ከማይክሮፎን የሲግናል ናሙናዎችን ያቀርባል. በነባሪ, ይህ በሴኮንድ 8000 ናሙናዎች ፍጥነት ይከሰታል. የሚዲያ ዥረት ኦዲዮ ማጣሪያዎች የሚጠቀሙት የውሂብ ቢት ጥልቀት 16 ቢት ነው (ይህ አስፈላጊ አይደለም፣ ከፈለጉ፣ ከፍ ካለው ትንሽ ጥልቀት ጋር የሚሰሩ ማጣሪያዎችን መጻፍ ይችላሉ።) መረጃው ወደ 160 ናሙናዎች ብሎኮች ተመድቧል። ስለዚህ, እያንዳንዱ እገዳ 320 ባይት መጠኑ ነው. በመቀጠል, ውሂቡን ወደ ጄነሬተር ግቤት እንመግባለን, ሲጠፋ, ለውሂቡ "ግልጽ" ነው. በማረም ጊዜ ወደ ማይክሮፎን ማውራት ሰልችቶዎት እንደሆነ ጨምሬዋለሁ - ጄኔሬተሩን በድምጽ ምልክት መንገዱን “መተኮስ” ይችላሉ።
ከጄነሬተሩ በኋላ ምልክቱ ወደ ኢንኮደሩ ይሄዳል፣ ይህም ባለ 16-ቢት ናሙናዎቻችንን በµ-law (G.711 ስታንዳርድ) ወደ ስምንት-ቢት ይቀይራል። በመቀየሪያው ውፅዓት ላይ እኛ ቀድሞውኑ የግማሽ መጠኑን የውሂብ እገዳ አለን። በአጠቃላይ ትራፊክ መቆጠብ ካላስፈለገን ያለጭመቅ መረጃ ማስተላለፍ እንችላለን። እዚህ ግን ኢንኮደርን መጠቀም ጠቃሚ ነው፣ ምክንያቱም Wireshark ከRTP ዥረት ኦዲዮን ማባዛት የሚችለው በµ-law ወይም a-law መሰረት ሲጨመቅ ብቻ ነው።
ከመቀየሪያው በኋላ ቀለሉ የውሂብ ብሎኮች ወደ rtpsend ማጣሪያ ይላካሉ ፣ ይህም በ RTP ፓኬት ውስጥ ያስቀምጣቸዋል ፣ አስፈላጊዎቹን ባንዲራዎች ያዘጋጃል እና በ UDP ፓኬት መልክ በአውታረ መረቡ ላይ ለማስተላለፍ ለሚዲያ ዥረት ይሰጣል ።
የላይኛው የማጣሪያዎች ሰንሰለት የመቀበያ መንገዱን ይመሰርታል ፣ ከአውታረ መረቡ በሚዲያ ዥረቱ የተቀበሉት የ RTP እሽጎች ወደ rtprecv ማጣሪያ ውስጥ ይገባሉ ፣ በውጤታቸውም በውሂብ ብሎኮች መልክ ይታያሉ ፣ እያንዳንዱም ከተቀበለው ፓኬት ጋር ይዛመዳል። እገዳው የመጫኛ መረጃን ብቻ ይዟል፤ በቀደመው መጣጥፍ ላይ በምሳሌው ላይ በአረንጓዴ ታይተዋል።
በመቀጠል, ብሎኮች ወደ ዲኮደር ማጣሪያ ይላካሉ, ይህም በውስጣቸው ያሉትን ነጠላ-ባይት ናሙናዎችን ወደ መስመራዊ, 16-ቢት ይቀይራል. የትኛው አስቀድሞ በሚዲያ ዥረት ማጣሪያዎች ሊሰራ ይችላል። በእኛ ሁኔታ፣ በጆሮ ማዳመጫዎ ድምጽ ማጉያዎች ላይ መልሶ ለማጫወት በቀላሉ ወደ ድምጽ ካርድ እንልካቸዋለን።
አሁን ወደ ሶፍትዌር ትግበራ እንሂድ. ይህንን ለማድረግ ከዚህ በፊት የለየናቸውን ተቀባይ እና አስተላላፊ ፋይሎችን እናጣምራለን። ከዚህ በፊት ለወደቦች እና አድራሻዎች ቋሚ መቼቶችን እንጠቀም ነበር, አሁን ግን በጅምር ላይ የገለጽናቸውን መቼቶች ለመጠቀም ፕሮግራሙ ያስፈልገናል. ይህንን ለማድረግ የትእዛዝ መስመር ነጋሪ እሴቶችን ለማስኬድ ተግባር እንጨምራለን ። ከዚያ በኋላ ግንኙነት መመስረት የምንፈልገውን የኢንተርኮም አይፒ አድራሻ እና ወደብ ማዘጋጀት እንችላለን።
በመጀመሪያ ፣ ቅንብሮቹን የሚያከማችበትን መዋቅር ወደ ፕሮግራሙ እንጨምር-
struct _app_vars
{
int local_port; /* Локальный порт. */
int remote_port; /* Порт переговорного устройства на удаленном компьютере. */
char remote_addr[128]; /* IP-адрес удаленного компьютера. */
MSDtmfGenCustomTone dtmf_cfg; /* Настройки тестового сигнала генератора. */
};
typedef struct _app_vars app_vars;
ፕሮግራሙ ቫርስ የሚባል የዚህ አይነት መዋቅር ያውጃል።
በመቀጠል፣ የትእዛዝ መስመር ነጋሪ እሴቶችን ለመተንተን ተግባር እንጨምር፡-
/* Функция преобразования аргументов командной строки в
* настройки программы. */
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]);
}
}
}
በመተንተን ምክንያት, የትእዛዝ መስመር ግቤቶች በቫርስ መዋቅር መስኮች ውስጥ ይቀመጣሉ. የመተግበሪያው ዋና ተግባር ከማጣሪያዎች የማስተላለፊያ እና የመቀበያ መንገዶችን መሰብሰብ ይሆናል ፣ ምልክት ማድረጊያውን ካገናኙ በኋላ መቆጣጠሪያው ወደ ማለቂያ ወደሌለው ዑደት ይተላለፋል ፣ ይህም የጄነሬተር ድግግሞሽ ወደ ዜሮ ከተዋቀረ የሙከራ ጄነሬተርን እንደገና ያስጀምረዋል ። ያለማቋረጥ ይሠራል.
ጄኔሬተሩ በዲዛይኑ ምክንያት እነዚህን ዳግም ማስጀመር ያስፈልገዋል፤ በሆነ ምክንያት ከ16 ሰከንድ በላይ የሚቆይ ምልክት መስራት አይችልም። የእሱ ቆይታ በ 32-ቢት ቁጥር መገለጹን ልብ ሊባል ይገባል.
አጠቃላይ ፕሮግራሙ ይህን ይመስላል።
/* Файл 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);
}
}
እናጠናቅቅ። ከዚያ ፕሮግራሙ በሁለት ኮምፒተሮች ላይ ሊሠራ ይችላል. ወይም በአንደኛው, አሁን እንደማደርገው. TSharkን በሚከተሉት ነጋሪ እሴቶች እንጀምራለን፡
$ sudo tshark -i lo -f "udp dst port 7010" -P -V -O RTP -o rtp.heuristic_rtp:TRUE -x
በኮንሶሉ ውስጥ ያለው የማስጀመሪያ መስክ ስለ ቀረጻ ጅምር መልእክት ብቻ ካሳየ ይህ ጥሩ ምልክት ነው - ይህ ማለት ወደባችን በሌሎች ፕሮግራሞች ያልተያዘ ነው ማለት ነው። በሌላ ተርሚናል ላይ፣ ይህንን የወደብ ቁጥር በመግለጽ “የርቀት” ኢንተርኮምን የሚያስመስል የፕሮግራም ምሳሌ እንጀምራለን፡-
$ ./mstest8 --port 9010 --lport 7010
ከፕሮግራሙ ጽሑፍ ላይ እንደሚታየው, ነባሪው የአይፒ አድራሻ 127.0.0.1 (አካባቢያዊ loopback) ነው.
በሌላ ተርሚናል ውስጥ የፕሮግራሙን ሁለተኛ ምሳሌ እንጀምራለን, ይህም የአካባቢያዊ መሳሪያን ያስመስላል. አብሮገነብ የሙከራ ጀነሬተር እንዲሰራ የሚያስችል ተጨማሪ ነጋሪ እሴት እንጠቀማለን፡-
$ ./mstest8 --port 7010 --lport 9010 --gen 440
በዚህ ጊዜ ወደ "ርቀት" መሳሪያው የሚተላለፉ እሽጎች በኮንሶሉ ውስጥ በ TShark መብረቅ መጀመር አለባቸው እና ከኮምፒዩተር ድምጽ ማጉያው የማያቋርጥ ድምጽ ይሰማል.
ሁሉም ነገር እንደተፃፈ ከሆነ, የፕሮግራሙን ሁለተኛ ቅጂ እንደገና እንጀምራለን, ነገር ግን ያለ ቁልፍ እና ክርክር "- Gen 440". አሁን የጄነሬተር ሚና ትጫወታለህ. ከዚህ በኋላ ወደ ማይክሮፎኑ ድምጽ ማሰማት ይችላሉ, በድምጽ ማጉያው ወይም በጆሮ ማዳመጫው ውስጥ ያለውን ተዛማጅ ድምጽ መስማት አለብዎት. የአኮስቲክ ራስን መነቃቃት እንኳን ሊከሰት ይችላል፤ የተናጋሪውን ድምጽ ይቀንሱ እና ውጤቱ ይጠፋል።
በሁለት ኮምፒውተሮች ላይ ከሮጡ እና ስለ አይፒ አድራሻዎች ግራ ካልጋቡ ፣ ከዚያ ተመሳሳይ ውጤት ይጠብቀዎታል - ባለ ሁለት መንገድ ዲጂታል ጥራት ያለው የድምፅ ግንኙነት።
በሚቀጥለው ርዕስ ውስጥ የራሳችንን ማጣሪያዎች - ፕለጊኖች እንዴት እንደሚጽፉ እንማራለን, ለዚህ ችሎታ ምስጋና ይግባውና የሚዲያ ዥረቱን ለድምጽ እና ለቪዲዮ ብቻ ሳይሆን በሌላ የተወሰነ አካባቢም መጠቀም ይችላሉ.
ምንጭ: hab.com