mediastreamer2_text_stream_tester.c 11.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
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
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
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
17
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 19 20
*/

#include "mediastreamer2/mediastream.h"
21
#include "mediastreamer2/msrtt4103.h"
22 23 24 25 26 27 28 29 30 31 32 33 34
#include "mediastreamer2_tester.h"
#include "mediastreamer2_tester_private.h"
#include <math.h>

#ifdef _MSC_VER
#define unlink _unlink
#endif

static RtpProfile rtp_profile;

#define T140_PAYLOAD_TYPE 98
#define T140_RED_PAYLOAD_TYPE 99

35
static MSFactory *_factory = NULL;
36
static int tester_init(void) {
37
	_factory = ms_factory_new_with_voip();
38

39 40 41 42 43 44 45
	ortp_init();
	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) {
46

47
	ms_factory_destroy(_factory);
48 49 50 51 52 53 54 55
	rtp_profile_clear_all(&rtp_profile);
	return 0;
}

typedef struct _text_stream_tester_stats_t {
	OrtpEvQueue *q;
	rtp_stats_t rtp;
	int number_of_received_char;
Simon Morlat's avatar
Simon Morlat committed
56
	char received_chars[4096];
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
} 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;
}

79
text_stream_tester_t* text_stream_tester_new(void) {
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
	text_stream_tester_t* tst = ms_new0(text_stream_tester_t, 1);
	text_stream_tester_set_local_ip(tst, "127.0.0.1");
	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);
	ms_free(obj);
}

static void create_text_stream(text_stream_tester_t *tst, int payload_type) {
102
	tst->ts = text_stream_new2(_factory, tst->local_ip, tst->local_rtp, tst->local_rtcp);
103 104 105 106 107 108 109 110 111 112
	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);
	reset_stats(&tst->stats);
	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) {
113
	ortp_ev_queue_destroy(tst->stats.q);
114 115 116
	text_stream_stop(tst->ts);
}

117 118 119 120 121 122
static void real_time_text_character_received(void *userdata, struct _MSFilter *f, unsigned int id, void *arg) {
	if (id == MS_RTT_4103_RECEIVED_CHAR) {
		text_stream_tester_t *tst = (text_stream_tester_t *)userdata;
		if (tst->stats.q != NULL) {
			RealtimeTextReceivedCharacter *data = (RealtimeTextReceivedCharacter *)arg;
			ms_message("Received RTT char: %lu, %c", (unsigned long)data->character, (char)data->character);
123
			if (tst->stats.number_of_received_char < (int)sizeof(tst->stats.received_chars)-1){
124 125
				tst->stats.received_chars[tst->stats.number_of_received_char++] = (char)data->character;
			}else{
126
				ms_fatal("tst->stats.received_chars buffer overflow (number_of_received_char=%i)",
Simon Morlat's avatar
Simon Morlat committed
127
					tst->stats.number_of_received_char);
128
			}
129
			ms_free(data);
130 131 132 133
		}
	}
}

134 135 136 137 138 139 140 141 142
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);
	}
143

144
	text_stream_start(tst1->ts, &rtp_profile, tst2->local_ip, tst2->local_rtp, tst2->local_ip, tst2->local_rtcp, payload_type);
145
	ms_filter_add_notify_callback(tst1->ts->rttsink, real_time_text_character_received, tst1, TRUE);
146
	text_stream_start(tst2->ts, &rtp_profile, tst1->local_ip, tst1->local_rtp, tst1->local_ip, tst1->local_rtcp, payload_type);
147
	ms_filter_add_notify_callback(tst2->ts->rttsink, real_time_text_character_received, tst2, TRUE);
148 149 150 151 152 153 154 155 156 157 158
}

static void uninit_text_streams(text_stream_tester_t *tst1, text_stream_tester_t *tst2) {
	destroy_text_stream(tst1);
	destroy_text_stream(tst2);
}

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 !";
159 160
	size_t i = 0;
	int strcmpresult = -2;
161

162
	init_text_streams(marielle, margaux, FALSE, FALSE, NULL, T140_PAYLOAD_TYPE /* ignored */);
163

164 165 166 167
	for (; i < strlen(helloworld); i++) {
		char c = helloworld[i];
		text_stream_putchar32(margaux->ts, (uint32_t)c);
	}
168

169
	BC_ASSERT_TRUE(wait_for_until(&marielle->ts->ms, &margaux->ts->ms, &marielle->stats.number_of_received_char, (int)strlen(helloworld), 5000));
170 171 172 173 174
	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);
175 176 177 178 179 180 181 182
	text_stream_tester_destroy(marielle);
	text_stream_tester_destroy(margaux);
}

static void basic_text_stream2(void) {
	text_stream_tester_t* marielle = text_stream_tester_new();
	text_stream_tester_t* margaux = text_stream_tester_new();
	const char* helloworld = "Hello World !";
183 184
	size_t i = 0;
	int strcmpresult = -2;
185
	int dummy = 0;
186

187
	init_text_streams(marielle, margaux, FALSE, FALSE, NULL, T140_PAYLOAD_TYPE /* ignored */);
188

189 190 191
	for (; i < strlen(helloworld); i++) {
		char c = helloworld[i];
		text_stream_putchar32(margaux->ts, (uint32_t)c);
192
		wait_for_until(&marielle->ts->ms, &margaux->ts->ms, &dummy, 1, 500);
193
	}
194

195
	BC_ASSERT_TRUE(wait_for_until(&marielle->ts->ms, &margaux->ts->ms, &marielle->stats.number_of_received_char, (int)strlen(helloworld), 1000));
196 197 198 199 200 201 202
	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);
	text_stream_tester_destroy(marielle);
	text_stream_tester_destroy(margaux);
203 204
}

205 206 207
static void copy_paste_text_longer_than_rtt_buffer(void) {
	text_stream_tester_t* marielle = text_stream_tester_new();
	text_stream_tester_t* margaux = text_stream_tester_new();
208
	const char* helloworld = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus imperdiet ultricies condimentum. Pellentesque tellus massa, maximus id dignissim vel, aliquam eget sapien. Suspendisse convallis est ut cursus suscipit. Duis in massa dui. Vivamus lobortis maximus nisi, eget interdum ante faucibus ac. Donec varius lorem id arcu facilisis, et dignissim magna molestie. Nunc lobortis feugiat dapibus. Nam tempus auctor dignissim. Sed pellentesque urna vitae quam mattis, in dictum justo tristique. Nullam vehicula enim eu lacus sollicitudin aliquet. Nunc eget arcu id odio viverra ultrices. Ut sit amet urna id libero posuere viverra dapibus sed nunc. Nulla eget vehicula magna, ut pulvinar ex. Nulla tincidunt justo at ipsum pretium, quis tempus arcu semper. Pellentesque non commodo neque. Maecenas consequat dapibus justo vel ornare. Suspendisse varius diam ac tincidunt fermentum. Etiam orci neque, malesuada sit amet purus vehicula, vestibulum scelerisque lectus. Proin volutpat venenatis enim a sollicitudin. Praesent posuere.";
209 210
	size_t i = 0;
	int strcmpresult = -2;
211

212
	init_text_streams(marielle, margaux, FALSE, FALSE, NULL, T140_PAYLOAD_TYPE /* ignored */);
213

214 215 216 217
	for (; i < strlen(helloworld); i++) {
		char c = helloworld[i];
		text_stream_putchar32(margaux->ts, (uint32_t)c);
	}
218

219
	BC_ASSERT_FALSE(wait_for_until(&marielle->ts->ms, &margaux->ts->ms, &marielle->stats.number_of_received_char, (int)strlen(helloworld), 5000));
220 221
	ms_message("Received message is: %s", marielle->stats.received_chars);
	strcmpresult = strcmp(marielle->stats.received_chars, helloworld);
222
	BC_ASSERT_LOWER(strcmpresult, 0, int, "%d");
223 224 225 226 227 228

	uninit_text_streams(marielle, margaux);
	text_stream_tester_destroy(marielle);
	text_stream_tester_destroy(margaux);
}

229
#ifdef HAVE_SRTP
230 231 232 233
static void srtp_protected_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 !";
234 235
	size_t i = 0;
	int strcmpresult = -2;
236
	int dummy = 0;
237

238 239
	init_text_streams(marielle, margaux, FALSE, FALSE, NULL, T140_PAYLOAD_TYPE /* ignored */);
	BC_ASSERT_EQUAL(ms_media_stream_sessions_set_encryption_mandatory(&marielle->ts->ms.sessions, TRUE), 0, int, "%d");
240

241
	BC_ASSERT_TRUE(ms_srtp_supported());
242 243 244 245 246 247

	BC_ASSERT_EQUAL(ms_media_stream_sessions_set_srtp_send_key_b64(&(marielle->ts->ms.sessions), MS_AES_128_SHA1_32, "d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj"),0,int,"%d");
	BC_ASSERT_EQUAL(ms_media_stream_sessions_set_srtp_send_key_b64(&(margaux->ts->ms.sessions), MS_AES_128_SHA1_32, "6jCLmtRkVW9E/BUuJtYj/R2z6+4iEe06/DWohQ9F"),0,int,"%d");
	BC_ASSERT_EQUAL(ms_media_stream_sessions_set_srtp_recv_key_b64(&(margaux->ts->ms.sessions), MS_AES_128_SHA1_32, "d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj"),0,int,"%d");
	BC_ASSERT_EQUAL(ms_media_stream_sessions_set_srtp_recv_key_b64(&(marielle->ts->ms.sessions), MS_AES_128_SHA1_32, "6jCLmtRkVW9E/BUuJtYj/R2z6+4iEe06/DWohQ9F"),0,int,"%d");

248 249
	BC_ASSERT_TRUE(media_stream_secured(&marielle->ts->ms));
	BC_ASSERT_TRUE(media_stream_secured(&margaux->ts->ms));
250

251 252 253
	for (; i < strlen(helloworld); i++) {
		char c = helloworld[i];
		text_stream_putchar32(margaux->ts, (uint32_t)c);
254
		wait_for_until(&marielle->ts->ms, &margaux->ts->ms, &dummy, 1, 500);
255
	}
256

257
	BC_ASSERT_TRUE(wait_for_until(&marielle->ts->ms, &margaux->ts->ms, &marielle->stats.number_of_received_char, (int)strlen(helloworld), 1000));
258 259 260 261 262 263 264 265
	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);
	text_stream_tester_destroy(marielle);
	text_stream_tester_destroy(margaux);
}
266
#endif
267

268
static test_t tests[] = {
269 270 271
	TEST_NO_TAG("Basic text stream: copy paste short text", basic_text_stream),
	TEST_NO_TAG("Basic text stream: slow typing", basic_text_stream2),
	TEST_NO_TAG("copy paste text longer than buffer size", copy_paste_text_longer_than_rtt_buffer),
272
#ifdef HAVE_SRTP
273
	TEST_NO_TAG("slow typing with SRTP", srtp_protected_text_stream),
274
#endif
275 276 277 278 279 280
};

test_suite_t text_stream_test_suite = {
	"TextStream",
	tester_init,
	tester_cleanup,
281 282
	NULL,
	NULL,
283 284
	sizeof(tests) / sizeof(tests[0]),
	tests
285
};