Að kanna Mediastreamer2 VoIP vélina. 7. hluti

Efni greinarinnar er tekið úr mínum zen rás.

Að kanna Mediastreamer2 VoIP vélina. 7. hluti

Notkun TShark til að greina RTP pakka

Að kanna Mediastreamer2 VoIP vélina. 7. hluti

Í fortíðinni grein Við settum saman fjarstýringarrás úr tóngjafa og tónskynjara, en samskipti á milli þeirra fóru fram með RTP straumi.

Í þessari grein höldum við áfram að rannsaka hljóðmerkjasendingu með því að nota RTP samskiptareglur. Í fyrsta lagi skulum við skipta prófunarforritinu okkar í sendi og móttakara og læra hvernig á að skoða RTP strauminn með því að nota netumferðargreiningartæki.

Svo, svo að við getum betur séð hvaða forritaþættir eru ábyrgir fyrir RTP sendingu og hverjir eru ábyrgir fyrir móttöku, skiptum við mstest6.c skránni okkar í tvö sjálfstæð forrit fyrir sendi og móttakara; við munum setja sameiginlegar aðgerðir sem báðar nota í þriðju skránni, sem við köllum mstest_common.c, það verður tengt við sendi og móttakara með því að nota tilskipunina um:

/* Файл mstest_common.c Общие функции для передатчика и приемника. */
#include <mediastreamer2/msfilter.h>
#include <mediastreamer2/msticker.h>
#include <mediastreamer2/msrtp.h>
#include <ortp/rtpsession.h>
#include <ortp/payloadtype.h>

define PCMU 0

/*---------------------------------------------------------*/
/* Функция регистрации типов полезных нагрузок. */
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;
}

Nú er aðskilin sendiskráin:

/* Файл mstest6.c Имитатор пульта управления (передатчика). */
#include <mediastreamer2/dtmfgen.h>
#include <mediastreamer2/msrtp.h>
#include "mstest_common.c"

/*----------------------------------------------------------*/
int main()
{ 
  ms_init();

/* Создаем экземпляры фильтров. */
  MSFilter *voidsource = ms_filter_new(MS_VOID_SOURCE_ID); 
  MSFilter *dtmfgen = ms_filter_new(MS_DTMF_GEN_ID);

/* Создаем фильтр кодера. */
  MSFilter *encoder = ms_filter_create_encoder("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);

/* Создаем источник тактов - тикер. */ 
 MSTicker *ticker_tx = ms_ticker_new();

/* Соединяем фильтры передатчика. */ 
 ms_filter_link(voidsource, 0, dtmfgen, 0);  
 ms_filter_link(dtmfgen, 0, encoder, 0);
 ms_filter_link(encoder, 0, rtpsend, 0);

/* Подключаем источник тактов. */
  ms_ticker_attach(ticker_tx, voidsource);

/* Настраиваем структуру, управляющую выходным сигналом генератора. */ 
 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);
  }
}

Og að lokum, móttakaraskráin:

/* Файл mstest7.c Имитатор приемника. */
include <mediastreamer2/mssndcard.h>
include <mediastreamer2/mstonedetector.h>
include <mediastreamer2/msrtp.h>

/* Подключаем заголовочный файл с функциями управления событиями  медиастримера.*/
include <mediastreamer2/mseventqueue.h>
/* Подключаем файл общих функций. */
include "mstest_common.c"

/* Функция обратного вызова, она будет вызвана фильтром, как только он   обнаружит совпадение характеристик входного сигнала с заданными. */
static void tone_detected_cb(void *data, MSFilter *f, unsigned int event_id,MSToneDetectorEvent *ev)
{ 
 printf("Принята команда: %sn", ev->tone_name);
}

/*----------------------------------------------------------*/
int main()
{ 
 ms_init();

/* Создаем экземпляры фильтров. */  
 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 *decoder=ms_filter_create_decoder("PCMU");

/* Регистрируем типы нагрузки. */
  register_payloads();

/* Создаем 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_rx = ms_ticker_new();

/* Соединяем фильтры приёмника. */
  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_rx, rtprecv);
  char key='9';
  printf( "Для завершения программы введите 0.n");
  while(key != '0') 
 {
    key = getchar();
   /* Укладываем тред в спячку на 20мс, чтобы другие треды    * приложения получили время на работу. */
   ms_usleep(20000); 
 }
}

Við setjum saman sendi og móttakara og ræsum síðan hvert í sinni stjórnborði. Þá ætti það að virka eins og áður - aðeins við ættum að slá inn tölur frá 1 til 6 í sendiborðinu og svarið við þeim ætti að birtast í móttakaraborðinu. Tónar ættu að heyrast í hátalaranum. Ef allt er svo, þá höfum við komið á tengingu milli móttakara og sendis - það er samfelld sending á RTP pakka frá sendi til móttakara.

Nú er kominn tími til að setja upp umferðargreiningartæki; fyrir þetta munum við setja upp stjórnborðsútgáfu hins frábæra Wireshark forrits - það er kallað TShark. Ég valdi TShark til frekari umfjöllunar til að auðvelda lýsingu á dagskrárstjórnun. Með Wireshark þyrfti ég hafsjó af skjámyndum, sem gætu fljótt orðið úrelt þegar ný útgáfa af Wireshark kemur út.

Ef þú veist hvernig á að nota Wireshark geturðu notað það til að kynna þér dæmin okkar. En jafnvel í þessu tilfelli mæli ég með því að þú náir tshark, þar sem það mun hjálpa þér að gera sjálfvirkan prófun á VoIP forritunum þínum, auk þess að framkvæma fjartöku.

Settu upp TShark með skipuninni:

$ sudo apt-get install tshark

Hefð er fyrir því að athuga uppsetningarniðurstöðuna með því að biðja um útgáfu forritsins:

$ tshark --version

Ef viðunandi svar berst höldum við áfram.

Þar sem pakkarnir okkar fara aðeins inn í tölvuna í bili, getum við sagt tshark að sýna aðeins slíka pakka. Til að gera þetta þarftu að velja pakkatöku úr viðmótinu lykkja (loopback) með því að fara framhjá TShark valkostinum -íló:

$ sudo tshark -i lo

Skilaboð um pakka sem sendarinn okkar sendir munu strax byrja að streyma inn í stjórnborðið (sífellt, óháð því hvort við ýttum á hnappinn á fjarstýringunni eða ekki). Kannski eru forrit á tölvunni þinni sem senda líka pakka í gegnum heimtaug og þá fáum við blöndu af pakka okkar og annarra. Til að vera viss um að á listanum sjáum við aðeins pakka sem fjarstýringin okkar sendir, munum við bæta við síu eftir gáttanúmeri. Með því að ýta á Ctrl-C stöðvum við greiningartækið og sláum inn síu fyrir gáttarnúmerið sem fjarstýringin notar sem áfangagátt fyrir sendingu sína (8010): -f "udp port 8010". Nú mun skipanalínan okkar líta svona út:

$ sudo tshark -i lo -f "udp port 8010"

Eftirfarandi úttak mun birtast í stjórnborðinu (fyrstu 10 línurnar):

 1 0.000000000    127.0.0.1 → 127.0.0.1    UDP 214 8010 → 7010 Len=172 
 2 0.020059705    127.0.0.1 → 127.0.0.1    UDP 214 8010 → 7010 Len=172
 3 0.040044409    127.0.0.1 → 127.0.0.1    UDP 214 8010 → 7010 Len=172 
 4 0.060057104    127.0.0.1 → 127.0.0.1    UDP 214 8010 → 7010 Len=172
 5 0.080082311    127.0.0.1 → 127.0.0.1    UDP 214 8010 → 7010 Len=172  
 6 0.100597153    127.0.0.1 → 127.0.0.1    UDP 214 8010 → 7010 Len=172 
 7 0.120122668    127.0.0.1 → 127.0.0.1    UDP 214 8010 → 7010 Len=172
 8 0.140204789    127.0.0.1 → 127.0.0.1    UDP 214 8010 → 7010 Len=172
 9 0.160719008    127.0.0.1 → 127.0.0.1    UDP 214 8010 → 7010 Len=172
10 0.180673685    127.0.0.1 → 127.0.0.1    UDP 214 8010 → 7010 Len=172

Í bili eru þetta ekki pakkar, heldur númeraður listi yfir atburði, þar sem hver lína er skilaboð um næsta pakka sem var tekið eftir á viðmótinu. Þar sem við höfum þegar séð um pakkasíun sjáum við í skráningunni aðeins skilaboð um pakka frá sendinum okkar. Næst skulum við ráða þessa töflu með dálkanúmerum:

Viðburðanúmer.
Tími þess sem hún gerðist.
Uppruna IP vistfang pakkans og áfangastað IP vistfang pakkans.
Samskiptareglur pakkans eru sýndar sem UDP vegna þess að RTP pakkar eru sendir sem farmur innan UDP pakka.
Pakkastærð í bætum.
Upprunagáttarnúmer pakkans og áfangagáttarnúmer pakkans.
Stærð pakkafarms, héðan getum við ályktað að sendirinn okkar framleiðir RTP pakka sem eru 172 bæti að stærð, sem, eins og önd í kistu, eru staðsettir í UDP pakka sem er 214 bæti að stærð.
Nú er kominn tími til að líta inn í UDP pakkana, fyrir þetta munum við ræsa TShark með auknu lyklasetti:

sudo tshark -i lo -f "udp port 8010"  -P -V -O rtp -o rtp.heuristic_rtp:TRUE -x

Fyrir vikið verður úttak forritsins auðgað - afkóðun á innra innihaldi pakkans sem olli því verður bætt við hvern atburð. Til að fá betri yfirsýn yfir úttakið geturðu annað hvort stöðvað TShark með því að ýta á Ctrl-C, eða afrita úttak þess í skrá með því að bæta leiðslu við tee-forritið við keyrsluskipunina, tilgreina skráarnafnið, tee :

$ sudo tshark -i lo -f "udp port 8010"  -P -V -O rtp -o rtp.heuristic_rtp:TRUE -x | tee  log.txt

Nú skulum við líta á það sem við fengum í skránni, hér er fyrsti pakkinn úr henni:

1 0.000000000    127.0.0.1 → 127.0.0.1    RTP 214 PT=ITU-T G.711 PCMU, SSRC=0x6B8B4567, Seq=58366, Time=355368720
Frame 1: 214 bytes on wire (1712 bits), 214 bytes captured (1712 bits) on interface 0
Ethernet II, Src: 00:00:00_00:00:00 (00:00:00:00:00:00), Dst: 00:00:00_00:00:00 (00:00:00:00:00:00)
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1User Datagram Protocol, Src Port: 8010, Dst Port: 7010
Real-Time Transport Protocol    [Stream setup by HEUR RT (frame 1)]
        [Setup frame: 1] 
       [Setup Method: HEUR RT]
    10.. .... = Version: RFC 1889 Version (2)
    ..0. .... = Padding: False
    ...0 .... = Extension: False
    .... 0000 = Contributing source identifiers count: 0   
   0... .... = Marker: False
    Payload type: ITU-T G.711 PCMU (0)
    Sequence number: 58366    [Extended sequence number: 58366]
    Timestamp: 355368720
    Synchronization Source identifier: 0x6b8b4567 (1804289383)
    Payload: ffffffffffffffffffffffffffffffffffffffffffffffff...

0000  00 00 00 00 00 00 00 00 00 00 00 00 08 00 45 00   ..............E.
0010  00 c8 3c 69 40 00 40 11 ff b9 7f 00 00 01 7f 00   ..<i@.@.........
0020  00 01 1f 4a 1b 62 00 b4 fe c7 80 00 e3 fe 15 2e   ...J.b..........
0030  7f 10 6b 8b 45 67 ff ff ff ff ff ff ff ff ff ff   ..k.Eg..........
0040  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff   ................
0050  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff   ................
0060  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff   ................
0070  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff   ................
0080  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff   ................
0090  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff   ................
00a0  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff   ................
00b0  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff   ................
00c0  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff   ................
00d0  ff ff ff ff ff ff                                  ......

Við munum verja næstu grein til að greina upplýsingarnar sem eru í þessari skráningu og munum óhjákvæmilega tala um innri uppbyggingu RTP pakkans.

Heimild: www.habr.com

Bæta við athugasemd