Commit 34190f2d authored by Sylvain Berfini's avatar Sylvain Berfini 🎩

Started RTT integration

parent e9b2d8d4
......@@ -29,7 +29,8 @@ extern "C"{
typedef enum _MSFormatType{
......@@ -800,11 +800,11 @@ typedef struct _VideoStream VideoStream;
MS2_PUBLIC VideoStream *video_stream_new(int loc_rtp_port, int loc_rtcp_port, bool_t use_ipv6);
* Creates an VideoStream object listening on a RTP port for a dedicated address.
* Creates a VideoStream object listening on a RTP port for a dedicated address.
* @param loc_ip the local ip to listen for RTP packets. Can be ::, O.O.O.O or any ip4/6 addresses
* @param [in] loc_rtp_port the local UDP port to listen for RTP packets.
* @param [in] loc_rtcp_port the local UDP port to listen for RTCP packets
* @return a new AudioStream.
* @return a new VideoStream.
MS2_PUBLIC VideoStream *video_stream_new2(const char* ip, int loc_rtp_port, int loc_rtcp_port);
......@@ -1165,8 +1165,127 @@ MS2_PUBLIC void audio_stream_set_audio_route(AudioStream *stream, MSAudioRoute r
* @}
* @addtogroup text_stream_api
* @{
#define TS_OUTBUF_SIZE 32
#define TS_REDGEN 2
#define TS_KEEP_ALIVE_INTERVAL 25000 //10000
#define TS_SEND_INTERVAL 299
#define TS_FLAG_NOTFIRST 0x01
struct _TextStream
MediaStream ms;
int flags;
RtpSession *rtp_io_session; /**< The RTP session used for RTP input/output. */
int pt_t140;
int pt_red;
int prevseqno;
uint8_t inbuf[TS_INBUF_SIZE];
size_t inbufsize;
uint8_t* inbufpos;
int pribuf;
size_t bufsize[TS_NUMBER_OF_OUTBUF];
uint32_t timestamp[TS_NUMBER_OF_OUTBUF];
typedef struct _TextStream TextStream;
* Creates a TextStream object listening on a RTP port.
* @param loc_rtp_port the local UDP port to listen for RTP packets.
* @param loc_rtcp_port the local UDP port to listen for RTCP packets
* @param ipv6 TRUE if ipv6 must be used.
* @return a new TextStream.
MS2_PUBLIC TextStream *text_stream_new(int loc_rtp_port, int loc_rtcp_port, bool_t ipv6);
* Creates a TextStream object from initialized MSMediaStreamSessions.
* @param sessions the MSMediaStreamSessions
* @return a new TextStream
TextStream *text_stream_new_with_sessions(const MSMediaStreamSessions *sessions);
* Creates a TextStream object listening on a RTP port for a dedicated address.
* @param loc_ip the local ip to listen for RTP packets. Can be ::, O.O.O.O or any ip4/6 addresses
* @param [in] loc_rtp_port the local UDP port to listen for RTP packets.
* @param [in] loc_rtcp_port the local UDP port to listen for RTCP packets
* @return a new TextStream.
MS2_PUBLIC TextStream *text_stream_new2(const char* ip, int loc_rtp_port, int loc_rtcp_port);
* Starts a text stream.
* @param[in] stream TextStream object previously created with text_stream_new().
* @param[in] profile RtpProfile object holding the PayloadType that can be used during the text session.
* @param[in] rem_rtp_addr The remote IP address where to send the text to.
* @param[in] rem_rtp_port The remote port where to send the text to.
* @param[in] rem_rtcp_addr The remote IP address for RTCP.
* @param[in] rem_rtcp_port The remote port for RTCP.
* @param[in] payload_type The payload type number used to send the text stream. A valid PayloadType must be available at this index in the profile.
MS2_PUBLIC TextStream* text_stream_start(TextStream *stream, RtpProfile *profile, const char *rem_rtp_addr, int rem_rtp_port, const char *rem_rtcp_addr, int rem_rtcp_port, int payload_type);
* Stops the text streaming thread and free everything
MS2_PUBLIC void text_stream_stop (TextStream * stream);
* Executes background low priority tasks related to text processing (RTP statistics analysis).
* It should be called periodically, for example with an interval of 100 ms or so.
* @param[in] stream TextStream object previously created with text_stream_new().
MS2_PUBLIC void text_stream_iterate(TextStream *stream);
* Reads a character from the stream.
* @param[in] stream TextStream object previously created with text_stream_new().
* @return the character read or '\0' if there are no more character to read in the steam.
char text_stream_getchar(TextStream *stream);
* Writes a character to the stream.
* To write an utf8 character, just call it multiple times.
* @param[in] stream TextStream object previously created with text_stream_new().
* @param[in] c the Char to send.
void text_stream_putchar(TextStream *stream, const char c);
* Reads a character from the stream in UTF-32 format.
* @param[in] stream TextStream object previously created with text_stream_new().
* @return the character in UTF-32 format.
uint32_t text_stream_getchar32(TextStream *stream);
* Writes a character to stream in UTF-32 format.
* @param[in] stream TextStream object previously created with text_stream_new().
* @param[in] i the Char in UTF-32 format.
void text_stream_putchar32(TextStream *stream, uint32_t i);
* @}
#ifdef __cplusplus
......@@ -93,6 +93,7 @@ libmediastreamer_voip_la_SOURCES+= voip/private.h \
voip/mediastream.c \
voip/audiostream.c \
voip/ringstream.c \
voip/rfc4103_textstream.c \
voip/msmediaplayer.c \
voip/ice.c \
otherfilters/msrtp.c \
......@@ -350,6 +350,7 @@ const char * ms_format_type_to_string(MSFormatType type){
case MSAudio: return "MSAudio";
case MSVideo: return "MSVideo";
case MSText: return "MSText";
return "invalid";
......@@ -317,6 +317,10 @@ void media_stream_iterate(MediaStream *stream){
if (stream->evd) {
if (stream->type == MSText) { // TODO: find a better way
text_stream_iterate((TextStream *)stream);
if (stream->evq){
OrtpEvent *ev=NULL;
......@@ -434,6 +438,7 @@ bool_t media_stream_secured (const MediaStream *stream) {
switch (stream->type) {
case MSAudio:
case MSText:
/*fixme need also audio stream direction to be more precise*/
return ms_media_stream_sessions_secured(&stream->sessions, MediaStreamSendRecv);
case MSVideo:{
This diff is collapsed.
......@@ -15,6 +15,7 @@ mediastreamer2_tester_SOURCES= \
mediastreamer2_sound_card_tester.c \
mediastreamer2_adaptive_tester.c \
mediastreamer2_audio_stream_tester.c \
mediastreamer2_text_stream_tester.c \
mediastreamer2_framework_tester.c \
mediastreamer2_player_tester.c \
mediastreamer2_neon_tester.c \
......@@ -60,6 +60,7 @@ void mediastreamer2_tester_init(void(*ftester_printf)(int level, const char *fmt
#ifdef __ARM_NEON__
void mediastreamer2_tester_uninit(void) {
......@@ -45,6 +45,7 @@ extern test_suite_t audio_stream_test_suite;
extern test_suite_t video_stream_test_suite;
extern test_suite_t framework_test_suite;
extern test_suite_t player_test_suite;
extern test_suite_t text_stream_test_suite;
#ifdef __ARM_NEON__
extern test_suite_t neon_test_suite;
mediastreamer2 library - modular sound and video processing and streaming
Copyright (C) 2006-2013 Belledonne Communications, Grenoble
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "mediastreamer2/mediastream.h"
#include "mediastreamer2_tester.h"
#include "mediastreamer2_tester_private.h"
#include <math.h>
#ifdef _MSC_VER
#define unlink _unlink
static RtpProfile rtp_profile;
#define T140_PAYLOAD_TYPE 98
#define T140_RED_PAYLOAD_TYPE 99
static int tester_init(void) {
rtp_profile_set_payload(&rtp_profile, T140_PAYLOAD_TYPE, &payload_type_t140);
rtp_profile_set_payload(&rtp_profile, T140_RED_PAYLOAD_TYPE, &payload_type_t140_red);
return 0;
static int tester_cleanup(void) {
return 0;
typedef struct _text_stream_tester_stats_t {
OrtpEvQueue *q;
rtp_stats_t rtp;
int number_of_received_char;
char received_chars[128];
} text_stream_tester_stats_t;
typedef struct _text_stream_tester_t {
TextStream *ts;
text_stream_tester_stats_t stats;
char* local_ip;
int local_rtp;
int local_rtcp;
int payload_type;
} text_stream_tester_t;
static void reset_stats(text_stream_tester_stats_t *s) {
memset(s, 0, sizeof(text_stream_tester_stats_t));
void text_stream_tester_set_local_ip(text_stream_tester_t* obj, const char* ip) {
char* new_ip = ip ? ms_strdup(ip) : NULL;
if (obj->local_ip) ms_free(obj->local_ip);
obj->local_ip = new_ip;
text_stream_tester_t* text_stream_tester_new() {
text_stream_tester_t* tst = ms_new0(text_stream_tester_t, 1);
text_stream_tester_set_local_ip(tst, "");
tst->local_rtp = -1; /*random*/
tst->local_rtcp = -1; /*random*/
return tst;
text_stream_tester_t* text_stream_tester_create(const char* local_ip, int local_rtp, int local_rtcp) {
text_stream_tester_t *tst = text_stream_tester_new();
if (local_ip)
text_stream_tester_set_local_ip(tst, local_ip);
tst->local_rtp = local_rtp;
tst->local_rtcp = local_rtcp;
return tst;
void text_stream_tester_destroy(text_stream_tester_t* obj) {
if(obj->local_ip) ms_free(obj->local_ip);
static void create_text_stream(text_stream_tester_t *tst, int payload_type) {
tst->ts = text_stream_new2(tst->local_ip, tst->local_rtp, tst->local_rtcp);
tst->local_rtp = rtp_session_get_local_port(tst->ts->ms.sessions.rtp_session);
tst->local_rtcp = rtp_session_get_local_rtcp_port(tst->ts->ms.sessions.rtp_session);
rtp_session_set_multicast_loopback(tst->ts->ms.sessions.rtp_session, TRUE);
tst->stats.q = ortp_ev_queue_new();
rtp_session_register_event_queue(tst->ts->ms.sessions.rtp_session, tst->stats.q);
tst->payload_type = payload_type;
static void destroy_text_stream(text_stream_tester_t *tst) {
static void init_text_streams(text_stream_tester_t *tst1, text_stream_tester_t *tst2, bool_t avpf, bool_t one_way, OrtpNetworkSimulatorParams *params, int payload_type) {
create_text_stream(tst1, payload_type);
create_text_stream(tst2, payload_type);
/* Configure network simulator. */
if ((params != NULL) && (params->enabled == TRUE)) {
rtp_session_enable_network_simulation(tst1->ts->ms.sessions.rtp_session, params);
rtp_session_enable_network_simulation(tst2->ts->ms.sessions.rtp_session, params);
text_stream_start(tst1->ts, &rtp_profile, tst2->local_ip, tst2->local_rtp, tst2->local_ip, tst2->local_rtcp, payload_type);
text_stream_start(tst2->ts, &rtp_profile, tst1->local_ip, tst1->local_rtp, tst1->local_ip, tst1->local_rtcp, payload_type);
static void uninit_text_streams(text_stream_tester_t *tst1, text_stream_tester_t *tst2) {
static void event_queue_cb(MediaStream *ms, void *user_pointer) {
text_stream_tester_t *tst = (text_stream_tester_t *)user_pointer;
if (tst->stats.q != NULL) {
OrtpEvent *ev = NULL;
while ((ev = ortp_ev_queue_get(tst->stats.q)) != NULL) {
OrtpEventType evt = ortp_event_get_type(ev);
OrtpEventData *evd = ortp_event_get_data(ev);
ms_message("Received RTT char: %lu, %c", (unsigned long)evd->info.received_rtt_character, (char)evd->info.received_rtt_character);
tst->stats.received_chars[tst->stats.number_of_received_char++] = (char)evd->info.received_rtt_character;
static void basic_text_stream(void) {
text_stream_tester_t* marielle = text_stream_tester_new();
text_stream_tester_t* margaux = text_stream_tester_new();
const char* helloworld = "Hello World !";
int i = 0, strcmpresult = -2;
init_text_streams(marielle, margaux, FALSE, FALSE, NULL, T140_PAYLOAD_TYPE);
for (; i < strlen(helloworld); i++) {
char c = helloworld[i];
text_stream_putchar32(margaux->ts, (uint32_t)c);
BC_ASSERT_TRUE(wait_for_until_with_parse_events(&marielle->ts->ms, &margaux->ts->ms, &marielle->stats.number_of_received_char, strlen(helloworld), 5000, event_queue_cb, marielle, NULL, NULL));
ms_message("Received message is: %s", marielle->stats.received_chars);
strcmpresult = strcmp(marielle->stats.received_chars, helloworld);
BC_ASSERT_EQUAL(strcmpresult, 0, int, "%d");
uninit_text_streams(marielle, margaux);
static test_t tests[] = {
{ "Basic text stream", basic_text_stream }
test_suite_t text_stream_test_suite = {
sizeof(tests) / sizeof(tests[0]),
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment