Нийтлэлийн материалыг миний нийтлэлээс авсан болно .
Дуплекс интерком

Хамгийн сүүлд Дуплекс интерком зарласан бөгөөд бид үүнийг хийх болно.
Диаграммыг гарчгийн зурагт үзүүлэв. Доод шүүлтүүрийн хэлхээ нь дууны картаас эхэлдэг дамжуулах замыг бүрдүүлдэг. Энэ нь микрофоноос дохионы дээжийг гаргадаг. Анхдагч байдлаар, энэ нь секундэд 8000 дээжийн хурдаар тохиолддог. Медиа дамжуулагчийн аудио шүүлтүүрт ашигладаг өгөгдлийн нягтрал нь 16 бит (энэ нь тийм ч чухал биш, хэрэв хүсвэл илүү өндөр нарийвчлалтай ажилладаг шүүлтүүрийг бичиж болно). Өгөгдлийг 160 түүвэрт блок болгон бүлэглэсэн бөгөөд блок бүрийг 320 байт хэмжээтэй болгодог. Дараа нь бид өгөгдлийг генераторын оролт руу өгдөг бөгөөд энэ нь идэвхгүй болсон үед өгөгдөлд "ил тод" байдаг. Хэрэв та дибаг хийх явцад микрофон руу ярихаас залхаж байвал генераторыг ашиглан аялгууг "буудах" боломжтой болгохын тулд би үүнийг нэмсэн.
Генераторын дараа дохио нь кодлогч руу очдог бөгөөд энэ нь μ-хууль (G.711 стандарт) ашиглан бидний 16 битийн дээжийг 8 бит болгон хувиргадаг. Кодлогчийн гаралт дээр бид хагас хэмжээтэй өгөгдлийн блоктой боллоо. Ерөнхийдөө, хэрэв бид зурвасын өргөнийг хэмнэх шаардлагагүй бол өгөгдлийг шахахгүйгээр дамжуулах боломжтой. Гэхдээ Wireshark нь µ-хууль эсвэл α-хууль ашиглан шахагдсан тохиолдолд л RTP урсгалаас аудио тоглуулж чаддаг тул кодлогч ашиглах нь энд ашигтай.
Кодлогчийн дараа илүү хөнгөн өгөгдлийн блокуудыг rtpsend шүүлтүүр рүү илгээдэг бөгөөд энэ нь тэдгээрийг RTP багцад оруулж, шаардлагатай тугуудыг байрлуулж, сүлжээгээр UDP пакет хэлбэрээр дамжуулах медиа дамжуулагч руу дамжуулдаг.
Дээд шүүлтүүрийн гинж нь хүлээн авах замыг бүрдүүлдэг. Сүлжээнээс медиа дамжуулагчийн хүлээн авсан RTP пакетууд нь rtprecv шүүлтүүрт тэжээгддэг бөгөөд тэдгээрийн гаралтын үед тэдгээр нь өгөгдлийн блок хэлбэрээр гарч ирдэг бөгөөд тус бүр нь хүлээн авсан нэг пакеттай тохирдог. Блок нь зөвхөн ачааллын өгөгдлийг агуулдаг бөгөөд өмнөх нийтлэлийн зурагт ногоон өнгөөр үзүүлсэн.
Дараа нь блокуудыг декодчилогч шүүлтүүрт оруулдаг бөгөөд энэ нь тэдгээрт агуулагдсан нэг байт дээжийг шугаман 16 битийн өгөгдөл болгон хувиргадаг. Дараа нь тэдгээрийг медиа дамжуулагчийн шүүлтүүрээр боловсруулж болно. Манай тохиолдолд бид тэдгээрийг зүгээр л дууны картанд өгч, таны чихэвчний чанга яригч дээр тоглуулах боломжтой.
Одоо програм хангамжийн хэрэгжилт рүү шилжье. Үүнийг хийхийн тулд бид өмнө нь салгасан хүлээн авагч болон дамжуулагч файлуудыг нэгтгэх болно. Өмнө нь бид тогтмол порт болон хаягийн тохиргоог ашигладаг байсан бол одоо эхлүүлэх үед бидний зааж өгсөн тохиргоог ашиглах боломжтой програм хэрэгтэй байна. Үүнийг хийхийн тулд бид командын мөрийн аргументуудыг боловсруулах функцийг нэмнэ. Үүний дараа бид холбогдохыг хүссэн интерком төхөөрөмжийн IP хаяг болон портыг зааж өгөх боломжтой болно.
Эхлээд програмын тохиргоог хадгалах бүтцийг нэмж оруулъя.
struct _app_vars
{
int local_port; /* Локальный порт. */
int remote_port; /* Порт переговорного устройства на удаленном компьютере. */
char remote_addr[128]; /* IP-адрес удаленного компьютера. */
MSDtmfGenCustomTone dtmf_cfg; /* Настройки тестового сигнала генератора. */
};
typedef struct _app_vars app_vars;Хөтөлбөр нь 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]);
}
}
}Шинжилгээ хийсний дараа тушаалын мөрийн аргументуудыг vars бүтцийн талбарт байрлуулна. Програмын үндсэн функц нь шүүлтүүрээс дамжуулах, хүлээн авах замыг угсарна. Тикерийг холбосны дараа хяналтыг хязгааргүй давталт руу шилжүүлэх бөгөөд хэрэв генераторын давтамжийг тэгээс өөр утгад тохируулсан бол туршилтын генераторыг дахин ажиллуулснаар тасралтгүй ажиллах болно.
Эдгээр дахин эхлүүлэх нь түүний дизайны улмаас генераторын хувьд зайлшгүй шаардлагатай болно; ямар нэг шалтгааны улмаас энэ нь 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Програмын текстээс харахад өгөгдмөл IP хаяг нь 127.0.0.1 (локал давталт) юм.
Өөр нэг терминал дээр бид локал төхөөрөмжийг дуурайдаг програмын хоёр дахь хувилбарыг ажиллуулдаг. Бид суурилуулсан тест үүсгэгчийг идэвхжүүлэх нэмэлт аргументыг ашигладаг:
$ ./mstest8 --port 7010 --lport 9010 --gen 440Энэ үед "алсын" төхөөрөмж рүү дамжуулагдсан пакетууд TShark консол дээр анивчаж эхлэх бөгөөд компьютерийн чанга яригчаас тасралтгүй дууны дохио сонсогдоно.
Хэрэв бүх зүйл төлөвлөгөөний дагуу явагдсан бол "--gen 440" товчлуур болон аргументгүйгээр програмын хоёр дахь хувилбарыг дахин эхлүүлнэ үү. Та одоо генераторын үүргийг гүйцэтгэх болно. Үүний дараа та микрофон руу бага зэрэг чимээ гаргаж болно; Та чанга яригч эсвэл чихэвчнээс тохирох дууг сонсох ёстой. Та бүр акустик өөрийгөө өдөөж магадгүй; чанга яригчийн дууг багасгах нь үр нөлөөг арилгах болно.
Хэрэв та үүнийг хоёр компьютер дээр ажиллуулж, IP хаягийг нь будлиулаагүй бол ижил үр дүнд хүрэх болно - хоёр талын тоон чанарын дуут холбоо.
Дараагийн өгүүллээр бид өөрийн шүүлтүүр буюу залгаасуудыг хэрхэн бичих талаар сурах болно. Энэ ур чадвар нь танд медиа дамжуулагчийг зөвхөн аудио, видео бичлэгийн зориулалтаар ашиглахаас гадна бусад тодорхой хэсэгт ашиглах боломжийг олгоно.
Эх сурвалж: www.habr.com
