static void adaptive_opus_audio_stream()  {
	bool_t supported = ms_filter_codec_supported("opus");
	if( supported ) {
		// at 8KHz -> 24kb/s
		// at 48KHz -> 48kb/s
		float bw_usage;
		stream_manager_t * marielle, * margaux;

		// on EDGEBW, both should be overconsumming
		start_adaptive_stream(AudioStreamType, &marielle, &margaux, OPUS_PAYLOAD_TYPE, 8000, EDGE_BW, 0, 0, 0);
		iterate_adaptive_stream(marielle, margaux, 10000, NULL, 0);
		bw_usage=media_stream_get_up_bw(&marielle->audio_stream->ms)*1./EDGE_BW;
		CU_ASSERT_IN_RANGE(bw_usage, 2.f, 3.f); // bad! since this codec cant change its ptime and it is the lower bitrate, no improvement can occur
		stop_adaptive_stream(marielle,margaux);

		start_adaptive_stream(AudioStreamType, &marielle, &margaux, OPUS_PAYLOAD_TYPE, 48000, EDGE_BW, 0, 0, 0);
		iterate_adaptive_stream(marielle, margaux, 10000, NULL, 0);
		bw_usage=media_stream_get_up_bw(&marielle->audio_stream->ms)*1./EDGE_BW;
		CU_ASSERT_IN_RANGE(bw_usage, 1.f, 1.4f); // bad!
		stop_adaptive_stream(marielle,margaux);

		// on 3G BW, both should be at max
		start_adaptive_stream(AudioStreamType, &marielle, &margaux, OPUS_PAYLOAD_TYPE, 8000, THIRDGENERATION_BW, 0, 0, 0);
		iterate_adaptive_stream(marielle, margaux, 10000, NULL, 0);
		bw_usage=media_stream_get_up_bw(&marielle->audio_stream->ms)*1./THIRDGENERATION_BW;
		CU_ASSERT_IN_RANGE(bw_usage, .1f, .15f);
		stop_adaptive_stream(marielle,margaux);

		start_adaptive_stream(AudioStreamType, &marielle, &margaux, OPUS_PAYLOAD_TYPE, 48000, THIRDGENERATION_BW, 0, 0, 0);
		iterate_adaptive_stream(marielle, margaux, 10000, NULL, 0);
		bw_usage=media_stream_get_up_bw(&marielle->audio_stream->ms)*1./THIRDGENERATION_BW;
		CU_ASSERT_IN_RANGE(bw_usage, .2f, .3f);
		stop_adaptive_stream(marielle,margaux);
	}
}
static void adaptative_pcma_audio_stream() {
	bool_t supported = ms_filter_codec_supported("pcma");
	if( supported ) {
		// at 8KHz -> 80 kb/s
		float bw_usage;

		// yet non-adaptative codecs cannot respect low throughput limitations
		bw_usage = adaptive_audio_stream(PCMA8_PAYLOAD_TYPE, 8000, EDGE_BW, 10);
		CU_ASSERT_IN_RANGE(bw_usage,6.f, 8.f); // this is bad!
		bw_usage = adaptive_audio_stream(PCMA8_PAYLOAD_TYPE, 8000, THIRDGENERATION_BW, 5);
		CU_ASSERT_IN_RANGE(bw_usage, .3f, .5f);
	}
}
static void adaptive_speek16_audio_stream()  {
	bool_t supported = ms_filter_codec_supported("speex");
	if( supported ) {
		// at 16KHz -> 20 kb/s
		// at 32KHz -> 30 kb/s
		float bw_usage;

		bw_usage = adaptive_audio_stream(SPEEX16_PAYLOAD_TYPE, 32000, EDGE_BW, 12);
		CU_ASSERT_IN_RANGE(bw_usage, .9f, 1.f);
		bw_usage = adaptive_audio_stream(SPEEX16_PAYLOAD_TYPE, 16000, EDGE_BW, 8);
		CU_ASSERT_IN_RANGE(bw_usage, .9f, 1.f);
		bw_usage = adaptive_audio_stream(SPEEX16_PAYLOAD_TYPE, 32000, THIRDGENERATION_BW, 5);
		CU_ASSERT_IN_RANGE(bw_usage, .1f, .2f);
	}
}
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);
		}
	}
}
static void adaptive_vp8() {
	stream_manager_t * marielle, * margaux;

	start_adaptive_stream(VideoStreamType, &marielle, &margaux, VP8_PAYLOAD_TYPE, 300000, 0, 25, 50, 0);
	iterate_adaptive_stream(marielle, margaux, 100000, &marielle->rtcp_count, 12);
	CU_ASSERT_IN_RANGE(marielle->adaptive_stats.loss_estim, 20, 30);
	CU_ASSERT_TRUE(marielle->adaptive_stats.congestion_bw_estim > 200);
	stop_adaptive_stream(marielle,margaux);

	start_adaptive_stream(VideoStreamType, &marielle, &margaux, VP8_PAYLOAD_TYPE, 300000, 45000, 0, 50,0);
	iterate_adaptive_stream(marielle, margaux, 100000, &marielle->rtcp_count, 12);
	CU_ASSERT_IN_RANGE(marielle->adaptive_stats.loss_estim, 0, 2);
	CU_ASSERT_IN_RANGE(marielle->adaptive_stats.congestion_bw_estim, 30, 60);
	stop_adaptive_stream(marielle,margaux);

	start_adaptive_stream(VideoStreamType, &marielle, &margaux, VP8_PAYLOAD_TYPE, 300000, 70000,0, 50,0);
	iterate_adaptive_stream(marielle, margaux, 100000, &marielle->rtcp_count, 12);
	CU_ASSERT_IN_RANGE(marielle->adaptive_stats.loss_estim, 0, 2);
	CU_ASSERT_IN_RANGE(marielle->adaptive_stats.congestion_bw_estim, 50, 95);
	stop_adaptive_stream(marielle,margaux);

	start_adaptive_stream(VideoStreamType, &marielle, &margaux, VP8_PAYLOAD_TYPE, 300000, 100000,15, 50,0);
	iterate_adaptive_stream(marielle, margaux, 100000, &marielle->rtcp_count, 12);
	CU_ASSERT_IN_RANGE(marielle->adaptive_stats.loss_estim, 10, 20);
	CU_ASSERT_IN_RANGE(marielle->adaptive_stats.congestion_bw_estim, 80, 125);
	stop_adaptive_stream(marielle,margaux);
}
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) {
	bool_t supported = ms_filter_codec_supported("VP8");
	if( supported ) {
		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__);
		}
	}
}
static void adaptive_opus_audio_stream()  {
	bool_t supported = ms_filter_codec_supported("opus");
	if( supported ) {
		// at 8KHz -> 24kb/s
		// at 48KHz -> 48kb/s
		float bw_usage;

		// on EDGEBW, both should be overconsumming
		bw_usage = adaptive_audio_stream(OPUS_PAYLOAD_TYPE, 8000, EDGE_BW, 14);
		CU_ASSERT_IN_RANGE(bw_usage, 1.f, 3.f); // bad! since this codec cant change its ptime and it is the lower bitrate, no improvement can occur
		bw_usage = adaptive_audio_stream(OPUS_PAYLOAD_TYPE, 48000, EDGE_BW, 11);
		CU_ASSERT_IN_RANGE(bw_usage, 1.f, 1.2f); // bad!

		// on 3G BW, both should be at max
		bw_usage = adaptive_audio_stream(OPUS_PAYLOAD_TYPE, 8000, THIRDGENERATION_BW, 5);
		CU_ASSERT_IN_RANGE(bw_usage, .1f, .15f);
		bw_usage = adaptive_audio_stream(OPUS_PAYLOAD_TYPE, 48000, THIRDGENERATION_BW, 5);
		CU_ASSERT_IN_RANGE(bw_usage, .2f, .3f);
	}
}
static void adaptive_pcma_audio_stream() {
	bool_t supported = ms_filter_codec_supported("pcma");
	if( supported ) {
		// at 8KHz -> 80 kb/s
		float bw_usage;
		stream_manager_t * marielle, * margaux;

		// yet non-adaptative codecs cannot respect low throughput limitations
		start_adaptive_stream(AudioStreamType, &marielle, &margaux, PCMA8_PAYLOAD_TYPE, 8000, EDGE_BW, 0, 0, 0);
		iterate_adaptive_stream(marielle, margaux, 10000, NULL, 0);
		bw_usage=media_stream_get_up_bw(&marielle->audio_stream->ms)*1./EDGE_BW;
		CU_ASSERT_IN_RANGE(bw_usage,6.f, 8.f); // this is bad!
		stop_adaptive_stream(marielle,margaux);

		start_adaptive_stream(AudioStreamType, &marielle, &margaux, PCMA8_PAYLOAD_TYPE, 8000, THIRDGENERATION_BW, 0, 0, 0);
		iterate_adaptive_stream(marielle, margaux, 10000, NULL, 0);
		bw_usage=media_stream_get_up_bw(&marielle->audio_stream->ms)*1./THIRDGENERATION_BW;
		CU_ASSERT_IN_RANGE(bw_usage, .3f, .5f);
		stop_adaptive_stream(marielle,margaux);
	}
}
static void adaptive_speex16_audio_stream()  {
	bool_t supported = ms_filter_codec_supported("speex");
	if( supported ) {
		// at 16KHz -> 20 kb/s
		// at 32KHz -> 30 kb/s
		float bw_usage;
		stream_manager_t * marielle, * margaux;

		start_adaptive_stream(AudioStreamType, &marielle, &margaux, SPEEX16_PAYLOAD_TYPE, 32000, EDGE_BW / 2., 0, 0, 0);
		iterate_adaptive_stream(marielle, margaux, 10000, NULL, 0);
		bw_usage=media_stream_get_up_bw(&marielle->audio_stream->ms)*1./(EDGE_BW / 2.);
		CU_ASSERT_IN_RANGE(bw_usage, 1.f, 5.f);
		stop_adaptive_stream(marielle,margaux);
	}
}
void upload_bitrate(const char* codec, int payload, int target_bw, int expect_bw) {
	bool_t supported = ms_filter_codec_supported(codec);
	if( supported ) {
		float upload_bw;
		stream_manager_t * marielle, * margaux;

		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);
		iterate_adaptive_stream(marielle, margaux, 15000, NULL, 0);
		upload_bw=media_stream_get_up_bw(&marielle->audio_stream->ms) / 1000;
		CU_ASSERT_IN_RANGE(upload_bw, expect_bw-2, expect_bw+2);
		stop_adaptive_stream(marielle,margaux);
	}
}