Commit e643594a authored by Simon Morlat's avatar Simon Morlat

new rate control: everything compiles

parent f37f0e86
......@@ -34,15 +34,19 @@ extern "C" {
typedef struct _MSAudioBitrateController MSAudioBitrateController;
enum MSRateControlActionType{
enum _MSRateControlActionType{
MSRateControlActionDoNothing,
MSRateControlActionDecreaseBitrate,
MSRateControlActionDecreasePacketRate,
MSRateControlActionIncreaseQuality
};
typedef enum _MSRateControlActionType MSRateControlActionType;
const char *ms_rate_control_action_type_name(MSRateControlActionType t);
typedef struct _MSRateControlAction{
enum MSRateControlActionType type;
MSRateControlActionType type;
int value;
}MSRateControlAction;
......@@ -50,7 +54,7 @@ typedef struct _MSBitrateDriver MSBitrateDriver;
typedef struct _MSBitrateDriverDesc MSBitrateDriverDesc;
struct _MSBitrateDriverDesc{
void (*execute_action)(MSBitrateDriver *obj, const MSRateControlAction *action);
int (*execute_action)(MSBitrateDriver *obj, const MSRateControlAction *action);
void (*uninit)(MSBitrateDriver *obj);
};
......@@ -60,20 +64,24 @@ struct _MSBitrateDriverDesc{
**/
struct _MSBitrateDriver{
MSBitrateDriverDesc *desc;
int refcnt;
};
void ms_bitrate_driver_execute_action(MSBitrateDriver *obj, const MSRateControlAction *action);
void ms_bitrate_driver_destroy(MSBitrateDriver *obj);
int ms_bitrate_driver_execute_action(MSBitrateDriver *obj, const MSRateControlAction *action);
MSBitrateDriver * ms_bitrate_driver_ref(MSBitrateDriver *obj);
void ms_bitrate_driver_unref(MSBitrateDriver *obj);
MSBitrateDriver *ms_audio_bitrate_driver_new(MSFilter *encoder);
typedef struct _MSQosAnalyser MSQosAnalyser;
typedef struct _MSQosAnalyserDesc MSQosAnalyserDesc;
struct _MSQosAnalyserDesc{
bool_t (*process_rtcp)(MSQosAnalyzer *obj, mblk_t *rtcp);
void (*suggest_action)(MSQosAnalyzer *obj, MSRateControlAction *action);
bool_t (*has_improved)(MSQosAnalyzer *obj);
void uninit(MSQosAnalyzer);
bool_t (*process_rtcp)(MSQosAnalyser *obj, mblk_t *rtcp);
void (*suggest_action)(MSQosAnalyser *obj, MSRateControlAction *action);
bool_t (*has_improved)(MSQosAnalyser *obj);
void (*uninit)(MSQosAnalyser *);
};
/**
......@@ -82,21 +90,66 @@ struct _MSQosAnalyserDesc{
**/
struct _MSQosAnalyser{
MSQosAnalyserDesc *desc;
int refcnt;
};
MSQosAnalyser * ms_qos_analyser_ref(MSQosAnalyser *obj);
void ms_qos_analyser_unref(MSQosAnalyser *obj);
void ms_qos_analyser_suggest_action(MSQosAnalyser *obj, MSRateControlAction *action);
bool_t ms_qos_analyser_has_improved(MSQosAnalyser *obj);
bool_t ms_qos_analyser_process_rtcp(MSQosAnalyser *obj, mblk_t *rtcp);
/**
* The simple qos analyzer is an implementation of MSQosAnalizer that performs analysis for single stream.
**/
MSQosAnalyzer * ms_simple_qos_analyser_new(RtpSession *session);
MSQosAnalyser * ms_simple_qos_analyser_new(RtpSession *session);
/**
* The MSBitrateController the overall behavior and state machine of the adaptive rate control system.
* It requires a MSQosAnalyser to obtain analyse of the quality of service, and a MSBitrateDriver
* to run the actions on media streams, like decreasing or increasing bitrate.
**/
typedef struct _MSBitrateController MSBitrateController;
/**
* Instanciates MSBitrateController
* @param qosanalyser a Qos analyser object
* @param driver a bitrate driver object.
* The newly created bitrate controller owns references to the analyser and the driver.
**/
MSBitrateController *ms_bitrate_controller_new(MSQosAnalyser *qosanalyser, MSBitrateDriver *driver);
#define MS_AUDIO_RATE_CONTROL_OPTIMIZE_QUALITY (1)
#define MS_AUDIO_RATE_CONTROL_OPTIMIZE_LATENCY (1<<1)
/**
* Asks the bitrate controller to process a newly received RTCP packet.
* @param MSBitrateController the bitrate controller object.
* @param rtcp an RTCP packet received for the media session(s) being managed by the controller.
* If the RTCP packet contains useful feedback regarding quality of the media streams received by the far end,
* then the bitrate controller may take decision and execute actions on the local media streams to adapt the
* output bitrate.
**/
void ms_bitrate_controller_process_rtcp(MSBitrateController *obj, mblk_t *rtcp);
MSAudioBitrateController *ms_audio_bitrate_controller_new(RtpSession *session, MSFilter *encoder, unsigned int flags);
/**
* Destroys the bitrate controller
*
* If no other entity holds references to the underlyings MSQosAnalyser and MSBitrateDriver object,
* then they will be destroyed too.
**/
void ms_bitrate_controller_destroy(MSBitrateController *obj);
void ms_audio_bitrate_controller_process_rtcp(MSAudioBitrateController *obj, mblk_t *rtcp);
void ms_audio_bitrate_controller_destroy(MSAudioBitrateController *obj);
/**
* Convenience function to create a bitrate controller managing a single audio stream.
* @param session the RtpSession object for the media stream
* @param encoder the MSFilter object responsible for encoding the audio data.
* @param flags unused.
* This function actually calls internally:
* <br>
* \code
* ms_bitrate_controller_new(ms_simple_qos_analyser_new(session),ms_audio_bitrate_driver_new(encoder));
* \endcode
**/
MSBitrateController *ms_audio_bitrate_controller_new(RtpSession *session, MSFilter *encoder, unsigned int flags);
#ifdef __cplusplus
......
......@@ -64,7 +64,7 @@ struct _AudioStream
time_t last_packet_time;
EchoLimiterType el_type; /*use echo limiter: two MSVolume, measured input level controlling local output level*/
OrtpEvQueue *evq;
MSAudioBitrateController *rc;
MSBitrateController *rc;
MSQualityIndicator *qi;
time_t start_time;
bool_t play_dtmfs;
......
......@@ -60,6 +60,7 @@ libmediastreamer_la_SOURCES= mscommon.c $(GITVERSION_FILE) \
l16.c \
audioconference.c \
bitratedriver.c \
qosanalyzer.c \
bitratecontrol.c
#dummy c++ file to force libtool to use c++ linking (because of msdscap-mingw.cc)
......
......@@ -70,7 +70,7 @@ void audio_stream_free(AudioStream *stream)
if (stream->read_resampler!=NULL) ms_filter_destroy(stream->read_resampler);
if (stream->write_resampler!=NULL) ms_filter_destroy(stream->write_resampler);
if (stream->dtmfgen_rtp!=NULL) ms_filter_destroy(stream->dtmfgen_rtp);
if (stream->rc) ms_audio_bitrate_controller_destroy(stream->rc);
if (stream->rc) ms_bitrate_controller_destroy(stream->rc);
if (stream->qi) ms_quality_indicator_destroy(stream->qi);
ms_free(stream);
}
......@@ -176,7 +176,7 @@ static void audio_stream_process_rtcp(AudioStream *stream, mblk_t *m){
flost=(float)(100.0*report_block_get_fraction_lost(rb)/256.0);
ms_message("audio_stream_process_rtcp: interarrival jitter=%u , "
"lost packets percentage since last report=%f, round trip time=%f seconds",ij,flost,rt);
if (stream->rc) ms_audio_bitrate_controller_process_rtcp(stream->rc,m);
if (stream->rc) ms_bitrate_controller_process_rtcp(stream->rc,m);
if (stream->qi) ms_quality_indicator_update_from_feedback(stream->qi,m);
}
}while(rtcp_next_packet(m));
......
......@@ -40,35 +40,38 @@ const char *state_name(enum state_t st){
return "bad state";
}
struct _MSAudioBitrateController{
QosAnalyser analyzer;
RtpSession *session;
MSFilter *encoder;
struct _MSBitrateController{
MSQosAnalyser *analyser;
MSBitrateDriver *driver;
enum state_t state;
int stable_count;
int probing_up_count;
};
MSAudioBitrateController *ms_audio_bitrate_controller_new(RtpSession *session, MSFilter *encoder, unsigned int flags){
MSAudioBitrateController *rc=ms_new0(MSAudioBitrateController,1);
ms_qos_analyser_init(&rc->analyser,session);
return rc;
MSBitrateController *ms_bitrate_controller_new(MSQosAnalyser *qosanalyser, MSBitrateDriver *driver){
MSBitrateController *obj=ms_new0(MSBitrateController,1);
obj->analyser=ms_qos_analyser_ref(qosanalyser);
obj->driver=ms_bitrate_driver_ref(driver);
return obj;
}
static int execute_action(MSBitrateController *obj, const MSRateControlAction *action){
return ms_bitrate_driver_execute_action(obj->driver,action);
}
static void state_machine(MSAudioBitrateController *obj){
action_t action;
static void state_machine(MSBitrateController *obj){
MSRateControlAction action;
switch(obj->state){
case Stable:
obj->stable_count++;
case Init:
ms_qos_analyser_suggest_action(&obj->analyser,&action);
if (action.type!=DoNothing){
ms_qos_analyser_suggest_action(obj->analyser,&action);
if (action.type!=MSRateControlActionDoNothing){
execute_action(obj,&action);
obj->state=Probing;
}else if (obj->stable_count>=5){
action.type=IncreaseQuality;
action.type=MSRateControlActionIncreaseQuality;
execute_action(obj,&action);
obj->state=ProbingUp;
obj->probing_up_count=0;
......@@ -76,11 +79,11 @@ static void state_machine(MSAudioBitrateController *obj){
break;
case Probing:
obj->stable_count=0;
if (has_improved(obj)){
if (ms_qos_analyser_has_improved(obj->analyser)){
obj->state=Stable;
}else{
ms_qos_analyser_suggest_action(&obj->analyser,&action);
if (action.type!=DoNothing){
ms_qos_analyser_suggest_action(obj->analyser,&action);
if (action.type!=MSRateControlActionDoNothing){
execute_action(obj,&action);
}
}
......@@ -88,14 +91,14 @@ static void state_machine(MSAudioBitrateController *obj){
case ProbingUp:
obj->stable_count=0;
obj->probing_up_count++;
ms_qos_analyser_suggest_action(&obj->analyser,&action);
if (action.type!=DoNothing){
ms_qos_analyser_suggest_action(obj->analyser,&action);
if (action.type!=MSRateControlActionDoNothing){
execute_action(obj,&action);
obj->state=Probing;
}else{
/*continue with slow ramp up*/
if (obj->probing_up_count==2){
action.type=IncreaseQuality;
action.type=MSRateControlActionIncreaseQuality;
if (execute_action(obj,&action)==-1){
/* we reached the maximum*/
obj->state=Init;
......@@ -107,19 +110,26 @@ static void state_machine(MSAudioBitrateController *obj){
default:
break;
}
ms_message("AudioBitrateController: current state is %s",state_name(obj->state));
ms_message("MSBitrateController: current state is %s",state_name(obj->state));
}
void ms_audio_bitrate_controller_process_rtcp(MSAudioBitrateController *obj, mblk_t *rtcp){
if (ms_qos_analyser_process_rtcp(&obj->analyser,rtcp)){
void ms_bitrate_controller_process_rtcp(MSBitrateController *obj, mblk_t *rtcp){
if (ms_qos_analyser_process_rtcp(obj->analyser,rtcp)){
state_machine(obj);
}
}
void ms_audio_bitrate_controller_destroy(MSAudioBitrateController *obj){
void ms_bitrate_controller_destroy(MSBitrateController *obj){
ms_qos_analyser_unref(obj->analyser);
ms_bitrate_driver_unref(obj->driver);
ms_free(obj);
}
MSBitrateController *ms_audio_bitrate_controller_new(RtpSession *session, MSFilter *encoder, unsigned int flags){
return ms_bitrate_controller_new(
ms_simple_qos_analyser_new(session),
ms_audio_bitrate_driver_new(encoder));
}
......@@ -22,16 +22,27 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "mediastreamer2/bitratecontrol.h"
void ms_bitrate_driver_execute_action(MSBitrateDriver *obj, const MSRateControlAction *action){
static const int max_ptime=100;
int ms_bitrate_driver_execute_action(MSBitrateDriver *obj, const MSRateControlAction *action){
if (obj->desc->execute_action)
obj->desc->execute_action(obj,action);
return obj->desc->execute_action(obj,action);
else ms_error("Driver does not implement execute_action");
return -1;
}
MSBitrateDriver * ms_bitrate_driver_ref(MSBitrateDriver *obj){
obj->refcnt++;
return obj;
}
void ms_bitrate_driver_destroy(MSBitrateDriver *obj){
if (obj->desc->uninit)
obj->desc->uninit(obj);
ms_free(obj);
void ms_bitrate_driver_unref(MSBitrateDriver *obj){
obj->refcnt--;
if (obj->refcnt<=0){
if (obj->desc->uninit)
obj->desc->uninit(obj);
ms_free(obj);
}
}
struct _MSAudioBitrateDriver{
......@@ -63,9 +74,9 @@ static int inc_ptime(MSAudioBitrateDriver *obj){
return 0;
}
static int audio_bitrate_driver_execute_action(MSBitrateDriver *objbase, MSRateControlAction *action){
MSAudioBitrateDriver *obj=(MSBitrateDriver*)objbase;
ms_message("MSAudioBitrateDriver: executing action of type %s, value=%i",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){
......@@ -128,8 +139,9 @@ static MSBitrateDriverDesc audio_bitrate_driver={
MSBitrateDriver *ms_audio_bitrate_driver_new(MSFilter *encoder){
MSAudioBitrateDriver *obj=ms_new0(MSAudioBitrateDriver,1);
obj->parent.desc=&audio_bitrate_driver;
obj->encoder=encoder;
obj->cur_ptime=obj->min_ptime=20;
obj->cur_bitrate=obj->nom_bitrate=0;
return obj;
return (MSBitrateDriver*)obj;
}
......@@ -26,7 +26,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
* Analyses a received RTCP packet.
* Returns TRUE is relevant information has been found in the rtcp message, FALSE otherwise.
**/
bool_t ms_qos_analyzer_process_rtcp(MSQosAnalyzer *obj,mblk_t *msg){
bool_t ms_qos_analyser_process_rtcp(MSQosAnalyser *obj,mblk_t *msg){
if (obj->desc->process_rtcp){
return obj->desc->process_rtcp(obj,msg);
}
......@@ -34,25 +34,33 @@ bool_t ms_qos_analyzer_process_rtcp(MSQosAnalyzer *obj,mblk_t *msg){
return FALSE;
}
void ms_qos_analyser_suggest_action(MSQosAnalyzer *obj, MSRateControlActionType *action){
void ms_qos_analyser_suggest_action(MSQosAnalyser *obj, MSRateControlAction *action){
if (obj->desc->suggest_action){
obj->desc->suggest_action(obj,action);
}
return;
}
bool_t ms_qos_analyzer_has_improved(MSQosAnalyzer *obj){
bool_t ms_qos_analyser_has_improved(MSQosAnalyser *obj){
if (obj->desc->has_improved){
return obj->desc->has_improved(obj,action);
return obj->desc->has_improved(obj);
}
ms_error("Unimplemented has_improved() call.");
return TRUE;
}
void ms_qos_analyzer_destroy(MSQosAnalyzer *obj){
if (obj->desc->uninit)
obj->desc->uninit(obj);
ms_free(obj);
MSQosAnalyser *ms_qos_analyser_ref(MSQosAnalyser *obj){
obj->refcnt++;
return obj;
}
void ms_qos_analyser_unref(MSQosAnalyser *obj){
obj->refcnt--;
if (obj->refcnt<=0){
if (obj->desc->uninit)
obj->desc->uninit(obj);
ms_free(obj);
}
}
#define STATS_HISTORY 3
......@@ -60,7 +68,6 @@ void ms_qos_analyzer_destroy(MSQosAnalyzer *obj){
static const float unacceptable_loss_rate=20;
static const int big_jitter=20; /*ms */
static const float significant_delay=0.2; /*seconds*/
static const int max_ptime=100;
typedef struct rtpstats{
......@@ -71,7 +78,7 @@ typedef struct rtpstats{
}rtpstats_t;
static const char *action_type_name(enum MSRateControlActionType t){
const char *ms_rate_control_action_type_name(MSRateControlActionType t){
switch(t){
case MSRateControlActionDoNothing:
return "DoNothing";
......@@ -87,14 +94,14 @@ static const char *action_type_name(enum MSRateControlActionType t){
typedef struct _MSSimpleQosAnalyser{
MSQosAnalyzer parent;
MSQosAnalyser parent;
RtpSession *session;
int clockrate;
rtpstats_t stats[STATS_HISTORY];
int curindex;
bool_t rt_prop_doubled;
bool_t pad[3];
}MSQosAnalyser;
}MSSimpleQosAnalyser;
......@@ -109,7 +116,7 @@ static bool_t rt_prop_doubled(rtpstats_t *cur,rtpstats_t *prev){
return FALSE;
}
static bool_t rt_prop_increased(MSSimpleQosAnalyzer *obj){
static bool_t rt_prop_increased(MSSimpleQosAnalyser *obj){
rtpstats_t *cur=&obj->stats[obj->curindex % STATS_HISTORY];
rtpstats_t *prev=&obj->stats[(STATS_HISTORY+obj->curindex-1) % STATS_HISTORY];
......@@ -122,7 +129,7 @@ static bool_t rt_prop_increased(MSSimpleQosAnalyzer *obj){
static bool_t simple_analyser_process_rtcp(MSQosAnalyser *objbase, mblk_t *rtcp){
MSSimpleQosAnalyzer *obj=(MSSimpleQosAnalyzer*)objbase;
MSSimpleQosAnalyser *obj=(MSSimpleQosAnalyser*)objbase;
rtpstats_t *cur;
const report_block_t *rb=NULL;
if (rtcp_is_SR(rtcp)){
......@@ -130,7 +137,7 @@ static bool_t simple_analyser_process_rtcp(MSQosAnalyser *objbase, mblk_t *rtcp)
}else if (rtcp_is_RR(rtcp)){
rb=rtcp_RR_get_report_block(rtcp,0);
}
if (rb){
if (rb && report_block_get_ssrc(rb)==rtp_session_get_send_ssrc(obj->session)){
obj->curindex++;
cur=&obj->stats[obj->curindex % STATS_HISTORY];
......@@ -150,8 +157,8 @@ static bool_t simple_analyser_process_rtcp(MSQosAnalyser *objbase, mblk_t *rtcp)
return rb!=NULL;
}
static void simple_analyser_suggest_action(MSQosAnalyser *objbase, MSRateControlActionType *action){
MSSimpleQosAnalyzer *obj=(MSSimpleQosAnalyzer*)objbase;
static void simple_analyser_suggest_action(MSQosAnalyser *objbase, MSRateControlAction *action){
MSSimpleQosAnalyser *obj=(MSSimpleQosAnalyser*)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){
......@@ -173,7 +180,7 @@ static void simple_analyser_suggest_action(MSQosAnalyser *objbase, MSRateControl
}
static bool_t simple_analyser_has_improved(MSQosAnalyser *objbase){
MSSimpleQosAnalyzer *obj=(MSSimpleQosAnalyzer*)objbase;
MSSimpleQosAnalyser *obj=(MSSimpleQosAnalyser*)objbase;
rtpstats_t *cur=&obj->stats[obj->curindex % STATS_HISTORY];
rtpstats_t *prev=&obj->stats[(STATS_HISTORY+obj->curindex-1) % STATS_HISTORY];
......@@ -194,16 +201,16 @@ end:
return FALSE;
}
static MSQosAnalyzerDesc simple_analyzer_desc={
static MSQosAnalyserDesc simple_analyser_desc={
simple_analyser_process_rtcp,
simple_analyser_suggest_action,
simple_analyzer_has_improved
simple_analyser_has_improved
};
MSQosAnalyzer * ms_simple_qos_analyser_new(RtpSession *session){
MSSimpleQosAnalyzer *obj=ms_new0(MSSimpleQosAnalyzer,1);
MSQosAnalyser * ms_simple_qos_analyser_new(RtpSession *session){
MSSimpleQosAnalyser *obj=ms_new0(MSSimpleQosAnalyser,1);
obj->session=session;
obj->parent.desc=&simple_analyzer_desc;
return (MSQosAnalyzer*)obj;
obj->parent.desc=&simple_analyser_desc;
return (MSQosAnalyser*)obj;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment