We study the Mediastreamer2 VoIP engine. Part 6

Article material taken from my zen channel .



Audio transmission via RTP stream



In the last article, we assembled a remote control circuit from a generator and a detector of tonal signals that work inside one program. In this article, we will learn how to use the RTP protocol (RFC 3550 - RTP: A Transport Protocol for Real-Time Applications ) to receive / transmit audio over an Ethernet network.


RTP (Real Time Protocol) , , , , , . . , .


UDP-, . RTP- . , , , , . , , .


. , , , ..


. RFC3551 (RTP Profile for Audio and Video Conferenceswith Minimal Control) . - - .


, ( 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 (encoder), 16- , u- (-). decoder.


, ( # include , ):


/*  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(" : %s\n", 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(" : %c\n", 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);
}
}

Compile, run. The program will work as in the previous example, but the data will be transmitted through the RTP stream.


In the next article, we will divide this program into two independent applications - a receiver and a transmitter and run them in different terminals. In parallel, we will learn how to analyze RTP packets using TShark.


All Articles