Mediastreamer2 VoIP انجڻ جي ڳولا. حصو 6

مضمون جو مواد منهنجي طرفان ورتو ويو آهي زين چينل.

آر ٽي پي اسٽريم ذريعي آڊيو سگنل منتقل ڪرڻ

Mediastreamer2 VoIP انجڻ جي ڳولا. حصو 6

آخري ۾ مضمون اسان هڪ ريموٽ ڪنٽرول سرڪٽ گڏ ڪيو آهي هڪ ٽون جنريٽر ۽ هڪ ٽون ڊيڪٽر کان جيڪو ساڳئي پروگرام ۾ ڪم ڪري ٿو. هن آرٽيڪل ۾ اسين سکنداسين ته ڪيئن استعمال ڪجي RTP پروٽوڪول (RFC 3550 - RTP: حقيقي وقت جي ايپليڪيشنن لاءِ هڪ ٽرانسپورٽ پروٽوڪول) هڪ ايٿرنيٽ نيٽ ورڪ تي هڪ آڊيو سگنل وصول ڪرڻ / منتقل ڪرڻ لاء.

آر ٽي پي پروٽوڪول (حقيقي وقت پروٽوڪول) ترجمو ٿيل مطلب حقيقي وقت پروٽوڪول، اهو آڊيو، وڊيو، ڊيٽا، هر شي کي منتقل ڪرڻ لاء استعمال ڪيو ويندو آهي جيڪو حقيقي وقت ۾ ٽرانسميشن جي ضرورت آهي. اچو ته مثال طور هڪ آڊيو سگنل وٺو. پروٽوڪول جي لچڪ اهڙي آهي ته اها توهان کي اجازت ڏئي ٿي هڪ آڊيو سگنل منتقل ڪرڻ جي اڳواٽ معيار سان.

ٽرانسميشن يو ڊي پي پيڪٽ استعمال ڪندي ڪئي وئي آهي، جنهن جو مطلب آهي ته پيڪٽ نقصان ٽرانسميشن دوران ڪافي قابل قبول آهي. هر پيٽ ۾ هڪ خاص RTP هيڊر ۽ منتقل ٿيل سگنل جي ڊيٽا بلاڪ شامل آهي. هيڊر ۾ بي ترتيب طور تي چونڊيل سگنل ماخذ جي سڃاڻپ ڪندڙ، سگنل جي منتقلي جي قسم بابت معلومات، ۽ هڪ منفرد پيڪٽ جي ترتيب نمبر تي مشتمل آهي ته جيئن پيڪيٽس کي صحيح ترتيب ۾ ترتيب ڏئي سگهجي جڏهن ڊيڪوڊنگ ڪئي وئي، قطع نظر ته اهي آرڊر جنهن ۾ اهي ڊيليور ڪيا ويا آهن. نيٽ ورڪ هيڊر ۾ اضافي معلومات پڻ شامل ٿي سگھي ٿي، جنهن کي نام نهاد ايڪسٽينشن چيو وڃي ٿو، جيڪو هيڊر کي ڪنهن مخصوص ايپليڪيشن ٽاسڪ ۾ استعمال لاءِ ترتيب ڏيڻ جي اجازت ڏئي ٿو.

ڊيٽا بلاڪ پيڪٽ جي پيل لوڊ تي مشتمل آهي. مواد جي اندروني تنظيم لوڊ جي قسم تي منحصر آهي، اهو هڪ مونو سگنل جا نمونا، هڪ اسٽيريو سگنل، هڪ وڊيو تصويري لائن، وغيره.

لوڊ جو قسم ست-بٽ نمبر سان اشارو ڪيو ويو آهي. سفارش RFC3551 (آر ٽي پي پروفائل آڊيو ۽ وڊيو ڪانفرنسن لاءِ گھٽ ۾ گھٽ ڪنٽرول سان) لوڊ جي ڪيترن ئي قسمن کي قائم ڪري ٿو؛ لاڳاپيل جدول لوڊ جي قسمن جي وضاحت ۽ ڪوڊس جي معني مهيا ڪري ٿي جن جي ذريعي اهي نامزد ڪيا ويا آهن. ڪجهه ڪوڊ سختي سان ڪنهن به قسم جي لوڊ سان جڙيل نه آهن؛ انهن کي استعمال ڪري سگهجي ٿو هڪ خودمختياري لوڊ ڪرڻ لاءِ.

ڊيٽا بلاڪ جي ماپ مٿي محدود آهي وڌ ۾ وڌ پيڪٽ جي سائيز جي ذريعي جيڪا ڪنهن نيٽ ورڪ تي بغير ڪنهن ڀاڱي جي منتقل ڪري سگهجي ٿي (MTU پيٽرول). عام طور تي، هي 1500 بائيٽ کان وڌيڪ ناهي. اهڙيءَ طرح، هر سيڪنڊ ۾ منتقل ٿيل ڊيٽا جي مقدار کي وڌائڻ لاءِ، توهان پيڪيٽ جي سائيز کي هڪ خاص نقطي تائين وڌائي سگهو ٿا، ۽ پوءِ توهان کي پيڪيٽ موڪلڻ جي تعدد کي وڌائڻو پوندو. ميڊيا اسٽريمر ۾، هي هڪ ترتيب ڏيڻ واري سيٽنگ آهي. ڊفالٽ طور اهو 50 هز آهي، يعني. 50 پيڪيٽ في سيڪنڊ. اسان منتقل ٿيل RTP پيڪٽس جي تسلسل کي RTP وهڪرو سڏينداسين.

ماخذ ۽ وصول ڪندڙ جي وچ ۾ ڊيٽا کي منتقل ڪرڻ شروع ڪرڻ لاء، اهو ڪافي آهي ته ٽرانسميٽر وصول ڪندڙ جي IP پتي ۽ پورٽ نمبر ڄاڻي ٿو جيڪو اهو حاصل ڪرڻ لاء استعمال ڪندو آهي. اهي. بغير ڪنهن ابتدائي طريقيڪار جي، ذريعو ڊيٽا کي منتقل ڪرڻ شروع ڪري ٿو، ۽ وصول ڪندڙ، موڙ ۾، فوري طور تي حاصل ڪرڻ ۽ ان کي پروسيس ڪرڻ لاء تيار آهي. معيار جي مطابق، RTP اسٽريم کي منتقل ڪرڻ يا وصول ڪرڻ لاءِ استعمال ٿيل پورٽ نمبر برابر هجڻ لازمي آهي.

حالتن ۾ جتي وصول ڪندڙ جي ايڊريس کي اڳ ۾ ڄاڻڻ ناممڪن آهي، سرور استعمال ڪيا ويندا آهن جتي وصول ڪندڙ پنهنجو پتو ڇڏيندا آهن، ۽ ٽرانسميٽر وصول ڪندڙ جي ڪجهه منفرد نالي جي حوالي سان ان جي درخواست ڪري سگهي ٿو.

انهن حالتن ۾ جتي ڪميونيڪيشن چينل جي معيار يا وصول ڪندڙ جون صلاحيتون اڻڄاتل آهن، هڪ تاثراتي چينل منظم ڪيو ويو آهي جنهن جي ذريعي وصول ڪندڙ ٽرانسميٽر کي ان جي صلاحيتن بابت، پيڪيٽس جو تعداد ان کي مس ڪري، وغيره بابت ڄاڻ ڏئي سگهي ٿو. هي چينل RTCP پروٽوڪول استعمال ڪري ٿو. هن چينل ۾ منتقل ٿيل پيڪيٽ جي فارميٽ جي وضاحت RFC 3605 ۾ ڪئي وئي آهي. نسبتاً گهٽ ڊيٽا هن چينل تي، 200..300 بائيٽ في سيڪنڊ جي رفتار سان منتقل ڪئي ويندي آهي، تنهنڪري عام طور تي، ان جي موجودگي بوجھ نه هوندي آهي. پورٽ نمبر جنهن تي RTCP پيڪٽس موڪليا وڃن ٿا اهو بي جوڙ هجڻ گهرجي ۽ هڪ پورٽ نمبر کان وڏو هجڻ گهرجي جتان RTP وهڪرو اچي ٿو. اسان جي مثال ۾، اسان هن چينل کي استعمال نه ڪنداسين، ڇو ته رسيور ۽ چينل جون صلاحيتون واضح طور تي اسان جي حد کان وڌيڪ معمولي ضرورتن کان وڌيڪ آهن.

اسان جي پروگرام ۾، ڊيٽا ٽرانسميشن سرڪٽ، پوئين مثال جي برعڪس، ٻن حصن ۾ ورهايو ويندو: هڪ منتقلي رستو ۽ وصول ڪرڻ وارو رستو. هر هڪ حصي لاءِ اسان پنهنجو پنهنجو گھڙي جو ذريعو ٺاهينداسين، جيئن عنوان واري تصوير ۾ ڏيکاريل آهي.

انھن جي وچ ۾ ھڪڙي طرفي رابطي کي RTP پروٽوڪول استعمال ڪندي ڪيو ويندو. هن مثال ۾، اسان کي ٻاهرين نيٽ ورڪ جي ضرورت ناهي، ڇاڪاڻ ته ٻئي ٽرانسميٽر ۽ وصول ڪندڙ ساڳئي ڪمپيوٽر تي واقع هوندا - پيڪيٽ ان جي اندر سفر ڪندا.

RTP اسٽريم قائم ڪرڻ لاءِ، ميڊيا اسٽريمر ٻه فلٽر استعمال ڪري ٿو: MS_RTP_SEND ۽ MS_RTP_RECV. پهريون هڪ ٻئي کي منتقل ڪري ٿو ۽ RTP وهڪرو وصول ڪري ٿو. انهن فلٽرن کي ڪم ڪرڻ لاءِ، انهن کي هڪ پوائنٽر پاس ڪرڻ جي ضرورت آهي هڪ RTP سيشن اعتراض ڏانهن، جيڪو يا ته ڊيٽا بلاڪ جي هڪ وهڪرو کي RTP پيڪٽس جي هڪ وهڪرو ۾ تبديل ڪري سگهي ٿو يا ان جي سامهون ڪري سگهي ٿو. جيئن ته ميڊيا اسٽريمر جو اندروني ڊيٽا فارميٽ RTP پيڪيٽ جي ڊيٽا فارميٽ سان نه ٿو ملي، ان ڪري ڊيٽا کي MS_RTP_SEND ۾ منتقل ڪرڻ کان اڳ، توهان کي هڪ انڪوڊر فلٽر استعمال ڪرڻو پوندو جيڪو 16-bit آڊيو سگنل جي نمونن کي اٺ بٽ انڪوڊ ۾ تبديل ڪري ٿو. 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 پروگرام.

جو ذريعو: www.habr.com

تبصرو شامل ڪريو