diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 610815802..6f886d336 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -597,7 +597,7 @@ int sal_call_set_local_media_description(SalOp *op, SalMediaDescription *desc){ static belle_sip_header_allow_t *create_allow(){ belle_sip_header_allow_t* header_allow; - header_allow = belle_sip_header_allow_create("INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO, UPDATE"); + header_allow = belle_sip_header_allow_create("INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO"); return header_allow; } diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 70fe1656a..bb0e8c619 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1693,17 +1693,65 @@ static void post_configure_audio_streams(LinphoneCall*call){ linphone_call_start_recording(call); } -static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *md, const SalStreamDescription *desc, int *used_pt){ +static int get_ideal_audio_bw(LinphoneCall *call, const SalMediaDescription *md, const SalStreamDescription *desc){ + int remote_bw=0; + int upload_bw; + int total_upload_bw=linphone_core_get_upload_bandwidth(call->core); + const LinphoneCallParams *params=&call->params; + bool_t will_use_video=linphone_core_media_description_contains_video_stream(md); + bool_t forced=FALSE; + + if (desc->bandwidth>0) remote_bw=desc->bandwidth; + else if (md->bandwidth>0) { + /*case where b=AS is given globally, not per stream*/ + remote_bw=md->bandwidth; + } + if (params->up_bw>0){ + forced=TRUE; + upload_bw=params->up_bw; + }else upload_bw=total_upload_bw; + upload_bw=get_min_bandwidth(upload_bw,remote_bw); + if (!will_use_video || forced) return upload_bw; + + if (bandwidth_is_greater(upload_bw,512)){ + upload_bw=100; + }else if (bandwidth_is_greater(upload_bw,256)){ + upload_bw=64; + }else if (bandwidth_is_greater(upload_bw,128)){ + upload_bw=40; + }else if (bandwidth_is_greater(upload_bw,0)){ + upload_bw=24; + } + return upload_bw; +} + +static int get_video_bw(LinphoneCall *call, const SalMediaDescription *md, const SalStreamDescription *desc){ + int remote_bw=0; int bw; + if (desc->bandwidth>0) remote_bw=desc->bandwidth; + else if (md->bandwidth>0) { + /*case where b=AS is given globally, not per stream*/ + remote_bw=get_remaining_bandwidth_for_video(md->bandwidth,call->audio_bw); + } + bw=get_min_bandwidth(get_remaining_bandwidth_for_video(linphone_core_get_upload_bandwidth(call->core),call->audio_bw),remote_bw); + return bw; +} + +static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *md, const SalStreamDescription *desc, int *used_pt){ + int bw=0; const MSList *elem; RtpProfile *prof=rtp_profile_new("Call profile"); bool_t first=TRUE; - int remote_bw=0; LinphoneCore *lc=call->core; int up_ptime=0; const LinphoneCallParams *params=&call->params; + *used_pt=-1; - + if (desc->type==SalAudio) + bw=get_ideal_audio_bw(call,md,desc); + else if (desc->type==SalVideo) + bw=get_video_bw(call,md,desc); + for(elem=desc->payloads;elem!=NULL;elem=elem->next){ PayloadType *pt=(PayloadType*)elem->data; int number; @@ -1712,8 +1760,11 @@ static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *m pt=payload_type_clone(pt); if ((pt->flags & PAYLOAD_TYPE_FLAG_CAN_SEND) && first) { + /*first codec in list is the selected one*/ if (desc->type==SalAudio){ - linphone_core_update_allocated_audio_bandwidth_in_call(call,pt); + /*this will update call->audio_bw*/ + linphone_core_update_allocated_audio_bandwidth_in_call(call,pt,bw); + bw=call->audio_bw; if (params->up_ptime) up_ptime=params->up_ptime; else up_ptime=linphone_core_get_upload_ptime(lc); @@ -1721,27 +1772,9 @@ static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *m *used_pt=payload_type_get_number(pt); first=FALSE; } - if (desc->bandwidth>0) remote_bw=desc->bandwidth; - else if (md->bandwidth>0) { - /*case where b=AS is given globally, not per stream*/ - remote_bw=md->bandwidth; - if (desc->type==SalVideo){ - remote_bw=get_video_bandwidth(remote_bw,call->audio_bw); - } - } - - if (desc->type==SalAudio){ - int audio_bw=call->audio_bw; - if (params->up_bw){ - if (params->up_bw< audio_bw) - audio_bw=params->up_bw; - } - bw=get_min_bandwidth(audio_bw,remote_bw); - }else bw=get_min_bandwidth(get_video_bandwidth(linphone_core_get_upload_bandwidth (lc),call->audio_bw),remote_bw); - if (bw>0) pt->normal_bitrate=bw*1000; - else if (desc->type==SalAudio){ - pt->normal_bitrate=-1; - } + if (pt->flags & PAYLOAD_TYPE_BITRATE_OVERRIDE){ + pt->normal_bitrate=get_min_bandwidth(pt->normal_bitrate,bw*1000); + } else pt->normal_bitrate=bw*1000; if (desc->ptime>0){ up_ptime=desc->ptime; } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 7194bbf2c..fc02cbb23 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -1580,6 +1580,33 @@ LINPHONE_PUBLIC int linphone_core_set_video_codecs(LinphoneCore *lc, MSList *cod */ LINPHONE_PUBLIC bool_t linphone_core_payload_type_enabled(LinphoneCore *lc, const PayloadType *pt); +/** + * Tells whether the specified payload type represents a variable bitrate codec. + * @param[in] lc #LinphoneCore object. + * @param[in] pt The #PayloadType we want to know + * @returns TRUE if the payload type represents a VBR codec, FALSE if disabled. + * @ingroup media_parameters + */ +LINPHONE_PUBLIC bool_t linphone_core_payload_type_is_vbr(LinphoneCore *lc, const PayloadType *pt); + +/** + * Set an explicit bitrate (IP bitrate, not codec bitrate) for a given codec, in kbit/s. + * @param[in] lc the #LinphoneCore object + * @param[in] pt the #PayloadType to modify. + * @param[in] bitrate the IP bitrate in kbit/s. + * @ingroup media_parameters +**/ +LINPHONE_PUBLIC void linphone_core_set_payload_type_bitrate(LinphoneCore *lc, PayloadType *pt, int bitrate); + +/** + * Get the bitrate explicitely set with linphone_core_set_payload_type_bitrate(). + * @param[in] lc the #LinphoneCore object + * @param[in] pt the #PayloadType to modify. + * @return bitrate the IP bitrate in kbit/s, or -1 if an error occured. + * @ingroup media_parameters +**/ +LINPHONE_PUBLIC int linphone_core_get_payload_type_bitrate(LinphoneCore *lc, const PayloadType *pt); + /** * Enable or disable the use of the specified payload type. * @param[in] lc #LinphoneCore object. @@ -1616,7 +1643,7 @@ LINPHONE_PUBLIC int linphone_core_get_payload_type_number(LinphoneCore *lc, cons LINPHONE_PUBLIC const char *linphone_core_get_payload_type_description(LinphoneCore *lc, PayloadType *pt); -LINPHONE_PUBLIC bool_t linphone_core_check_payload_type_usability(LinphoneCore *lc, PayloadType *pt); +LINPHONE_PUBLIC bool_t linphone_core_check_payload_type_usability(LinphoneCore *lc, const PayloadType *pt); /** * Create a proxy config with default values from Linphone core. diff --git a/coreapi/misc.c b/coreapi/misc.c index fed8191b4..f46ec403b 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -77,6 +77,11 @@ bool_t linphone_core_payload_type_enabled(LinphoneCore *lc, const PayloadType *p return FALSE; } +bool_t linphone_core_payload_type_is_vbr(LinphoneCore *lc, const PayloadType *pt){ + if (pt->type==PAYLOAD_VIDEO) return TRUE; + return !!(pt->flags & PAYLOAD_TYPE_IS_VBR); +} + int linphone_core_enable_payload_type(LinphoneCore *lc, PayloadType *pt, bool_t enabled){ if (ms_list_find(lc->codecs_conf.audio_codecs,pt) || ms_list_find(lc->codecs_conf.video_codecs,pt)){ payload_type_set_enable(pt,enabled); @@ -103,62 +108,124 @@ const char *linphone_core_get_payload_type_description(LinphoneCore *lc, Payload return NULL; } - -/*this function makes a special case for speex/8000. -This codec is variable bitrate. The 8kbit/s mode is interesting when having a low upload bandwidth, but its quality -is not very good. We 'd better use its 15kbt/s mode when we have enough bandwidth*/ -static int get_codec_bitrate(LinphoneCore *lc, const PayloadType *pt){ - int upload_bw=linphone_core_get_upload_bandwidth(lc); - if (bandwidth_is_greater(upload_bw,129) || (bandwidth_is_greater(upload_bw,33) && !linphone_core_video_enabled(lc)) ) { - if (strcmp(pt->mime_type,"speex")==0 && pt->clock_rate==8000){ - return 15000; +void linphone_core_set_payload_type_bitrate(LinphoneCore *lc, PayloadType *pt, int bitrate){ + if (ms_list_find(lc->codecs_conf.audio_codecs, (PayloadType*) pt) || ms_list_find(lc->codecs_conf.video_codecs, (PayloadType*)pt)){ + if (pt->flags & PAYLOAD_TYPE_IS_VBR){ + pt->normal_bitrate=bitrate*1000; + pt->flags|=PAYLOAD_TYPE_BITRATE_OVERRIDE; + }else{ + ms_error("Cannot set an explicit bitrate for codec %s/%i, because it is not VBR.",pt->mime_type,pt->clock_rate); } } - return pt->normal_bitrate; + ms_error("linphone_core_set_payload_type_bitrate() payload type not in audio or video list !"); } + /* *((codec-birate*ptime/8) + RTP header + UDP header + IP header)*8/ptime; *ptime=1/npacket */ -static double get_audio_payload_bandwidth(LinphoneCore *lc, const PayloadType *pt){ + +static double get_audio_payload_bandwidth_from_codec_bitrate(const PayloadType *pt){ double npacket=50; double packet_size; int bitrate; + if (strcmp(payload_type_get_mime(&payload_type_aaceld_44k), payload_type_get_mime(pt))==0) { /*special case of aac 44K because ptime= 10ms*/ npacket=100; + }else if (strcmp(payload_type_get_mime(&payload_type_ilbc), payload_type_get_mime(pt))==0) { + npacket=1000/30.0; } - bitrate=get_codec_bitrate(lc,pt); + bitrate=pt->normal_bitrate; packet_size= (((double)bitrate)/(npacket*8))+UDP_HDR_SZ+RTP_HDR_SZ+IP4_HDR_SZ; return packet_size*8.0*npacket; } -void linphone_core_update_allocated_audio_bandwidth_in_call(LinphoneCall *call, const PayloadType *pt){ - call->audio_bw=(int)(ceil(get_audio_payload_bandwidth(call->core,pt)/1000.0)); /*rounding codec bandwidth should be avoid, specially for AMR*/ +typedef struct vbr_codec_bitrate{ + int max_avail_bitrate; + int min_rate; + int recomended_bitrate; +}vbr_codec_bitrate_t; + +static vbr_codec_bitrate_t defauls_vbr[]={ + //{ 100, 44100, 100 }, + { 64, 44100, 50 }, + { 64, 16000, 40 }, + { 32, 16000, 32 }, + { 32, 8000, 32 }, + { 0 , 8000, 24 }, + { 0 , 0, 0 } +}; + +static int lookup_vbr_typical_bitrate(int maxbw, int clock_rate){ + vbr_codec_bitrate_t *it; + if (maxbw<=0) maxbw=defauls_vbr[0].max_avail_bitrate; + for(it=defauls_vbr;it->min_rate!=0;it++){ + if (maxbw>=it->max_avail_bitrate && clock_rate>=it->min_rate) + return it->recomended_bitrate; + } + ms_error("lookup_vbr_typical_bitrate(): should not happen."); + return 32; +} + +static int get_audio_payload_bandwidth(LinphoneCore *lc, const PayloadType *pt, int maxbw){ + if (linphone_core_payload_type_is_vbr(lc,pt)){ + if (pt->flags & PAYLOAD_TYPE_BITRATE_OVERRIDE){ + ms_message("PayloadType %s/%i has bitrate override",pt->mime_type,pt->clock_rate); + return pt->normal_bitrate/1000; + } + return lookup_vbr_typical_bitrate(maxbw,pt->clock_rate); + }else return (int)ceil(get_audio_payload_bandwidth_from_codec_bitrate(pt)/1000.0);/*rounding codec bandwidth should be avoid, specially for AMR*/ +} + +int linphone_core_get_payload_type_bitrate(LinphoneCore *lc, const PayloadType *pt){ + int maxbw=get_min_bandwidth(linphone_core_get_download_bandwidth(lc), + linphone_core_get_upload_bandwidth(lc)); + if (pt->type==PAYLOAD_AUDIO_CONTINUOUS || pt->type==PAYLOAD_AUDIO_PACKETIZED){ + return get_audio_payload_bandwidth(lc,pt,maxbw); + }else if (pt->type==PAYLOAD_VIDEO){ + int video_bw; + linphone_core_update_allocated_audio_bandwidth(lc); + if (maxbw<=0) { + video_bw=1500; /*default bitrate for video stream when no bandwidth limit is set, around 1.5 Mbit/s*/ + }else{ + video_bw=get_remaining_bandwidth_for_video(maxbw,lc->audio_bw); + } + return video_bw; + } + return 0; +} + +void linphone_core_update_allocated_audio_bandwidth_in_call(LinphoneCall *call, const PayloadType *pt, int maxbw){ + call->audio_bw=get_audio_payload_bandwidth(call->core,pt,maxbw); ms_message("Audio bandwidth for this call is %i",call->audio_bw); } void linphone_core_update_allocated_audio_bandwidth(LinphoneCore *lc){ const MSList *elem; - PayloadType *max=NULL; + int maxbw=get_min_bandwidth(linphone_core_get_download_bandwidth(lc), + linphone_core_get_upload_bandwidth(lc)); + int max_codec_bitrate=0; + for(elem=linphone_core_get_audio_codecs(lc);elem!=NULL;elem=elem->next){ PayloadType *pt=(PayloadType*)elem->data; if (payload_type_enabled(pt)){ - int pt_bitrate=get_codec_bitrate(lc,pt); - if (max==NULL) max=pt; - else if (max->normal_bitrateaudio_bw=(int)(get_audio_payload_bandwidth(lc,max)/1000.0); + if (max_codec_bitrate) { + lc->audio_bw=max_codec_bitrate; } } -bool_t linphone_core_is_payload_type_usable_for_bandwidth(LinphoneCore *lc, PayloadType *pt, int bandwidth_limit) +bool_t linphone_core_is_payload_type_usable_for_bandwidth(LinphoneCore *lc, const PayloadType *pt, int bandwidth_limit) { double codec_band; bool_t ret=FALSE; @@ -166,7 +233,7 @@ bool_t linphone_core_is_payload_type_usable_for_bandwidth(LinphoneCore *lc, Payl switch (pt->type){ case PAYLOAD_AUDIO_CONTINUOUS: case PAYLOAD_AUDIO_PACKETIZED: - codec_band=get_audio_payload_bandwidth(lc,pt); + codec_band=get_audio_payload_bandwidth(lc,pt,bandwidth_limit); ret=bandwidth_is_greater(bandwidth_limit*1000,codec_band); //ms_message("Payload %s: %g",pt->mime_type,codec_band); break; @@ -181,43 +248,8 @@ bool_t linphone_core_is_payload_type_usable_for_bandwidth(LinphoneCore *lc, Payl } /* return TRUE if codec can be used with bandwidth, FALSE else*/ -bool_t linphone_core_check_payload_type_usability(LinphoneCore *lc, PayloadType *pt) -{ - double codec_band; - int allowed_bw,video_bw; - bool_t ret=FALSE; - - linphone_core_update_allocated_audio_bandwidth(lc); - allowed_bw=get_min_bandwidth(linphone_core_get_download_bandwidth(lc), - linphone_core_get_upload_bandwidth(lc)); - if (allowed_bw==0) { - allowed_bw=-1; - video_bw=1500; /*around 1.5 Mbit/s*/ - }else - video_bw=get_video_bandwidth(allowed_bw,lc->audio_bw); - - switch (pt->type){ - case PAYLOAD_AUDIO_CONTINUOUS: - case PAYLOAD_AUDIO_PACKETIZED: - codec_band=get_audio_payload_bandwidth(lc,pt); - ret=bandwidth_is_greater(allowed_bw*1000,codec_band); - /*hack to avoid using uwb codecs when having low bitrate and video*/ - if (bandwidth_is_greater(199,allowed_bw)){ - if (linphone_core_video_enabled(lc) && pt->clock_rate>16000){ - ret=FALSE; - } - } - //ms_message("Payload %s: %g",pt->mime_type,codec_band); - break; - case PAYLOAD_VIDEO: - if (video_bw>0){ - pt->normal_bitrate=video_bw*1000; - ret=TRUE; - } - else ret=FALSE; - break; - } - return ret; +bool_t linphone_core_check_payload_type_usability(LinphoneCore *lc, const PayloadType *pt){ + return linphone_core_is_payload_type_usable_for_bandwidth(lc, pt, linphone_core_get_payload_type_bitrate(lc,pt)); } bool_t lp_spawn_command_line_sync(const char *command, char **result,int *command_ret){ diff --git a/coreapi/private.h b/coreapi/private.h index 08cd1a3f3..3553ca353 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -292,7 +292,7 @@ static inline bool_t bandwidth_is_greater(int bw1, int bw2){ else return bw1>=bw2; } -static inline int get_video_bandwidth(int total, int audio){ +static inline int get_remaining_bandwidth_for_video(int total, int audio){ if (total<=0) return 0; return total-audio-10; } @@ -307,6 +307,7 @@ static inline void set_string(char **dest, const char *src){ } #define PAYLOAD_TYPE_ENABLED PAYLOAD_TYPE_USER_FLAG_0 +#define PAYLOAD_TYPE_BITRATE_OVERRIDE PAYLOAD_TYPE_USER_FLAG_3 void linphone_process_authentication(LinphoneCore* lc, SalOp *op); void linphone_authentication_ok(LinphoneCore *lc, SalOp *op); @@ -321,7 +322,7 @@ void linphone_subscription_answered(LinphoneCore *lc, SalOp *op); void linphone_subscription_closed(LinphoneCore *lc, SalOp *op); void linphone_core_update_allocated_audio_bandwidth(LinphoneCore *lc); -void linphone_core_update_allocated_audio_bandwidth_in_call(LinphoneCall *call, const PayloadType *pt); +void linphone_core_update_allocated_audio_bandwidth_in_call(LinphoneCall *call, const PayloadType *pt, int maxbw); int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call); void linphone_core_resolve_stun_server(LinphoneCore *lc); @@ -655,7 +656,7 @@ struct _LinphoneCore char *play_file; char *rec_file; time_t prevtime; - int audio_bw; + int audio_bw; /*IP bw consumed by audio codec, set as soon as used codec is known, its purpose is to know the remaining bw for video*/ LinphoneCoreWaitingCallback wait_cb; void *wait_ctx; unsigned long video_window_id; @@ -731,7 +732,7 @@ void linphone_core_set_state(LinphoneCore *lc, LinphoneGlobalState gstate, const void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *call); void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *new_md); -bool_t linphone_core_is_payload_type_usable_for_bandwidth(LinphoneCore *lc, PayloadType *pt, int bandwidth_limit); +bool_t linphone_core_is_payload_type_usable_for_bandwidth(LinphoneCore *lc, const PayloadType *pt, int bandwidth_limit); #define linphone_core_ready(lc) ((lc)->state==LinphoneGlobalOn || (lc)->state==LinphoneGlobalShutdown) void _linphone_core_configure_resolver(); diff --git a/gtk/propertybox.c b/gtk/propertybox.c index 86356a97b..598e2f384 100644 --- a/gtk/propertybox.c +++ b/gtk/propertybox.c @@ -565,7 +565,7 @@ static void linphone_gtk_init_codec_list(GtkTreeView *listview){ "foreground",CODEC_COLOR, NULL); gtk_tree_view_append_column (listview, column); - column = gtk_tree_view_column_new_with_attributes (_("Bitrate (kbit/s)"), + column = gtk_tree_view_column_new_with_attributes (_("IP Bitrate (kbit/s)"), renderer, "text", CODEC_BITRATE, "foreground",CODEC_COLOR, @@ -621,7 +621,7 @@ static void linphone_gtk_show_codecs(GtkTreeView *listview, const MSList *codecl } /* get an iterator */ gtk_list_store_append(store,&iter); - bitrate=payload_type_get_bitrate(pt)/1000.0; + bitrate=linphone_core_get_payload_type_bitrate(linphone_gtk_get_core(),pt); rate=payload_type_get_rate(pt); if (pt->recv_fmtp!=NULL) params=pt->recv_fmtp; gtk_list_store_set(store,&iter, CODEC_NAME,payload_type_get_mime(pt), @@ -657,7 +657,7 @@ static void linphone_gtk_check_codec_bandwidth(GtkTreeView *v){ gfloat bitrate; gtk_tree_model_get(model,&iter,CODEC_PRIVDATA,&pt,-1); - bitrate=payload_type_get_bitrate(pt)/1000.0; + bitrate=linphone_core_get_payload_type_bitrate(linphone_gtk_get_core(),pt); gtk_list_store_set(GTK_LIST_STORE(model),&iter,CODEC_COLOR, (gpointer)get_codec_color(linphone_gtk_get_core(),pt), CODEC_BITRATE, bitrate,-1); }while(gtk_tree_model_iter_next(model,&iter)); diff --git a/tester/call_tester.c b/tester/call_tester.c index a6dc8c4ae..1fd301fb4 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -25,6 +25,7 @@ #include "liblinphone_tester.h" static void call_base(LinphoneMediaEncryption mode, bool_t enable_video,bool_t enable_relay,LinphoneFirewallPolicy policy); +static void disable_all_codecs_except_one(LinphoneCore *lc, const char *mime); void call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *msg){ char* to=linphone_address_as_string(linphone_call_get_call_log(call)->to); @@ -249,6 +250,39 @@ static void simple_call(void) { linphone_core_manager_destroy(pauline); } +static void call_with_specified_codec_bitrate(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + const LinphoneCallStats *pauline_stats,*marie_stats; + bool_t call_ok; + if (linphone_core_find_payload_type(marie->lc,"opus",48000,-1)==NULL){ + ms_warning("opus codec not supported, test skipped."); + goto end; + } + + disable_all_codecs_except_one(marie->lc,"opus"); + disable_all_codecs_except_one(pauline->lc,"opus"); + + linphone_core_set_payload_type_bitrate(marie->lc, + linphone_core_find_payload_type(marie->lc,"opus",48000,-1), + 50); + linphone_core_set_payload_type_bitrate(pauline->lc, + linphone_core_find_payload_type(pauline->lc,"opus",48000,-1), + 24); + + CU_ASSERT_TRUE((call_ok=call(pauline,marie))); + if (!call_ok) goto end; + liblinphone_tester_check_rtcp(marie,pauline); + marie_stats=linphone_call_get_audio_stats(linphone_core_get_current_call(marie->lc)); + pauline_stats=linphone_call_get_audio_stats(linphone_core_get_current_call(pauline->lc)); + CU_ASSERT_TRUE(marie_stats->download_bandwidth<30); + CU_ASSERT_TRUE(pauline_stats->download_bandwidth>45); + +end: + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + static void simple_call_compatibility_mode(void) { char route[256]; LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); @@ -2122,6 +2156,7 @@ test_t call_tests[] = { { "Call statistics not used if no config", statistics_not_used_without_config}, { "Call statistics not sent if call did not start", statistics_not_sent_if_call_not_started}, { "Call statistics sent if call ended normally", statistics_sent_at_call_termination}, + { "Call with specified codec bitrate", call_with_specified_codec_bitrate} }; test_suite_t call_test_suite = {