static void stateful_analyzer_suggest_action(MSQosAnalyzer *objbase, MSRateControlAction *action){ MSStatefulQosAnalyzer *obj=(MSStatefulQosAnalyzer*)objbase; float curbw = obj->latest ? obj->latest->bandwidth : 0.f; float bw = compute_available_bw(obj); /*try a burst every 50 seconds (10 RTCP packets)*/ if (obj->curindex % 10 == 0){ ms_debug("MSQosStatefulAnalyzer[%p]: try burst!", obj); obj->burst_state = MSStatefulQosAnalyzerBurstEnable; } /*test a min burst to avoid overestimation of available bandwidth*/ else if (obj->curindex % 10 == 2 || obj->curindex % 10 == 3){ ms_debug("MSQosStatefulAnalyzer[%p]: try minimal burst!", obj); bw *= .33; } /*no bandwidth estimation computed*/ if (bw <= 0 || curbw <= 0){ action->type=MSRateControlActionDoNothing; action->value=0; }else if (bw > curbw){ action->type=MSRateControlActionIncreaseQuality; action->value=MAX(0, 100. * (bw / curbw - 1)); }else{ action->type=MSRateControlActionDecreaseBitrate; action->value=MAX(10, -100. * (bw / curbw - 1)); } ms_debug("MSQosStatefulAnalyzer[%p]: %s of value %d", obj, ms_rate_control_action_type_name(action->type), action->value); }
static int audio_bitrate_driver_execute_action(MSBitrateDriver *objbase, const MSRateControlAction *action){ MSAudioBitrateDriver *obj=(MSAudioBitrateDriver*)objbase; ms_message("MSAudioBitrateDriver: executing action of type %s, value=%i",ms_rate_control_action_type_name(action->type),action->value); if (action->type==MSRateControlActionDecreaseBitrate){ /*reducing bitrate of the codec actually doesn't work very well (not enough). Increasing ptime is much more efficient*/ if (inc_ptime(obj)==-1){ if (obj->nom_bitrate>0){ int cur_br=0; int new_br; if (obj->nom_bitrate==0){ if (ms_filter_call_method(obj->encoder,MS_FILTER_GET_BITRATE,&obj->nom_bitrate)!=0){ ms_message("MSAudioBitrateDriver: Encoder has nominal bitrate %i",obj->nom_bitrate); } obj->cur_bitrate=obj->nom_bitrate; } /*if max ptime is reached, then try to reduce the codec bitrate if possible */ if (ms_filter_call_method(obj->encoder,MS_FILTER_GET_BITRATE,&cur_br)!=0){ ms_message("AudioBitrateController: GET_BITRATE failed"); return 0; } new_br=cur_br-((cur_br*action->value)/100); ms_message("MSAudioBitrateDriver: Attempting to reduce audio bitrate to %i",new_br); if (ms_filter_call_method(obj->encoder,MS_FILTER_SET_BITRATE,&new_br)!=0){ ms_message("MSAudioBitrateDriver: SET_BITRATE failed, incrementing ptime"); inc_ptime(obj); return 0; } new_br=0; ms_filter_call_method(obj->encoder,MS_FILTER_GET_BITRATE,&new_br); ms_message("MSAudioBitrateDriver: bitrate actually set to %i",new_br); obj->cur_bitrate=new_br; } } }else if (action->type==MSRateControlActionDecreasePacketRate){ inc_ptime(obj); }else if (action->type==MSRateControlActionIncreaseQuality){ if (obj->cur_bitrate<obj->nom_bitrate){ ms_message("MSAudioBitrateDriver: increasing bitrate of codec"); if (ms_filter_call_method(obj->encoder,MS_FILTER_SET_BITRATE,&obj->nom_bitrate)!=0){ ms_message("MSAudioBitrateDriver: could not restore nominal codec bitrate (%i)",obj->nom_bitrate); }else obj->cur_bitrate=obj->nom_bitrate; }else if (obj->cur_ptime>obj->min_ptime){ obj->cur_ptime-=obj->min_ptime; apply_ptime(obj); }else return -1; } return 0; }
static void simple_analyzer_suggest_action(MSQosAnalyzer *objbase, MSRateControlAction *action){ MSSimpleQosAnalyzer *obj=(MSSimpleQosAnalyzer*)objbase; rtpstats_t *cur=&obj->stats[obj->curindex % STATS_HISTORY]; /*big losses and big jitter */ if (cur->lost_percentage>=unacceptable_loss_rate && cur->int_jitter>=big_jitter){ action->type=MSRateControlActionDecreaseBitrate; action->value=(int)MIN(cur->lost_percentage,50); ms_message("MSSimpleQosAnalyzer: loss rate unacceptable and big jitter"); }else if (simple_rt_prop_increased(obj)){ action->type=MSRateControlActionDecreaseBitrate; action->value=20; ms_message("MSSimpleQosAnalyzer: rt_prop doubled."); }else if (cur->lost_percentage>=unacceptable_loss_rate){ /*big loss rate but no jitter, and no big rtp_prop: pure lossy network*/ action->type=MSRateControlActionDecreaseBitrate; action->value=(int)MIN(cur->lost_percentage,50); ms_message("MSSimpleQosAnalyzer: loss rate unacceptable."); }else{ action->type=MSRateControlActionDoNothing; ms_message("MSSimpleQosAnalyzer: everything is fine."); } if (objbase->on_action_suggested!=NULL){ int i; char *data[4]; int datac = sizeof(data) / sizeof(data[0]); data[0]=ms_strdup("%loss rt_prop_increased int_jitter_ms rt_prop_ms"); data[1]=ms_strdup_printf("%d %d %d %d" , (int)cur->lost_percentage , (simple_rt_prop_increased(obj)==TRUE) , (int)cur->int_jitter , (int)(1000*cur->rt_prop)); data[2]=ms_strdup("action_type action_value"); data[3]=ms_strdup_printf("%s %d" , ms_rate_control_action_type_name(action->type) , action->value); objbase->on_action_suggested(objbase->on_action_suggested_user_pointer, datac, (const char**)data); for (i=0;i<datac;++i){ ms_free(data[i]); } } }
static int bandwidth_driver_execute_action(MSBitrateDriver *objbase, const MSRateControlAction *action){ MSBandwidthBitrateDriver *obj=(MSBandwidthBitrateDriver*)objbase; int ret=0; if (obj->nom_bitrate==0&&obj->venc){ ms_filter_call_method(obj->venc,MS_FILTER_GET_BITRATE,&obj->nom_bitrate); if (obj->nom_bitrate==0){ ms_warning("MSBandwidthBitrateDriver: Not doing adaptive rate control on video encoder, it does not seem to support that."); return -1; } } if (!obj->venc){ ret=1; } switch(action->type){ case MSRateControlActionDecreaseBitrate: if (obj->venc){ ret=bandwidth_change_video_bitrate(obj,action); } if (ret!=0 && obj->audio_driver){ ret=ms_bitrate_driver_execute_action(obj->audio_driver,action); } break; case MSRateControlActionDecreasePacketRate: if (obj->audio_driver){ ret=bandwidth_change_ptime((MSAudioBitrateDriver*) obj->audio_driver, 100); }else{ ret=1; } break; case MSRateControlActionIncreaseQuality: if (obj->venc){ ret=bandwidth_change_video_bitrate(obj,action); } if (ret!=0 && obj->audio_driver){ ret=ms_bitrate_driver_execute_action(obj->audio_driver,action); } break; case MSRateControlActionDoNothing: break; } ms_message("MSBandwidthBitrateDriver: Action %s %s", ms_rate_control_action_type_name(action->type), ret == 0 ? "succeeded" : "failed"); return ret; }
static void stateful_analyzer_suggest_action(MSQosAnalyzer *objbase, MSRateControlAction *action){ MSStatefulQosAnalyzer *obj=(MSStatefulQosAnalyzer*)objbase; float curbw = 0; float bw = 0; rtcpstatspoint_t* greatest_pt = NULL; /*if this is the first measure, there is not enough reliable data to use; we assume loss rate is due to non congestionned network. This is mainly useful in the case loss rate is high (>30%), to reduce quality even before the second RTCP report which can be really used. */ if (obj->curindex==1){ if (obj->network_loss_rate!=0.f){ action->type=MSRateControlActionDecreaseBitrate; action->value=obj->network_loss_rate; } }else { curbw = obj->latest ? obj->latest->bandwidth : 0.f; bw = compute_available_bw(obj); greatest_pt = ms_list_size(obj->rtcpstatspoint) ? (rtcpstatspoint_t*)ms_list_nth_data(obj->rtcpstatspoint, ms_list_size(obj->rtcpstatspoint)-1) : NULL; /*try a burst every 50 seconds (10 RTCP packets)*/ if (obj->curindex % 10 == 6){ ms_message("MSStatefulQosAnalyzer[%p]: try burst!", obj); obj->burst_state = MSStatefulQosAnalyzerBurstEnable; } /*test a min burst to avoid overestimation of available bandwidth but only if there is some loss*/ else if (greatest_pt!=NULL && greatest_pt->loss_percent>1 && (obj->curindex % 10 == 2 || obj->curindex % 10 == 3)){ ms_message("MSStatefulQosAnalyzer[%p]: try minimal burst!", obj); bw *= .33; } /*no bandwidth estimation computed*/ if (bw <= 0 || curbw <= 0){ action->type=MSRateControlActionDoNothing; action->value=0; }else if (bw > curbw){ action->type=MSRateControlActionIncreaseQuality; action->value=MAX(0, 100. * (bw / curbw - 1)); }else{ action->type=MSRateControlActionDecreaseBitrate; action->value=MAX(10, -100. * (bw / curbw - 1)); } } ms_message("MSStatefulQosAnalyzer[%p]: %s of value %d", obj, ms_rate_control_action_type_name(action->type), action->value); if (objbase->on_action_suggested!=NULL){ int i; char *data[4]; int datac = sizeof(data) / sizeof(data[0]); data[0]=ms_strdup("%loss rtt_ms cur_bw"); data[1]=ms_strdup_printf("%d %d %d" , obj->latest?(int)obj->latest->loss_percent:0 , obj->latest?(int)obj->latest->rtt:0 , obj->latest?(int)obj->latest->bandwidth:0 ); data[2]=ms_strdup("action_type action_value est_bw"); data[3]=ms_strdup_printf("%s %d %d" , ms_rate_control_action_type_name(action->type) , action->value , (int)bw ); objbase->on_action_suggested(objbase->on_action_suggested_user_pointer, datac, (const char**)data); for (i=0;i<datac;++i){ ms_free(data[i]); } } }
static int audio_bitrate_driver_execute_action(MSBitrateDriver *objbase, const MSRateControlAction *action){ MSAudioBitrateDriver *obj=(MSAudioBitrateDriver*)objbase; ms_message("MSAudioBitrateDriver: executing action of type %s, value=%i",ms_rate_control_action_type_name(action->type),action->value); if (obj->nom_bitrate==0){ ms_filter_call_method(obj->encoder,MS_FILTER_GET_BITRATE,&obj->nom_bitrate); if (obj->nom_bitrate==0){ ms_warning("MSAudioBitrateDriver: Not doing bitrate control on audio encoder, it does not seem to support that. Controlling ptime only."); obj->nom_bitrate=-1; }else obj->cur_bitrate=obj->nom_bitrate; } if (obj->cur_ptime==0){ ms_filter_call_method(obj->encoder,MS_AUDIO_ENCODER_GET_PTIME,&obj->cur_ptime); if (obj->cur_ptime==0){ ms_warning("MSAudioBitrateDriver: encoder %s does not implement MS_AUDIO_ENCODER_GET_PTIME. Consider to implement this method for better accuracy of rate control.",obj->encoder->desc->name); obj->cur_ptime=obj->min_ptime; } } if (action->type==MSRateControlActionDecreaseBitrate){ /*reducing bitrate of the codec isn't sufficient. Increasing ptime is much more efficient*/ if (inc_ptime(obj)==-1){ if (obj->nom_bitrate>0){ int cur_br=0; int new_br; /*if max ptime is reached, then try to reduce the codec bitrate if possible */ if (ms_filter_call_method(obj->encoder,MS_FILTER_GET_BITRATE,&cur_br)!=0){ ms_message("MSAudioBitrateDriver: GET_BITRATE failed"); return 0; } obj->cur_bitrate=cur_br; new_br=cur_br-((cur_br*action->value)/100); ms_message("MSAudioBitrateDriver: Attempting to reduce audio bitrate to %i",new_br); if (ms_filter_call_method(obj->encoder,MS_FILTER_SET_BITRATE,&new_br)!=0){ ms_message("MSAudioBitrateDriver: SET_BITRATE failed, incrementing ptime"); inc_ptime(obj); return 0; } new_br=0; ms_filter_call_method(obj->encoder,MS_FILTER_GET_BITRATE,&new_br); ms_message("MSAudioBitrateDriver: bitrate actually set to %i",new_br); obj->cur_bitrate=new_br; } } }else if (action->type==MSRateControlActionDecreasePacketRate){ inc_ptime(obj); }else if (action->type==MSRateControlActionIncreaseQuality){ if (obj->nom_bitrate>0){ if (ms_filter_call_method(obj->encoder,MS_FILTER_GET_BITRATE,&obj->cur_bitrate)==0){ if (obj->cur_bitrate > 0 && obj->cur_bitrate<obj->nom_bitrate){ obj->cur_bitrate=(obj->cur_bitrate*140)/100; if (obj->cur_bitrate> obj->nom_bitrate) obj->cur_bitrate=obj->nom_bitrate; ms_message("MSAudioBitrateDriver: increasing bitrate of codec to %i",obj->cur_bitrate); if (ms_filter_call_method(obj->encoder,MS_FILTER_SET_BITRATE,&obj->cur_bitrate)!=0){ ms_message("MSAudioBitrateDriver: could not set codec bitrate to %i",obj->cur_bitrate); }else obj->cur_bitrate=obj->nom_bitrate; /* so that we do not attempt this anymore*/ return 0; } }else ms_warning("MSAudioBitrateDriver: MS_FILTER_GET_BITRATE failed."); } if (obj->cur_ptime>obj->min_ptime){ obj->cur_ptime-=obj->min_ptime; apply_ptime(obj); }else return -1; } return 0; }
static int audio_bitrate_driver_execute_action(MSBitrateDriver *objbase, const MSRateControlAction *action){ MSAudioBitrateDriver *obj=(MSAudioBitrateDriver*)objbase; ms_message("MSAudioBitrateDriver: executing action of type %s, value=%i",ms_rate_control_action_type_name(action->type),action->value); if (obj->nom_bitrate==0){ ms_filter_call_method(obj->encoder,MS_FILTER_GET_BITRATE,&obj->nom_bitrate); if (obj->nom_bitrate==0){ ms_warning("MSAudioBitrateDriver: Not doing bitrate control on audio encoder, it does not seem to support that. Controlling ptime only."); obj->nom_bitrate=-1; }else obj->cur_bitrate=obj->nom_bitrate; } if (obj->cur_ptime==0 || ms_filter_has_method(obj->encoder,MS_AUDIO_ENCODER_GET_PTIME)){ /*always sync current ptime if possible*/ ms_filter_call_method(obj->encoder,MS_AUDIO_ENCODER_GET_PTIME,&obj->cur_ptime); if (obj->cur_ptime==0){ ms_warning("MSAudioBitrateDriver: encoder %s does not implement MS_AUDIO_ENCODER_GET_PTIME. Consider to implement this method for better accuracy of rate control.",obj->encoder->desc->name); obj->cur_ptime=obj->min_ptime; } } if (action->type==MSRateControlActionDecreaseBitrate){ /*reducing bitrate of the codec isn't sufficient. Increasing ptime is much more efficient*/ if ((obj->encoder_caps & MS_AUDIO_ENCODER_CAP_AUTO_PTIME) || inc_ptime(obj)){ if (obj->nom_bitrate>0){ int cur_br=0; int new_br; /*if max ptime is reached, then try to reduce the codec bitrate if possible */ if (ms_filter_call_method(obj->encoder,MS_FILTER_GET_BITRATE,&cur_br)!=0){ ms_message("MSAudioBitrateDriver: GET_BITRATE failed"); return 0; } obj->cur_bitrate=cur_br; new_br=cur_br-((cur_br*action->value)/100); ms_message("MSAudioBitrateDriver: Attempting to reduce audio bitrate from %i to %i",cur_br,new_br); if (ms_filter_call_method(obj->encoder,MS_FILTER_SET_BITRATE,&new_br)!=0){ ms_message("MSAudioBitrateDriver: SET_BITRATE failed, incrementing ptime"); return inc_ptime(obj); } else { rtp_session_set_target_upload_bandwidth(obj->session, new_br); } new_br=0; ms_filter_call_method(obj->encoder,MS_FILTER_GET_BITRATE,&new_br); ms_message("MSAudioBitrateDriver: bitrate actually set to %i",new_br); obj->cur_bitrate=new_br; } } }else if (action->type==MSRateControlActionDecreasePacketRate){ return inc_ptime(obj); }else if (action->type==MSRateControlActionIncreaseQuality){ int ret=0; if (!(obj->encoder_caps & MS_AUDIO_ENCODER_CAP_AUTO_PTIME)){ if (obj->cur_ptime>obj->min_ptime){ ret=dec_ptime(obj); } } if (obj->nom_bitrate>0){ int cur_bitrate=0; if (ms_filter_call_method(obj->encoder,MS_FILTER_GET_BITRATE,&cur_bitrate)==0){ if (cur_bitrate > 0 && cur_bitrate<obj->nom_bitrate){ obj->cur_bitrate=(obj->cur_bitrate*140)/100; if (obj->cur_bitrate>= obj->nom_bitrate) { obj->cur_bitrate=obj->nom_bitrate; ret=-1;/*we reached the nominal value*/ } ms_message("MSAudioBitrateDriver: increasing bitrate of codec to %i",obj->cur_bitrate); if (ms_filter_call_method(obj->encoder,MS_FILTER_SET_BITRATE,&obj->cur_bitrate)!=0){ ms_message("MSAudioBitrateDriver: could not set codec bitrate to %i",obj->cur_bitrate); }else { rtp_session_set_target_upload_bandwidth(obj->session, obj->cur_bitrate); } } }else ms_warning("MSAudioBitrateDriver: MS_FILTER_GET_BITRATE failed."); } return ret; } return 0; }