mediastreamer2_adaptive_tester.c 17.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
/*
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
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

#include "mediastreamer2/mediastream.h"
#include "mediastreamer2/dtmfgen.h"
#include "mediastreamer2/msfileplayer.h"
#include "mediastreamer2/msfilerec.h"
#include "mediastreamer2/msrtp.h"
#include "mediastreamer2/mstonedetector.h"
#include "mediastreamer2_tester.h"
#include "mediastreamer2_tester_private.h"
Ghislain MARY's avatar
Ghislain MARY committed
28
#include "qosanalyzer.h"
29 30 31 32 33 34 35 36

#include <stdio.h>
#include "CUnit/Basic.h"


static RtpProfile rtp_profile;

#define OPUS_PAYLOAD_TYPE    121
37
#define SPEEX_PAYLOAD_TYPE 122
38 39 40 41 42 43
#define SILK16_PAYLOAD_TYPE  123
#define PCMA8_PAYLOAD_TYPE 8
#define H263_PAYLOAD_TYPE 34
#define H264_PAYLOAD_TYPE 102
#define VP8_PAYLOAD_TYPE 103

44 45
#define EDGE_BW 10
#define THIRDGENERATION_BW 200
46 47 48 49 50 51 52

static int tester_init(void) {
	ms_init();
	ms_filter_enable_statistics(TRUE);
	ortp_init();
	rtp_profile_set_payload (&rtp_profile,0,&payload_type_pcmu8000);
	rtp_profile_set_payload (&rtp_profile,OPUS_PAYLOAD_TYPE,&payload_type_opus);
53
	rtp_profile_set_payload (&rtp_profile,SPEEX_PAYLOAD_TYPE,&payload_type_speex_wb);
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
	rtp_profile_set_payload (&rtp_profile,SILK16_PAYLOAD_TYPE,&payload_type_silk_wb);
	rtp_profile_set_payload (&rtp_profile,PCMA8_PAYLOAD_TYPE,&payload_type_pcma8000);

	rtp_profile_set_payload (&rtp_profile,H263_PAYLOAD_TYPE,&payload_type_h263);
	rtp_profile_set_payload(&rtp_profile,H264_PAYLOAD_TYPE,&payload_type_h264);
	rtp_profile_set_payload(&rtp_profile, VP8_PAYLOAD_TYPE, &payload_type_vp8);
	return 0;
}

static int tester_cleanup(void) {
	ortp_exit();
	ms_exit();
	rtp_profile_clear_all(&rtp_profile);
	return 0;
}

70 71
#define HELLO_16K_1S_FILE  "sounds/hello16000-1s.wav"
#define RECORDED_16K_1S_FILE  "sounds/recorded_hello16000-1s.wav"
72 73

typedef struct _stream_manager_t {
Simon Morlat's avatar
Simon Morlat committed
74
	MSFormatType type;
75 76 77 78 79 80 81
	int local_rtp;
	int local_rtcp;

	union{
		AudioStream* audio_stream;
		VideoStream* video_stream;
	};
82

83 84
	int rtcp_count;

85 86 87 88 89
	struct {
		float loss_estim;
		float congestion_bw_estim;
	} adaptive_stats;

90
	void* user_data;
91

92 93
} stream_manager_t ;

94
stream_manager_t * stream_manager_new(MSFormatType type) {
95 96 97 98
	stream_manager_t * mgr = ms_new0(stream_manager_t,1);
	mgr->type=type;
	mgr->local_rtp=(rand() % ((2^16)-1024) + 1024) & ~0x1;
	mgr->local_rtcp=mgr->local_rtp+1;
99
	mgr->user_data = 0;
100

Simon Morlat's avatar
Simon Morlat committed
101
	if (mgr->type==MSAudio){
102 103
		mgr->audio_stream=audio_stream_new (mgr->local_rtp, mgr->local_rtcp,FALSE);
	}else{
104
#if VIDEO_ENABLED
105
		mgr->video_stream=video_stream_new (mgr->local_rtp, mgr->local_rtcp,FALSE);
106
#else
107
		ms_fatal("Unsupported stream type [%s]",ms_format_type_to_string(mgr->type));
108 109
#endif

110 111 112
	}
	return mgr;
}
113

114
static void stream_manager_delete(stream_manager_t * mgr) {
115

Simon Morlat's avatar
Simon Morlat committed
116
	if (mgr->type==MSAudio){
117 118 119 120
		if( mgr->user_data){
			unlink((char*)mgr->user_data);
			// don't reset user_data, it is up to the user to free() it
		}
121

122 123
		audio_stream_stop(mgr->audio_stream);
	}else{
124
#if VIDEO_ENABLED
125
		video_stream_stop(mgr->video_stream);
126
#else
127
		ms_fatal("Unsupported stream type [%s]",ms_format_type_to_string(mgr->type));
128
#endif
129 130 131 132 133 134 135 136 137 138
	}
	ms_free(mgr);
}

static void audio_manager_start(stream_manager_t * mgr
								,int payload_type
								,int remote_port
								,int target_bitrate
								,const char* player_file
								,const char* recorder_file){
139

140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
	media_stream_set_target_network_bitrate(&mgr->audio_stream->ms,target_bitrate);

	CU_ASSERT_EQUAL(audio_stream_start_full(mgr->audio_stream
												, &rtp_profile
												, "127.0.0.1"
												, remote_port
												, "127.0.0.1"
												, remote_port+1
												, payload_type
												, 50
												, player_file
												, recorder_file
												, NULL
												, NULL
												, 0),0);
}

157
#if VIDEO_ENABLED
158 159 160 161 162
static void video_manager_start(	stream_manager_t * mgr
									,int payload_type
									,int remote_port
									,int target_bitrate
									,MSWebCam * cam) {
163
	int result;
164 165
	media_stream_set_target_network_bitrate(&mgr->video_stream->ms,target_bitrate);

166
	result=video_stream_start(mgr->video_stream
167 168 169 170 171 172 173 174 175 176
												, &rtp_profile
												, "127.0.0.1"
												, remote_port
												, "127.0.0.1"
												, remote_port+1
												, payload_type
												, 60
												, cam);
	CU_ASSERT_EQUAL(result,0);
}
177
#endif
178

179 180 181
static void qos_analyzer_on_action_suggested(void *user_data, int datac, const char** datav){
	stream_manager_t *mgr = (stream_manager_t*)user_data;
	mgr->rtcp_count++;
182

183 184 185 186 187 188
	if (mgr->type==MSVideo && mgr->video_stream->ms.rc_enable){
		const MSQosAnalyzer *analyzer=ms_bitrate_controller_get_qos_analyzer(mgr->video_stream->ms.rc);
		if (analyzer->type==MSQosAnalyzerAlgorithmStateful){
			const MSStatefulQosAnalyzer *stateful_analyzer=((const MSStatefulQosAnalyzer*)analyzer);
			mgr->adaptive_stats.loss_estim=stateful_analyzer->network_loss_rate;
			mgr->adaptive_stats.congestion_bw_estim=stateful_analyzer->congestion_bandwidth;
189 190 191 192
		}
	}
}

193
void start_adaptive_stream(MSFormatType type, stream_manager_t ** pmarielle, stream_manager_t ** pmargaux,
194
	int payload, int initial_bitrate, int max_bw, float loss_rate, int latency, float dup_ratio) {
195
	int pause_time=0;
196
	PayloadType* pt;
197
	MediaStream *marielle_ms,*margaux_ms;
198
	OrtpNetworkSimulatorParams params={0};
199
#if VIDEO_ENABLED
200
	MSWebCam * marielle_webcam=ms_web_cam_manager_get_default_cam (ms_web_cam_manager_get());
201
#endif
202 203
	stream_manager_t *marielle=*pmarielle=stream_manager_new(type);
	stream_manager_t *margaux=*pmargaux=stream_manager_new(type);
204

205 206
	char* file = ms_strdup_printf("%s/%s", mediastreamer2_tester_get_file_root(), HELLO_16K_1S_FILE);
	char* recorded_file = ms_strdup_printf("%s/%s", mediastreamer2_tester_get_writable_dir(), RECORDED_16K_1S_FILE);
207

208
	marielle->user_data = recorded_file;
209 210
	params.enabled=TRUE;
	params.loss_rate=loss_rate;
211
	params.max_bandwidth=max_bw;
212
	params.latency=latency;
213

Simon Morlat's avatar
Simon Morlat committed
214
	if (type == MSAudio){
215 216 217 218 219 220 221
		marielle_ms=&marielle->audio_stream->ms;
		margaux_ms=&margaux->audio_stream->ms;
	}else{
		marielle_ms=&marielle->video_stream->ms;
		margaux_ms=&margaux->video_stream->ms;
	}

222
	/* Disable avpf. */
223
	pt = rtp_profile_get_payload(&rtp_profile, VP8_PAYLOAD_TYPE);
224 225 226
	CU_ASSERT_PTR_NOT_NULL_FATAL(pt);
	payload_type_unset_flag(pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED);

227 228

	media_stream_enable_adaptive_bitrate_control(marielle_ms,TRUE);
229
	media_stream_set_adaptive_bitrate_algorithm(marielle_ms, MSQosAnalyzerAlgorithmStateful);
230 231
	rtp_session_set_duplication_ratio(marielle_ms->sessions.rtp_session, dup_ratio);

Simon Morlat's avatar
Simon Morlat committed
232
	if (marielle->type == MSAudio){
233
		audio_manager_start(marielle,payload,margaux->local_rtp,initial_bitrate,file,NULL);
234 235
		ms_filter_call_method(marielle->audio_stream->soundread,MS_FILE_PLAYER_LOOP,&pause_time);

236
		audio_manager_start(margaux,payload,marielle->local_rtp,0,NULL,recorded_file);
237
	}else{
238
#if VIDEO_ENABLED
239
		marielle->video_stream->staticimage_webcam_fps_optimization = FALSE;
240
		video_manager_start(marielle,payload,margaux->local_rtp,0,marielle_webcam);
241
		video_stream_set_direction(margaux->video_stream,VideoStreamRecvOnly);
242
		video_manager_start(margaux,payload,marielle->local_rtp,0,NULL);
243
#else
244
		ms_fatal("Unsupported stream type [%s]",ms_format_type_to_string(marielle->type));
245
#endif
246
	}
247

248 249 250
	ms_qos_analyzer_set_on_action_suggested(ms_bitrate_controller_get_qos_analyzer(marielle_ms->rc),
						qos_analyzer_on_action_suggested,
						*pmarielle);
251
	rtp_session_enable_network_simulation(margaux_ms->sessions.rtp_session,&params);
252

253 254
	ms_free(recorded_file);
	ms_free(file);
255

256
}
257

258
static void iterate_adaptive_stream(stream_manager_t * marielle, stream_manager_t * margaux,
259
	int timeout_ms, int* current, int expected){
260
	int retry=0;
261 262

	MediaStream *marielle_ms,*margaux_ms;
Simon Morlat's avatar
Simon Morlat committed
263
	if (marielle->type == MSAudio){
264 265 266 267 268 269 270
		marielle_ms=&marielle->audio_stream->ms;
		margaux_ms=&margaux->audio_stream->ms;
	}else{
		marielle_ms=&marielle->video_stream->ms;
		margaux_ms=&margaux->video_stream->ms;
	}

271 272 273
	while ((!current||*current<expected) && retry++ <timeout_ms/100) {
		media_stream_iterate(marielle_ms);
		media_stream_iterate(margaux_ms);
274
		// handle_queue_events(marielle);
275 276
		if (retry%10==0) {
			 ms_message("stream [%p] bandwidth usage: [d=%.1f,u=%.1f] kbit/sec"	,
277
				marielle_ms, media_stream_get_down_bw(marielle_ms)/1000, media_stream_get_up_bw(marielle_ms)/1000);
278
			 ms_message("stream [%p] bandwidth usage: [d=%.1f,u=%.1f] kbit/sec"	,
279
				margaux_ms, media_stream_get_down_bw(margaux_ms)/1000, media_stream_get_up_bw(margaux_ms)/1000);
280 281 282 283 284
		 }
		ms_usleep(100000);
	}
}

285 286
static void stop_adaptive_stream(stream_manager_t *marielle, stream_manager_t *margaux){
	stream_manager_delete(marielle);
287
	stream_manager_delete(margaux);
288
}
289

290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320
typedef struct {
		OrtpLossRateEstimator *estimator;
		OrtpEvQueue *q;
		int loss_rate;
}LossRateEstimatorCtx;
static void event_queue_cb(MediaStream *ms, void *user_pointer) {
	LossRateEstimatorCtx *ctx = (LossRateEstimatorCtx*)user_pointer;
	if (ctx->q != NULL) {
		OrtpEvent *ev = NULL;
		while ((ev = ortp_ev_queue_get(ctx->q)) != NULL) {
			OrtpEventType evt = ortp_event_get_type(ev);
			OrtpEventData *evd = ortp_event_get_data(ev);
			if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) {
				do {
					const report_block_t *rb=NULL;
					if (rtcp_is_SR(evd->packet)){
						rb=rtcp_SR_get_report_block(evd->packet,0);
					}else if (rtcp_is_RR(evd->packet)){
						rb=rtcp_RR_get_report_block(evd->packet,0);
					}

					if (rb&&ortp_loss_rate_estimator_process_report_block(ctx->estimator,&ms->sessions.rtp_session->rtp,rb)){
						float diff = fabs(ortp_loss_rate_estimator_get_value(ctx->estimator) - ctx->loss_rate);
						CU_ASSERT_IN_RANGE(diff, 0, 10);
					}
				} while (rtcp_next_packet(evd->packet));
			}
			ortp_event_destroy(ev);
		}
	}
}
321

322
/********************************** Tests are starting now ********************/
323 324 325 326 327 328
static void packet_duplication() {
	const rtp_stats_t *stats;
	double dup_ratio;
	stream_manager_t * marielle, * margaux;

	dup_ratio = 0;
329
	start_adaptive_stream(MSAudio, &marielle, &margaux, SPEEX_PAYLOAD_TYPE, 32000, 0, 0, 50,dup_ratio);
330
	media_stream_enable_adaptive_bitrate_control(&marielle->audio_stream->ms,FALSE);
331
	iterate_adaptive_stream(marielle, margaux, 10000, NULL, 0);
332 333 334 335 336 337 338 339 340
	stats=rtp_session_get_stats(margaux->video_stream->ms.sessions.rtp_session);
	CU_ASSERT_EQUAL(stats->packet_dup_recv, dup_ratio ? stats->packet_recv / (dup_ratio+1) : 0);
	/*in theory, cumulative loss should be the invert of duplicated count, but
	since cumulative loss is computed only on received RTCP report and duplicated
	count is updated on each RTP packet received, we cannot accurately compare these values*/
	CU_ASSERT_TRUE(stats->cum_packet_loss <= -.5*stats->packet_dup_recv);
	stop_adaptive_stream(marielle,margaux);

	dup_ratio = 1;
341
	start_adaptive_stream(MSAudio, &marielle, &margaux, SPEEX_PAYLOAD_TYPE, 32000, 0, 0, 50,dup_ratio);
342
	media_stream_enable_adaptive_bitrate_control(&marielle->audio_stream->ms,FALSE);
343
	iterate_adaptive_stream(marielle, margaux, 10000, NULL, 0);
344 345 346 347 348 349
	stats=rtp_session_get_stats(margaux->video_stream->ms.sessions.rtp_session);
	CU_ASSERT_EQUAL(stats->packet_dup_recv, dup_ratio ? stats->packet_recv / (dup_ratio+1) : 0);
	CU_ASSERT_TRUE(stats->cum_packet_loss <= -.5*stats->packet_dup_recv);
	stop_adaptive_stream(marielle,margaux);
}

350 351 352 353 354
static void upload_bandwidth_computation() {
	bool_t supported = ms_filter_codec_supported("pcma");
	if( supported ) {
		stream_manager_t * marielle, * margaux;
		int i;
355

356 357 358 359 360 361 362
		start_adaptive_stream(MSAudio, &marielle, &margaux, PCMA8_PAYLOAD_TYPE, 8000, 0, 0, 0, 0);
		media_stream_enable_adaptive_bitrate_control(&marielle->audio_stream->ms,FALSE);

		for (i = 0; i < 5; i++){
			rtp_session_set_duplication_ratio(marielle->audio_stream->ms.sessions.rtp_session, i);
			iterate_adaptive_stream(marielle, margaux, 5000, NULL, 0);
			/*since PCMA uses 80kbit/s, upload bandwidth should just be 80+80*duplication_ratio kbit/s */
Gautier Pelloux-Prayer's avatar
Gautier Pelloux-Prayer committed
363
			CU_ASSERT_TRUE(fabs(rtp_session_get_send_bandwidth(marielle->audio_stream->ms.sessions.rtp_session)/1000. - 80.*(i+1)) < 5.f);
364
		}
365
		stop_adaptive_stream(marielle,margaux);
366 367
	}
}
368

369 370 371 372 373 374 375 376
static void loss_rate_estimation() {
	bool_t supported = ms_filter_codec_supported("pcma");
	if( supported ) {
		LossRateEstimatorCtx ctx;
		stream_manager_t * marielle, * margaux;
		int loss_rate = 15;

		start_adaptive_stream(MSAudio, &marielle, &margaux, PCMA8_PAYLOAD_TYPE, 8000, 0, loss_rate, 0, 0);
Simon Morlat's avatar
Simon Morlat committed
377
		ctx.estimator=ortp_loss_rate_estimator_new(120, 2500, marielle->audio_stream->ms.sessions.rtp_session);
378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394
		ctx.q = ortp_ev_queue_new();
		rtp_session_register_event_queue(marielle->audio_stream->ms.sessions.rtp_session, ctx.q);
		ctx.loss_rate = loss_rate;

		/*loss rate should be the initial one*/
		wait_for_until_with_parse_events(&marielle->audio_stream->ms, &margaux->audio_stream->ms, &loss_rate, 100, 10000, event_queue_cb,&ctx,NULL,NULL);

		/*let's set some duplication. loss rate should NOT be changed */
		rtp_session_set_duplication_ratio(marielle->audio_stream->ms.sessions.rtp_session, 10);
		wait_for_until_with_parse_events(&marielle->audio_stream->ms, &margaux->audio_stream->ms, &loss_rate, 100, 10000, event_queue_cb,&ctx,NULL,NULL);

		stop_adaptive_stream(marielle,margaux);
		ortp_loss_rate_estimator_destroy(ctx.estimator);
		ortp_ev_queue_destroy(ctx.q);
	}
}

395
void upload_bitrate(const char* codec, int payload, int target_bw, int expect_bw) {
396
	bool_t supported = ms_filter_codec_supported(codec);
397
	if( supported ) {
398
		float upload_bw;
399 400
		stream_manager_t * marielle, * margaux;

401 402 403 404
		start_adaptive_stream(MSAudio, &marielle, &margaux, payload, target_bw*1000, target_bw*1000, 0, 50,0);
		//these tests check that encoders stick to the guidelines, so we must use NOT
		//the adaptive algorithm which would modify these guidelines
		media_stream_enable_adaptive_bitrate_control(&marielle->audio_stream->ms,FALSE);
405
		iterate_adaptive_stream(marielle, margaux, 15000, NULL, 0);
406
		upload_bw=media_stream_get_up_bw(&marielle->audio_stream->ms) / 1000;
407
		CU_ASSERT_IN_RANGE(upload_bw, expect_bw-2, expect_bw+2);
408
		stop_adaptive_stream(marielle,margaux);
409 410 411
	}
}

412 413 414 415 416
static void upload_bitrate_pcma_3g() {
	// pcma codec bitrate is always 64 kbits, only ptime can change from 20ms to 100ms.
	// ptime=20  ms -> network bitrate=80 kbits/s
	// ptime=100 ms -> network bitrate=67 kbits/s
	upload_bitrate("pcma", PCMA8_PAYLOAD_TYPE, THIRDGENERATION_BW, 80);
417 418
}

419 420 421 422 423
static void upload_bitrate_speex_low()  {
	// speex codec bitrate can vary from 16 kbits/s to 42 kbits/s
	// bitrate=42 kbits/s ptime=20  ms -> network bitrate=58 kbits/s
	// bitrate=16 kbits/s ptime=100 ms -> network bitrate=19 kbits/s
	upload_bitrate("speex", SPEEX_PAYLOAD_TYPE, 25, 25);
424
}
425

426 427
static void upload_bitrate_speex_3g()  {
	upload_bitrate("speex", SPEEX_PAYLOAD_TYPE, THIRDGENERATION_BW, 59);
428 429 430
}


431 432 433 434 435 436 437 438
static void upload_bitrate_opus_edge() {
	// opus codec bitrate can vary from 6 kbits/s to 184 kbits/s
	// bitrate=6   kbits/s and ptime=100  ms -> network bitrate=  9 kbits/s
	// bitrate=184 kbits/s and ptime=20   ms -> network bitrate=200 kbits/s
	// upload_bitrate("opus", OPUS_PAYLOAD_TYPE, EDGE_BW, 9);
	ms_warning("%s TODO: fix me. ptime in preprocess should be computed to stick the guidelines", __FUNCTION__);
	//until ptime is correctly set on startup, this will not work: currently ptime is set to 40ms but this
	// is not sufficient to match the guidelines without adaptive algorithm.
439
}
440

441 442
static void upload_bitrate_opus_3g() {
	upload_bitrate("opus", OPUS_PAYLOAD_TYPE, THIRDGENERATION_BW, 200);
443
}
444

445
#if VIDEO_ENABLED
446
void adaptive_video(int max_bw, int exp_min_bw, int exp_max_bw, int loss_rate, int exp_min_loss, int exp_max_loss) {
447
	bool_t supported = ms_filter_codec_supported("VP8");
448
	if( supported ) {
449 450 451 452 453 454 455 456
		stream_manager_t * marielle, * margaux;
		start_adaptive_stream(MSVideo, &marielle, &margaux, VP8_PAYLOAD_TYPE, 300*1000, max_bw*1000, loss_rate, 50,0);
		iterate_adaptive_stream(marielle, margaux, 100000, &marielle->rtcp_count, 7);
		CU_ASSERT_TRUE(marielle->adaptive_stats.loss_estim >= exp_min_loss);
		CU_ASSERT_TRUE(marielle->adaptive_stats.loss_estim <= exp_max_loss);
		CU_ASSERT_TRUE(marielle->adaptive_stats.congestion_bw_estim >= exp_min_bw);
		CU_ASSERT_TRUE(marielle->adaptive_stats.congestion_bw_estim <= exp_max_bw);
		stop_adaptive_stream(marielle,margaux);
457 458
	}
}
459

460
static void adaptive_vp8_ideal() {
461
	adaptive_video(0, 200, 10000, 0, 0, 1);
462 463
}
static void adaptive_vp8_lossy() {
464
	adaptive_video(0, 200, 10000, 25, 20, 30);
465 466 467 468 469 470 471 472
}
static void adaptive_vp8_congestion() {
	adaptive_video(70, 50, 95, 0, 0, 2);
}
static void adaptive_vp8_lossy_congestion() {
	ms_warning("Disabled yet, too much instable");
	// adaptive_video(130, 110, 150, 7, 4, 10);
}
473
#endif
474

475 476

static test_t tests[] = {
477 478 479
	{ "Packet duplication", packet_duplication},
	{ "Upload bandwidth computation", upload_bandwidth_computation },
	{ "Loss rate estimation", loss_rate_estimation },
480 481 482 483 484 485 486

	{ "Upload bitrate [pcma] - 3g", upload_bitrate_pcma_3g },
	{ "Upload bitrate [speex] - low", upload_bitrate_speex_low },
	{ "Upload bitrate [speex] - 3g", upload_bitrate_speex_3g },
	{ "Upload bitrate [opus] - edge", upload_bitrate_opus_edge },
	{ "Upload bitrate [opus] - 3g", upload_bitrate_opus_3g },

Gautier Pelloux-Prayer's avatar
Gautier Pelloux-Prayer committed
487
#if VIDEO_ENABLED
488 489 490 491 492
	{ "Network detection [VP8] - ideal", adaptive_vp8_ideal },
	{ "Network detection [VP8] - lossy", adaptive_vp8_lossy },
	{ "Network detection [VP8] - congested", adaptive_vp8_congestion },
	{ "Network detection [VP8] - lossy congested", adaptive_vp8_lossy_congestion },
#endif
493 494 495
};

test_suite_t adaptive_test_suite = {
496
	"AdaptiveAlgorithm",
497 498 499 500 501
	tester_init,
	tester_cleanup,
	sizeof(tests) / sizeof(tests[0]),
	tests
};