Mediastreamer2 VoIP انجن کی تلاش۔ حصہ 6

مضمون کا مواد میری تحریر سے لیا گیا ہے۔ زین چینل.

آر ٹی پی اسٹریم کے ذریعے آڈیو سگنل منتقل کرنا

Mediastreamer2 VoIP انجن کی تلاش۔ حصہ 6

ماضی میں آرٹیکل ہم نے ایک ٹون جنریٹر سے ایک ریموٹ کنٹرول سرکٹ اور ایک ٹون ڈیٹیکٹر جو اسی پروگرام کے اندر کام کرتا ہے اسمبل کیا ہے۔ اس آرٹیکل میں ہم RTP پروٹوکول (RFC 3550 - استعمال کرنے کا طریقہ سیکھیں گے۔ RTP: ریئل ٹائم ایپلی کیشنز کے لیے ایک ٹرانسپورٹ پروٹوکول) ایتھرنیٹ نیٹ ورک پر آڈیو سگنل وصول کرنے/منتقل کرنے کے لیے۔

آر ٹی پی پروٹوکول (ریئل ٹائم پروٹوکول) ترجمہ کا مطلب ہے ریئل ٹائم پروٹوکول، یہ آڈیو، ویڈیو، ڈیٹا، ہر وہ چیز جو حقیقی وقت میں ٹرانسمیشن کی ضرورت ہوتی ہے منتقل کرنے کے لیے استعمال ہوتا ہے۔ آئیے مثال کے طور پر ایک آڈیو سگنل لیتے ہیں۔ پروٹوکول کی لچک ایسی ہے کہ یہ آپ کو پہلے سے طے شدہ معیار کے ساتھ آڈیو سگنل منتقل کرنے کی اجازت دیتا ہے۔

ٹرانسمیشن UDP پیکٹ کا استعمال کرتے ہوئے کی جاتی ہے، جس کا مطلب ہے کہ ٹرانسمیشن کے دوران پیکٹ کا نقصان کافی قابل قبول ہے۔ ہر پیکٹ میں ایک خصوصی RTP ہیڈر اور منتقل شدہ سگنل کا ڈیٹا بلاک ہوتا ہے۔ ہیڈر میں تصادفی طور پر منتخب کردہ سگنل سورس شناخت کنندہ، منتقل کیے جانے والے سگنل کی قسم کے بارے میں معلومات، اور ایک منفرد پیکٹ ترتیب نمبر ہوتا ہے تاکہ پیکٹ کو ڈی کوڈنگ کرتے وقت درست ترتیب میں ترتیب دیا جا سکے، قطع نظر اس کے کہ وہ کس ترتیب سے ڈیلیور کیے گئے ہوں۔ نیٹ ورک ہیڈر میں اضافی معلومات بھی شامل ہو سکتی ہے، نام نہاد ایکسٹینشن، جو ہیڈر کو کسی مخصوص ایپلیکیشن ٹاسک میں استعمال کے لیے ڈھالنے کی اجازت دیتی ہے۔

ڈیٹا بلاک میں پیکٹ کا پے لوڈ ہوتا ہے۔ مواد کی اندرونی تنظیم بوجھ کی قسم پر منحصر ہے، یہ مونو سگنل، سٹیریو سگنل، ویڈیو امیج لائن وغیرہ کے نمونے ہو سکتے ہیں۔

لوڈ کی قسم کو سات بٹ نمبر سے ظاہر کیا جاتا ہے۔ تجویز RFC3551 (کم سے کم کنٹرول کے ساتھ آڈیو اور ویڈیو کانفرنسز کے لیے RTP پروفائل) کئی قسم کے بوجھ کو قائم کرتا ہے؛ متعلقہ جدول بوجھ کی اقسام اور کوڈز کے معنی کی وضاحت فراہم کرتا ہے جن کے ذریعے انہیں نامزد کیا گیا ہے۔ کچھ کوڈز کسی بھی قسم کے بوجھ سے سختی سے منسلک نہیں ہوتے ہیں؛ انہیں صوابدیدی بوجھ کو نامزد کرنے کے لیے استعمال کیا جا سکتا ہے۔

ڈیٹا بلاک کا سائز اوپر پیکٹ کے زیادہ سے زیادہ سائز سے محدود ہے جو کسی مخصوص نیٹ ورک پر بغیر سیگمنٹیشن (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 بٹ آڈیو سگنل کے نمونوں کو آٹھ بٹ انکوڈ میں تبدیل کرتا ہے۔ 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);
}
}

ہم مرتب کرتے ہیں اور چلاتے ہیں۔ یہ پروگرام پچھلی مثال کی طرح کام کرے گا، لیکن ڈیٹا آر ٹی پی سٹریم کے ذریعے منتقل کیا جائے گا۔

اگلے مضمون میں ہم اس پروگرام کو دو آزاد ایپلی کیشنز میں تقسیم کریں گے - ایک ریسیور اور ایک ٹرانسمیٹر اور انہیں مختلف ٹرمینلز میں لانچ کریں گے۔ ایک ہی وقت میں، ہم TShark پروگرام کا استعمال کرتے ہوئے RTP پیکٹ کا تجزیہ کرنے کا طریقہ سیکھیں گے۔

ماخذ: www.habr.com

نیا تبصرہ شامل کریں