Commit 373d61d1 authored by Simon Morlat's avatar Simon Morlat

integrate new rate control algorithm. Not yet functional, testing needed.

parent e3906d90
......@@ -28,11 +28,44 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
extern "C" {
#endif
struct _MediaStream;
typedef struct _MSBandwidthControllerStats{
float estimated_download_bandwidth; /*in bits/seconds*/
float controlled_stream_bandwidth;
bool_t in_congestion;
}MSBandwidthControllerStats;
struct _MSBandwidthController{
bctbx_list_t *streams; /*list of MediaStream objects*/
struct _MediaStream *controlled_stream; /*the most bandwidth consuming stream, which is the one flow controlled*/
MSBandwidthControllerStats stats;
};
/**
* Audio Bitrate controller object
* The MSBandwidthController is a object managing several streams (audio, video) and monitoring congestion of inbound streams.
* If a congestion is detected, it will send RTCP TMMBR packet to the remote sender in order to stop the congestion and adapt
* the incoming bitrate of received streams to the available bandwidth.
* It superseeds the MSBitrateController, MSQosAnalyzer, MSBitrateDriver objects, which were using different but less robust techniques
* to detect congestion and adapt bandwidth usage.
**/
typedef struct _MSBandwidthController MSBandwidthController;
MS2_PUBLIC MSBandwidthController *ms_bandwidth_controller_new(void);
MS2_PUBLIC void ms_bandwidth_controller_add_stream(MSBandwidthController *obj, struct _MediaStream *stream);
MS2_PUBLIC void ms_bandwidth_controller_remove_stream(MSBandwidthController *obj, struct _MediaStream *stream);
MS2_PUBLIC const MSBandwidthControllerStats * ms_bandwidth_controller_get_stats(MSBandwidthController *obj);
MS2_PUBLIC void ms_bandwidth_controller_destroy(MSBandwidthController *obj);
/**
* Audio Bitrate controller object.
* @deprecated
**/
typedef struct _MSAudioBitrateController MSAudioBitrateController;
enum _MSRateControlActionType{
......@@ -58,9 +91,10 @@ struct _MSBitrateDriverDesc{
void (*uninit)(MSBitrateDriver *obj);
};
/*
/**
* The MSBitrateDriver has the responsibility to execute rate control actions.
* This is an abstract interface.
* @deprecated
**/
struct _MSBitrateDriver{
MSBitrateDriverDesc *desc;
......@@ -98,6 +132,7 @@ MS2_PUBLIC MSQosAnalyzerAlgorithm ms_qos_analyzer_algorithm_from_string(const ch
* A MSQosAnalyzer is responsible to analyze RTCP feedback and suggest
* actions on bitrate or packet rate accordingly.
* This is an abstract interface.
* @deprecated
**/
struct _MSQosAnalyzer{
MSQosAnalyzerDesc *desc;
......
......@@ -132,7 +132,6 @@ struct _MediaStream {
bool_t is_beginning;
bool_t owns_sessions;
bool_t pad;
int dscp;
/**
* defines encoder target network bit rate, uses #media_stream_set_target_network_bitrate() setter.
* */
......@@ -140,6 +139,7 @@ struct _MediaStream {
media_stream_process_rtcp_callback_t process_rtcp;
OrtpEvDispatcher *evd;
MSFactory *factory;
MSBandwidthController *bandwidth_controller;
};
MS2_PUBLIC void media_stream_init(MediaStream *stream, MSFactory *factory, const MSMediaStreamSessions *sessions);
......
......@@ -173,6 +173,7 @@ set(VOIP_SOURCE_FILES_C
utils/stream_regulator.c
voip/audioconference.c
voip/audiostream.c
voip/bandwidthcontroller.c
voip/bitratecontrol.c
voip/bitratedriver.c
voip/ice.c
......
......@@ -114,6 +114,7 @@ libmediastreamer_voip_la_SOURCES+= voip/private.h \
voip/bitratedriver.c \
voip/qosanalyzer.c voip/qosanalyzer.h \
voip/bitratecontrol.c \
voip/bandwidthcontroller.c \
crypto/zrtp.c \
voip/stun.c \
crypto/ms_srtp.c \
......
......@@ -809,7 +809,6 @@ int audio_stream_start_from_io(AudioStream *stream, RtpProfile *profile, const c
stream->dtmfgen=NULL;
rtp_session_signal_connect(rtps,"telephone-event",(RtpCallback)on_dtmf_received,stream);
rtp_session_signal_connect(rtps,"payload_type_changed",(RtpCallback)audio_stream_payload_type_changed,stream);
rtp_session_set_dscp(rtps, stream->ms.dscp);
if (stream->ms.state==MSStreamPreparing){
/*we were using the dummy preload graph, destroy it but keep sound filters unless no soundcard is given*/
......
......@@ -48,6 +48,8 @@ ms_time(time_t *t) {
}
#endif
static void tmmbr_received(const OrtpEventData *evd, void *user_pointer);
static void disable_checksums(ortp_socket_t sock) {
#if defined(DISABLE_CHECKSUMS) && defined(SO_NO_CHECK)
......@@ -116,6 +118,11 @@ void media_stream_init(MediaStream *stream, MSFactory *factory, const MSMediaStr
if (sessions->dtls_context != NULL) {
ms_dtls_srtp_set_stream_sessions(sessions->dtls_context, &stream->sessions);
}
ortp_ev_dispatcher_connect(stream->evd
, ORTP_EVENT_RTCP_PACKET_RECEIVED
, RTCP_RTPFB
, (OrtpEvDispatcherCb)tmmbr_received
, stream);
}
RtpSession * ms_create_duplex_rtp_session(const char* local_ip, int loc_rtp_port, int loc_rtcp_port, int mtu) {
......@@ -182,6 +189,7 @@ void ms_media_stream_sessions_uninit(MSMediaStreamSessions *sessions){
}
void media_stream_free(MediaStream *stream) {
ortp_ev_dispatcher_disconnect(stream->evd, ORTP_EVENT_RTCP_PACKET_RECEIVED, RTCP_RTPFB, (OrtpEvDispatcherCb)tmmbr_received);
if (stream->sessions.zrtp_context != NULL) {
ms_zrtp_set_stream_sessions(stream->sessions.zrtp_context, NULL);
}
......@@ -221,10 +229,7 @@ void media_stream_get_local_rtp_stats(MediaStream *stream, rtp_stats_t *lstats)
int media_stream_set_dscp(MediaStream *stream, int dscp) {
ms_message("Setting DSCP to %i for %s stream.", dscp, media_stream_type_str(stream));
stream->dscp = dscp;
if ((stream->sessions.rtp_session != NULL) && (stream->sessions.rtp_session->rtp.gs.rem_addr.ss_family != AF_UNSPEC))
return rtp_session_set_dscp(stream->sessions.rtp_session, dscp);
return 0;
return rtp_session_set_dscp(stream->sessions.rtp_session, dscp);
}
void media_stream_enable_adaptive_bitrate_control(MediaStream *stream, bool_t enabled) {
......@@ -614,3 +619,36 @@ MSWebCamDesc *ms_mire_webcam_desc_get(void){
#endif
static void apply_bitrate_limit(MediaStream *obj, int br_limit){
if (!obj->encoder){
ms_warning("TMMNR not applicable because no encoder for this stream.");
return;
}
if (rtp_session_get_target_upload_bandwidth(obj->sessions.rtp_session) == br_limit) return;
if (ms_filter_call_method(obj->encoder,MS_FILTER_SET_BITRATE, &br_limit) != 0){
ms_warning("Failed to apply bitrate constraint to %s", obj->encoder->desc->name);
}
rtp_session_set_target_upload_bandwidth(obj->sessions.rtp_session, br_limit);
}
static void tmmbr_received(const OrtpEventData *evd, void *user_pointer) {
MediaStream *ms = (MediaStream *)user_pointer;
switch (rtcp_RTPFB_get_type(evd->packet)) {
case RTCP_RTPFB_TMMBR: {
int tmmbr_mxtbr = rtcp_RTPFB_tmmbr_get_max_bitrate(evd->packet);
ms_message("MediaStream[%p]: received a TMMBR for %i kbits/s"
, ms, (int)(tmmbr_mxtbr/1000));
apply_bitrate_limit(ms, tmmbr_mxtbr);
break;
}
default:
break;
}
}
......@@ -882,7 +882,6 @@ static int video_stream_start_with_source_and_output(VideoStream *stream, RtpPro
rtp_session_signal_connect(stream->ms.sessions.rtp_session,"payload_type_changed",
(RtpCallback)video_stream_payload_type_changed,&stream->ms);
rtp_session_set_dscp(rtps, stream->ms.dscp);
rtp_session_get_jitter_buffer_params(stream->ms.sessions.rtp_session,&jbp);
jbp.max_packets=1000;//needed for high resolution video
......
......@@ -426,7 +426,7 @@ static void chaotic_start_basic(void) {
pcap_tester_audio("./scenarios/opus-poor-quality.pcapng", OrtpJitterBufferBasic, -1
, payload_type_opus.clock_rate, OPUS_PAYLOAD_TYPE);
BC_ASSERT_GREATER((int)final_audio_rtp_stats.outoftime, 200, int, "%i");
BC_ASSERT_LOWER((int)final_audio_rtp_stats.outoftime, 240, int, "%i");
BC_ASSERT_LOWER((int)final_audio_rtp_stats.outoftime, 250, int, "%i");
BC_ASSERT_EQUAL((int)final_audio_rtp_stats.discarded, 0, int, "%i");
BC_ASSERT_EQUAL((int)final_audio_rtp_stats.packet_recv, 4228, int, "%i");
}
......
......@@ -81,6 +81,12 @@ extern void libmswebrtc_init();
static int cond=1;
typedef enum _RcAlgo{
RCAlgoNone,
RCAlgoSimple,
RCAlgoAdvanced,
RCAlgoInvalid
}RcAlgo;
typedef struct _MediastreamIceCandidate {
char ip[64];
......@@ -98,6 +104,7 @@ typedef struct _MediastreamDatas {
int bitrate;
int mtu;
MSVideoSize vs;
RcAlgo rc_algo;
bool_t ec;
bool_t agc;
bool_t eq;
......@@ -112,15 +119,13 @@ typedef struct _MediastreamDatas {
bool_t use_ng;
bool_t two_windows;
bool_t el;
bool_t use_rc;
bool_t enable_srtp;
bool_t interactive;
bool_t enable_avpf;
bool_t enable_rtcp;
bool_t freeze_on_error;
bool_t pad[3];
float el_speed;
float el_thres;
float el_force;
......@@ -144,6 +149,7 @@ typedef struct _MediastreamDatas {
RtpSession *session;
OrtpEvQueue *q;
RtpProfile *profile;
MSBandwidthController *bw_controller;
IceSession *ice_session;
MediastreamIceCandidate ice_local_candidates[MEDIASTREAM_MAX_ICE_CANDIDATES];
......@@ -176,6 +182,7 @@ static void display_items(void *user_data, uint32_t csrc, rtcp_sdes_type_t t, co
static void parse_rtcp(mblk_t *m);
static void parse_events(RtpSession *session, OrtpEvQueue *q);
static bool_t parse_window_ids(const char *ids, int* video_id, int* preview_id);
static RcAlgo parse_rc_algo(const char *algo);
const char *usage="mediastream --local <port>\n"
"--remote <ip:port> \n"
......@@ -220,7 +227,7 @@ const char *usage="mediastream --local <port>\n"
"[ --no-rtcp ]\n"
"[ --outfile <output wav file> specify a wav file to write audio into, instead of soundcard ]\n"
"[ --playback-card <name> ]\n"
"[ --rc (enable adaptive rate control) ]\n"
"[ --rc <rate control algorithm> possible values are: none, simple, advanced ]\n"
"[ --srtp <local master_key> <remote master_key> (enable srtp, master key is generated if absent from comand line) ]\n"
"[ --verbose (most verbose messages) ]\n"
"[ --video-display-filter <name> ]\n"
......@@ -304,6 +311,7 @@ MediastreamDatas* init_default_args(void) {
args->interactive=FALSE;
args->is_verbose=FALSE;
args->device_rotation=-1;
args->rc_algo = RCAlgoNone;
#ifdef VIDEO_ENABLED
args->video=NULL;
......@@ -322,7 +330,6 @@ MediastreamDatas* init_default_args(void) {
args->el_sustain=-1;
args->el_transmit_thres=-1;
args->ng_floorgain=-1;
args->use_rc=FALSE;
args->zrtp_secrets=NULL;
args->custom_pt=NULL;
args->video_window_id = -1;
......@@ -460,7 +467,12 @@ bool_t parse_args(int argc, char** argv, MediastreamDatas* out) {
}else if (strcmp(argv[i],"--ng")==0){
out->use_ng=1;
}else if (strcmp(argv[i],"--rc")==0){
out->use_rc=1;
i++;
out->rc_algo = parse_rc_algo(argv[i]);
if (out->rc_algo == RCAlgoInvalid){
ms_error("Invalid argument for --rc");
return FALSE;
}
}else if (strcmp(argv[i],"--ng-threshold")==0){
i++;
out->ng_threshold=(float)atof(argv[i]);
......@@ -737,6 +749,10 @@ void setup_media_streams(MediastreamDatas* args) {
#endif
args->profile=rtp_profile_clone_full(&av_profile);
args->q=ortp_ev_queue_new();
if (args->rc_algo == RCAlgoAdvanced){
args->bw_controller = ms_bandwidth_controller_new();
}
if (args->mtu) ms_factory_set_mtu(factory, args->mtu);
ms_factory_enable_statistics(factory, TRUE);
......@@ -802,11 +818,14 @@ void setup_media_streams(MediastreamDatas* args) {
MSSndCard *play= args->playback_card==NULL ? ms_snd_card_manager_get_default_capture_card(manager) :
get_sound_card(manager,args->playback_card);
args->audio=audio_stream_new(factory, args->localport,args->localport+1,ms_is_ipv6(args->ip));
if (args->bw_controller){
ms_bandwidth_controller_add_stream(args->bw_controller, (MediaStream*)args->audio);
}
audio_stream_enable_automatic_gain_control(args->audio,args->agc);
audio_stream_enable_noise_gate(args->audio,args->use_ng);
audio_stream_set_echo_canceller_params(args->audio,args->ec_len_ms,args->ec_delay_ms,args->ec_framesize);
audio_stream_enable_echo_limiter(args->audio,args->el);
audio_stream_enable_adaptive_bitrate_control(args->audio,args->use_rc);
audio_stream_enable_adaptive_bitrate_control(args->audio,args->rc_algo == RCAlgoSimple);
if (capt)
ms_snd_card_set_preferred_sample_rate(capt,rtp_profile_get_payload(args->profile, args->payload)->clock_rate);
if (play)
......@@ -910,6 +929,9 @@ void setup_media_streams(MediastreamDatas* args) {
}
ms_message("Starting video stream.\n");
args->video=video_stream_new(factory, args->localport, args->localport+1, ms_is_ipv6(args->ip));
if (args->bw_controller){
ms_bandwidth_controller_add_stream(args->bw_controller, (MediaStream*)args->video);
}
if (args->video_display_filter)
video_stream_set_display_filter_name(args->video, args->video_display_filter);
......@@ -929,7 +951,7 @@ void setup_media_streams(MediastreamDatas* args) {
#endif
video_stream_set_event_callback(args->video,video_stream_event_cb, args);
video_stream_set_freeze_on_error(args->video,args->freeze_on_error);
video_stream_enable_adaptive_bitrate_control(args->video,args->use_rc);
video_stream_enable_adaptive_bitrate_control(args->video, args->rc_algo == RCAlgoSimple);
if (args->camera)
cam=ms_web_cam_manager_get_cam(ms_factory_get_web_cam_manager(factory),args->camera);
if (cam==NULL)
......@@ -1107,7 +1129,11 @@ void mediastream_run_loop(MediastreamDatas* args) {
void clear_mediastreams(MediastreamDatas* args) {
ms_message("stopping all...\n");
ms_message("Average quality indicator: %f",args->audio ? audio_stream_get_average_quality_rating(args->audio) : -1);
if (args->bw_controller){
ms_bandwidth_controller_destroy(args->bw_controller);
}
if (args->audio) {
audio_stream_stop(args->audio);
}
......@@ -1363,3 +1389,11 @@ static bool_t parse_window_ids(const char *ids, int* video_id, int* preview_id)
free(copy);
return TRUE;
}
static RcAlgo parse_rc_algo(const char *algo){
if (algo == NULL) return RCAlgoInvalid;
if (strcasecmp(algo,"simple")==0) return RCAlgoSimple;
if (strcasecmp(algo, "advanced")==0) return RCAlgoAdvanced;
if (strcasecmp(algo, "none")==0) return RCAlgoNone;
return RCAlgoInvalid;
}
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