Commit 3a6aa9f0 authored by Simon Morlat's avatar Simon Morlat

deep modifications about audio & video codec bitrates are handled.

- vbr codecs can automatically have different output bitrates depending on whether video is used and/or allowed total output bandwidth
- application can specify an output IP bitrate for a given codec, which allows to control the quality of vbr codecs.
Note: a belle-sip upgrade is required to fix a bug around channels parsing in rtpmap.
parent c5f702ed
......@@ -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;
}
......
......@@ -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;
}
......
......@@ -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.
......
......@@ -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_bitrate<pt_bitrate){
max=pt;
int pt_bitrate=get_audio_payload_bandwidth(lc,pt,maxbw);
if (max_codec_bitrate==0) {
max_codec_bitrate=pt_bitrate;
}else if (max_codec_bitrate<pt_bitrate){
max_codec_bitrate=pt_bitrate;
}
}
}
if (max) {
lc->audio_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){
......
......@@ -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();
......
......@@ -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));
......
......@@ -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 = {
......
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