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 iterate_adaptive_stream(stream_manager_t * marielle, stream_manager_t * margaux,
	int timeout_ms, int* current, int expected){
	int retry=0;

	MediaStream *marielle_ms,*margaux_ms;
	if (marielle->type == AudioStreamType){
		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;
	}

	while ((!current||*current<expected) && retry++ <timeout_ms/100) {
		media_stream_iterate(marielle_ms);
		media_stream_iterate(margaux_ms);
		handle_queue_events(marielle);
		if (retry%10==0) {
			 ms_message("stream [%p] bandwidth usage: [d=%.1f,u=%.1f] kbit/sec"	,
				marielle_ms, media_stream_get_down_bw(marielle_ms)/1000, media_stream_get_up_bw(marielle_ms)/1000);
			 ms_message("stream [%p] bandwidth usage: [d=%.1f,u=%.1f] kbit/sec"	,
				margaux_ms, media_stream_get_down_bw(margaux_ms)/1000, media_stream_get_up_bw(margaux_ms)/1000);
		 }
		ms_usleep(100000);
	}
}
bool_t wait_for_list_with_parse_events(MSList *mss, int *counter, int value, int timeout_ms, MSList *cbs, MSList *ptrs) {
	MSList *msi;
	MSList *cbi;
	MSList *ptri;
	int retry = 0;

	while ((*counter < value) && (retry++ < (timeout_ms / 100))) {
		for (msi = mss, cbi = cbs, ptri = ptrs; msi != NULL; msi = msi->next) {
			MediaStream *stream = (MediaStream *)msi->data;
			ms_tester_iterate_cb cb = NULL;
			media_stream_iterate(stream);
			if ((retry % 10) == 0) {
				ms_message("stream [%p] bandwidth usage: [d=%.1f,u=%.1f] kbit/sec",
					stream,
					media_stream_get_down_bw(stream) / 1000,
					media_stream_get_up_bw(stream) / 1000);
			}
			if (cbi && ptri) {
				cb = (ms_tester_iterate_cb)cbi->data;
				cb(stream, ptri->data);
			}
			if (cbi) cbi = cbi->next;
			if (ptri) ptri = ptri->next;
		}
		ms_usleep(100000);
	}

	if (*counter < value)
		return FALSE;
	return TRUE;
}
static float adaptive_audio_stream(int codec_payload, int initial_bitrate,int target_bw, int max_recv_rtcp_packet) {
	stream_manager_t * marielle = stream_manager_new();
	stream_manager_t * margaux = stream_manager_new();
	int pause_time=0;

	OrtpNetworkSimulatorParams params={0};
	params.enabled=TRUE;
	params.loss_rate=0;
	params.max_bandwidth=target_bw;
	params.max_buffer_size=initial_bitrate;
	float bw_usage_ratio;
	float marielle_send_bw;

	media_stream_enable_adaptive_bitrate_control(&marielle->stream->ms,TRUE);

	stream_manager_start(marielle,codec_payload, margaux->local_rtp,initial_bitrate,HELLO_16K_1S_FILE,NULL);
	ms_filter_call_method(marielle->stream->soundread,MS_FILE_PLAYER_LOOP,&pause_time);

	stream_manager_start(margaux,codec_payload, marielle->local_rtp,-1,NULL,RECORDED_16K_1S_FILE);
	rtp_session_enable_network_simulation(margaux->stream->ms.sessions.rtp_session,&params);

	wait_for_until(&marielle->stream->ms,&margaux->stream->ms,&marielle->stats.number_of_EndOfFile,10,2500*max_recv_rtcp_packet);

	marielle_send_bw=media_stream_get_up_bw(&marielle->stream->ms);
	bw_usage_ratio=marielle_send_bw/params.max_bandwidth;
	ms_message("marielle sent bw=[%f], target was [%f] bw_usage_ratio [%f]",marielle_send_bw,params.max_bandwidth,bw_usage_ratio);

	stream_manager_delete(marielle);
	stream_manager_delete(margaux);

	unlink(RECORDED_16K_1S_FILE);

	return bw_usage_ratio;
}
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);
	}
}
static void qos_analyzer_on_action_suggested(void *user_data, int datac, const char** datav){
	reporting_session_report_t *report = (reporting_session_report_t*)user_data;
	LinphoneCall *call = report->call;
	char * appendbuf;
	int i;
	int ptime = -1;
	int bitrate[3] = {-1, -1, -1};
	int up_bw[3] = {-1, -1, -1};
	int down_bw[3] = {-1, -1, -1};
	MediaStream *streams[3] = { (MediaStream*) call->audiostream, (MediaStream *) call->videostream, (MediaStream *) call->textstream };
	for (i = 0; i < 3; i++){
		if (streams[i] != NULL){
			if (streams[i]->encoder != NULL){
				if (ms_filter_has_method(streams[i]->encoder,MS_FILTER_GET_BITRATE)){
					ms_filter_call_method(streams[i]->encoder,MS_FILTER_GET_BITRATE,&bitrate[i]);
					bitrate[i] /= 1000;
				}
			}
			up_bw[i] = (int)(media_stream_get_up_bw(streams[i])/1000.f);
			down_bw[i] = (int)(media_stream_get_down_bw(streams[i])/1000.f);
		}
	}
	if (call->audiostream!=NULL){
		if (call->audiostream->ms.encoder!=NULL){
			if(ms_filter_has_method(call->audiostream->ms.encoder,MS_AUDIO_ENCODER_GET_PTIME)){
				ms_filter_call_method(call->audiostream->ms.encoder,MS_AUDIO_ENCODER_GET_PTIME,&ptime);
			}
		}
	}

	appendbuf=ms_strdup_printf("%s%d;", report->qos_analyzer.timestamp?report->qos_analyzer.timestamp:"", ms_time(0));
	STR_REASSIGN(report->qos_analyzer.timestamp,appendbuf);

	STR_REASSIGN(report->qos_analyzer.input_leg, ms_strdup_printf("%s aenc_ptime aenc_br a_dbw a_ubw venc_br v_dbw v_ubw tenc_br t_dbw t_ubw", datav[0]));
	appendbuf=ms_strdup_printf("%s%s %d %d %d %d %d %d %d %d %d %d;", report->qos_analyzer.input?report->qos_analyzer.input:"", datav[1],
		ptime, bitrate[0], down_bw[0], up_bw[0], bitrate[1], down_bw[1], up_bw[1], bitrate[2], down_bw[2], up_bw[2]);
	STR_REASSIGN(report->qos_analyzer.input,appendbuf);
	STR_REASSIGN(report->qos_analyzer.output_leg, ms_strdup(datav[2]));
	appendbuf=ms_strdup_printf("%s%s;", report->qos_analyzer.output?report->qos_analyzer.output:"", datav[3]);
	STR_REASSIGN(report->qos_analyzer.output, appendbuf);
}
static void audio_stream_dtmf(int codec_payload, int initial_bitrate,int target_bw, int max_recv_rtcp_packet) {
	stream_manager_t * marielle = stream_manager_new();
	stream_manager_t * margaux = stream_manager_new();
	int pause_time=0;

	OrtpNetworkSimulatorParams params={0};
	params.enabled=TRUE;
	params.loss_rate=0;
	params.max_bandwidth=target_bw;
	params.max_buffer_size=initial_bitrate;
	float recv_send_bw_ratio;
	int rtcp_interval = 1000;
	float marielle_send_bw;

	media_stream_enable_adaptive_bitrate_control(&marielle->stream->ms,TRUE);


	stream_manager_start(marielle,codec_payload, margaux->local_rtp,initial_bitrate,HELLO_16K_1S_FILE,NULL);
	ms_filter_call_method(marielle->stream->soundread,MS_FILE_PLAYER_LOOP,&pause_time);

	unlink("blibi.wav");
	stream_manager_start(margaux,codec_payload, marielle->local_rtp,-1,NULL,"blibi.wav");
	rtp_session_enable_network_simulation(margaux->stream->ms.session,&params);
	rtp_session_set_rtcp_report_interval(margaux->stream->ms.session, rtcp_interval);

	wait_for_until(&marielle->stream->ms,&margaux->stream->ms,&marielle->stats.number_of_EndOfFile,10,rtcp_interval*max_recv_rtcp_packet);

	marielle_send_bw=media_stream_get_up_bw(&marielle->stream->ms);
	recv_send_bw_ratio=params.max_bandwidth/marielle_send_bw;
	ms_message("marielle sent bw= [%f] , target was [%f] recv/send [%f]",marielle_send_bw,params.max_bandwidth,recv_send_bw_ratio);
	CU_ASSERT_TRUE(recv_send_bw_ratio>0.9);

	stream_manager_delete(marielle);
	stream_manager_delete(margaux);

}