diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 812fa8cf7..0d3bfcdbc 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -46,10 +46,12 @@ static MSList *make_codec_list(LinphoneCore *lc, const MSList *codecs, bool_t on return l; } -static SalMediaDescription *create_local_media_description(LinphoneCore *lc, - LinphoneCall *call, const char *username, bool_t only_one_codec){ +SalMediaDescription *create_local_media_description(LinphoneCore *lc, + LinphoneCall *call, bool_t with_video, bool_t only_one_codec){ MSList *l; PayloadType *pt; + const char *username=(call->dir==LinphoneCallOutgoing) ? + linphone_address_get_username(call->log->from): linphone_address_get_username(call->log->to); SalMediaDescription *md=sal_media_description_new(); md->nstreams=1; strncpy(md->addr,call->localip,sizeof(md->addr)); @@ -69,7 +71,7 @@ static SalMediaDescription *create_local_media_description(LinphoneCore *lc, if (lc->dw_audio_bw>0) md->streams[0].bandwidth=lc->dw_audio_bw; - if (linphone_core_video_enabled (lc)){ + if (with_video){ md->nstreams++; md->streams[1].port=call->video_port; md->streams[1].proto=SalProtoRtpAvp; @@ -134,7 +136,7 @@ static void discover_mtu(LinphoneCore *lc, const char *remote){ } } -LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to) +LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params) { LinphoneCall *call=ms_new0(LinphoneCall,1); call->dir=LinphoneCallOutgoing; @@ -143,8 +145,7 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr call->core=lc; linphone_core_get_local_ip(lc,linphone_address_get_domain(to),call->localip); linphone_call_init_common(call,from,to); - call->localdesc=create_local_media_description (lc,call, - linphone_address_get_username(from),FALSE); + call->localdesc=create_local_media_description (lc,call,params->has_video,FALSE); if (linphone_core_get_firewall_policy(call->core)==LinphonePolicyUseStun) linphone_core_run_stun_tests(call->core,call); discover_mtu(lc,linphone_address_get_domain (to)); @@ -179,7 +180,7 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro linphone_core_get_local_ip(lc,linphone_address_get_domain(from),call->localip); linphone_call_init_common(call, from, to); call->localdesc=create_local_media_description (lc,call, - linphone_address_get_username(me),lc->sip_conf.only_one_codec); + linphone_core_video_enabled(lc),lc->sip_conf.only_one_codec); if (linphone_core_get_firewall_policy(call->core)==LinphonePolicyUseStun) linphone_core_run_stun_tests(call->core,call); discover_mtu(lc,linphone_address_get_domain(from)); @@ -777,4 +778,10 @@ void linphone_call_stop_media_streams(LinphoneCall *call){ } } +void linphone_call_params_enable_video(LinphoneCallParams *cp, bool_t enabled){ + cp->has_video=enabled; +} +void linphone_call_params_destroy(LinphoneCallParams *p){ + ms_free(p); +} diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index b35ea38d7..c0f7d83fd 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1965,12 +1965,39 @@ int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, LinphonePro * @ingroup call_control * @param lc the LinphoneCore object * @param url the destination of the call (sip address, or phone number). + * + * The application doesn't own a reference to the returned LinphoneCall object. + * Use linphone_call_ref() to safely keep the LinphoneCall pointer valid within your application. + * + * @Returns a LinphoneCall object or NULL in case of failure **/ LinphoneCall * linphone_core_invite(LinphoneCore *lc, const char *url){ + LinphoneCall *call; + LinphoneCallParams *p=linphone_core_create_default_call_parameters (lc); + call=linphone_core_invite_with_params(lc,url,p); + linphone_call_params_destroy(p); + return call; +} + + +/** + * Initiates an outgoing call according to supplied call parameters + * + * @ingroup call_control + * @param lc the LinphoneCore object + * @param url the destination of the call (sip address, or phone number). + * @param p call parameters + * + * The application doesn't own a reference to the returned LinphoneCall object. + * Use linphone_call_ref() to safely keep the LinphoneCall pointer valid within your application. + * + * @Returns a LinphoneCall object or NULL in case of failure +**/ +LinphoneCall * linphone_core_invite_with_params(LinphoneCore *lc, const char *url, const LinphoneCallParams *p){ LinphoneAddress *addr=linphone_core_interpret_url(lc,url); if (addr){ LinphoneCall *call; - call=linphone_core_invite_address(lc,addr); + call=linphone_core_invite_address_with_params(lc,addr,p); linphone_address_destroy(addr); return call; } @@ -1982,12 +2009,40 @@ LinphoneCall * linphone_core_invite(LinphoneCore *lc, const char *url){ * * @ingroup call_control * @param lc the LinphoneCore object - * @param real_parsed_url the destination of the call (sip address). + * @param addr the destination of the call (sip address). * * The LinphoneAddress can be constructed directly using linphone_address_new(), or * created by linphone_core_interpret_url(). + * The application doesn't own a reference to the returned LinphoneCall object. + * Use linphone_call_ref() to safely keep the LinphoneCall pointer valid within your application. + * + * @Returns a LinphoneCall object or NULL in case of failure **/ -LinphoneCall * linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddress *real_parsed_url) +LinphoneCall * linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddress *addr){ + LinphoneCall *call; + LinphoneCallParams *p=linphone_core_create_default_call_parameters (lc); + call=linphone_core_invite_address_with_params (lc,addr,p); + linphone_call_params_destroy(p); + return call; +} + + +/** + * Initiates an outgoing call given a destination LinphoneAddress + * + * @ingroup call_control + * @param lc the LinphoneCore object + * @param addr the destination of the call (sip address). + @param params call parameters + * + * The LinphoneAddress can be constructed directly using linphone_address_new(), or + * created by linphone_core_interpret_url(). + * The application doesn't own a reference to the returned LinphoneCall object. + * Use linphone_call_ref() to safely keep the LinphoneCall pointer valid within your application. + * + * @Returns a LinphoneCall object or NULL in case of failure +**/ +LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const LinphoneAddress *addr, const LinphoneCallParams *params) { int err=0; const char *route=NULL; @@ -2011,8 +2066,8 @@ LinphoneCall * linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddr linphone_core_get_default_proxy(lc,&proxy); route=linphone_core_get_route(lc); - real_url=linphone_address_as_string(real_parsed_url); - dest_proxy=linphone_core_lookup_known_proxy(lc,real_parsed_url); + real_url=linphone_address_as_string(addr); + dest_proxy=linphone_core_lookup_known_proxy(lc,addr); if (proxy!=dest_proxy && dest_proxy!=NULL) { ms_message("Overriding default proxy setting for this call:"); @@ -2029,7 +2084,7 @@ LinphoneCall * linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddr parsed_url2=linphone_address_new(from); - call=linphone_call_new_outgoing(lc,parsed_url2,linphone_address_clone(real_parsed_url)); + call=linphone_call_new_outgoing(lc,parsed_url2,linphone_address_clone(addr),params); sal_op_set_route(call->op,route); if(linphone_core_add_call(lc,call)!= 0) @@ -2092,6 +2147,26 @@ bool_t linphone_core_inc_invite_pending(LinphoneCore*lc){ return FALSE; } +/** + * Updates a running call according to supplied call parameters. + * + * For the moment, this is limited to enabling or disabling the video stream. + * + * @Returns 0 if successful, -1 otherwise. +**/ +int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, LinphoneCallParams *params){ + int err; + + if (call->localdesc) + sal_media_description_unref(call->localdesc); + call->localdesc=create_local_media_description (lc,call, + params->has_video,FALSE); + if (lc->vtable.display_status) + lc->vtable.display_status(lc,_("Modifying call parameters...")); + err=sal_call_update(call->op); + return err; +} + /** * Accept an incoming call. @@ -3838,3 +3913,9 @@ const char *linphone_global_state_to_string(LinphoneGlobalState gs){ LinphoneGlobalState linphone_core_get_global_state(const LinphoneCore *lc){ return lc->state; } + +LinphoneCallParams *linphone_core_create_default_call_parameters(LinphoneCore *lc){ + LinphoneCallParams *p=ms_new0(LinphoneCallParams,1); + p->has_video=linphone_core_video_enabled(lc); + return p; +} diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index f577ae985..35623d590 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -155,6 +155,17 @@ const rtp_stats_t *linphone_call_log_get_remote_stats(const LinphoneCallLog *cl) char * linphone_call_log_to_str(LinphoneCallLog *cl); +/** + * The LinphoneCallParams is an object contaning various call related parameters. + * It can be used to retrieve parameters from a currently running call or modify the call's characterisitcs + * dynamically. +**/ +struct _LinphoneCallParams; +typedef struct _LinphoneCallParams LinphoneCallParams; + +void linphone_call_params_enable_video(LinphoneCallParams *cp, bool_t enabled); +void linphone_call_params_destroy(LinphoneCallParams *cp); + /** * The LinphoneCall object represents a call issued or received by the LinphoneCore **/ @@ -194,6 +205,7 @@ LinphoneCallLog *linphone_call_get_call_log(const LinphoneCall *call); const char *linphone_call_get_refer_to(const LinphoneCall *call); bool_t linphone_call_has_transfer_pending(const LinphoneCall *call); int linphone_call_get_duration(const LinphoneCall *call); +const LinphoneCallParams linphone_call_get_current_params(const LinphoneCall *call); void *linphone_call_get_user_pointer(LinphoneCall *call); void linphone_call_set_user_pointer(LinphoneCall *call, void *user_pointer); @@ -522,6 +534,10 @@ LinphoneCall * linphone_core_invite(LinphoneCore *lc, const char *url); LinphoneCall * linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddress *addr); +LinphoneCall * linphone_core_invite_with_params(LinphoneCore *lc, const char *url, const LinphoneCallParams *params); + +LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const LinphoneAddress *addr, const LinphoneCallParams *params); + int linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall *call, const char *refer_to); bool_t linphone_core_inc_invite_pending(LinphoneCore*lc); @@ -542,6 +558,10 @@ int linphone_core_pause_all_calls(LinphoneCore *lc); int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *call); +int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, LinphoneCallParams *params); + +LinphoneCallParams *linphone_core_create_default_call_parameters(LinphoneCore *lc); + LinphoneCall *linphone_core_get_call_by_remote_address(LinphoneCore *lc, const char *remote_address); void linphone_core_send_dtmf(LinphoneCore *lc,char dtmf); diff --git a/coreapi/private.h b/coreapi/private.h index b9e33b049..943bd29c9 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -81,7 +81,12 @@ struct _LinphoneCall bool_t audio_muted; }; -LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to); +struct _LinphoneCallParams{ + bool_t has_video; + bool_t pad[3]; +}; + +LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params); LinphoneCall * linphone_call_new_incoming(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op); void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message); @@ -414,6 +419,9 @@ int linphone_core_get_calls_nb(const LinphoneCore *lc); void linphone_core_set_state(LinphoneCore *lc, LinphoneGlobalState gstate, const char *message); +SalMediaDescription *create_local_media_description(LinphoneCore *lc, + LinphoneCall *call, bool_t with_video, bool_t only_one_codec); + #define HOLD_OFF (0) #define HOLD_ON (1) diff --git a/coreapi/sal.h b/coreapi/sal.h index 7c6c7867b..835232d03 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -277,6 +277,7 @@ int sal_call_notify_ringing(SalOp *h); int sal_call_accept(SalOp*h); int sal_call_decline(SalOp *h, SalReason reason, const char *redirection /*optional*/); int sal_call_hold(SalOp *h, bool_t holdon); +int sal_call_update(SalOp *h); SalMediaDescription * sal_call_get_final_media_description(SalOp *h); int sal_refer(SalOp *h, const char *refer_to); int sal_refer_accept(SalOp *h); diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index 749bfce6b..9e08d10fe 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -1771,10 +1771,12 @@ void sal_set_keepalive_period(Sal *ctx,unsigned int value) { ctx->keepalive_period=value; eXosip_set_option (EXOSIP_OPT_UDP_KEEP_ALIVE, &value); } + const char * sal_address_get_port(const SalAddress *addr) { const osip_from_t *u=(const osip_from_t*)addr; return null_if_empty(u->url->port); } + int sal_address_get_port_int(const SalAddress *uri) { const char* port = sal_address_get_port(uri); if (port != NULL) { @@ -1813,3 +1815,29 @@ int sal_call_hold(SalOp *h, bool_t holdon) return err; } +/* sends a reinvite. Local media description may have changed by application since call establishment*/ +int sal_call_update(SalOp *h){ + int err=0; + osip_message_t *reinvite=NULL; + + eXosip_lock(); + if(eXosip_call_build_request(h->did,"INVITE",&reinvite) != OSIP_SUCCESS || reinvite==NULL){ + eXosip_unlock(); + return -1; + } + eXosip_unlock(); + osip_message_set_subject(reinvite,osip_strdup("Phone call parameters updated")); + osip_message_set_allow(reinvite, "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO"); + if (h->base.root->session_expires!=0){ + osip_message_set_header(reinvite, "Session-expires", "200"); + osip_message_set_supported(reinvite, "timer"); + } + if (h->base.local_media){ + h->sdp_offering=TRUE; + set_sdp_from_desc(reinvite,h->base.local_media); + }else h->sdp_offering=FALSE; + eXosip_lock(); + err = eXosip_call_send_request(h->did, reinvite); + eXosip_unlock(); + return err; +}