Vekolîna motora VoIP ya Mediastreamer2. Beş 6

Madeya gotarê ji min hatiye girtin kanala zen.

Veguheztina sînyalek dengî bi riya stream RTP

Vekolîna motora VoIP ya Mediastreamer2. Beş 6

Di ya paşîn de gotara Me ji jeneratorek tone û detektorek tone ku di nav heman bernameyê de kar dikin çerxek kontrolê ya dûr kom kiriye. Di vê gotarê de em ê fêr bibin ka meriv çawa protokola RTP bikar tîne (RFC 3550 - RTP: Protokolek Veguhastinê ji bo Serlêdanên Rast-Time) ji bo wergirtina/veguheztina sînyalek dengî li ser tora Ethernet.

Protokola RTP (Protokola dema rast) wergerandin tê wateya protokola rast-ê, ew ji bo veguheztina deng, vîdyo, dane, her tiştê ku di wextê rast de veguheztinê hewce dike tê bikar anîn. Werin em îşaretek dengî wekî mînak bigirin. Zehmetiya protokolê wisa ye ku ew dihêle hûn îşaretek dengî bi qalîteya pêşwext veguhezînin.

Veguheztin bi karanîna pakêtên UDP ve tête kirin, ku tê vê wateyê ku windabûna pakêtê di dema veguheztinê de pir tê pejirandin. Her pakêt sernavek RTP-ya taybetî û bloka daneya sînyala hatî veguheztin vedihewîne. Sernivîs nasnameyek çavkaniya sînyalê ya ku bi rengekî rasthatî hilbijartî, agahdariya li ser celebê sînyala ku tê veguheztin, û jimareyek rêza pakêtê ya yekta vedihewîne da ku pakêt dema deşîfrekirinê di rêza rast de werin rêz kirin, bêyî ku rêza ku ew ji hêla tora. Sernav dikare agahdariya zêde jî hebe, bi navê dirêjkirinê, ku destûrê dide sernavê ji bo karanîna di karekî serîlêdana taybetî de were adaptekirin.

Bloka daneyê bargiraniya pakêtê dihewîne. Organîzasyona navxweyî ya naverokê bi celebê barkirinê ve girêdayî ye, ew dikare nimûneyên nîşanek mono, nîşanek stereo, xetek wêneya vîdyoyê, hwd.

Cûreya barkirinê bi hejmarek heft-bit tê destnîşan kirin. Pêşniyara RFC3551 (Profîla RTP ji bo Konferansên Deng û Vîdyoyê bi Kontrola Kêmtirîn) gelek celeb bargiraniyê saz dike; tabloya têkildar danasîna celebên barkirinê û wateya kodên ku ew pê têne destnîşan kirin peyda dike. Hin kod bi hişkî bi her cûre bargiraniyê ve ne girêdayî ne; ew dikarin ji bo destnîşankirina barek kêfî werin bikar anîn.

Mezinahiya bloka daneyê li jor bi mezinahiya pakêtê ya herî zêde ya ku dikare li ser tora diyarkirî bê dabeşkirin (parametreya MTU) were veguheztin sînorkirî ye. Bi gelemperî, ev ji 1500 bytes ne bêtir e. Bi vî rengî, ji bo ku hûn mîqdara daneya ku di çirkeyê de hatî veguheztin zêde bikin, hûn dikarin mezinahiya pakêtê heya nuqteyek diyarkirî zêde bikin, û dûv re hûn hewce ne ku frekansa şandina pakêtan zêde bikin. Di weşanek medyayê de, ev mîhengek mîhengbar e. Bi xwerû ew 50 Hz e, yanî. 50 pakêt di çirkeyê de. Em ê rêza pakêtên RTP yên hatine veguheztin wekî çemek RTP bi nav bikin.

Ji bo destpêkirina şandina daneyan di navbera çavkanî û wergir de, bes e ku veguhezkar navnîşana IP-ya wergir û jimareya portê ya ku ew ji bo wergirtinê bikar tîne dizane. Ewan. bêyî prosedurên pêşîn, çavkanî dest bi veguheztina daneyan dike, û wergir, di encamê de, amade ye ku tavilê wê werbigire û pêvajoyê bike. Li gorî standardê, jimareya portê ya ku ji bo veguheztin an wergirtina herikîna RTP-ê tê bikar anîn divê yek be.

Di rewşên ku ne gengaz e ku meriv berê navnîşana wergir zanibe, servers têne bikar anîn ku wergir navnîşana xwe dihêlin, û veguhezkar dikare bi hin navên yekta yên wergir daxwaz bike.

Di rewşên ku qalîteya kanala danûstendinê an jî kapasîteyên wergirê nenas in, kanalek bertek tê organîze kirin ku bi navgîniya wergir dikare veguhezderê li ser kapasîteyên xwe, hejmara pakêtên ku winda kiriye, hwd agahdar bike. Ev kanal protokola RTCP bikar tîne. Formata paketên ku di vê kanalê de têne şandin di RFC 3605 de hatî destnîşan kirin. Daneyên nisbeten hindik li ser vê kanalê têne şandin, 200..300 byte di çirkekê de, ji ber vê yekê bi gelemperî hebûna wê ne giran e. Hejmara portê ya ku pakêtên RTCP jê re têne şandin divê cêv be û yek jê mezintir be ji jimareya portê ya ku herika RTP jê tê. Di mînaka me de, em ê vê kanalê bikar neynin, ji ber ku kapasîteyên wergir û kanalê eşkere ji hewcedariyên me, heya nuha hindik, derbas dikin.

Di bernameya me de, çerxa veguheztina daneyê, berevajî mînaka berê, dê bibe du beş: rêyek veguheztinê û rêyek wergirtinê. Ji bo her beşê em ê çavkaniya demjimêra xwe çêbikin, wekî ku di wêneya sernavê de tê xuyang kirin.

Têkiliya yek-alî di navbera wan de dê bi karanîna protokola RTP-ê pêk were. Di vê nimûneyê de, em ne hewceyê torgilokek derveyî ne, ji ber ku hem veguhezker û hem jî wergir dê li ser heman komputerê bin - pakêt dê di hundurê wê de bigerin.

Ji bo sazkirina weşanek RTP, weşana medyayê du parzûnan bikar tîne: MS_RTP_SEND û MS_RTP_RECV. Yekem ya duyemîn dişîne û stream RTP distîne. Ji bo ku van parzûnan bixebitin, ew hewce ne ku îşaretek bigihînin objeyek danişîna RTP, ku dikare herikek blokên daneyê veguhezîne çemek pakêtên RTP an jî berevajî vê yekê bike. Ji ber ku formata daneya navxweyî ya weşangera medyayê bi formata daneya pakêta RTP re nagire, berî ku daneyan veguhezînin MS_RTP_SEND, hûn hewce ne ku parzûnek şîfrekerê bikar bînin ku nimûneyên sînyala dengî ya 16-bit vediguhezîne nav heşt-bit ku li gorî kodê kodkirî ye. u-law (mu-law). Li aliyê wergirtinê, parzûna dekoder fonksiyona berevajî pêk tîne.

Li jêr metna bernameyê ye ku nexşeya ku di jimarê de hatî xuyang kirin pêk tîne (# sembolên berî rêwerzên tevlê hatine rakirin, ji bîr nekin ku wan têxin nav xwe):

/* Файл 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);
}
}

Em berhev dikin û dimeşînin. Bername dê wekî mînaka berê bixebite, lê dê dane bi rêka RTP-ê ve were şandin.

Di gotara din de em ê vê bernameyê li du serîlêdanên serbixwe dabeş bikin - wergirê û veguhezker û wan di termînalên cihêreng de bidin destpêkirin. Di heman demê de, em ê fêr bibin ka meriv çawa pakêtên RTP-ê bi karanîna bernameya TShark analîz dike.

Source: www.habr.com

Add a comment