mediastreamer2_adaptive_tester.c 18.1 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 28 29 30 31 32 33 34 35
/*
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"

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


static RtpProfile rtp_profile;

#define OPUS_PAYLOAD_TYPE    121
36
#define SPEEX_PAYLOAD_TYPE 122
37 38 39 40 41 42
#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

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

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);
52
	rtp_profile_set_payload (&rtp_profile,SPEEX_PAYLOAD_TYPE,&payload_type_speex_wb);
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
	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;
}

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

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

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

82 83
	int rtcp_count;

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

89
	void* user_data;
90

91 92
} stream_manager_t ;

93
stream_manager_t * stream_manager_new(MSFormatType type) {
94 95 96 97
	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;
98
	mgr->user_data = 0;
99

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

109 110 111
	}
	return mgr;
}
112

113
static void stream_manager_delete(stream_manager_t * mgr) {
114

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

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

139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
	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);
}

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

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

178 179 180
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++;
181

182 183 184 185 186 187
	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;
188 189 190 191
		}
	}
}

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

204 205
	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);
206

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

Simon Morlat's avatar
Simon Morlat committed
213
	if (type == MSAudio){
214 215 216 217 218 219 220
		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;
	}

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

226 227

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

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

235
		audio_manager_start(margaux,payload,marielle->local_rtp,0,NULL,recorded_file);
236
	}else{
237
#if VIDEO_ENABLED
238
		video_manager_start(marielle,payload,margaux->local_rtp,0,marielle_webcam);
239 240
		video_stream_set_direction(margaux->video_stream,VideoStreamRecvOnly);

241
		video_manager_start(margaux,payload,marielle->local_rtp,0,NULL);
242
#else
243
		ms_fatal("Unsupported stream type [%s]",ms_format_type_to_string(marielle->type));
244
#endif
245
	}
246

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

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

255
}
256

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

	MediaStream *marielle_ms,*margaux_ms;
Simon Morlat's avatar
Simon Morlat committed
262
	if (marielle->type == MSAudio){
263 264 265 266 267 268 269
		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;
	}

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

284 285
static void stop_adaptive_stream(stream_manager_t *marielle, stream_manager_t *margaux){
	stream_manager_delete(marielle);
286
	stream_manager_delete(margaux);
287
}
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
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);
		}
	}
}
320

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

	dup_ratio = 0;
328
	start_adaptive_stream(MSAudio, &marielle, &margaux, SPEEX_PAYLOAD_TYPE, 32000, 0, 0, 50,dup_ratio);
329
	media_stream_enable_adaptive_bitrate_control(&marielle->audio_stream->ms,FALSE);
330
	iterate_adaptive_stream(marielle, margaux, 10000, NULL, 0);
331 332 333 334 335 336 337 338 339
	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;
340
	start_adaptive_stream(MSAudio, &marielle, &margaux, SPEEX_PAYLOAD_TYPE, 32000, 0, 0, 50,dup_ratio);
341
	media_stream_enable_adaptive_bitrate_control(&marielle->audio_stream->ms,FALSE);
342
	iterate_adaptive_stream(marielle, margaux, 10000, NULL, 0);
343 344 345 346 347 348
	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);
}

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

355 356 357 358 359 360 361
		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
362
			CU_ASSERT_TRUE(fabs(rtp_session_get_send_bandwidth(marielle->audio_stream->ms.sessions.rtp_session)/1000. - 80.*(i+1)) < 5.f);
363
		}
364
		stop_adaptive_stream(marielle,margaux);
365 366
	}
}
367

368 369 370 371 372 373 374 375
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
376
		ctx.estimator=ortp_loss_rate_estimator_new(120, 2500, marielle->audio_stream->ms.sessions.rtp_session);
377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393
		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);
	}
}

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

400 401 402 403
		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);
404
		iterate_adaptive_stream(marielle, margaux, 15000, NULL, 0);
405
		upload_bw=media_stream_get_up_bw(&marielle->audio_stream->ms) / 1000;
406
		CU_ASSERT_IN_RANGE(upload_bw, expect_bw-2, expect_bw+2);
407
		stop_adaptive_stream(marielle,margaux);
408 409 410
	}
}

411 412 413 414 415
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);
416 417
}

418 419 420 421 422
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);
423
}
424

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


430 431 432 433 434 435 436 437
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.
438
}
439

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

444
#if VIDEO_ENABLED
445
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) {
446
	bool_t supported = ms_filter_codec_supported("VP8");
447
	if( supported ) {
448 449 450 451 452 453 454 455 456 457 458 459 460 461 462
		bool_t has_cam  = ms_web_cam_manager_get_default_cam(ms_web_cam_manager_get())
							!= ms_web_cam_manager_get_cam(ms_web_cam_manager_get(), "StaticImage: Static picture");
		if (has_cam) {
			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_IN_RANGE(marielle->adaptive_stats.loss_estim, exp_min_loss, exp_max_loss);
			CU_ASSERT_IN_RANGE(marielle->adaptive_stats.congestion_bw_estim, exp_min_bw, exp_max_bw);
			stop_adaptive_stream(marielle,margaux);
		} else {
			/*ortp_loss_estimator rely on the fact that we receive some packets: however when
			using static picture camera, there is a traffic of around 1 packet per second which
			is totally unlikely leading in no QoS possibility*/
			ms_warning("%s test disabled because no real camera is available", __FUNCTION__);
		}
463 464
	}
}
465

466 467 468 469 470 471 472 473 474 475 476 477 478
static void adaptive_vp8_ideal() {
	adaptive_video(0, 200, 1000, 0, 0, 1);
}
static void adaptive_vp8_lossy() {
	adaptive_video(0, 200, 1000, 25, 20, 30);
}
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);
}
479
#endif
480

481 482

static test_t tests[] = {
483 484 485
	{ "Packet duplication", packet_duplication},
	{ "Upload bandwidth computation", upload_bandwidth_computation },
	{ "Loss rate estimation", loss_rate_estimation },
486 487 488 489 490 491 492

	{ "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
493
#if VIDEO_ENABLED
494 495 496 497 498
	{ "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
499 500 501
};

test_suite_t adaptive_test_suite = {
502
	"AdaptiveAlgorithm",
503 504 505 506 507
	tester_init,
	tester_cleanup,
	sizeof(tests) / sizeof(tests[0]),
	tests
};