የ Mediastreamer2 VoIP ሞተርን ማሰስ። ክፍል 6

የጽሁፉ ይዘት ከኔ የተወሰደ ነው። የዜን ቻናል.

የድምጽ ምልክት በ RTP ዥረት ማስተላለፍ

የ Mediastreamer2 VoIP ሞተርን ማሰስ። ክፍል 6

በመጨረሻው ጽሑፍ የርቀት መቆጣጠሪያ ወረዳን ከቶን ጀነሬተር እና በተመሳሳይ ፕሮግራም ውስጥ የሚሰራ የቶን ዳሳሽ ሰብስበናል። በዚህ ጽሑፍ ውስጥ የ RTP ፕሮቶኮልን (RFC 3550 -) እንዴት እንደሚጠቀሙ እንማራለን. RTP፡ ለእውነተኛ ጊዜ መተግበሪያዎች የትራንስፖርት ፕሮቶኮል) በኤተርኔት አውታረመረብ ላይ የድምፅ ምልክት ለመቀበል / ለማስተላለፍ.

አርቲፒ ፕሮቶኮል (እ.ኤ.አ.ሪል ታይም ፕሮቶኮል) የተተረጎመ ማለት የእውነተኛ ጊዜ ፕሮቶኮል ማለት ነው ፣ እሱ ኦዲዮ ፣ ቪዲዮ ፣ ዳታ ፣ በእውነተኛ ጊዜ ማስተላለፍ የሚፈልገውን ሁሉ ለማስተላለፍ ያገለግላል ። የድምጽ ምልክትን እንደ ምሳሌ እንውሰድ። የፕሮቶኮሉ ተለዋዋጭነት አስቀድሞ የተወሰነ ጥራት ያለው የድምጽ ምልክት ለማስተላለፍ የሚያስችል ነው።

ስርጭቱ የሚካሄደው የ UDP ፓኬቶችን በመጠቀም ነው, ይህ ማለት በሚተላለፉበት ጊዜ የፓኬት መጥፋት በጣም ተቀባይነት ያለው ነው. እያንዳንዱ ፓኬት ልዩ የ RTP ራስጌ እና የሚተላለፈው ምልክት የውሂብ እገዳ ይዟል. ራስጌው በዘፈቀደ የተመረጠ የሲግናል ምንጭ ለዪ፣ ስለሚተላለፍ ምልክት አይነት መረጃ እና ልዩ የሆነ የፓኬት ተከታታይ ቁጥር ይዟል ይህም ፓኬጆቹ ምንም አይነት ቅደም ተከተላቸው የደረሱበት ምንም ይሁን ምን እሽጎች ሲፈቱ በትክክለኛው ቅደም ተከተል እንዲቀመጡ ይደረጋል። አውታረ መረብ. ራስጌው በተጨማሪ መረጃን ሊይዝ ይችላል, ቅጥያ ተብሎ የሚጠራው, ይህም ራስጌው በአንድ የተወሰነ የመተግበሪያ ተግባር ውስጥ ለመጠቀም እንዲስማማ ያስችለዋል.

የውሂብ እገዳው የፓኬቱን ጭነት ይይዛል። የይዘቱ ውስጣዊ አደረጃጀት በጭነቱ አይነት ላይ የተመሰረተ ነው, እሱ የሞኖ ምልክት, የስቲሪዮ ምልክት, የቪዲዮ ምስል መስመር, ወዘተ ናሙናዎች ሊሆን ይችላል.

የጭነት አይነት በሰባት-ቢት ቁጥር ይገለጻል. የውሳኔ ሃሳብ RFC3551 (የ RTP መገለጫ ለኦዲዮ እና ቪዲዮ ኮንፈረንስ በትንሹ ቁጥጥር) በርካታ የጭነት ዓይነቶችን ያቋቁማል፤ ተጓዳኙ ሠንጠረዥ የጭነት ዓይነቶችን እና የተሾሙበትን የኮዶች ትርጉም መግለጫ ይሰጣል። አንዳንድ ኮዶች ከማንኛውም አይነት ጭነት ጋር በጥብቅ የተሳሰሩ አይደሉም፤ የዘፈቀደ ጭነትን ለመሰየም ሊያገለግሉ ይችላሉ።

የውሂብ እገዳው መጠን በተወሰነው አውታረ መረብ ላይ ያለ ክፍፍል (MTU parameter) ሊተላለፍ በሚችለው ከፍተኛው የፓኬት መጠን የተገደበ ነው። በአጠቃላይ ይህ ከ 1500 ባይት አይበልጥም. ስለዚህ, በሰከንድ የሚተላለፈውን የውሂብ መጠን ለመጨመር የፓኬቱን መጠን እስከ አንድ ነጥብ ድረስ ከፍ ማድረግ ይችላሉ, ከዚያም ፓኬቶችን የመላኪያ ድግግሞሽ መጨመር ያስፈልግዎታል. በሚዲያ ዥረት ውስጥ፣ ይህ ሊዋቀር የሚችል መቼት ነው። በነባሪነት 50 Hz ነው, ማለትም. በሰከንድ 50 ፓኬቶች. የተላለፉ የ RTP ፓኬቶችን ቅደም ተከተል የ RTP ዥረት እንላቸዋለን።

በምንጩ እና በተቀባዩ መካከል መረጃን ማስተላለፍ ለመጀመር አስተላላፊው የተቀባዩን አይፒ አድራሻ እና ለመቀበል የሚጠቀምበትን የወደብ ቁጥር ማወቁ በቂ ነው። እነዚያ። ያለ ምንም ቅድመ ሂደቶች, ምንጩ መረጃን ማስተላለፍ ይጀምራል, እና ተቀባዩ, በተራው, ወዲያውኑ ለመቀበል እና ለማስኬድ ዝግጁ ነው. በመስፈርቱ መሰረት የRTP ዥረት ለማስተላለፍም ሆነ ለመቀበል የሚያገለግለው የወደብ ቁጥር እኩል መሆን አለበት።

የተቀባዩን አድራሻ አስቀድሞ ማወቅ በማይቻልበት ሁኔታ ሰርቨሮች ተቀባዮች አድራሻቸውን በሚለቁበት ጊዜ ያገለግላሉ ፣ እና አስተላላፊው ልዩ የሆነ የተቀባዩን ስም በመጥቀስ ሊጠይቀው ይችላል።

የመገናኛ ቻናሉ ጥራት ወይም የተቀባዩ አቅም በማይታወቅበት ጊዜ ተቀባዩ ስለ አቅሙ፣ ስላመለጣቸው ፓኬጆች ብዛት፣ ወዘተ ለአስተላላፊው ማሳወቅ የሚችልበት የግብረ መልስ ቻናል ይዘጋጃል። ይህ ቻናል የ RTCP ፕሮቶኮልን ይጠቀማል። በዚህ ቻናል ውስጥ የሚተላለፉ የፓኬቶች ቅርጸት በ RFC 3605 ውስጥ ይገለጻል. በአንፃራዊነት ትንሽ መረጃ በዚህ ቻናል ላይ ይተላለፋል, በሰከንድ 200 ባይት, ስለዚህ በአጠቃላይ መገኘቱ ከባድ አይደለም. የ RTCP እሽጎች የሚላኩበት የወደብ ቁጥር ያልተለመደ እና የ RTP ዥረት ከሚመጣበት የወደብ ቁጥር የበለጠ መሆን አለበት። በምሳሌአችን ይህንን ቻናል አንጠቀምም ምክንያቱም የተቀባዩ እና ቻናሉ አቅም በግልፅ ከፍላጎታችን ስለሚበልጥ።

በፕሮግራማችን ውስጥ የውሂብ ማስተላለፊያ ዑደት, ከቀዳሚው ምሳሌ በተለየ መልኩ, በሁለት ክፍሎች ይከፈላል-ማስተላለፊያ መንገድ እና መቀበያ መንገድ. በርዕስ ስዕሉ ላይ እንደሚታየው ለእያንዳንዱ ክፍል የራሳችንን የሰዓት ምንጭ እንሰራለን ።

በመካከላቸው ባለ አንድ መንገድ ግንኙነት የ RTP ፕሮቶኮልን በመጠቀም ይከናወናል. በዚህ ምሳሌ ውስጥ, አስተላላፊው እና ተቀባዩ ሁለቱም በአንድ ኮምፒዩተር ላይ ስለሚገኙ ውጫዊ አውታረ መረብ አያስፈልገንም - ፓኬጆቹ በውስጡ ይጓዛሉ.

የRTP ዥረት ለመመስረት የሚዲያ ዥረቱ ሁለት ማጣሪያዎችን ይጠቀማል፡ MS_RTP_SEND እና MS_RTP_RECV። የመጀመሪያው ሁለተኛውን ያስተላልፋል እና የ RTP ዥረት ይቀበላል. እነዚህ ማጣሪያዎች እንዲሰሩ ጠቋሚን ወደ አርቲፒ ክፍለ ጊዜ ነገር ማስተላለፍ አለባቸው፣ ይህም የውሂብ ብሎኮችን ዥረት ወደ RTP ፓኬቶች ዥረት ሊለውጥ ወይም ተቃራኒውን ሊያደርግ ይችላል። የሚዲያ ዥረት አቅራቢው የውስጥ ዳታ ቅርጸት ከአርቲፒ ፓኬት የመረጃ ቅርፀት ጋር ስለማይዛመድ ውሂቡን ወደ MS_RTP_SEND ከማስተላለፍዎ በፊት፣ ባለ 16-ቢት የድምጽ ሲግናል ናሙናዎችን ወደ ስምንት ቢት ኮድ ወደ ሚለው መሰረት የሚቀይር ኢንኮደር ማጣሪያ መጠቀም ያስፈልግዎታል። u-law (mu-law)። በመቀበያው በኩል, ዲኮደር ማጣሪያው ተቃራኒውን ተግባር ያከናውናል.

ከዚህ በታች በሥዕሉ ላይ የሚታየውን እቅድ የሚተገበረው የፕሮግራሙ ጽሑፍ ነው (መመሪያዎችን ከማካተቱ በፊት ያሉት # ምልክቶች ተወግደዋል ፣ እነሱን ማካተትዎን አይርሱ)

/* Файл mstest6.c Имитатор пульта управления и приемника. */
#include <mediastreamer2/msfilter.h>
#include <mediastreamer2/msticker.h>
#include <mediastreamer2/dtmfgen.h>
#include <mediastreamer2/mssndcard.h>
#include <mediastreamer2/msvolume.h>
#include <mediastreamer2/mstonedetector.h>
#include <mediastreamer2/msrtp.h>
#include <ortp/rtpsession.h>
#include <ortp/payloadtype.h>
/* Подключаем заголовочный файл с функциями управления событиями
* медиастримера.*/
include <mediastreamer2/mseventqueue.h>
#define PCMU 0
/* Функция обратного вызова, она будет вызвана фильтром, как только он
обнаружит совпадение характеристик входного сигнала с заданными. */
static void tone_detected_cb(void *data, MSFilter *f, unsigned int event_id,
MSToneDetectorEvent *ev)
{
printf("Принята команда: %sn", ev->tone_name);
}
/*----------------------------------------------------------------------------*/
/* Функция регистрации типов полезных нагрузок. */
void register_payloads(void)
{
/*Регистрируем типы нагрузок в таблице профилей. Позднее, по индексу
взятому из заголовка RTP-пакета из этой таблицы будут извлекаться
параметры нагрузки, необходимые для декодирования данных пакета. */
rtp_profile_set_payload (&av_profile, PCMU, &payload_type_pcm8000);
}
/*----------------------------------------------------------------------------*/
/* Эта функция создана из функции create_duplex_rtpsession() в audiostream.c
медиастримера2. */
static RtpSession *
create_rtpsession (int loc_rtp_port, int loc_rtcp_port,
bool_t ipv6, RtpSessionMode mode)
{
RtpSession *rtpr;
rtpr = rtp_session_new ((int) mode);
rtp_session_set_scheduling_mode (rtpr, 0);
rtp_session_set_blocking_mode (rtpr, 0);
rtp_session_enable_adaptive_jitter_compensation (rtpr, TRUE);
rtp_session_set_symmetric_rtp (rtpr, TRUE);
rtp_session_set_local_addr (rtpr, ipv6 ? "::" : "0.0.0.0", loc_rtp_port,
loc_rtcp_port);
rtp_session_signal_connect (rtpr, "timestamp_jump",
(RtpCallback) rtp_session_resync, 0);
rtp_session_signal_connect (rtpr, "ssrc_changed",
(RtpCallback) rtp_session_resync, 0);
rtp_session_set_ssrc_changed_threshold (rtpr, 0);
rtp_session_set_send_payload_type(rtpr, PCMU);
/* По умолчанию выключаем RTCP-сессию, так как наш пульт не будет использовать её. */
rtp_session_enable_rtcp (rtpr, FALSE);
return rtpr;
}
/*----------------------------------------------------------------------------*/
int main()
{
ms_init();
/* Создаем экземпляры фильтров. */
MSFilter *voidsource = ms_filter_new(MS_VOID_SOURCE_ID);
MSFilter *dtmfgen = ms_filter_new(MS_DTMF_GEN_ID);
MSFilter *volume = ms_filter_new(MS_VOLUME_ID);
MSSndCard *card_playback =
ms_snd_card_manager_get_default_card(ms_snd_card_manager_get());
MSFilter *snd_card_write = ms_snd_card_create_writer(card_playback);
MSFilter *detector = ms_filter_new(MS_TONE_DETECTOR_ID);
/* Очищаем массив находящийся внутри детектора тонов, он описывает
* особые приметы разыскиваемых сигналов.*/
ms_filter_call_method(detector, MS_TONE_DETECTOR_CLEAR_SCANS, 0);
/* Подключаем к фильтру функцию обратного вызова. */
ms_filter_set_notify_callback(detector,
(MSFilterNotifyFunc)tone_detected_cb, NULL);
/* Создаем массив, каждый элемент которого описывает характеристику
* одного из тонов, который требуется обнаруживать: Текстовое имя
* данного элемента, частота в герцах, длительность в миллисекундах,
* минимальный уровень относительно 0,775В. */
MSToneDetectorDef scan[6]=
{
{"V+",440, 100, 0.1}, /* Команда "Увеличить громкость". */
{"V-",540, 100, 0.1}, /* Команда "Уменьшить громкость". */
{"C+",640, 100, 0.1}, /* Команда "Увеличить номер канала". */
{"C-",740, 100, 0.1}, /* Команда "Уменьшить номер канала". */
{"ON",840, 100, 0.1}, /* Команда "Включить телевизор". */
{"OFF", 940, 100, 0.1}/* Команда "Выключить телевизор". */
};
/* Передаем "приметы" сигналов детектор тонов. */
int i;
for (i = 0; i < 6; i++)
{
ms_filter_call_method(detector, MS_TONE_DETECTOR_ADD_SCAN,
&scan[i]);
}
/* Создаем фильтры кодера и декодера */
MSFilter *encoder = ms_filter_create_encoder("PCMU");
MSFilter *decoder=ms_filter_create_decoder("PCMU");
/* Регистрируем типы нагрузки. */
register_payloads();
/* Создаем RTP-сессию передатчика. */
RtpSession *tx_rtp_session = create_rtpsession (8010, 8011, FALSE, RTP_SESSION_SENDONLY);
rtp_session_set_remote_addr_and_port(tx_rtp_session,"127.0.0.1", 7010, 7011);
rtp_session_set_send_payload_type(tx_rtp_session, PCMU);
MSFilter *rtpsend = ms_filter_new(MS_RTP_SEND_ID);
ms_filter_call_method(rtpsend, MS_RTP_SEND_SET_SESSION, tx_rtp_session);
/* Создаем RTP-сессию приемника. */
MSFilter *rtprecv = ms_filter_new(MS_RTP_RECV_ID);
RtpSession *rx_rtp_session = create_rtpsession (7010, 7011, FALSE, RTP_SESSION_RECVONLY);
ms_filter_call_method(rtprecv, MS_RTP_RECV_SET_SESSION, rx_rtp_session);
/* Создаем источники тактов - тикеры. */
MSTicker *ticker_tx = ms_ticker_new();
MSTicker *ticker_rx = ms_ticker_new();
/* Соединяем фильтры передатчика. */
ms_filter_link(voidsource, 0, dtmfgen, 0);
ms_filter_link(dtmfgen, 0, volume, 0);
ms_filter_link(volume, 0, encoder, 0);
ms_filter_link(encoder, 0, rtpsend, 0);
/* Соединяем фильтры приёмника. */
ms_filter_link(rtprecv, 0, decoder, 0);
ms_filter_link(decoder, 0, detector, 0);
ms_filter_link(detector, 0, snd_card_write, 0);
/* Подключаем источник тактов. */
ms_ticker_attach(ticker_tx, voidsource);
ms_ticker_attach(ticker_rx, rtprecv);
/* Настраиваем структуру, управляющую выходным сигналом генератора. */
MSDtmfGenCustomTone dtmf_cfg;
dtmf_cfg.tone_name[0] = 0;
dtmf_cfg.duration = 1000;
dtmf_cfg.frequencies[0] = 440;
/* Будем генерировать один тон, частоту второго тона установим в 0. */
dtmf_cfg.frequencies[1] = 0;
dtmf_cfg.amplitude = 1.0;
dtmf_cfg.interval = 0.;
dtmf_cfg.repeat_count = 0.;
/* Организуем цикл сканирования нажатых клавиш. Ввод нуля завершает
* цикл и работу программы. */
char key='9';
printf("Нажмите клавишу команды, затем ввод.n"
"Для завершения программы введите 0.n");
while(key != '0')
{
key = getchar();
if ((key >= 49) && (key <= 54))
{
printf("Отправлена команда: %cn", key);
/* Устанавливаем частоту генератора в соответствии с
* кодом нажатой клавиши. */
dtmf_cfg.frequencies[0] = 440 + 100*(key-49);
/* Включаем звуковой генератор c обновленной частотой. */
ms_filter_call_method(dtmfgen, MS_DTMF_GEN_PLAY_CUSTOM,
(void*)&dtmf_cfg);
}
/* Укладываем тред в спячку на 20мс, чтобы другие треды
* приложения получили время на работу. */
ms_usleep(20000);
}
}

አዘጋጅተን እንሮጣለን. ፕሮግራሙ እንደ ቀደመው ምሳሌ ይሰራል ነገር ግን ውሂቡ በ RTP ዥረት በኩል ይተላለፋል።

በሚቀጥለው ጽሁፍ ይህንን ፕሮግራም በሁለት ገለልተኛ አፕሊኬሽኖች - ተቀባይ እና አስተላላፊ ከፋፍለን በተለያዩ ተርሚናሎች እንጀምራለን። በተመሳሳይ ጊዜ የ TShark ፕሮግራምን በመጠቀም የ RTP ፓኬቶችን እንዴት መተንተን እንደሚቻል እንማራለን.

ምንጭ: hab.com

አስተያየት ያክሉ