support early media sending for outgoing calls

This commit is contained in:
Simon Morlat 2010-11-24 22:37:20 +01:00
parent 801508597b
commit f55a93216d
10 changed files with 241 additions and 115 deletions

View file

@ -144,7 +144,10 @@ static LPC_COMMAND commands[] = {
},
{ "call", lpc_cmd_call, "Call a SIP uri or number",
#ifdef VIDEO_ENABLED
"'call <sip-url or number> [--audio-only]' \t: initiate a call to the specified destination.\n"
"'call <sip-url or number> [options]' \t: initiate a call to the specified destination.\n"
"Options can be:\n"
"--audio-only : initiate the call without video.\n"
"--early-media : sends audio and video stream immediately when remote proposes early media.\n"
#else
"'call <sip-url or number>' \t: initiate a call to the specified destination.\n"
#endif
@ -542,17 +545,22 @@ lpc_cmd_call(LinphoneCore *lc, char *args)
{
LinphoneCall *call;
LinphoneCallParams *cp=linphone_core_create_default_call_parameters (lc);
char *opt;
char *opt1,*opt2;
if ( linphone_core_in_call(lc) )
{
linphonec_out("Terminate or hold on the current call first.\n");
return 1;
}
opt=strstr(args,"--audio-only");
if (opt){
opt[0]='\0';
opt1=strstr(args,"--audio-only");
opt2=strstr(args,"--early-media");
if (opt1){
opt1[0]='\0';
linphone_call_params_enable_video (cp,FALSE);
}
if (opt2){
opt2[0]='\0';
linphone_call_params_enable_early_media_sending(cp,TRUE);
}
if ( NULL == (call=linphone_core_invite_with_params(lc, args,cp)) )
{
linphonec_out("Error from linphone_core_invite.\n");

View file

@ -356,10 +356,28 @@ static void linphonec_call_state_changed(LinphoneCore *lc, LinphoneCall *call, L
break;
case LinphoneCallOutgoingInit:
linphonec_call_identify(call);
id=(long)linphone_call_get_user_pointer (call);
from=linphone_call_get_remote_address_as_string(call);
linphonec_out("Establishing call id to %s, assigned id %i\n", from,id);
break;
case LinphoneCallUpdatedByRemote:
linphonec_call_updated(call);
break;
case LinphoneCallOutgoingProgress:
linphonec_out("Call %i to %s in progress.\n", id, from);
break;
case LinphoneCallOutgoingRinging:
linphonec_out("Call %i to %s ringing.\n", id, from);
break;
case LinphoneCallConnected:
linphonec_out("Call %i with %s connected.\n", id, from);
break;
case LinphoneCallOutgoingEarlyMedia:
linphonec_out("Call %i with %s early media.\n", id, from);
break;
case LinphoneCallError:
linphonec_out("Call %i with %s error.\n", id, from);
break;
default:
break;
}

View file

@ -27,12 +27,60 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
static void register_failure(SalOp *op, SalError error, SalReason reason, const char *details);
static void linphone_connect_incoming(LinphoneCore *lc, LinphoneCall *call){
void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *new_md){
SalMediaDescription *oldmd=call->resultdesc;
if (lc->ringstream!=NULL){
ring_stop(lc->ringstream);
lc->ringstream=NULL;
}
linphone_call_start_media_streams(call);
if (new_md!=NULL){
sal_media_description_ref(new_md);
call->media_pending=FALSE;
}else{
call->media_pending=TRUE;
}
call->resultdesc=new_md;
if (call->audiostream && call->audiostream->ticker){
/* we already started media: check if we really need to restart it*/
if (oldmd){
if (sal_media_description_equals(oldmd,new_md)){
sal_media_description_unref(oldmd);
if (call->all_muted){
ms_message("Early media finished, unmuting inputs...");
/*we were in early media, now we want to enable real media */
linphone_call_enable_camera (call,linphone_call_camera_enabled (call));
if (call->audiostream)
linphone_core_mute_mic (lc, linphone_core_is_mic_muted(lc));
}
ms_message("No need to restart streams, SDP is unchanged.");
return;
}else{
ms_message("Media descriptions are different, need to restart the streams.");
}
}
linphone_call_stop_media_streams (call);
linphone_call_init_media_streams (call);
}
if (oldmd)
sal_media_description_unref(oldmd);
if (new_md) {
bool_t all_muted=FALSE;
bool_t send_ringbacktone=FALSE;
if (call->audiostream==NULL){
/*this happens after pausing the call locally. The streams is destroyed and then we wait the 200Ok to recreate it*/
linphone_call_init_media_streams (call);
}
if (call->state==LinphoneCallIncomingEarlyMedia ||
(call->state==LinphoneCallOutgoingEarlyMedia && !call->params.real_early_media)){
all_muted=TRUE;
}else if (call->state==LinphoneCallIncomingEarlyMedia && linphone_core_get_remote_ringback_tone (lc)!=NULL){
send_ringbacktone=TRUE;
}
linphone_call_start_media_streams(call,all_muted,send_ringbacktone);
}
}
static bool_t is_duplicate_call(LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to){
@ -55,7 +103,9 @@ static void call_received(SalOp *h){
char *tmp;
LinphoneAddress *from_parsed;
LinphoneAddress *from_addr, *to_addr;
const char * early_media=linphone_core_get_remote_ringback_tone (lc);
SalMediaDescription *md;
bool_t propose_early_media=lp_config_get_int(lc->config,"sip","incoming_calls_early_media",FALSE);
const char *ringback_tone=linphone_core_get_remote_ringback_tone (lc);
/* first check if we can answer successfully to this invite */
if (lc->presence_mode==LinphoneStatusBusy ||
@ -93,16 +143,14 @@ static void call_received(SalOp *h){
call=linphone_call_new_incoming(lc,from_addr,to_addr,h);
sal_call_set_local_media_description(h,call->localdesc);
call->resultdesc=sal_call_get_final_media_description(h);
if (call->resultdesc)
sal_media_description_ref(call->resultdesc);
if (call->resultdesc && sal_media_description_empty(call->resultdesc)){
md=sal_call_get_final_media_description(h);
if (md && sal_media_description_empty(md)){
sal_call_decline(h,SalReasonMedia,NULL);
linphone_call_unref(call);
return;
}
/* the call is acceptable so we can now add it to our list */
linphone_core_add_call(lc,call);
@ -136,17 +184,18 @@ static void call_received(SalOp *h){
}else{
/*TODO : play a tone within the context of the current call */
}
sal_call_notify_ringing(h,early_media!=NULL);
#if !(__IPHONE_OS_VERSION_MIN_REQUIRED >= 40000)
linphone_call_init_media_streams(call);
if (early_media!=NULL){
linphone_call_start_early_media (call);
linphone_call_set_state(call,LinphoneCallIncomingReceived,"Incoming call");
sal_call_notify_ringing(h,propose_early_media || ringback_tone!=NULL);
if (propose_early_media || ringback_tone!=NULL){
linphone_call_set_state(call,LinphoneCallIncomingEarlyMedia,"Incoming call early media");
linphone_core_update_streams(lc,call,md);
}
#endif
ms_free(barmesg);
ms_free(tmp);
linphone_call_set_state(call,LinphoneCallIncomingReceived,"Incoming call");
if (sal_call_get_replaces(call->op)!=NULL && lp_config_get_int(lc->config,"sip","auto_answer_replacing_calls",1)){
linphone_core_accept_call(lc,call);
}
@ -183,8 +232,6 @@ static void call_ringing(SalOp *h){
ms_message("Early media already started.");
return;
}
sal_media_description_ref(md);
call->resultdesc=md;
if (lc->vtable.show) lc->vtable.show(lc);
if (lc->vtable.display_status)
lc->vtable.display_status(lc,_("Early media."));
@ -194,8 +241,7 @@ static void call_ringing(SalOp *h){
lc->ringstream=NULL;
}
ms_message("Doing early media...");
linphone_call_start_media_streams(call);
call->media_pending=TRUE;
linphone_core_update_streams (lc,call,md);
}
}
@ -207,33 +253,23 @@ static void call_ringing(SalOp *h){
static void call_accepted(SalOp *op){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
SalMediaDescription *md;
if (call==NULL){
ms_warning("No call to accept.");
return ;
}
if ((call->audiostream!=NULL) && (call->audiostream->ticker!=NULL)){
/*case where we accepted early media or already in call*/
linphone_call_stop_media_streams(call);
}
if (call->audiostream==NULL){
linphone_call_init_media_streams(call);
}
if (call->resultdesc)
sal_media_description_unref(call->resultdesc);
call->resultdesc=sal_call_get_final_media_description(op);
if (call->resultdesc){
sal_media_description_ref(call->resultdesc);
call->media_pending=FALSE;
}
md=sal_call_get_final_media_description(op);
if (call->state==LinphoneCallOutgoingProgress ||
call->state==LinphoneCallOutgoingRinging ||
call->state==LinphoneCallOutgoingEarlyMedia){
linphone_call_set_state(call,LinphoneCallConnected,"Connected");
}
if (call->resultdesc && !sal_media_description_empty(call->resultdesc)){
if (sal_media_description_has_dir(call->resultdesc,SalStreamSendOnly) ||
sal_media_description_has_dir(call->resultdesc,SalStreamInactive)){
if (md && !sal_media_description_empty(md)){
if (sal_media_description_has_dir(md,SalStreamSendOnly) ||
sal_media_description_has_dir(md,SalStreamInactive)){
if (lc->vtable.display_status){
char *tmp=linphone_call_get_remote_address_as_string (call);
char *msg=ms_strdup_printf(_("Call with %s is paused."),tmp);
@ -242,7 +278,7 @@ static void call_accepted(SalOp *op){
ms_free(msg);
}
linphone_call_set_state(call,LinphoneCallPaused,"Call paused");
}else if (sal_media_description_has_dir(call->resultdesc,SalStreamRecvOnly)){
}else if (sal_media_description_has_dir(md,SalStreamRecvOnly)){
/*we are put on hold when the call is initially accepted */
if (lc->vtable.display_status){
char *tmp=linphone_call_get_remote_address_as_string (call);
@ -258,7 +294,7 @@ static void call_accepted(SalOp *op){
}
linphone_call_set_state(call,LinphoneCallStreamsRunning,"Connected (streams running)");
}
linphone_connect_incoming (lc,call);
linphone_core_update_streams (lc,call,md);
}else{
/*send a bye*/
ms_error("Incompatible SDP offer received in 200Ok, need to abort the call");
@ -274,18 +310,9 @@ static void call_ack(SalOp *op){
return ;
}
if (call->media_pending){
if (call->audiostream->ticker!=NULL){
/*case where we accepted early media */
linphone_call_stop_media_streams(call);
linphone_call_init_media_streams(call);
}
if (call->resultdesc)
sal_media_description_unref(call->resultdesc);
call->resultdesc=sal_call_get_final_media_description(op);
if (call->resultdesc)
sal_media_description_ref(call->resultdesc);
if (call->resultdesc && !sal_media_description_empty(call->resultdesc)){
linphone_connect_incoming(lc,call);
SalMediaDescription *md=sal_call_get_final_media_description(op);
if (md && !sal_media_description_empty(md)){
linphone_core_update_streams (lc,call,md);
linphone_call_set_state (call,LinphoneCallStreamsRunning,"Connected (streams running)");
}else{
/*send a bye*/
@ -293,7 +320,6 @@ static void call_ack(SalOp *op){
linphone_core_abort_call(lc,call,"No codec intersection");
return;
}
call->media_pending=FALSE;
}
}
@ -302,17 +328,14 @@ static void call_updating(SalOp *op){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
LinphoneCallState prevstate=LinphoneCallIdle;
SalMediaDescription *md;
if (call->resultdesc)
sal_media_description_unref(call->resultdesc);
call->resultdesc=sal_call_get_final_media_description(op);
if (call->resultdesc)
sal_media_description_ref(call->resultdesc);
if (call->resultdesc && !sal_media_description_empty(call->resultdesc))
md=sal_call_get_final_media_description(op);
if (md && !sal_media_description_empty(md))
{
if ((call->state==LinphoneCallPausedByRemote || call->state==LinphoneCallPaused) &&
sal_media_description_has_dir(call->resultdesc,SalStreamSendRecv) && strcmp(call->resultdesc->addr,"0.0.0.0")!=0){
sal_media_description_has_dir(md,SalStreamSendRecv) && strcmp(md->addr,"0.0.0.0")!=0){
/*make sure we can be resumed */
if (lc->current_call!=NULL && lc->current_call!=call){
ms_warning("Attempt to be resumed but already in call with somebody else!");
@ -325,9 +348,9 @@ static void call_updating(SalOp *op){
linphone_call_set_state (call,LinphoneCallStreamsRunning,"Connected (streams running)");
}
else if(call->state==LinphoneCallStreamsRunning &&
( sal_media_description_has_dir(call->resultdesc,SalStreamRecvOnly)
|| sal_media_description_has_dir(call->resultdesc,SalStreamInactive)
|| strcmp(call->resultdesc->addr,"0.0.0.0")==0)){
( sal_media_description_has_dir(md,SalStreamRecvOnly)
|| sal_media_description_has_dir(md,SalStreamInactive)
|| strcmp(md->addr,"0.0.0.0")==0)){
if(lc->vtable.display_status)
lc->vtable.display_status(lc,_("We are being paused..."));
linphone_call_set_state (call,LinphoneCallPausedByRemote,"Call paused by remote");
@ -340,9 +363,7 @@ static void call_updating(SalOp *op){
}
/*accept the modification (sends a 200Ok)*/
sal_call_accept(op);
linphone_call_stop_media_streams (call);
linphone_call_init_media_streams (call);
linphone_call_start_media_streams (call);
linphone_core_update_streams (lc,call,md);
if (prevstate!=LinphoneCallIdle){
linphone_call_set_state (call,prevstate,"Connected (streams running)");
}

View file

@ -279,6 +279,8 @@ const char *linphone_call_state_to_string(LinphoneCallState cs){
return "LinphoneCallPausedByRemote";
case LinphoneCallUpdatedByRemote:
return "LinphoneCallUpdatedByRemote";
case LinphoneCallIncomingEarlyMedia:
return "LinphoneCallIncomingEarlyMedia";
}
return "undefined state";
}
@ -521,6 +523,17 @@ bool_t linphone_call_params_video_enabled(const LinphoneCallParams *cp){
return cp->has_video;
}
/**
* Enable sending of real early media (during outgoing calls).
**/
void linphone_call_params_enable_early_media_sending(LinphoneCallParams *cp, bool_t enabled){
cp->real_early_media=enabled;
}
bool_t linphone_call_params_early_media_sending_enabled(const LinphoneCallParams *cp){
return cp->real_early_media;
}
/**
*
**/
@ -638,9 +651,10 @@ static void post_configure_audio_streams(LinphoneCall*call){
float ng_floorgain=lp_config_get_float(lc->config,"sound","ng_floorgain",0);
int dc_removal=lp_config_get_int(lc->config,"sound","dc_removal",0);
if (mic_gain!=-1)
if (!call->audio_muted)
audio_stream_set_mic_gain(st,mic_gain);
call->audio_muted=FALSE;
else
audio_stream_set_mic_gain(st,0);
recv_gain = lc->sound_conf.soft_play_lev;
if (recv_gain != 0) {
@ -738,18 +752,21 @@ static RtpProfile *make_profile(LinphoneCore *lc, const SalMediaDescription *md,
return prof;
}
static void setup_ring_player(LinphoneCore *lc, LinphoneCall *call){
int pause_time=3000;
audio_stream_play(call->audiostream,lc->sound_conf.ringback_tone);
ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time);
}
static void _linphone_call_start_media_streams(LinphoneCall *call, bool_t send_early_media){
void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_muted, bool_t send_ringbacktone){
LinphoneCore *lc=call->core;
LinphoneAddress *me=linphone_core_get_primary_contact_parsed(lc);
const char *tool="linphone-" LINPHONE_VERSION;
char *cname;
int used_pt=-1;
if(call->audiostream == NULL)
{
ms_fatal("start_media_stream() called without prior init !");
@ -783,12 +800,11 @@ static void _linphone_call_start_media_streams(LinphoneCall *call, bool_t send_e
if (stream->port==0 || stream->dir==SalStreamRecvOnly){
captcard=NULL;
playfile=NULL;
}else if (stream->dir==SalStreamSendOnly || send_early_media){
}else if (stream->dir==SalStreamSendOnly){
playcard=NULL;
captcard=NULL;
recfile=NULL;
if (send_early_media)
playfile=NULL;
if (!send_ringbacktone) playfile=NULL;
}
/*if playfile are supplied don't use soundcards*/
if (lc->use_files) {
@ -809,13 +825,18 @@ static void _linphone_call_start_media_streams(LinphoneCall *call, bool_t send_e
captcard,
captcard==NULL ? FALSE : linphone_core_echo_cancellation_enabled(lc));
post_configure_audio_streams(call);
if (send_early_media) setup_ring_player(lc,call);
if (all_inputs_muted){
audio_stream_set_mic_gain(call->audiostream,0);
}
if (send_ringbacktone){
setup_ring_player(lc,call);
}
audio_stream_set_rtcp_information(call->audiostream, cname, tool);
}else ms_warning("No audio stream accepted ?");
}
}
#ifdef VIDEO_ENABLED
if (!send_early_media){
{
const SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc,
SalProtoRtpAvp,SalVideo);
used_pt=-1;
@ -859,7 +880,7 @@ static void _linphone_call_start_media_streams(LinphoneCall *call, bool_t send_e
/*either inactive or incompatible with local capabilities*/
is_inactive=TRUE;
}
if (call->camera_active==FALSE){
if (call->camera_active==FALSE || all_inputs_muted){
cam=get_nowebcam_device();
}
if (!is_inactive){
@ -876,21 +897,14 @@ static void _linphone_call_start_media_streams(LinphoneCall *call, bool_t send_e
}
}
#endif
call->all_muted=all_inputs_muted;
goto end;
end:
ms_free(cname);
linphone_address_destroy(me);
}
void linphone_call_start_media_streams(LinphoneCall *call){
_linphone_call_start_media_streams(call,FALSE);
}
void linphone_call_start_early_media(LinphoneCall *call){
_linphone_call_start_media_streams(call,TRUE);
}
static void linphone_call_log_fill_stats(LinphoneCallLog *log, AudioStream *st){
audio_stream_get_local_rtp_stats (st,&log->local_stats);
}

View file

@ -467,8 +467,9 @@ static void sound_config_read(LinphoneCore *lc)
gain=lp_config_get_float(lc->config,"sound","playback_gain_db",0);
linphone_core_set_playback_gain_db (lc,gain);
/*
linphone_core_set_remote_ringback_tone (lc,lp_config_get_string(lc->config,"sound","ringback_tone",NULL));
*/
}
static void sip_config_read(LinphoneCore *lc)
@ -2221,6 +2222,7 @@ int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *call)
LinphoneProxyConfig *cfg=NULL;
const char *contact=NULL;
SalOp *replaced;
SalMediaDescription *new_md;
if (call==NULL){
//if just one call is present answer the only one ...
@ -2276,26 +2278,21 @@ int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *call)
contact=get_fixed_contact(lc,call,cfg);
if (contact)
sal_op_set_contact(call->op,contact);
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 40000
linphone_call_init_media_streams(call);
#else
if (call->audiostream!=NULL && call->audiostream->ticker!=NULL){
/*case where we sent early media*/
linphone_call_stop_media_streams (call);
linphone_call_init_media_streams (call);
}
#endif
if (call->audiostream==NULL)
linphone_call_init_media_streams(call);
sal_call_accept(call->op);
if (lc->vtable.display_status!=NULL)
lc->vtable.display_status(lc,_("Connected."));
lc->current_call=call;
linphone_call_set_state(call,LinphoneCallConnected,"Connected");
call->resultdesc=sal_call_get_final_media_description(call->op);
if (call->resultdesc){
linphone_call_start_media_streams(call);
new_md=sal_call_get_final_media_description(call->op);
linphone_core_update_streams(lc, call, new_md);
if (new_md){
linphone_call_set_state(call,LinphoneCallStreamsRunning,"Connected (streams running)");
sal_media_description_ref(call->resultdesc);
}else call->media_pending=TRUE;
ms_message("call answered.");
return 0;
}
@ -2946,17 +2943,12 @@ void linphone_core_mute_mic(LinphoneCore *lc, bool_t val){
}
bool_t linphone_core_is_mic_muted(LinphoneCore *lc) {
float gain=1.0;
LinphoneCall *call=linphone_core_get_current_call(lc);
if (call==NULL){
ms_warning("linphone_core_is_mic_muted(): No current call !");
return FALSE;
}
if (call->audiostream && call->audiostream->volsend){
ms_filter_call_method(call->audiostream->volsend,MS_VOLUME_GET_GAIN,&gain);
}else ms_warning("Could not get gain: gain control wasn't activated. ");
return gain==0 || call->audio_muted;
return call->audio_muted;
}
// returns rtp transmission status for an active stream

View file

@ -178,6 +178,8 @@ typedef struct _LinphoneCallParams LinphoneCallParams;
LinphoneCallParams * linphone_call_params_copy(const LinphoneCallParams *cp);
void linphone_call_params_enable_video(LinphoneCallParams *cp, bool_t enabled);
bool_t linphone_call_params_video_enabled(const LinphoneCallParams *cp);
void linphone_call_params_enable_early_media_sending(LinphoneCallParams *cp, bool_t enabled);
bool_t linphone_call_params_early_media_sending_enabled(const LinphoneCallParams *cp);
void linphone_call_params_destroy(LinphoneCallParams *cp);
/**
@ -216,7 +218,8 @@ typedef enum _LinphoneCallState{
LinphoneCallError, /**<The call encountered an error*/
LinphoneCallEnd, /**<The call ended normally*/
LinphoneCallPausedByRemote, /**<The call is paused by remote end*/
LinphoneCallUpdatedByRemote /**<The call's parameters are updated, used for example when video is asked by remote */
LinphoneCallUpdatedByRemote, /**<The call's parameters are updated, used for example when video is asked by remote */
LinphoneCallIncomingEarlyMedia /**<We are proposing early media to an incoming call */
} LinphoneCallState;
const char *linphone_call_state_to_string(LinphoneCallState cs);
@ -779,8 +782,10 @@ void linphone_core_set_ring(LinphoneCore *lc, const char *path);
const char *linphone_core_get_ring(const LinphoneCore *lc);
void linphone_core_set_ringback(LinphoneCore *lc, const char *path);
const char * linphone_core_get_ringback(const LinphoneCore *lc);
void linphone_core_set_remote_ringback_tone(LinphoneCore *lc,const char *);
const char *linphone_core_get_remote_ringback_tone(const LinphoneCore *lc);
int linphone_core_preview_ring(LinphoneCore *lc, const char *ring,LinphoneCoreCbFunc func,void * userdata);
void linphone_core_enable_echo_cancellation(LinphoneCore *lc, bool_t val);
bool_t linphone_core_echo_cancellation_enabled(LinphoneCore *lc);

View file

@ -59,7 +59,8 @@
struct _LinphoneCallParams{
LinphoneCall *referer; /*in case this call creation is consecutive to an incoming transfer, this points to the original call */
bool_t has_video;
bool_t pad[3];
bool_t real_early_media; /*send real media even during early media (for outgoing calls)*/
bool_t pad[2];
};
struct _LinphoneCall
@ -90,6 +91,7 @@ struct _LinphoneCall
bool_t media_pending;
bool_t audio_muted;
bool_t camera_active;
bool_t all_muted; /*this flag is set during early medias*/
};
@ -187,8 +189,7 @@ int linphone_proxy_config_normalize_number(LinphoneProxyConfig *cfg, const char
void linphone_core_text_received(LinphoneCore *lc, const char *from, const char *msg);
void linphone_call_init_media_streams(LinphoneCall *call);
void linphone_call_start_media_streams(LinphoneCall *call);
void linphone_call_start_early_media(LinphoneCall *call);
void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_muted, bool_t send_ringbacktone);
void linphone_call_stop_media_streams(LinphoneCall *call);
const char * linphone_core_get_identity(LinphoneCore *lc);
@ -438,7 +439,7 @@ void linphone_core_set_state(LinphoneCore *lc, LinphoneGlobalState gstate, const
SalMediaDescription *create_local_media_description(LinphoneCore *lc,
LinphoneCall *call, bool_t with_video, bool_t only_one_codec);
void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *new_md);
#define linphone_core_ready(lc) ((lc)->state!=LinphoneGlobalStartup)
void _linphone_core_configure_resolver();

View file

@ -94,6 +94,72 @@ bool_t sal_media_description_has_dir(const SalMediaDescription *md, SalStreamDir
return found;
}
/*
static bool_t fmtp_equals(const char *p1, const char *p2){
if (p1 && p2 && strcmp(p1,p2)==0) return TRUE;
if (p1==NULL && p2==NULL) return TRUE;
return FALSE;
}
*/
static bool_t payload_type_equals(const PayloadType *p1, const PayloadType *p2){
if (p1->type!=p2->type) return FALSE;
if (strcmp(p1->mime_type,p2->mime_type)!=0) return FALSE;
if (p1->clock_rate!=p2->clock_rate) return FALSE;
if (p1->channels!=p2->channels) return FALSE;
/*
Do not compare fmtp right now: they are modified internally when the call is started
*/
/*
if (!fmtp_equals(p1->recv_fmtp,p2->recv_fmtp) ||
!fmtp_equals(p1->send_fmtp,p2->send_fmtp))
return FALSE;
*/
return TRUE;
}
static bool_t payload_list_equals(const MSList *l1, const MSList *l2){
const MSList *e1,*e2;
for(e1=l1,e2=l2;e1!=NULL && e2!=NULL; e1=e1->next,e2=e2->next){
PayloadType *p1=(PayloadType*)e1->data;
PayloadType *p2=(PayloadType*)e2->data;
if (!payload_type_equals(p1,p2))
return FALSE;
}
if (e1!=NULL || e2!=NULL){
/*means one list is longer than the other*/
abort();
return FALSE;
}
return TRUE;
}
bool_t sal_stream_description_equals(const SalStreamDescription *sd1, const SalStreamDescription *sd2){
if (sd1->proto!=sd2->proto) return FALSE;
if (sd1->type!=sd2->type) return FALSE;
if (strcmp(sd1->addr,sd2->addr)!=0) return FALSE;
if (sd1->port!=sd2->port) return FALSE;
if (!payload_list_equals(sd1->payloads,sd2->payloads)) return FALSE;
if (sd1->bandwidth!=sd2->bandwidth) return FALSE;
if (sd1->ptime!=sd2->ptime) return FALSE;
/* compare candidates: TODO */
if (sd1->dir!=sd2->dir) return FALSE;
return TRUE;
}
bool_t sal_media_description_equals(const SalMediaDescription *md1, const SalMediaDescription *md2){
int i;
if (strcmp(md1->addr,md2->addr)!=0) return FALSE;
if (md1->nstreams!=md2->nstreams) return FALSE;
if (md1->bandwidth!=md2->bandwidth) return FALSE;
for(i=0;i<md1->nstreams;++i){
if (!sal_stream_description_equals(&md1->streams[i],&md2->streams[i]))
return FALSE;
}
return TRUE;
}
static void assign_string(char **str, const char *arg){
if (*str){
ms_free(*str);

View file

@ -127,6 +127,7 @@ SalMediaDescription *sal_media_description_new();
void sal_media_description_ref(SalMediaDescription *md);
void sal_media_description_unref(SalMediaDescription *md);
bool_t sal_media_description_empty(const SalMediaDescription *md);
bool_t sal_media_description_equals(const SalMediaDescription *md1, const SalMediaDescription *md2);
bool_t sal_media_description_has_dir(const SalMediaDescription *md, SalStreamDir dir);
SalStreamDescription *sal_media_description_find_stream(SalMediaDescription *md,
SalMediaProto proto, SalStreamType type);

@ -1 +1 @@
Subproject commit ffacf56718c198cb80a290f7a65975916d8a9b6b
Subproject commit b1a4c2b6470a6de62a8e58d4f2874eda091a8db3