From 4e5ba9e8d4d82ed08bc838d5ba0accfdfb9eb01b Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 27 Apr 2010 11:48:54 +0200 Subject: [PATCH 01/45] new interface for multi-call, renaming of LCState into LinphoneCallState. --- console/commands.c | 4 +- console/linphonec.c | 10 +- coreapi/Makefile.am | 1 + coreapi/callbacks.c | 24 ++-- coreapi/linphonecall.c | 208 +++++++++++++++++++++++++++++++++ coreapi/linphonecore.c | 251 +++++++++------------------------------- coreapi/linphonecore.h | 44 +++++-- coreapi/private.h | 15 +-- gtk-glade/incall_view.c | 2 +- gtk-glade/main.c | 12 +- 10 files changed, 334 insertions(+), 237 deletions(-) create mode 100644 coreapi/linphonecall.c diff --git a/console/commands.c b/console/commands.c index d52a0e840..3de69279b 100644 --- a/console/commands.c +++ b/console/commands.c @@ -381,7 +381,7 @@ lpc_cmd_call(LinphoneCore *lc, char *args) } else { - if ( -1 == linphone_core_invite(lc, args) ) + if ( NULL == linphone_core_invite(lc, args) ) { linphonec_out("Error from linphone_core_invite.\n"); } @@ -438,7 +438,7 @@ static int lpc_cmd_refer(LinphoneCore *lc, char *args) { if (args) - linphone_core_refer(lc, args); + linphone_core_refer(lc, linphone_core_get_current_call(lc), args); else{ linphonec_out("refer needs an argument\n"); } diff --git a/console/linphonec.c b/console/linphonec.c index 2d1ce98b3..c4ca44840 100644 --- a/console/linphonec.c +++ b/console/linphonec.c @@ -112,7 +112,7 @@ static char **linephonec_readline_completion(const char *text, #endif /* These are callback for linphone core */ -static void linphonec_call_received(LinphoneCore *lc, const char *from); +static void linphonec_call_received(LinphoneCore *lc, LinphoneCall *call); static void linphonec_prompt_for_auth(LinphoneCore *lc, const char *realm, const char *username); static void linphonec_display_refer (LinphoneCore * lc,const char *refer_to); @@ -124,7 +124,7 @@ static void linphonec_notify_received(LinphoneCore *lc,const char *from,const ch static void linphonec_notify_presence_received(LinphoneCore *lc,LinphoneFriend *fid); static void linphonec_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url); -static void linphonec_bye_received(LinphoneCore *lc, const char *from); +static void linphonec_bye_received(LinphoneCore *lc, LinphoneCall *call); static void linphonec_text_received(LinphoneCore *lc, LinphoneChatRoom *cr, const char *from, const char *msg); static void linphonec_display_status (LinphoneCore * lc, const char *something); @@ -259,9 +259,11 @@ linphonec_display_url (LinphoneCore * lc, const char *something, const char *url * Linphone core callback */ static void -linphonec_call_received(LinphoneCore *lc, const char *from) +linphonec_call_received(LinphoneCore *lc, LinphoneCall *call) { + char *from=linphone_call_get_remote_address_as_string(call); linphonec_set_caller(from); + ms_free(from); if ( auto_answer) { answer_call=TRUE; } @@ -336,7 +338,7 @@ linphonec_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, * Linphone core callback */ static void -linphonec_bye_received(LinphoneCore *lc, const char *from) +linphonec_bye_received(LinphoneCore *lc, LinphoneCall *call) { // Should change prompt back to original maybe diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index 014ae308e..b497c1ea1 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -33,6 +33,7 @@ liblinphone_la_SOURCES=\ lpconfig.c lpconfig.h \ chat.c \ general_state.c \ + linphonecall.c \ sipsetup.c sipsetup.h \ siplogin.c diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index cdb180428..044469d2d 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -30,7 +30,7 @@ static void linphone_connect_incoming(LinphoneCore *lc, LinphoneCall *call){ lc->vtable.show(lc); if (lc->vtable.display_status) lc->vtable.display_status(lc,_("Connected.")); - call->state=LCStateAVRunning; + call->state=LinphoneCallAVRunning; if (lc->ringstream!=NULL){ ring_stop(lc->ringstream); lc->ringstream=NULL; @@ -82,7 +82,7 @@ static void call_received(SalOp *h){ sal_media_description_ref(call->resultdesc); if (call->resultdesc && sal_media_description_empty(call->resultdesc)){ sal_call_decline(h,SalReasonMedia,NULL); - linphone_call_destroy(call); + linphone_call_unref(call); lc->call=NULL; return; } @@ -103,10 +103,10 @@ static void call_received(SalOp *h){ ms_message("Starting local ring..."); lc->ringstream=ring_start(lc->sound_conf.local_ring,2000,lc->sound_conf.ring_sndcard); } - linphone_call_set_state(call,LCStateRinging); + call->state=LinphoneCallRinging; sal_call_notify_ringing(h); linphone_core_init_media_streams(lc,lc->call); - if (lc->vtable.inv_recv) lc->vtable.inv_recv(lc,tmp); + if (lc->vtable.inv_recv) lc->vtable.inv_recv(lc,call); ms_free(barmesg); ms_free(tmp); } @@ -146,7 +146,7 @@ static void call_ringing(SalOp *h){ linphone_core_start_media_streams(lc,call); call->media_pending=TRUE; } - call->state=LCStateRinging; + call->state=LinphoneCallRinging; } static void call_accepted(SalOp *op){ @@ -160,7 +160,7 @@ static void call_accepted(SalOp *op){ ms_warning("call_accepted: ignoring."); return; } - if (call->state==LCStateAVRunning){ + if (call->state==LinphoneCallAVRunning){ return ; /*already accepted*/ } if (lc->audiostream->ticker!=NULL){ @@ -234,7 +234,8 @@ static void call_updated(SalOp *op){ static void call_terminated(SalOp *op, const char *from){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); - if (sal_op_get_user_pointer(op)!=lc->call){ + LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); + if (linphone_call_get_state(call)==LinphoneCallTerminated){ ms_warning("call_terminated: ignoring."); return; } @@ -246,17 +247,18 @@ static void call_terminated(SalOp *op, const char *from){ linphone_core_stop_media_streams(lc,lc->call); lc->vtable.show(lc); lc->vtable.display_status(lc,_("Call terminated.")); + linphone_call_set_terminated(call); gstate_new_state(lc, GSTATE_CALL_END, NULL); if (lc->vtable.bye_recv!=NULL){ LinphoneAddress *addr=linphone_address_new(from); char *tmp; linphone_address_clean(addr); tmp=linphone_address_as_string(addr); - lc->vtable.bye_recv(lc,tmp); + lc->vtable.bye_recv(lc,call); ms_free(tmp); linphone_address_destroy(addr); } - linphone_call_destroy(lc->call); + linphone_call_unref(call); lc->call=NULL; } @@ -330,7 +332,7 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de } linphone_core_stop_media_streams(lc,call); if (call!=NULL) { - linphone_call_destroy(call); + linphone_call_set_terminated(call); if (sr!=SalReasonDeclined) gstate_new_state(lc, GSTATE_CALL_ERROR, msg); else gstate_new_state(lc, GSTATE_CALL_END, NULL); lc->call=NULL; @@ -446,7 +448,7 @@ static void ping_reply(SalOp *op){ LinphoneCall *call=(LinphoneCall*) sal_op_get_user_pointer(op); ms_message("ping reply !"); if (call){ - if (call->state==LCStatePreEstablishing){ + if (call->state==LinphoneCallPreEstablishing){ linphone_core_start_invite(call->core,call,NULL); } } diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c new file mode 100644 index 000000000..6df039221 --- /dev/null +++ b/coreapi/linphonecall.c @@ -0,0 +1,208 @@ + +/* +linphone +Copyright (C) 2010 Belledonne Communications SARL + (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "linphonecore.h" +#include "sipsetup.h" +#include "lpconfig.h" +#include "private.h" + + + + +static MSList *make_codec_list(LinphoneCore *lc, const MSList *codecs, bool_t only_one_codec){ + MSList *l=NULL; + const MSList *it; + for(it=codecs;it!=NULL;it=it->next){ + PayloadType *pt=(PayloadType*)it->data; + if ((pt->flags & PAYLOAD_TYPE_ENABLED) && linphone_core_check_payload_type_usability(lc,pt)){ + l=ms_list_append(l,payload_type_clone(pt)); + if (only_one_codec) break; + } + } + return l; +} + +static SalMediaDescription *create_local_media_description(LinphoneCore *lc, + const char *localip, const char *username, bool_t only_one_codec){ + MSList *l; + PayloadType *pt; + SalMediaDescription *md=sal_media_description_new(); + md->nstreams=1; + strncpy(md->addr,localip,sizeof(md->addr)); + strncpy(md->username,username,sizeof(md->username)); + md->bandwidth=linphone_core_get_download_bandwidth(lc); + /*set audio capabilities */ + strncpy(md->streams[0].addr,localip,sizeof(md->streams[0].addr)); + md->streams[0].port=linphone_core_get_audio_port(lc); + md->streams[0].proto=SalProtoRtpAvp; + md->streams[0].type=SalAudio; + md->streams[0].ptime=lc->net_conf.down_ptime; + l=make_codec_list(lc,lc->codecs_conf.audio_codecs,only_one_codec); + pt=payload_type_clone(rtp_profile_get_payload_from_mime(&av_profile,"telephone-event")); + l=ms_list_append(l,pt); + md->streams[0].payloads=l; + + if (lc->dw_audio_bw>0) + md->streams[0].bandwidth=lc->dw_audio_bw; + + if (linphone_core_video_enabled (lc)){ + md->nstreams++; + md->streams[1].port=linphone_core_get_video_port(lc); + md->streams[1].proto=SalProtoRtpAvp; + md->streams[1].type=SalVideo; + l=make_codec_list(lc,lc->codecs_conf.video_codecs,only_one_codec); + md->streams[1].payloads=l; + if (lc->dw_video_bw) + md->streams[1].bandwidth=lc->dw_video_bw; + } + return md; +} + +static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){ + call->refcnt=1; + call->state=LinphoneCallInit; + call->start_time=time(NULL); + call->media_start_time=0; + call->log=linphone_call_log_new(call, from, to); + linphone_core_notify_all_friends(call->core,LINPHONE_STATUS_ONTHEPHONE); + if (linphone_core_get_firewall_policy(call->core)==LINPHONE_POLICY_USE_STUN) + linphone_core_run_stun_tests(call->core,call); +} + +static void discover_mtu(LinphoneCore *lc, const char *remote){ + int mtu; + if (lc->net_conf.mtu==0 ){ + /*attempt to discover mtu*/ + mtu=ms_discover_mtu(remote); + if (mtu>0){ + ms_set_mtu(mtu); + ms_message("Discovered mtu is %i, RTP payload max size is %i", + mtu, ms_get_payload_max_size()); + } + } +} + +LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to) +{ + LinphoneCall *call=ms_new0(LinphoneCall,1); + call->dir=LinphoneCallOutgoing; + call->op=sal_op_new(lc->sal); + sal_op_set_user_pointer(call->op,call); + call->core=lc; + linphone_core_get_local_ip(lc,linphone_address_get_domain(to),call->localip); + call->localdesc=create_local_media_description (lc,call->localip, + linphone_address_get_username(from),FALSE); + linphone_call_init_common(call,from,to); + discover_mtu(lc,linphone_address_get_domain (to)); + return call; +} + +LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op){ + LinphoneCall *call=ms_new0(LinphoneCall,1); + LinphoneAddress *me=linphone_core_get_primary_contact_parsed(lc); + char *to_str; + char *from_str; + + call->dir=LinphoneCallIncoming; + sal_op_set_user_pointer(op,call); + call->op=op; + call->core=lc; + + if (lc->sip_conf.ping_with_options){ + /*the following sends an option request back to the caller so that + we get a chance to discover our nat'd address before answering.*/ + call->ping_op=sal_op_new(lc->sal); + to_str=linphone_address_as_string(to); + from_str=linphone_address_as_string(from); + sal_op_set_route(call->ping_op,sal_op_get_network_origin(call->op)); + sal_ping(call->ping_op,to_str,from_str); + ms_free(to_str); + ms_free(from_str); + } + + linphone_address_clean(from); + linphone_core_get_local_ip(lc,linphone_address_get_domain(from),call->localip); + call->localdesc=create_local_media_description (lc,call->localip, + linphone_address_get_username(me),lc->sip_conf.only_one_codec); + linphone_call_init_common(call, from, to); + discover_mtu(lc,linphone_address_get_domain(from)); + linphone_address_destroy(me); + return call; +} + +void linphone_call_set_terminated(LinphoneCall *call){ + LinphoneCallStatus status=LinphoneCallAborted; + if (call->state==LinphoneCallAVRunning){ + status=LinphoneCallSuccess; + } + linphone_call_log_completed(call->log,call, status); + call->state=LinphoneCallTerminated; +} + +static void linphone_call_destroy(LinphoneCall *obj) +{ + linphone_core_notify_all_friends(obj->core,obj->core->prev_mode); + + linphone_core_update_allocated_audio_bandwidth(obj->core); + if (obj->op!=NULL) { + sal_op_release(obj->op); + obj->op=NULL; + } + if (obj->resultdesc!=NULL) { + sal_media_description_unref(obj->resultdesc); + obj->resultdesc=NULL; + } + if (obj->localdesc!=NULL) { + sal_media_description_unref(obj->localdesc); + obj->localdesc=NULL; + } + if (obj->ping_op) { + sal_op_release(obj->ping_op); + } + ms_free(obj); +} + +void linphone_call_ref(LinphoneCall *obj){ + obj->refcnt++; +} + +void linphone_call_unref(LinphoneCall *obj){ + obj->refcnt--; + if (obj->refcnt==0) + linphone_call_destroy(obj); +} + +bool_t linphone_call_paused(LinphoneCall *call){ + return call->state==LinphoneCallPaused; +} + +const LinphoneAddress * linphone_call_get_remote_address(const LinphoneCall *call){ + return call->dir==LinphoneCallIncoming ? call->log->from : call->log->to; +} + +char *linphone_call_get_remote_address_as_string(const LinphoneCall *call){ + return linphone_address_as_string(linphone_call_get_remote_address(call)); +} + +LinphoneCallState linphone_call_get_state(const LinphoneCall *call){ + return call->state; +} + diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index eb2a58f93..2c084433a 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -62,150 +62,6 @@ int lc_callback_obj_invoke(LCCallbackObj *obj, LinphoneCore *lc){ return 0; } - -static MSList *make_codec_list(LinphoneCore *lc, const MSList *codecs, bool_t only_one_codec){ - MSList *l=NULL; - const MSList *it; - for(it=codecs;it!=NULL;it=it->next){ - PayloadType *pt=(PayloadType*)it->data; - if ((pt->flags & PAYLOAD_TYPE_ENABLED) && linphone_core_check_payload_type_usability(lc,pt)){ - l=ms_list_append(l,payload_type_clone(pt)); - if (only_one_codec) break; - } - } - return l; -} - -static SalMediaDescription *create_local_media_description(LinphoneCore *lc, - const char *localip, const char *username, bool_t only_one_codec){ - MSList *l; - PayloadType *pt; - SalMediaDescription *md=sal_media_description_new(); - md->nstreams=1; - strncpy(md->addr,localip,sizeof(md->addr)); - strncpy(md->username,username,sizeof(md->username)); - md->bandwidth=linphone_core_get_download_bandwidth(lc); - /*set audio capabilities */ - strncpy(md->streams[0].addr,localip,sizeof(md->streams[0].addr)); - md->streams[0].port=linphone_core_get_audio_port(lc); - md->streams[0].proto=SalProtoRtpAvp; - md->streams[0].type=SalAudio; - md->streams[0].ptime=lc->net_conf.down_ptime; - l=make_codec_list(lc,lc->codecs_conf.audio_codecs,only_one_codec); - pt=payload_type_clone(rtp_profile_get_payload_from_mime(&av_profile,"telephone-event")); - l=ms_list_append(l,pt); - md->streams[0].payloads=l; - - if (lc->dw_audio_bw>0) - md->streams[0].bandwidth=lc->dw_audio_bw; - - if (linphone_core_video_enabled (lc)){ - md->nstreams++; - md->streams[1].port=linphone_core_get_video_port(lc); - md->streams[1].proto=SalProtoRtpAvp; - md->streams[1].type=SalVideo; - l=make_codec_list(lc,lc->codecs_conf.video_codecs,only_one_codec); - md->streams[1].payloads=l; - if (lc->dw_video_bw) - md->streams[1].bandwidth=lc->dw_video_bw; - } - return md; -} - -static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){ - call->state=LCStateInit; - call->start_time=time(NULL); - call->media_start_time=0; - call->log=linphone_call_log_new(call, from, to); - linphone_core_notify_all_friends(call->core,LINPHONE_STATUS_ONTHEPHONE); - if (linphone_core_get_firewall_policy(call->core)==LINPHONE_POLICY_USE_STUN) - linphone_core_run_stun_tests(call->core,call); -} - -static void discover_mtu(LinphoneCore *lc, const char *remote){ - int mtu; - if (lc->net_conf.mtu==0 ){ - /*attempt to discover mtu*/ - mtu=ms_discover_mtu(remote); - if (mtu>0){ - ms_set_mtu(mtu); - ms_message("Discovered mtu is %i, RTP payload max size is %i", - mtu, ms_get_payload_max_size()); - } - } -} - -LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to) -{ - LinphoneCall *call=ms_new0(LinphoneCall,1); - call->dir=LinphoneCallOutgoing; - call->op=sal_op_new(lc->sal); - sal_op_set_user_pointer(call->op,call); - call->core=lc; - linphone_core_get_local_ip(lc,linphone_address_get_domain(to),call->localip); - call->localdesc=create_local_media_description (lc,call->localip, - linphone_address_get_username(from),FALSE); - linphone_call_init_common(call,from,to); - discover_mtu(lc,linphone_address_get_domain (to)); - return call; -} - -LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op){ - LinphoneCall *call=ms_new0(LinphoneCall,1); - LinphoneAddress *me=linphone_core_get_primary_contact_parsed(lc); - char *to_str; - char *from_str; - - call->dir=LinphoneCallIncoming; - sal_op_set_user_pointer(op,call); - call->op=op; - call->core=lc; - - if (lc->sip_conf.ping_with_options){ - /*the following sends an option request back to the caller so that - we get a chance to discover our nat'd address before answering.*/ - call->ping_op=sal_op_new(lc->sal); - to_str=linphone_address_as_string(to); - from_str=linphone_address_as_string(from); - sal_op_set_route(call->ping_op,sal_op_get_network_origin(call->op)); - sal_ping(call->ping_op,to_str,from_str); - ms_free(to_str); - ms_free(from_str); - } - - linphone_address_clean(from); - linphone_core_get_local_ip(lc,linphone_address_get_domain(from),call->localip); - call->localdesc=create_local_media_description (lc,call->localip, - linphone_address_get_username(me),lc->sip_conf.only_one_codec); - linphone_call_init_common(call, from, to); - discover_mtu(lc,linphone_address_get_domain(from)); - linphone_address_destroy(me); - return call; -} - -void linphone_call_destroy(LinphoneCall *obj) -{ - linphone_core_notify_all_friends(obj->core,obj->core->prev_mode); - linphone_call_log_completed(obj->log,obj); - linphone_core_update_allocated_audio_bandwidth(obj->core); - if (obj->op!=NULL) { - sal_op_release(obj->op); - obj->op=NULL; - } - if (obj->resultdesc!=NULL) { - sal_media_description_unref(obj->resultdesc); - obj->resultdesc=NULL; - } - if (obj->localdesc!=NULL) { - sal_media_description_unref(obj->localdesc); - obj->localdesc=NULL; - } - if (obj->ping_op) { - sal_op_release(obj->ping_op); - } - ms_free(obj); -} - /*prevent a gcc bug with %c*/ static size_t my_strftime(char *s, size_t max, const char *fmt, const struct tm *tm){ #if !defined(_WIN32_WCE) @@ -294,32 +150,20 @@ static void call_logs_read_from_config_file(LinphoneCore *lc){ } -void linphone_call_log_completed(LinphoneCallLog *calllog, LinphoneCall *call){ +void linphone_call_log_completed(LinphoneCallLog *calllog, LinphoneCall *call, LinphoneCallStatus status){ LinphoneCore *lc=call->core; calllog->duration=time(NULL)-call->start_time; - switch(call->state){ - case LCStateInit: - case LCStatePreEstablishing: - calllog->status=LinphoneCallAborted; - break; - case LCStateRinging: - if (calllog->dir==LinphoneCallIncoming){ - char *info; - calllog->status=LinphoneCallMissed; - lc->missed_calls++; - info=ortp_strdup_printf(ngettext("You have missed %i call.", - "You have missed %i calls.", lc->missed_calls), - lc->missed_calls); - lc->vtable.display_status(lc,info); - ms_free(info); - } - else calllog->status=LinphoneCallAborted; - break; - case LCStateAVRunning: - calllog->status=LinphoneCallSuccess; - break; - } + + if (status==LinphoneCallMissed){ + char *info; + lc->missed_calls++; + info=ortp_strdup_printf(ngettext("You have missed %i call.", + "You have missed %i calls.", lc->missed_calls), + lc->missed_calls); + lc->vtable.display_status(lc,info); + ms_free(info); + }else calllog->status=status; lc->call_logs=ms_list_prepend(lc->call_logs,(void *)calllog); if (ms_list_size(lc->call_logs)>lc->max_call_logs){ MSList *elem,*prevelem=NULL; @@ -443,10 +287,10 @@ int linphone_core_get_current_call_duration(const LinphoneCore *lc){ return time(NULL)-call->media_start_time; } -const LinphoneAddress *linphone_core_get_remote_uri(LinphoneCore *lc){ +const LinphoneAddress *linphone_core_get_remote_address(LinphoneCore *lc){ LinphoneCall *call=lc->call; if (call==NULL) return 0; - return call->dir==LinphoneCallIncoming ? call->log->from : call->log->to; + return linphone_call_get_remote_address(call); } /** @@ -1652,17 +1496,18 @@ void linphone_core_iterate(LinphoneCore *lc){ if (lc->call!=NULL){ LinphoneCall *call=lc->call; - if (call->state==LCStatePreEstablishing && (curtime-call->start_time>=2)){ + if (call->state==LinphoneCallPreEstablishing && (curtime-call->start_time>=2)){ /*start the call even if the OPTIONS reply did not arrive*/ linphone_core_start_invite(lc,call,NULL); } - if (call->dir==LinphoneCallIncoming && call->state==LCStateRinging){ + if (call->dir==LinphoneCallIncoming && call->state==LinphoneCallRinging){ elapsed=curtime-call->start_time; ms_message("incoming call ringing for %i seconds",elapsed); if (elapsed>lc->sip_conf.inc_timeout){ + call->log->status=LinphoneCallMissed; linphone_core_terminate_call(lc,NULL); } - }else if (call->state==LCStateAVRunning){ + }else if (call->state==LinphoneCallAVRunning){ if (one_second_elapsed){ RtpSession *as=NULL,*vs=NULL; lc->prevtime=curtime; @@ -1807,7 +1652,7 @@ bool_t linphone_core_is_in_communication_with(LinphoneCore *lc, const char *to) { char *tmp; bool_t returned; - const LinphoneAddress *la=linphone_core_get_remote_uri(lc); + const LinphoneAddress *la=linphone_core_get_remote_address(lc); if(la == NULL) { return FALSE; @@ -1897,7 +1742,7 @@ int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, LinphonePro sal_op_set_contact(call->op, contact); ms_free(contact); } - call->state=LCStateInit; + call->state=LinphoneCallInit; linphone_core_init_media_streams(lc,lc->call); if (!lc->sip_conf.sdp_200_ack){ call->media_pending=TRUE; @@ -1919,7 +1764,7 @@ int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, LinphonePro ms_warning("Could not initiate call."); lc->vtable.display_status(lc,_("could not call")); linphone_core_stop_media_streams(lc,call); - linphone_call_destroy(call); + linphone_call_unref(call); lc->call=NULL; }else gstate_new_state(lc, GSTATE_CALL_OUT_INVITE, real_url); ms_free(real_url); @@ -1934,15 +1779,15 @@ int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, LinphonePro * @param lc the LinphoneCore object * @param url the destination of the call (sip address, or phone number). **/ -int linphone_core_invite(LinphoneCore *lc, const char *url){ +LinphoneCall * linphone_core_invite(LinphoneCore *lc, const char *url){ LinphoneAddress *addr=linphone_core_interpret_url(lc,url); if (addr){ - int err; - err=linphone_core_invite_address(lc,addr); + LinphoneCall *call; + call=linphone_core_invite_address(lc,addr); linphone_address_destroy(addr); - return err; + return call; } - return -1; + return NULL; } /** @@ -1952,7 +1797,7 @@ int linphone_core_invite(LinphoneCore *lc, const char *url){ * @param lc the LinphoneCore object * @param url the destination of the call (sip address). **/ -int linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddress *real_parsed_url) +LinphoneCall * linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddress *real_parsed_url) { int err=0; const char *route=NULL; @@ -1965,7 +1810,7 @@ int linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddress *real_p if (lc->call!=NULL){ lc->vtable.display_warning(lc,_("Sorry, having multiple simultaneous calls is not supported yet !")); - return -1; + return NULL; } linphone_core_get_default_proxy(lc,&proxy); @@ -1997,27 +1842,25 @@ int linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddress *real_p err=linphone_core_start_invite(lc,call,dest_proxy); }else{ /*defer the start of the call after the OPTIONS ping*/ - call->state=LCStatePreEstablishing; + call->state=LinphoneCallPreEstablishing; call->ping_op=sal_op_new(lc->sal); sal_ping(call->ping_op,from,real_url); call->start_time=time(NULL); } if (real_url!=NULL) ms_free(real_url); - return err; + return call; } -int linphone_core_refer(LinphoneCore *lc, const char *url) +int linphone_core_refer(LinphoneCore *lc, LinphoneCall *call, const char *url) { char *real_url=NULL; LinphoneAddress *real_parsed_url=linphone_core_interpret_url(lc,url); - LinphoneCall *call; if (!real_parsed_url){ /* bad url */ return -1; } - call=lc->call; if (call==NULL){ ms_warning("No established call to refer."); return -1; @@ -2291,7 +2134,7 @@ void linphone_core_start_media_streams(LinphoneCore *lc, LinphoneCall *call){ end: ms_free(cname); linphone_address_destroy(me); - lc->call->state=LCStateAVRunning; + lc->call->state=LinphoneCallAVRunning; } void linphone_core_stop_media_streams(LinphoneCore *lc, LinphoneCall *call){ @@ -2341,9 +2184,8 @@ void linphone_core_stop_media_streams(LinphoneCore *lc, LinphoneCall *call){ * however this feature is not supported yet. * Using NULL will accept the unique incoming call in progress. **/ -int linphone_core_accept_call(LinphoneCore *lc, const char *url) +int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *call) { - LinphoneCall *call=lc->call; LinphoneProxyConfig *cfg=NULL; const char *contact=NULL; @@ -2351,7 +2193,7 @@ int linphone_core_accept_call(LinphoneCore *lc, const char *url) return -1; } - if (call->state==LCStateAVRunning){ + if (call->state==LinphoneCallAVRunning){ /*call already accepted*/ return -1; } @@ -2390,9 +2232,8 @@ int linphone_core_accept_call(LinphoneCore *lc, const char *url) * @param url the destination of the call to be terminated, use NULL if there is * only one call (which is case in this version of liblinphone). **/ -int linphone_core_terminate_call(LinphoneCore *lc, const char *url) +int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *call) { - LinphoneCall *call=lc->call; if (call==NULL){ return -1; } @@ -2407,10 +2248,17 @@ int linphone_core_terminate_call(LinphoneCore *lc, const char *url) linphone_core_stop_media_streams(lc,call); lc->vtable.display_status(lc,_("Call ended") ); gstate_new_state(lc, GSTATE_CALL_END, NULL); - linphone_call_destroy(call); + linphone_call_set_terminated(call); + linphone_call_unref(call); return 0; } + +int linphone_core_terminate_all_calls(LinphoneCore *lc){ + /* TODO */ + return -1; +} + /** * Returns TRUE if there is a call running or pending. * @@ -2433,6 +2281,21 @@ struct _LinphoneCall *linphone_core_get_current_call(LinphoneCore *lc) return NULL; } +int linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call){ + /* TODO */ + return -1; +} + +int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *call){ + /* TODO */ + return -1; +} + +LinphoneCall *linphone_core_get_call_by_remote_address(LinphoneCore *lc){ + /* TODO */ + return NULL; +} + int linphone_core_send_publish(LinphoneCore *lc, LinphoneOnlineStatus presence_mode) { diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 945ea25ea..81d82627b 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -85,8 +85,24 @@ struct _SipSetupContext; struct _LinphoneCall; typedef struct _LinphoneCall LinphoneCall; -bool_t linphone_call_asked_to_autoanswer(struct _LinphoneCall *call); - +typedef enum _LinphoneCallState{ + LinphoneCallInit, + LinphoneCallPreEstablishing, + LinphoneCallRinging, + LinphoneCallAVRunning, + LinphoneCallPaused, + LinphoneCallTerminated +}LinphoneCallState; + +LinphoneCallState linphone_call_get_state(const LinphoneCall *call); +bool_t linphone_call_asked_to_autoanswer(LinphoneCall *call); +bool_t linphone_call_paused(LinphoneCall *call); +const LinphoneAddress * linphone_call_get_remote_address(const LinphoneCall *call); +char *linphone_call_get_remote_address_as_string(const LinphoneCall *call); +void linphone_call_ref(LinphoneCall *call); +void linphone_call_unref(LinphoneCall *call); + + /** * Enum representing the direction of a call. * @ingroup call_logs @@ -377,9 +393,9 @@ void gstate_initialize(struct _LinphoneCore *lc) ; /** Callback prototype */ typedef void (*ShowInterfaceCb)(struct _LinphoneCore *lc); /** Callback prototype */ -typedef void (*InviteReceivedCb)(struct _LinphoneCore *lc, const char *from); +typedef void (*InviteReceivedCb)(struct _LinphoneCore *lc, LinphoneCall *call); /** Callback prototype */ -typedef void (*ByeReceivedCb)(struct _LinphoneCore *lc, const char *from); +typedef void (*ByeReceivedCb)(struct _LinphoneCore *lc, LinphoneCall *call); /** Callback prototype */ typedef void (*DisplayStatusCb)(struct _LinphoneCore *lc, const char *message); /** Callback prototype */ @@ -481,11 +497,11 @@ void linphone_core_iterate(LinphoneCore *lc); LinphoneAddress * linphone_core_interpret_url(LinphoneCore *lc, const char *url); -int linphone_core_invite(LinphoneCore *lc, const char *url); +LinphoneCall * linphone_core_invite(LinphoneCore *lc, const char *url); -int linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddress *addr); +LinphoneCall * linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddress *addr); -int linphone_core_refer(LinphoneCore *lc, const char *url); +int linphone_core_refer(LinphoneCore *lc, LinphoneCall *call, const char *url); bool_t linphone_core_inc_invite_pending(LinphoneCore*lc); @@ -493,9 +509,17 @@ bool_t linphone_core_in_call(const LinphoneCore *lc); LinphoneCall *linphone_core_get_current_call(LinphoneCore *lc); -int linphone_core_accept_call(LinphoneCore *lc, const char *url); +int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *call); -int linphone_core_terminate_call(LinphoneCore *lc, const char *url); +int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *call); + +int linphone_core_terminate_all_calls(LinphoneCore *lc); + +int linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call); + +int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *call); + +LinphoneCall *linphone_core_get_call_by_remote_address(LinphoneCore *lc); void linphone_core_send_dtmf(LinphoneCore *lc,char dtmf); @@ -741,7 +765,7 @@ void linphone_core_set_record_file(LinphoneCore *lc, const char *file); gstate_t linphone_core_get_state(const LinphoneCore *lc, gstate_group_t group); int linphone_core_get_current_call_duration(const LinphoneCore *lc); -const LinphoneAddress *linphone_core_get_remote_uri(LinphoneCore *lc); +const LinphoneAddress *linphone_core_get_remote_address(LinphoneCore *lc); int linphone_core_get_mtu(const LinphoneCore *lc); void linphone_core_set_mtu(LinphoneCore *lc, int mtu); diff --git a/coreapi/private.h b/coreapi/private.h index 4a3c1dbaa..b672f4678 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -54,12 +54,7 @@ #endif #endif -typedef enum _LCState{ - LCStateInit, - LCStatePreEstablishing, - LCStateRinging, - LCStateAVRunning -}LCState; + struct _LinphoneCall @@ -76,18 +71,18 @@ struct _LinphoneCall char localip[LINPHONE_IPADDR_SIZE]; /* our best guess for local ipaddress for this call */ time_t start_time; /*time at which the call was initiated*/ time_t media_start_time; /*time at which it was accepted, media streams established*/ - LCState state; + LinphoneCallState state; + int refcnt; bool_t media_pending; }; LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to); LinphoneCall * linphone_call_new_incoming(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op); -#define linphone_call_set_state(lcall,st) (lcall)->state=(st) -void linphone_call_destroy(struct _LinphoneCall *obj); +void linphone_call_set_terminated(LinphoneCall *call); /* private: */ LinphoneCallLog * linphone_call_log_new(LinphoneCall *call, LinphoneAddress *local, LinphoneAddress * remote); -void linphone_call_log_completed(LinphoneCallLog *calllog, LinphoneCall *call); +void linphone_call_log_completed(LinphoneCallLog *calllog, LinphoneCall *call, LinphoneCallStatus status); void linphone_call_log_destroy(LinphoneCallLog *cl); diff --git a/gtk-glade/incall_view.c b/gtk-glade/incall_view.c index c3c95eabe..0dcc5506c 100644 --- a/gtk-glade/incall_view.c +++ b/gtk-glade/incall_view.c @@ -128,7 +128,7 @@ void linphone_gtk_in_call_view_set_in_call(){ GtkWidget *duration=linphone_gtk_get_widget(main_window,"in_call_duration"); GtkWidget *animation=linphone_gtk_get_widget(main_window,"in_call_animation"); GdkPixbufAnimation *pbuf=create_pixbuf_animation("incall_anim.gif"); - const LinphoneAddress *uri=linphone_core_get_remote_uri(lc); + const LinphoneAddress *uri=linphone_core_get_remote_address(lc); char *tmp=linphone_address_as_string(uri); display_peer_name_in_label(callee,tmp); ms_free(tmp); diff --git a/gtk-glade/main.c b/gtk-glade/main.c index 364accbb3..d4b0876da 100644 --- a/gtk-glade/main.c +++ b/gtk-glade/main.c @@ -42,8 +42,8 @@ static LinphoneCore *the_core=NULL; static GtkWidget *the_ui=NULL; static void linphone_gtk_show(LinphoneCore *lc); -static void linphone_gtk_inv_recv(LinphoneCore *lc, const char *from); -static void linphone_gtk_bye_recv(LinphoneCore *lc, const char *from); +static void linphone_gtk_inv_recv(LinphoneCore *lc, LinphoneCall *call); +static void linphone_gtk_bye_recv(LinphoneCore *lc, LinphoneCall *call); static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid); static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url); static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username); @@ -390,7 +390,7 @@ static void set_video_window_decorations(GdkWindow *w){ gdk_window_set_keep_above(w, FALSE); }else{ LinphoneAddress *uri = - linphone_address_clone(linphone_core_get_remote_uri(linphone_gtk_get_core())); + linphone_address_clone(linphone_core_get_remote_address(linphone_gtk_get_core())); char *display_name; linphone_address_clean(uri); @@ -704,10 +704,11 @@ static void linphone_gtk_show(LinphoneCore *lc){ linphone_gtk_show_main_window(); } -static void linphone_gtk_inv_recv(LinphoneCore *lc, const char *from){ +static void linphone_gtk_inv_recv(LinphoneCore *lc, LinphoneCall *call){ GtkWidget *w=linphone_gtk_create_window("incoming_call"); GtkWidget *label; gchar *msg; + char *from=linphone_call_get_remote_address_as_string(call); if (auto_answer){ g_timeout_add(2000,(GSourceFunc)linphone_gtk_auto_answer,w); @@ -727,9 +728,10 @@ static void linphone_gtk_inv_recv(LinphoneCore *lc, const char *from){ g_object_set_data(G_OBJECT(linphone_gtk_get_main_window()),"incoming_call",w); gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar")), from); + ms_free(from); } -static void linphone_gtk_bye_recv(LinphoneCore *lc, const char *from){ +static void linphone_gtk_bye_recv(LinphoneCore *lc, LinphoneCall *call){ } From 1aae3a919e706a18d78c3d9cd6c3b94dd5ebed99 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 29 Apr 2010 11:34:49 +0200 Subject: [PATCH 02/45] - change stun policy regarding symmetric firewalls - fix crash when received= but no rport= --- configure.in | 2 +- coreapi/misc.c | 4 ++++ coreapi/sal_eXosip2.c | 12 +++++++++--- mediastreamer2 | 2 +- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/configure.in b/configure.in index b96111c88..fec1ed279 100644 --- a/configure.in +++ b/configure.in @@ -1,6 +1,6 @@ dnl Process this file with autoconf to produce a configure script. -AC_INIT([linphone],[3.2.99.4],[linphone-developers@nongnu.org]) +AC_INIT([linphone],[3.2.99.5],[linphone-developers@nongnu.org]) AC_CANONICAL_SYSTEM dnl Source packaging numbers diff --git a/coreapi/misc.c b/coreapi/misc.c index 86b527e94..62fa0b1f0 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -548,8 +548,10 @@ void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){ }else{ if (!cone_audio) { ms_warning("NAT is symmetric for audio port"); + /* ac->addr[0]='\0'; ac->port=0; + */ } } if (sock2>=0){ @@ -558,8 +560,10 @@ void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){ }else{ if (!cone_video) { ms_warning("NAT is symmetric for video port."); + /* vc->addr[0]='\0'; vc->port=0; + */ } } } diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index afbc4f85f..d1ade9af2 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -361,10 +361,15 @@ MSList *sal_get_pending_auths(Sal *sal){ static int extract_received_rport(osip_message_t *msg, const char **received, int *rportval){ osip_via_t *via=NULL; osip_generic_param_t *param=NULL; - const char *rport; - + const char *rport=NULL; + + *rportval=5060; + *received=NULL; osip_message_get_via(msg,0,&via); if (!via) return -1; + if (via->port && via->port[0]!='\0') + *rportval=atoi(via->port); + osip_via_param_get_byname(via,"rport",¶m); if (param) { rport=param->gvalue; @@ -375,7 +380,8 @@ static int extract_received_rport(osip_message_t *msg, const char **received, in param=NULL; osip_via_param_get_byname(via,"received",¶m); if (param) *received=param->gvalue; - else return -1; + + if (rport==NULL && *received==NULL) return -1; return 0; } diff --git a/mediastreamer2 b/mediastreamer2 index 166db20a4..b437bd3bc 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 166db20a49a308e161d7b5c74fdc5aff000db9a2 +Subproject commit b437bd3bcac6ce8f09218168ae75cc11e9a9255e From e7918babef666f1866fd70c0975673badb1f29fd Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 29 Apr 2010 11:54:18 +0200 Subject: [PATCH 03/45] merge multicall patch from Aurelien --- console/commands.c | 194 +++++++++++++++++++-- console/linphonec.c | 4 +- coreapi/callbacks.c | 79 +++++---- coreapi/chat.c | 2 +- coreapi/linphonecall.c | 9 + coreapi/linphonecore.c | 351 +++++++++++++++++++++++++++++++++----- coreapi/linphonecore.h | 5 +- coreapi/private.h | 17 +- coreapi/sal.h | 4 +- coreapi/sal_eXosip2.c | 45 +++++ coreapi/sal_eXosip2_sdp.c | 21 ++- gtk-glade/incall_view.c | 53 +++++- gtk-glade/linphone.h | 1 + gtk-glade/main.c | 6 +- gtk-glade/main.glade | 16 ++ pixmaps/Makefile.am | 1 + 16 files changed, 698 insertions(+), 110 deletions(-) diff --git a/console/commands.c b/console/commands.c index 3de69279b..d9538786b 100644 --- a/console/commands.c +++ b/console/commands.c @@ -78,6 +78,8 @@ static int lpc_cmd_ports(LinphoneCore *lc, char *args); static int lpc_cmd_speak(LinphoneCore *lc, char *args); static int lpc_cmd_codec(LinphoneCore *lc, char *args); static int lpc_cmd_echocancellation(LinphoneCore *lc, char *args); +static int lpc_cmd_pause(LinphoneCore *lc, char *args); +static int lpc_cmd_resume(LinphoneCore *lc, char *args); /* Command handler helpers */ static void linphonec_proxy_add(LinphoneCore *lc); @@ -120,17 +122,21 @@ void linphonec_out(const char *fmt,...); LPC_COMMAND commands[] = { { "help", lpc_cmd_help, "Print commands help", NULL }, { "call", lpc_cmd_call, "Call a SIP uri", - "'call ' " - ": initiate a call to the specified destination." + "'call ' \t: initiate a call to the specified destination.\n" + "'call show' \t: show all the current calls status.\n" }, { "chat", lpc_cmd_chat, "Chat with a SIP uri", "'chat \"message\"' " ": send a chat message \"message\" to the specified destination." }, - { "terminate", lpc_cmd_terminate, "Terminate the current call", - NULL }, + { "terminate", lpc_cmd_terminate, "Terminate a call", + "'terminate' : Terminate the current call\n" + "'terminate ' : Terminate the call with remote address\n" + "'terminate ' : Terminate all the current calls\n" + }, { "answer", lpc_cmd_answer, "Answer a call", - "Accept an incoming call." + "'answer' : Answer the current incoming call\n" + "'answer ' : Answer the call with remote address\n" }, { "autoanswer", lpc_cmd_autoanswer, "Show/set auto-answer mode", "'autoanswer' \t: show current autoanswer mode\n" @@ -223,7 +229,12 @@ LPC_COMMAND commands[] = { "'ec on [] [] []' : turn EC on with given delay, tail length and framesize\n" "'ec off' : turn echo cancellation (EC) off\n" "'ec show' : show EC status" }, - { (char *)NULL, (lpc_cmd_handler)NULL, (char *)NULL, (char *)NULL } + { "pause", lpc_cmd_pause, "pause a call", + "'pause' : pause the current call\n"}, + { "resume", lpc_cmd_resume, "resume a call", + "'resume' : resume the unique call\n" + "'resume ' : hold off the call with cid \n"}, + { (char *)NULL, (lpc_cmd_handler)NULL, (char *)NULL, (char *)NULL } }; /*************************************************************************** @@ -374,13 +385,34 @@ lpc_cmd_call(LinphoneCore *lc, char *args) { return 0; } - - if ( lc->call != NULL ) + if(!strcmp(args,"show")) { - linphonec_out("Terminate current call first.\n"); + MSList *calls = linphone_core_get_calls(lc); + if(calls) + { + MSList *p_calls = calls; + linphonec_out("\t\t\t\t\r\n"); + while(p_calls != NULL) + { + linphonec_out("%s\t\t\t%s\r\n", + linphone_call_get_remote_address_as_string(p_calls->data), + (((LinphoneCall *)p_calls->data)==linphone_core_get_current_call(lc))?"yes":"no"); + p_calls = p_calls->next; + } + ms_list_free(calls); + } + else + { + linphonec_out("No active call.\n"); + } } else { + if ( linphone_core_in_call(lc) ) + { + linphonec_out("Terminate or hold on the current call first.\n"); + return 1; + } if ( NULL == linphone_core_invite(lc, args) ) { linphonec_out("Error from linphone_core_invite.\n"); @@ -448,21 +480,98 @@ lpc_cmd_refer(LinphoneCore *lc, char *args) static int lpc_cmd_terminate(LinphoneCore *lc, char *args) { - if ( -1 == linphone_core_terminate_call(lc, NULL) ) + char *arg1 = args; + char *arg2 = NULL; + char *ptr = args; + + if (!args) { - linphonec_out("No active call.\n"); + if(linphone_core_in_call(lc)) + { + if ( -1 == linphone_core_terminate_call(lc, linphone_core_get_current_call(lc)) ) + { + linphonec_out("Could not stop the active call.\n"); + } + } + else + { + linphonec_out("No active call.\n"); + } + return 1; } - return 1; + + /* Isolate first and second arg */ + while(*ptr && !isspace(*ptr)) ++ptr; + if ( *ptr ) + { + *ptr='\0'; + arg2=ptr+1; + while(*arg2 && isspace(*arg2)) ++arg2; + } + if (arg1 != 0) + { + if(strcmp(arg1,"all")==0) + { + linphonec_out("We are going to stop all the calls.\n"); + return (linphone_core_terminate_all_calls(lc)==0)?1:0; + } + else + { + char the_remote_address[255]; + int n = sscanf(arg1, "%s", the_remote_address); + if (n == 1) + { + if ( -1 == linphone_core_terminate_call(lc,linphone_core_get_call_by_remote_address(lc,the_remote_address))) + { + linphonec_out("Cannot stop the call with %s.\n",the_remote_address); + } + return 1; + } + } + } + return 0; + } static int lpc_cmd_answer(LinphoneCore *lc, char *args) { - if ( -1 == linphone_core_accept_call(lc, NULL) ) + char *arg1 = args; + char *arg2 = NULL; + char *ptr = args; + + if (!args) { - linphonec_out("No incoming call.\n"); + //TODO if just one call is present answer the only one ... + if ( -1 == linphone_core_accept_call(lc, linphone_core_get_current_call(lc)) )//TODO is there any current call here=> nope + { + linphonec_out("No incoming call.\n"); + } + return 1; } - return 1; + + // Isolate first and second arg + while(*ptr && !isspace(*ptr)) ++ptr; + if ( *ptr ) + { + *ptr='\0'; + arg2=ptr+1; + while(*arg2 && isspace(*arg2)) ++arg2; + } + if (arg1 != 0) + { + char the_remote_address[256]; + int n = sscanf(arg1, "%s", the_remote_address); + if (n == 1) + { + if ( -1 == linphone_core_accept_call(lc, linphone_core_get_call_by_remote_address(lc,the_remote_address)) ) + { + linphonec_out("Cannot answer the call from %s.\n",the_remote_address); + } + return 1; + } + } + return 0; } static int @@ -1063,7 +1172,62 @@ lpc_cmd_staticpic(LinphoneCore *lc, char *args) return 0; /* Syntax error */ } +static int lpc_cmd_pause(LinphoneCore *lc, char *args){ + if(linphone_core_in_call(lc)) + { + linphone_core_pause_call(lc,linphone_core_get_current_call(lc)); + return 1; + } + linphonec_out("you can only pause when a call is in process\n"); + return 0; +} + +static int lpc_cmd_resume(LinphoneCore *lc, char *args){ + + if(linphone_core_in_call(lc)) + { + linphonec_out("There is already a call in process pause or stop it first"); + } + if (args) + { + char the_remote_address[255]; + int n = sscanf(args, "%s", the_remote_address); + if (n == 1) + { + if(linphone_core_resume_call(lc,linphone_core_get_call_by_remote_address(lc,the_remote_address)) < 0) + { + linphonec_out("There was a problem to resume the call check the remote address you gave %s\n",args); + return 0; + } + else + { + return 1; + } + } + } + else + { + int returned = 0; + MSList *calls = linphone_core_get_calls(lc); + if(ms_list_size(calls) == 1) + { + if(linphone_core_resume_call(lc,calls->data) < 0) + { + linphonec_out("There was a problem to resume the unique call \n"); + returned = 0; + } + else + { + returned = 1; + } + ms_list_free(calls); + return returned; + } + } + return 0; + +} /*************************************************************************** * diff --git a/console/linphonec.c b/console/linphonec.c index c4ca44840..18a78c1fa 100644 --- a/console/linphonec.c +++ b/console/linphonec.c @@ -344,7 +344,9 @@ linphonec_bye_received(LinphoneCore *lc, LinphoneCall *call) // printing this is unneeded as we'd get a "Communication ended" // message trough display_status callback anyway - //printf("Bye received from %s\n", from); + char *from=linphone_call_get_remote_address_as_string(call); + printf("Bye received from %s\n", from); + ms_free(from); } /* diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 044469d2d..de05c798c 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -35,7 +35,8 @@ static void linphone_connect_incoming(LinphoneCore *lc, LinphoneCall *call){ ring_stop(lc->ringstream); lc->ringstream=NULL; } - linphone_core_start_media_streams(lc,call); + if(call == linphone_core_get_current_call(lc)) + linphone_core_start_media_streams(lc,call); } static void call_received(SalOp *h){ @@ -66,7 +67,7 @@ static void call_received(SalOp *h){ sal_op_release(h); return; } - if (lc->call!=NULL){/*busy*/ + if (!linphone_core_can_we_add_call(lc)){/*busy*/ sal_call_decline(h,SalReasonBusy,NULL); sal_op_release(h); return; @@ -75,7 +76,19 @@ static void call_received(SalOp *h){ to=sal_op_get_to(h); call=linphone_call_new_incoming(lc,linphone_address_new(from),linphone_address_new(to),h); - lc->call=call; + if(linphone_core_add_call(lc,call)!= 0) + { + ms_warning("we cannot have more calls\n"); + sal_call_decline(h,SalReasonMedia,NULL); + linphone_call_unref(call); + return; + } + if(linphone_core_get_current_call(lc)!=NULL) //we are already in call just inform that an incoming call is going on + { + char temp[256]; + snprintf(temp,sizeof(temp),"A new incoming call from %s during call",from); + lc->vtable.display_status(lc,temp); + } sal_call_set_local_media_description(h,call->localdesc); call->resultdesc=sal_call_get_final_media_description(h); if (call->resultdesc) @@ -83,7 +96,6 @@ static void call_received(SalOp *h){ if (call->resultdesc && sal_media_description_empty(call->resultdesc)){ sal_call_decline(h,SalReasonMedia,NULL); linphone_call_unref(call); - lc->call=NULL; return; } @@ -99,13 +111,13 @@ static void call_received(SalOp *h){ lc->vtable.display_status(lc,barmesg); /* play the ring */ - if (lc->sound_conf.ring_sndcard!=NULL){ + if (lc->sound_conf.ring_sndcard!=NULL && !linphone_core_in_call(lc)){ ms_message("Starting local ring..."); lc->ringstream=ring_start(lc->sound_conf.local_ring,2000,lc->sound_conf.ring_sndcard); } call->state=LinphoneCallRinging; sal_call_notify_ringing(h); - linphone_core_init_media_streams(lc,lc->call); + linphone_core_init_media_streams(lc,call); if (lc->vtable.inv_recv) lc->vtable.inv_recv(lc,call); ms_free(barmesg); ms_free(tmp); @@ -113,7 +125,7 @@ static void call_received(SalOp *h){ static void call_ringing(SalOp *h){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h)); - LinphoneCall *call=lc->call; + LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(h); SalMediaDescription *md; if (call==NULL) return; if (lc->vtable.display_status) @@ -143,7 +155,8 @@ static void call_ringing(SalOp *h){ lc->ringstream=NULL; } ms_message("Doing early media..."); - linphone_core_start_media_streams(lc,call); + if(call == linphone_core_get_current_call(lc)) + linphone_core_start_media_streams(lc,call); call->media_pending=TRUE; } call->state=LinphoneCallRinging; @@ -151,22 +164,21 @@ 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=lc->call; + LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); if (call==NULL){ ms_warning("No call to accept."); return ; } - if (sal_op_get_user_pointer(op)!=lc->call){ - ms_warning("call_accepted: ignoring."); - return; - } if (call->state==LinphoneCallAVRunning){ return ; /*already accepted*/ } - if (lc->audiostream->ticker!=NULL){ + if ((lc->audiostream!=NULL) && (lc->audiostream->ticker!=NULL)){ /*case where we accepted early media */ - linphone_core_stop_media_streams(lc,call); - linphone_core_init_media_streams(lc,call); + if(call == linphone_core_get_current_call(lc)) + { + linphone_core_stop_media_streams(lc,call); + linphone_core_init_media_streams(lc,call); + } } if (call->resultdesc) sal_media_description_unref(call->resultdesc); @@ -187,20 +199,19 @@ static void call_accepted(SalOp *op){ static void call_ack(SalOp *op){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); - LinphoneCall *call=lc->call; + LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); if (call==NULL){ ms_warning("No call to be ACK'd"); return ; } - if (sal_op_get_user_pointer(op)!=lc->call){ - ms_warning("call_ack: ignoring."); - return; - } if (call->media_pending){ if (lc->audiostream->ticker!=NULL){ /*case where we accepted early media */ - linphone_core_stop_media_streams(lc,call); - linphone_core_init_media_streams(lc,call); + if(call == linphone_core_get_current_call(lc)) + { + linphone_core_stop_media_streams(lc,call); + linphone_core_init_media_streams(lc,call); + } } if (call->resultdesc) sal_media_description_unref(call->resultdesc); @@ -222,8 +233,11 @@ static void call_ack(SalOp *op){ static void call_updated(SalOp *op){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); - linphone_core_stop_media_streams(lc,call); - linphone_core_init_media_streams(lc,call); + if(call == linphone_core_get_current_call(lc)) + { + linphone_core_stop_media_streams(lc,call); + linphone_core_init_media_streams(lc,call); + } if (call->resultdesc) sal_media_description_unref(call->resultdesc); call->resultdesc=sal_call_get_final_media_description(op); @@ -244,7 +258,8 @@ static void call_terminated(SalOp *op, const char *from){ ring_stop(lc->ringstream); lc->ringstream=NULL; } - linphone_core_stop_media_streams(lc,lc->call); + if(call == linphone_core_get_current_call(lc)) + linphone_core_stop_media_streams(lc,call); lc->vtable.show(lc); lc->vtable.display_status(lc,_("Call terminated.")); linphone_call_set_terminated(call); @@ -259,7 +274,6 @@ static void call_terminated(SalOp *op, const char *from){ linphone_address_destroy(addr); } linphone_call_unref(call); - lc->call=NULL; } static void call_failure(SalOp *op, SalError error, SalReason sr, const char *details){ @@ -270,12 +284,8 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de char *msg600=_("User does not want to be disturbed."); char *msg603=_("Call declined."); char *msg=NULL; - LinphoneCall *call=lc->call; + LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); - if (sal_op_get_user_pointer(op)!=lc->call){ - ms_warning("call_failure: ignoring."); - return; - } if (lc->vtable.show) lc->vtable.show(lc); if (error==SalErrorNoResponse){ @@ -330,12 +340,13 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de ring_stop(lc->ringstream); lc->ringstream=NULL; } - linphone_core_stop_media_streams(lc,call); + if(call == linphone_core_get_current_call(lc)) + linphone_core_stop_media_streams(lc,call); if (call!=NULL) { linphone_call_set_terminated(call); + linphone_call_unref(call);//TODO not an unref here ???//AUREL if (sr!=SalReasonDeclined) gstate_new_state(lc, GSTATE_CALL_ERROR, msg); else gstate_new_state(lc, GSTATE_CALL_END, NULL); - lc->call=NULL; } } diff --git a/coreapi/chat.c b/coreapi/chat.c index 73a5f7c9a..9ee70482c 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -55,7 +55,7 @@ void linphone_chat_room_send_message(LinphoneChatRoom *cr, const char *msg){ if(linphone_core_is_in_communication_with(cr->lc,cr->peer)) { ms_message("send SIP message into the call\n"); - op = cr->lc->call->op; + op = (linphone_core_get_current_call(cr->lc))->op; } else { diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 6df039221..5ca6f2351 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -177,6 +177,15 @@ static void linphone_call_destroy(LinphoneCall *obj) if (obj->ping_op) { sal_op_release(obj->ping_op); } + if(linphone_core_del_call(obj->core,obj) != 0) + { + ms_error("could not remove the call from the list !!!"); + } + if(obj == linphone_core_get_current_call(obj->core)) + { + ms_message("destroying the current call\n"); + linphone_core_unset_the_current_call(obj->core); + } ms_free(obj); } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 2c084433a..be7689a14 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -280,15 +280,19 @@ bool_t linphone_call_asked_to_autoanswer(LinphoneCall *call){ return FALSE; } -int linphone_core_get_current_call_duration(const LinphoneCore *lc){ - LinphoneCall *call=lc->call; +int linphone_core_get_call_duration(LinphoneCall *call){ if (call==NULL) return 0; if (call->media_start_time==0) return 0; return time(NULL)-call->media_start_time; } -const LinphoneAddress *linphone_core_get_remote_address(LinphoneCore *lc){ - LinphoneCall *call=lc->call; +int linphone_core_get_current_call_duration(const LinphoneCore *lc){ + LinphoneCall *call=linphone_core_get_current_call((LinphoneCore *)lc); + return linphone_core_get_call_duration(call); +} + +const LinphoneAddress *linphone_core_get_current_call_remote_address(struct _LinphoneCore *lc){ + LinphoneCall *call=linphone_core_get_current_call(lc); if (call==NULL) return 0; return linphone_call_get_remote_address(call); } @@ -1493,9 +1497,8 @@ void linphone_core_iterate(LinphoneCore *lc){ if (lc->auto_net_state_mon) monitor_network_state(lc,curtime); proxy_update(lc); - - if (lc->call!=NULL){ - LinphoneCall *call=lc->call; + LinphoneCall *call = linphone_core_get_current_call(lc); + if(call){ if (call->state==LinphoneCallPreEstablishing && (curtime-call->start_time>=2)){ /*start the call even if the OPTIONS reply did not arrive*/ linphone_core_start_invite(lc,call,NULL); @@ -1652,7 +1655,7 @@ bool_t linphone_core_is_in_communication_with(LinphoneCore *lc, const char *to) { char *tmp; bool_t returned; - const LinphoneAddress *la=linphone_core_get_remote_address(lc); + const LinphoneAddress *la=linphone_core_get_current_call_remote_address(lc); if(la == NULL) { return FALSE; @@ -1696,7 +1699,6 @@ static char *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , LinphonePr if (call->op && sal_op_get_contact(call->op)!=NULL){ return NULL; } - /* if the ping OPTIONS request succeeded use the contact guessed from the received, rport*/ if (call->ping_op){ @@ -1743,7 +1745,7 @@ int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, LinphonePro ms_free(contact); } call->state=LinphoneCallInit; - linphone_core_init_media_streams(lc,lc->call); + linphone_core_init_media_streams(lc,call); if (!lc->sip_conf.sdp_200_ack){ call->media_pending=TRUE; sal_call_set_local_media_description(call->op,call->localdesc); @@ -1763,9 +1765,9 @@ int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, LinphonePro if (err<0){ ms_warning("Could not initiate call."); lc->vtable.display_status(lc,_("could not call")); - linphone_core_stop_media_streams(lc,call); + if(call == linphone_core_get_current_call(lc)) + linphone_core_stop_media_streams(lc,call); linphone_call_unref(call); - lc->call=NULL; }else gstate_new_state(lc, GSTATE_CALL_OUT_INVITE, real_url); ms_free(real_url); ms_free(from); @@ -1808,11 +1810,14 @@ LinphoneCall * linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddr LinphoneProxyConfig *dest_proxy=NULL; LinphoneCall *call; - if (lc->call!=NULL){ - lc->vtable.display_warning(lc,_("Sorry, having multiple simultaneous calls is not supported yet !")); + if (linphone_core_in_call(lc)){ + lc->vtable.display_warning(lc,_("Sorry, you have to pause or stop the current call first !")); + return NULL; + } + if(!linphone_core_can_we_add_call(lc)){ + lc->vtable.display_warning(lc,_("Sorry, we have reached the maximum number of simultaneous calls")); return NULL; } - linphone_core_get_default_proxy(lc,&proxy); route=linphone_core_get_route(lc); @@ -1837,7 +1842,13 @@ LinphoneCall * linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddr call=linphone_call_new_outgoing(lc,parsed_url2,linphone_address_clone(real_parsed_url)); sal_op_set_route(call->op,route); - lc->call=call; + if(linphone_core_add_call(lc,call)!= 0) + { + ms_warning("we had a problem in adding the call into the invite ... weird\n"); + linphone_call_unref(call); + return NULL; + } + linphone_core_set_as_current_call(lc,call); if (dest_proxy!=NULL || lc->sip_conf.ping_with_options==FALSE){ err=linphone_core_start_invite(lc,call,dest_proxy); }else{ @@ -1873,13 +1884,16 @@ int linphone_core_refer(LinphoneCore *lc, LinphoneCall *call, const char *url) } /** - * Returns true if in incoming call is pending, ie waiting for being answered or declined. + * Returns true if an incoming call is pending, ie waiting for being answered or declined. * * @ingroup call_control **/ bool_t linphone_core_inc_invite_pending(LinphoneCore*lc){ - if (lc->call!=NULL && lc->call->dir==LinphoneCallIncoming){ - return TRUE; + LinphoneCall *call = linphone_core_get_current_call(lc); + if(call != NULL) + { + if(call->dir==LinphoneCallIncoming) + return TRUE; } return FALSE; } @@ -2134,7 +2148,7 @@ void linphone_core_start_media_streams(LinphoneCore *lc, LinphoneCall *call){ end: ms_free(cname); linphone_address_destroy(me); - lc->call->state=LinphoneCallAVRunning; + call->state=LinphoneCallAVRunning; } void linphone_core_stop_media_streams(LinphoneCore *lc, LinphoneCall *call){ @@ -2205,7 +2219,11 @@ int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *call) ms_message("ring stopped"); lc->ringstream=NULL; } - + if(linphone_core_set_as_current_call(lc,call)!=0) + { + ms_message("another call is already in process\n"); + } + linphone_core_get_default_proxy(lc,&cfg); /*try to be best-effort in giving real local or routable contact address*/ contact=get_fixed_contact(lc,call,cfg); @@ -2218,7 +2236,8 @@ int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *call) call->resultdesc=sal_call_get_final_media_description(call->op); if (call->resultdesc){ sal_media_description_ref(call->resultdesc); - linphone_core_start_media_streams(lc, call); + if(call == linphone_core_get_current_call(lc)) + linphone_core_start_media_streams(lc, call); }else call->media_pending=TRUE; ms_message("call answered."); return 0; @@ -2232,12 +2251,20 @@ int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *call) * @param url the destination of the call to be terminated, use NULL if there is * only one call (which is case in this version of liblinphone). **/ -int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *call) +int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *the_call) { - if (call==NULL){ - return -1; + LinphoneCall *call; + if (the_call == NULL){ + call = linphone_core_get_current_call(lc); + if(call == NULL) + { + return -1; + } + } + else + { + call = the_call; } - lc->call=NULL; sal_call_terminate(call->op); /*stop ringing*/ @@ -2245,7 +2272,8 @@ int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *call) ring_stop(lc->ringstream); lc->ringstream=NULL; } - linphone_core_stop_media_streams(lc,call); + if(call == linphone_core_get_current_call(lc)) + linphone_core_stop_media_streams(lc,call); lc->vtable.display_status(lc,_("Call ended") ); gstate_new_state(lc, GSTATE_CALL_END, NULL); linphone_call_set_terminated(call); @@ -2253,19 +2281,42 @@ int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *call) return 0; } - +/** + * Terminates all the calls. + * + * @ingroup call_control + * @param lc The LinphoneCore +**/ int linphone_core_terminate_all_calls(LinphoneCore *lc){ - /* TODO */ + MSList *calls; + + calls = lc->calls; + while(calls->next != NULL) + { + linphone_core_terminate_call(lc,(LinphoneCall *)calls->data); + calls = calls->next; + } + ms_list_free(lc->calls); return -1; } +/** + * Returns the calls MSList + * + * @ingroup call_control +**/ +MSList *linphone_core_get_calls(LinphoneCore *lc) +{ + return ms_list_copy(lc->calls); +} + /** * Returns TRUE if there is a call running or pending. * * @ingroup call_control **/ bool_t linphone_core_in_call(const LinphoneCore *lc){ - return lc->call!=NULL; + return linphone_core_get_current_call((LinphoneCore *)lc)!=NULL; } /** @@ -2273,26 +2324,133 @@ bool_t linphone_core_in_call(const LinphoneCore *lc){ * * @ingroup call_control **/ -struct _LinphoneCall *linphone_core_get_current_call(LinphoneCore *lc) +LinphoneCall *linphone_core_get_current_call(LinphoneCore *lc) { - if(linphone_core_in_call(lc)) - return lc->call; - else - return NULL; + if(lc->current_call != NULL) + return lc->current_call; + return NULL; } -int linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call){ - /* TODO */ - return -1; +/** + * Permits to pause the call + * + * @ingroup call_control +**/ +int linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *the_call) +{ + LinphoneCall *call = the_call; + if(lc == NULL) + { + ms_error("LinphoneCore was null\n"); + return -1; + } + if(call == NULL) + { + if(linphone_core_in_call(lc)) + { + call = linphone_core_get_current_call(lc); + } + else + { + ms_error("LinphoneCall was null\n"); + return -2; + } + } + if(linphone_core_get_current_call(lc) != call) + { + ms_error("The call asked to be paused was not the current on\n"); + return -3; + } + sal_call_hold(call->op,TRUE); + call->state = LinphoneCallPaused; + linphone_core_unset_the_current_call(lc); + linphone_core_stop_media_streams(lc,call); + lc->vtable.display_status(lc,_("Pause the current call")); + return 0; } -int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *call){ - /* TODO */ - return -1; +/** + * Permits to resume the call + * + * @ingroup call_control +**/ +int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *the_call) +{ + char temp[255]; + LinphoneCall *call = the_call; + if(lc == NULL) + { + ms_error("LinphoneCore was null\n"); + return -1; + } + if(call == NULL) + { + MSList *calls = linphone_core_get_calls(lc); + if(ms_list_size(calls) == 1) + { + call = ((LinphoneCall *)calls->data); + ms_list_free(calls); + } + else + { + ms_error("LinphoneCall was null\n"); + ms_list_free(calls); + return -2; + } + } + if(linphone_core_get_current_call(lc) != NULL) + { + ms_error("There is already a call in process pause or stop it first\n"); + return -3; + } + linphone_core_init_media_streams(lc,call); + sal_call_hold(call->op,FALSE); + call->state = LinphoneCallAVRunning; + linphone_core_set_as_current_call(lc,call); + linphone_core_start_media_streams(lc,call); + snprintf(temp,sizeof(temp),"Resume the call with %s",linphone_call_get_remote_address_as_string(call)); + lc->vtable.display_status(lc,temp); + + return 0; } -LinphoneCall *linphone_core_get_call_by_remote_address(LinphoneCore *lc){ - /* TODO */ +/** + * Compare the remote address with the one in call + * + * @param a the call + * @param b the remote address to compare with + * @return 0 if it's the good call else 1 + */ +static int linphone_call_remote_address_compare(const void * a, const void * b) +{ + if(b == NULL || a ==NULL) + return 1; + char *the_remote_address = ((char *)b); + LinphoneCall *call = ((LinphoneCall *)a); +#ifdef DEBUG + ms_message("the remote address:%s\n",the_remote_address); + ms_message("the call:%p => %s\n",call,linphone_call_get_remote_address_as_string(call)); +#endif + if(!strcmp(linphone_call_get_remote_address_as_string(call),the_remote_address)) + { + return 0; + } + return 1; +} + +/** + * Get the call with the remote_address specified + * @param lc + * @param remote_address + * @return the LinphoneCall of the call if found + */ +LinphoneCall *linphone_core_get_call_by_remote_address(LinphoneCore *lc, const char *remote_address){ + + MSList *the_call = ms_list_find_custom(lc->calls,linphone_call_remote_address_compare,(void *)remote_address); + if(the_call != NULL) + { + return ((LinphoneCall *)the_call->data); + } return NULL; } @@ -2767,7 +2925,7 @@ void linphone_core_send_dtmf(LinphoneCore *lc, char dtmf) } if (linphone_core_get_use_info_for_dtmf(lc)!=0){ /* Out of Band DTMF (use INFO method) */ - LinphoneCall *call=lc->call; + LinphoneCall *call=linphone_core_get_current_call(lc); if (call==NULL){ return; } @@ -3377,9 +3535,9 @@ LpConfig *linphone_core_get_config(LinphoneCore *lc){ static void linphone_core_uninit(LinphoneCore *lc) { - if (lc->call){ + if(linphone_core_get_calls_nb(lc)){ int i; - linphone_core_terminate_call(lc,NULL); + linphone_core_terminate_all_calls(lc); for(i=0;i<10;++i){ #ifndef WIN32 usleep(50000); @@ -3461,4 +3619,105 @@ void linphone_core_destroy(LinphoneCore *lc){ linphone_core_uninit(lc); ms_free(lc); } +/** + * Get the number of Call + * + * @ingroup call_control +**/ +int linphone_core_get_calls_nb(const LinphoneCore *lc) +{ + int returned; + if(lc->calls == NULL) + { + returned = 0; + } + else + { + returned = ms_list_size(lc->calls); + } + return returned; +} +/** + * Check if we do not have exceed the number of simultaneous call + * + * @ingroup call_control +**/ +bool_t linphone_core_can_we_add_call(LinphoneCore *lc) +{ + if(linphone_core_get_calls_nb(lc) < NB_MAX_CALLS) + return TRUE; + return FALSE; +} + +/** + * Unset the current call + * + * @ingroup call_control +**/ +int linphone_core_unset_the_current_call(LinphoneCore *lc) +{ + if(lc->current_call == NULL) + return -1; + lc->current_call = NULL; + ms_message("Current call unset\n"); + return 0; +} + +/** + * Set the call in parameter as the new current call + * + * @ingroup call_control +**/ +int linphone_core_set_as_current_call(LinphoneCore *lc, LinphoneCall *call) +{ + if(lc->current_call != NULL) + return -1; + lc->current_call = call; + return 0; +} + +/** + * Add the call in the LinphoneCall list + * + * @ingroup call_control +**/ +int linphone_core_add_call( LinphoneCore *lc, LinphoneCall *call) +{ + if(linphone_core_can_we_add_call(lc)) + { + MSList *the_calls = lc->calls; + the_calls = ms_list_append(the_calls,(void *)call); + lc->calls = the_calls; + return 0; + } + return -1; +} + +/** + * Add the call in the LinphoneCall list + * + * @ingroup call_control +**/ +int linphone_core_del_call( LinphoneCore *lc, LinphoneCall *call) +{ + MSList *it; + + MSList *the_calls = lc->calls; + if(call == linphone_core_get_current_call(lc)) + { + linphone_core_unset_the_current_call(lc); + } + it=ms_list_find(the_calls,call); + if (it) + { + the_calls = ms_list_remove_link(the_calls,it); + } + else + { + ms_warning("could not find the call into the list\n"); + return -1; + } + lc->calls = the_calls; + return 0; +} diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 81d82627b..c3d435c60 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -97,6 +97,7 @@ typedef enum _LinphoneCallState{ LinphoneCallState linphone_call_get_state(const LinphoneCall *call); bool_t linphone_call_asked_to_autoanswer(LinphoneCall *call); bool_t linphone_call_paused(LinphoneCall *call); +const LinphoneAddress * linphone_core_get_current_call_remote_address(struct _LinphoneCore *lc); const LinphoneAddress * linphone_call_get_remote_address(const LinphoneCall *call); char *linphone_call_get_remote_address_as_string(const LinphoneCall *call); void linphone_call_ref(LinphoneCall *call); @@ -519,7 +520,7 @@ int linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call); int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *call); -LinphoneCall *linphone_core_get_call_by_remote_address(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); @@ -812,5 +813,5 @@ void linphone_core_set_audio_transports(LinphoneCore *lc, RtpTransport *rtp, Rtp #ifdef __cplusplus } #endif - +MSList *linphone_core_get_calls(LinphoneCore *lc); #endif diff --git a/coreapi/private.h b/coreapi/private.h index b672f4678..fdd4f7856 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -355,7 +355,8 @@ struct _LinphoneCore MSList *auth_info; struct _RingStream *ringstream; LCCallbackObj preview_finished_cb; - struct _LinphoneCall *call; /* the current call, in the future it will be a list of calls (conferencing)*/ + LinphoneCall *current_call; /* the current call */ + MSList *calls; /* all the processed calls */ MSList *queued_calls; /* used by the autoreplier */ MSList *call_logs; MSList *chatrooms; @@ -394,4 +395,18 @@ struct _LinphoneCore bool_t network_reachable; }; +bool_t linphone_core_can_we_add_call(LinphoneCore *lc); +int linphone_core_add_call( LinphoneCore *lc, LinphoneCall *call); +int linphone_core_del_call( LinphoneCore *lc, LinphoneCall *call); +int linphone_core_set_as_current_call(LinphoneCore *lc, LinphoneCall *call); +int linphone_core_unset_the_current_call(LinphoneCore *lc); +int linphone_core_get_calls_nb(const LinphoneCore *lc); + +#define HOLD_OFF (0) +#define HOLD_ON (1) + +#ifndef NB_MAX_CALLS +#define NB_MAX_CALLS (10) +#endif + #endif /* _PRIVATE_H */ diff --git a/coreapi/sal.h b/coreapi/sal.h index 882761ffb..8aedd4487 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -98,6 +98,7 @@ typedef struct SalStreamDescription{ int bandwidth; int ptime; SalEndpointCandidate candidates[SAL_ENDPOINT_CANDIDATE_MAX]; + bool_t notsending; } SalStreamDescription; #define SAL_MEDIA_DESCRIPTION_MAX_STREAMS 4 @@ -109,6 +110,7 @@ typedef struct SalMediaDescription{ int nstreams; int bandwidth; SalStreamDescription streams[SAL_MEDIA_DESCRIPTION_MAX_STREAMS]; + bool_t notsending; } SalMediaDescription; SalMediaDescription *sal_media_description_new(); @@ -258,6 +260,7 @@ int sal_call(SalOp *h, const char *from, const char *to); 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); SalMediaDescription * sal_call_get_final_media_description(SalOp *h); int sal_refer(SalOp *h, const char *refer_to); int sal_refer_accept(SalOp *h); @@ -299,5 +302,4 @@ void __sal_op_init(SalOp *b, Sal *sal); void __sal_op_set_network_origin(SalOp *op, const char *origin /*a sip uri*/); void __sal_op_free(SalOp *b); - #endif diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index d1ade9af2..7c4a24db7 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -398,6 +398,19 @@ static void set_sdp(osip_message_t *sip,sdp_message_t *msg){ osip_free(sdp); } +static void set_hold_status_to_desc(SalMediaDescription *desc, bool_t holdon) +{ + int i; + if(desc == NULL) + return; + desc->notsending = holdon; + for(i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) + { + if(desc->streams != NULL) + desc->streams[i].notsending = holdon;//Audio + } +} + static void set_sdp_from_desc(osip_message_t *sip, const SalMediaDescription *desc){ sdp_message_t *msg=media_description_to_sdp(desc); if (msg==NULL) { @@ -1691,3 +1704,35 @@ void sal_address_destroy(SalAddress *u){ osip_from_free((osip_from_t*)u); } +/** + * Send a re-Invite used to hold the current call + * + * @ingroup call_control + * @param lc the LinphoneCore object + * @param url the destination of the call (sip address). +**/ +int sal_call_hold(SalOp *h, bool_t holdon) +{ + int err=0; + + osip_message_t *reinvite; + eXosip_call_build_request(h->did,"INVITE",&reinvite); + osip_message_set_subject(reinvite,osip_strdup("Phone Call Hold")); + 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"); + } + //add something to say that the distant sip phone will be in sendonly/sendrecv mode + if (h->base.local_media){ + h->sdp_offering=TRUE; + set_hold_status_to_desc(h->base.local_media,holdon); + 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; +} + diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c index 2165708b1..2c27c5236 100644 --- a/coreapi/sal_eXosip2_sdp.c +++ b/coreapi/sal_eXosip2_sdp.c @@ -121,12 +121,21 @@ static sdp_message_t *create_generic_sdp(const SalMediaDescription *desc) osip_strdup ("IN"), inet6 ? osip_strdup("IP6") : osip_strdup ("IP4"), osip_strdup (desc->addr)); sdp_message_s_name_set (local, osip_strdup ("A conversation")); - sdp_message_c_connection_add (local, -1, - osip_strdup ("IN"), inet6 ? osip_strdup ("IP6") : osip_strdup ("IP4"), - osip_strdup (desc->addr), NULL, NULL); + if(!desc->notsending) + { + sdp_message_c_connection_add (local, -1, + osip_strdup ("IN"), inet6 ? osip_strdup ("IP6") : osip_strdup ("IP4"), + osip_strdup (desc->addr), NULL, NULL); + } + else + { + sdp_message_c_connection_add (local, -1, + osip_strdup ("IN"), inet6 ? osip_strdup ("IP6") : osip_strdup ("IP4"), + inet6 ? osip_strdup ("0.0.0.0.0.0") : osip_strdup ("0.0.0.0"), NULL, NULL); + } sdp_message_t_time_descr_add (local, osip_strdup ("0"), osip_strdup ("0")); if (desc->bandwidth>0) sdp_message_b_bandwidth_add (local, -1, osip_strdup ("AS"), - int_2char(desc->bandwidth)); + int_2char(desc->bandwidth)); return local; } @@ -186,6 +195,10 @@ static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription for(elem=desc->payloads;elem!=NULL;elem=elem->next){ add_payload(msg, lineno, (PayloadType*)elem->data); } + if(desc->notsending)//to hold the distant SIP endpoint + sdp_message_a_attribute_add (msg, lineno, osip_strdup ("sendonly"),NULL); + else + sdp_message_a_attribute_add (msg, lineno, osip_strdup ("sendrecv"),NULL); } sdp_message_t *media_description_to_sdp(const SalMediaDescription *desc){ diff --git a/gtk-glade/incall_view.c b/gtk-glade/incall_view.c index 0dcc5506c..c3da047e1 100644 --- a/gtk-glade/incall_view.c +++ b/gtk-glade/incall_view.c @@ -128,7 +128,7 @@ void linphone_gtk_in_call_view_set_in_call(){ GtkWidget *duration=linphone_gtk_get_widget(main_window,"in_call_duration"); GtkWidget *animation=linphone_gtk_get_widget(main_window,"in_call_animation"); GdkPixbufAnimation *pbuf=create_pixbuf_animation("incall_anim.gif"); - const LinphoneAddress *uri=linphone_core_get_remote_address(lc); + const LinphoneAddress *uri=linphone_core_get_current_call_remote_address(lc); char *tmp=linphone_address_as_string(uri); display_peer_name_in_label(callee,tmp); ms_free(tmp); @@ -141,7 +141,9 @@ void linphone_gtk_in_call_view_set_in_call(){ g_object_unref(G_OBJECT(pbuf)); }else gtk_image_set_from_stock(GTK_IMAGE(animation),GTK_STOCK_INFO,GTK_ICON_SIZE_DIALOG); linphone_gtk_enable_mute_button( - GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(main_window,"incall_mute")),TRUE); + GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(main_window,"incall_mute")),TRUE); + linphone_gtk_enable_hold_button( + GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(main_window,"hold_call")),TRUE); } void linphone_gtk_in_call_view_update_duration(int duration){ @@ -179,6 +181,8 @@ void linphone_gtk_in_call_view_terminate(const char *error_msg){ } linphone_gtk_enable_mute_button( GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(main_window,"incall_mute")),FALSE); + linphone_gtk_enable_hold_button( + GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(main_window,"hold_call")),FALSE); g_timeout_add_seconds(2,(GSourceFunc)in_call_view_terminated,NULL); } @@ -206,7 +210,50 @@ void linphone_gtk_mute_toggled(GtkToggleButton *button){ linphone_gtk_draw_mute_button(button,active); } -void linphone_gtk_enable_mute_button(GtkToggleButton *button, gboolean sensitive){ +void linphone_gtk_enable_mute_button(GtkToggleButton *button, gboolean sensitive) +{ gtk_widget_set_sensitive(GTK_WIDGET(button),sensitive); linphone_gtk_draw_mute_button(button,FALSE); } + +void linphone_gtk_draw_hold_button(GtkToggleButton *button, gboolean active){ + GtkWidget *status=linphone_gtk_get_widget(linphone_gtk_get_main_window(),"in_call_status"); + if (active){ + GtkWidget *image=create_pixmap("hold_off.png"); + gtk_button_set_label(GTK_BUTTON(button),_("HoldOff")); + gtk_label_set_markup(GTK_LABEL(status),_("In call holded with")); + if (image!=NULL) { + gtk_button_set_image(GTK_BUTTON(button),image); + gtk_widget_show(image); + } + }else{ + GtkWidget *image=create_pixmap("hold_on.png"); + gtk_button_set_label(GTK_BUTTON(button),_("HoldOn")); + gtk_label_set_markup(GTK_LABEL(status),_("In call with")); + if (image!=NULL) { + gtk_button_set_image(GTK_BUTTON(button),image); + gtk_widget_show(image); + } + } +} + +void linphone_gtk_hold_toggled(GtkToggleButton *button){ + GtkWidget *mw=linphone_gtk_get_main_window(); + gboolean active=gtk_toggle_button_get_active(button); + if(active) + { + linphone_core_pause_call(linphone_gtk_get_core(),NULL); + gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"terminate_call"),FALSE); + } + else + { + linphone_core_resume_call(linphone_gtk_get_core(),NULL); + gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"terminate_call"),TRUE); + } + linphone_gtk_draw_hold_button(button,active); +} + +void linphone_gtk_enable_hold_button(GtkToggleButton *button, gboolean sensitive){ + gtk_widget_set_sensitive(GTK_WIDGET(button),sensitive); + linphone_gtk_hold_toggled(button); +} diff --git a/gtk-glade/linphone.h b/gtk-glade/linphone.h index b6dcd5df1..850277155 100644 --- a/gtk-glade/linphone.h +++ b/gtk-glade/linphone.h @@ -92,6 +92,7 @@ void linphone_gtk_in_call_view_set_in_call(void); void linphone_gtk_in_call_view_update_duration(int duration); void linphone_gtk_in_call_view_terminate(const char *error_msg); void linphone_gtk_enable_mute_button(GtkToggleButton *button, gboolean sensitive); +void linphone_gtk_enable_hold_button(GtkToggleButton *button, gboolean sensitive); void linphone_gtk_show_login_frame(LinphoneProxyConfig *cfg); diff --git a/gtk-glade/main.c b/gtk-glade/main.c index d4b0876da..2fd3f6d62 100644 --- a/gtk-glade/main.c +++ b/gtk-glade/main.c @@ -390,7 +390,7 @@ static void set_video_window_decorations(GdkWindow *w){ gdk_window_set_keep_above(w, FALSE); }else{ LinphoneAddress *uri = - linphone_address_clone(linphone_core_get_remote_address(linphone_gtk_get_core())); + linphone_address_clone(linphone_core_get_current_call_remote_address(linphone_gtk_get_core())); char *display_name; linphone_address_clean(uri); @@ -588,7 +588,7 @@ static void linphone_gtk_call_started(GtkWidget *mw){ static gboolean linphone_gtk_start_call_do(GtkWidget *uri_bar){ const char *entered=gtk_entry_get_text(GTK_ENTRY(uri_bar)); - if (linphone_core_invite(linphone_gtk_get_core(),entered)==0) { + if (linphone_core_invite(linphone_gtk_get_core(),entered)!=NULL) { completion_add_text(GTK_ENTRY(uri_bar),entered); }else{ linphone_gtk_call_terminated(NULL); @@ -1147,6 +1147,8 @@ static void linphone_gtk_init_main_window(){ "main_mute")),FALSE); linphone_gtk_enable_mute_button(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(main_window, "incall_mute")),FALSE); + linphone_gtk_enable_hold_button(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(main_window, + "hold_call")),FALSE); if (!linphone_gtk_use_in_call_view()) { gtk_widget_show(linphone_gtk_get_widget(main_window, "main_mute")); } diff --git a/gtk-glade/main.glade b/gtk-glade/main.glade index b858892fb..67701fb23 100644 --- a/gtk-glade/main.glade +++ b/gtk-glade/main.glade @@ -1190,6 +1190,7 @@ Fiber Channel True + spread Mute @@ -1205,6 +1206,21 @@ Fiber Channel 0 + + + HoldOn + True + False + True + True + + + + False + False + 1 + + False diff --git a/pixmaps/Makefile.am b/pixmaps/Makefile.am index 6247f4d27..47d2f51ab 100644 --- a/pixmaps/Makefile.am +++ b/pixmaps/Makefile.am @@ -3,6 +3,7 @@ pixmapdir=$(datadir)/pixmaps/linphone pixmap_DATA= \ +hold_on.png hold_off.png \ mic_muted.png mic_active.png \ linphone-3-250x130.png linphone-3.png linphone2-57x57.png \ linphone.png linphone-banner.png \ From 8fce88f12d51c4f8557e0ba1948f7ed705383760 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 29 Apr 2010 13:56:52 +0200 Subject: [PATCH 04/45] add hold on hold off icons --- pixmaps/hold_off.png | Bin 0 -> 2280 bytes pixmaps/hold_on.png | Bin 0 -> 1139 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 pixmaps/hold_off.png create mode 100644 pixmaps/hold_on.png diff --git a/pixmaps/hold_off.png b/pixmaps/hold_off.png new file mode 100644 index 0000000000000000000000000000000000000000..61ab330c6de2599eacbd98cf8d46f8682dd3e174 GIT binary patch literal 2280 zcmVP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2igQ0 z3@Rw*kr`wF00?MFL_t(o!_Aj%Y!y`+$A9O{%zYbs`*Hy-7SzB3;D)Y z+k5Z4&wglUxGnX|e%U?A$(cDbInV$3KmYTb=fMBCiSZ`idFP!;@p!yMQ51aN|F62| zdEsbTmfzjo-IGivhZ-6h{9goc;Mr#%oO0&O&iL!ESH@y7>3JUQ?d@2WHEO}JM#g*h zJP*(Fm_B_vuIqC7^5w!8O-+9*YioP{rS|rY>i~ROU%%pa>GbZzfdi5`bMW@>$M=02 z8XA~6b0)rj4Y=?7n5IcCm!nW9Ff=q2j=5Zpd_GU1P@t!$hp)c+3eWR!`ukB|dyS)A zT~}I8oLKPZ3m47;NPy<%W<_7Tcw2PgLW!avT3QfGm*O}MLI_;f4Lu5;15X{t!Eqcc z%fhy8Y}>{(O-$3obzSoLJcePAdhkKYKm3qCbaqxIlF2{abI(00fC`XKr|($3di8W? z?p*w?F4VW*MjSngT31JFHcKv-3k?TNN;!&l0A1J7b)89*CLx5NqoV`EFqnG({b(02 z;wuXF9e3bVR?fY=Z{H0-zY37c6J$_dg+OAzF2M_YcY1629@=2o6D6Z=w zr6ixvhej>S3N>QeHbM+XRaI4*nwq%j@yCf=yoei*)3;;^m)5T*dEh`9WlHRZZ!!QCSMHqr0wg84(`TLX+hby4|(boXWn=NDJ7O= zVHifJj{sEAUDqYQYZr^VyD3yu&{I>xzgMk7?e0d`bzIjC84MV}wrvIm2FT@dp+`S$ z-%fVfGKL(7(zZ5k+q@aevJgUq{}dYy7*czB`2DA!Qev9qQz?$ES%YO+3=R&`+1ZI@ zS=R$FO*0f(@X_~ux*8fdxnKcCB!YhOBr~3QW;jf_9GOgpzP>&(nGF5?{R|8Ykj-Y% zUw)ZMBWn#-RgDtvu(@k$mVu$-tu?k)Y~RkYvNB?s3=>*gnZ0Qfs;ZL7WXNPPA#=8E zBe!j1Q8tTJUQX9tcX4vvI;50g2YkSiQi@Rk#xo2Mq~obCynq{xB7oAiHfA?B6Ny9s zNF);U_4V=F#zxj;v#5qae&R&_)zE;VC}EdUB82b&OHmZA10aOBt}BXyrfC%B&!>Cm zPK>Ejk*3LQAAd}3Qxl0qf^$cXQ1{kb{HCV|0rbzD$v0cKhQcmp!1sMuN}1DjT?u!= zcnk!Hi{qD{H;>N!`>A^PVbs&7srvFu7F@l`f=q^6b2*Tb-g)ylzHuYUNa7mt8X*L} z@B2asPY7X^mzQhf0tgaGFa{zG<`hMtbI%@bUbYPN^l5HsZ%4%A#8WiKs#dA&cW)94{$l2qa*`bzRi9HoUqzN{$`F zxc6SpH8yf;!UQ_Y%1E3z!IbBoLseBYO(PPC5Rb=+L?T3^Q6iCu&@@dELinnxD!Q&; zzY7Aoi@gp{zjxoIbM0Ct4GbU_F68Xy&0MXiVQ}Y8{;_HmryPgakt5u)VFN-4B9RE1 zrV))sLuPbc7b8NHz_k#J-7du-R8=KfSI5L1JGi}~g8Z^&{Iqo|rfDLCVCaS$n7nu~ z16#JxrK%(kA7<*7E!WDfYq}Dy>-thkPY8i&nxjQnY`i#uBv-EFrsKy+Iu3SqHNBfQ zQ79Bbkp-Tbvu1JS%{OVCJsa)tVQzl!y>T7#eP7tN?KqCZbs8AkC)C%Yo;-=4NHF-o z16+On`7rGUpaC4m8O{~SBvq*t`oI9G_uuFChaMu9$%F#bG)(})aU9Pu3|}n{!PqLe z^ob`BUw_T_Q>IY<*kj~sYY~RQ`Sa()BQ*e0e5U-gdNmJpcT;ipERkG}U#(op`Q~P< zR0>VggzLJ}Fbpf7&->$QK>hh=Dpsr@cIXiOo`?PP(`4_vkK&>wr~}4U!NGd%%a=0{ zj}JSR&r`W=8=9t}X`1kTU+eGhw=P|}Gz`FXT|Zzz>+Pj<-8!`Iz5~zWpSRx1(6niz z#1t4UK4ivfsB_vhK3KRAtEL7#551*@s*M|o#bP3#&+C1CeO8!?UDv%lG&D2}VBbEJ zGiM+g#aXn7gH=^Ltm{-%RD{M;sZ@A;7ZpFW-LqEkX!NYHLxy{~oifjF%#jPd?D~x^y~SP)Dv}&R?w!jEGW{mX?a$yLWrGZOb2i_@Vdo;NTZZI{kXjj2XviZy*11I(P2e_=O7>Qc_A? z6ragO?U$;j@xG0K@g2v>CzHvHuIssujt-yym-ZjWFLS+zMTgY@0000kdg00001b5ch_0Itp) z=>Px#0%A)?L;(MXkIcUS000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2igQ03=k?U zHl{HE00Z|)L_t(Y$F0>(s9r}I2k_s_Ip@9i=FLa#m4qx@HPS?Bg(_%4glee>VmEFq zR1m~=VGD)UlDZHVuA&=J3KFnT1VL!1wo=fIanZU6(ugS$Yl+?lNk5XB``-J$=bV{w zaZXNdUAWPC;LM!ing8>DKIR$z#}RHWPaobmP$~aKvLb8CmA4LVpDgbKc=j{oL2a9Tm&;z4@0NlU&~Y<(a=fd3I|8IDPLuFCLu*6erzo054V+c5U0WZDGf*xBOn# zx#qcxXFhxWGLh%1+nzo$E0SI>NU|)AR(rixr?aw>>{!Y++;{s2pS-80=5HT;@K~Pw zJZB-vAdcjjn>#GHXgTeC;tS7z$F-Wpktj`me#Ar8B+-t7Rx9fS)P7+##-ccQ%hh#i za!A4yxVIH61ic=eR@O_3xh<_ci7)_2SXxPvgI=>~zo@koB%NNbmz;B}Ek#nBO9~=c z=RFIpR_|e_EbVHAai^E`I-Os;UuUKDFK=oUBZHNUf}-|ie{kHU4GW#DA6@vlhorIS zqMUOcR#W(Hj4yiCIa^k0S6%gl!oc^RC}| z%DN<~R4P%(+R6kFCaE-{&-tlmoO9Sde{{(c_6efI$e^USm{nDl0D^1cwVQ`k6KX?loE5y>y^P|8IK1=5z!1ZRT`CI zeWczCvWN-?*6s-PjTlhLidr_@%j~=pvOhVYvL>pnBvBsnA7*t3^^{jcVFXK})BfRG zmVV-}uZilhR(eGrnktmKn%~Sq6a{gF`=>`7by8>P>yCQV>xy8ev1ZMNc?dZ~g9}64 zhf0j1m;K5UHuYA5m5({$j9WY~HL(yTOPb~S12zu|GGVG}qd#Qj^M17K2(N?kTEDkqw>} ztwWkob3N?L-)*T$m$yd%ibLjZ6%?DYGB(&74CflqYs#C;>nm!yi@!O4{LW^Cc-57$ zCkI)l(~nIp$=>n!&_Bx?@%-8S*RQBK-QW4m+g|+qf&B_T<@gkjm2C?PJL9}-CJCkX zXHQ?a^yA&#@dAD|zWm9%zx(OC4{c;Wi=&sNl$`sL%V0Z&B8NUakh}QTcV2nvFW*1* z+J&^|asBwlrOh}Gdmh{JzE`+Rb1wbP!K?Gd#p3@l{tY?97!|qj=@tM0002ovPDHLk FV1g&PBk}+M literal 0 HcmV?d00001 From 53856588501c5e2943158603e78aad6a195576cb Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 3 May 2010 14:58:27 +0200 Subject: [PATCH 05/45] merge patch adding user pointers --- coreapi/linphonecall.c | 23 +++++++++++++++++++++++ coreapi/linphonecore.h | 3 +++ coreapi/private.h | 1 + 3 files changed, 27 insertions(+) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 5ca6f2351..5a85e7efa 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -215,3 +215,26 @@ LinphoneCallState linphone_call_get_state(const LinphoneCall *call){ return call->state; } +/** + * Get the user_pointer in the LinphoneCall + * + * @ingroup call_control + * + * return user_pointer an opaque user pointer that can be retrieved at any time +**/ +void *linphone_call_get_user_pointer(LinphoneCall *call) +{ + return call->user_pointer; +} + +/** + * Set the user_pointer in the LinphoneCall + * + * @ingroup call_control + * + * the user_pointer is an opaque user pointer that can be retrieved at any time in the LinphoneCall +**/ +void linphone_call_set_user_pointer(LinphoneCall *call, void *user_pointer) +{ + call->user_pointer = user_pointer; +} diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index c3d435c60..fc735fd6c 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -814,4 +814,7 @@ void linphone_core_set_audio_transports(LinphoneCore *lc, RtpTransport *rtp, Rtp } #endif MSList *linphone_core_get_calls(LinphoneCore *lc); +void *linphone_call_get_user_pointer(LinphoneCall *call); +void linphone_call_set_user_pointer(LinphoneCall *call, void *user_pointer); + #endif diff --git a/coreapi/private.h b/coreapi/private.h index fdd4f7856..f4e308f65 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -74,6 +74,7 @@ struct _LinphoneCall LinphoneCallState state; int refcnt; bool_t media_pending; + void * user_pointer; }; LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to); From 54939b2e06cf1cb3068111dd2702c6774d8cf56c Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 7 May 2010 17:36:32 +0200 Subject: [PATCH 06/45] merge patch that adds callback to notify about call changes (resume/paused) etc.. --- console/commands.c | 4 ++-- console/linphonec.c | 40 ++++++++++++++++++++++++++++++++-- coreapi/callbacks.c | 49 ++++++++++++++++++++++++++++++++++-------- coreapi/linphonecore.c | 8 ++++++- coreapi/linphonecore.h | 17 ++++++++++++++- coreapi/sal.h | 2 +- coreapi/sal_eXosip2.c | 4 ++-- gtk-glade/main.c | 4 ++-- mediastreamer2 | 2 +- 9 files changed, 109 insertions(+), 21 deletions(-) diff --git a/console/commands.c b/console/commands.c index d9538786b..73e1b2b54 100644 --- a/console/commands.c +++ b/console/commands.c @@ -542,8 +542,8 @@ lpc_cmd_answer(LinphoneCore *lc, char *args) if (!args) { - //TODO if just one call is present answer the only one ... - if ( -1 == linphone_core_accept_call(lc, linphone_core_get_current_call(lc)) )//TODO is there any current call here=> nope + //if just one call is present answer the only one in passing NULL to the linphone_core_accept_call ... + if ( -1 == linphone_core_accept_call(lc, NULL) ) { linphonec_out("No incoming call.\n"); } diff --git a/console/linphonec.c b/console/linphonec.c index 18a78c1fa..86187ad7c 100644 --- a/console/linphonec.c +++ b/console/linphonec.c @@ -113,9 +113,11 @@ static char **linephonec_readline_completion(const char *text, /* These are callback for linphone core */ static void linphonec_call_received(LinphoneCore *lc, LinphoneCall *call); +static void linphonec_paused_received(LinphoneCore *lc, LinphoneCall *call); +static void linphonec_resumed_received(LinphoneCore *lc, LinphoneCall *call); static void linphonec_prompt_for_auth(LinphoneCore *lc, const char *realm, const char *username); -static void linphonec_display_refer (LinphoneCore * lc,const char *refer_to); +static void linphonec_display_refer (LinphoneCore * lc,LinphoneCall *call, const char *refer_to); static void linphonec_display_something (LinphoneCore * lc, const char *something); static void linphonec_display_url (LinphoneCore * lc, const char *something, const char *url); static void linphonec_display_warning (LinphoneCore * lc, const char *something); @@ -131,6 +133,7 @@ static void linphonec_display_status (LinphoneCore * lc, const char *something); static void linphonec_general_state (LinphoneCore * lc, LinphoneGeneralState *gstate); static void linphonec_dtmf_received(LinphoneCore *lc, int dtmf); static void print_prompt(LinphoneCore *opm); +void linphonec_out(const char *fmt,...); /*************************************************************************** * * Global variables @@ -176,6 +179,11 @@ LinphoneCoreVTable linphonec_vtable .show =(ShowInterfaceCb) stub, .inv_recv = linphonec_call_received, .bye_recv = linphonec_bye_received, + .ringing_recv = (RingingReceivedCb) stub, + .connected_recv = (ConnectedReceivedCb) stub, + .failure_recv = (FailureReceivedCb) stub, + .paused_recv = linphonec_paused_received, + .resumed_recv = linphonec_resumed_received, .notify_recv = linphonec_notify_received, .notify_presence_recv = linphonec_notify_presence_received, .new_unknown_subscriber = linphonec_new_unknown_subscriber, @@ -209,7 +217,7 @@ LinphoneCoreVTable linphonec_vtable * Linphone core callback */ static void -linphonec_display_refer (LinphoneCore * lc,const char *refer_to) +linphonec_display_refer (LinphoneCore * lc,LinphoneCall *call, const char *refer_to) { fprintf (stdout, "The distant end point asked to transfer the call to %s,don't forget to terminate the call if not\n%s", refer_to,prompt); fflush(stdout); @@ -268,6 +276,34 @@ linphonec_call_received(LinphoneCore *lc, LinphoneCall *call) answer_call=TRUE; } } +/* + * Linphone core callback + */ +static void +linphonec_paused_received(LinphoneCore *lc, LinphoneCall *call) +{ + char *from=linphone_call_get_remote_address_as_string(call); + if(from) + { + linphonec_out("the call from %s have been paused\n",from); + ms_free(from); + } +} +/* + * Linphone core callback + */ +static void +linphonec_resumed_received(LinphoneCore *lc, LinphoneCall *call) +{ + char *from=linphone_call_get_remote_address_as_string(call); + if(from) + { + linphonec_out("the call from %s have been resumed\n",from); + ms_free(from); + } +} + + /* * Linphone core callback diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 0f1dc4126..cb9999a01 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -30,6 +30,8 @@ static void linphone_connect_incoming(LinphoneCore *lc, LinphoneCall *call){ lc->vtable.show(lc); if (lc->vtable.display_status) lc->vtable.display_status(lc,_("Connected.")); + if (lc->vtable.connected_recv) + lc->vtable.connected_recv(lc,call); call->state=LinphoneCallAVRunning; if (lc->ringstream!=NULL){ ring_stop(lc->ringstream); @@ -130,6 +132,8 @@ static void call_ringing(SalOp *h){ if (call==NULL) return; if (lc->vtable.display_status) lc->vtable.display_status(lc,_("Remote ringing.")); + if (lc->vtable.ringing_recv) + lc->vtable.ringing_recv(lc,call); md=sal_call_get_final_media_description(h); if (md==NULL){ if (lc->ringstream!=NULL) return; /*already ringing !*/ @@ -233,16 +237,40 @@ static void call_ack(SalOp *op){ static void call_updated(SalOp *op){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); - if(call == linphone_core_get_current_call(lc)) - { - linphone_core_stop_media_streams(lc,call); - linphone_core_init_media_streams(lc,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_empty(call->resultdesc)){ - linphone_connect_incoming(lc,call); + if (call->resultdesc && !sal_media_description_empty(call->resultdesc)) + { + if( (call->state == LinphoneCallPaused) && strcmp(call->resultdesc->addr,"0.0.0.0")) + { + if(lc->vtable.display_status) + lc->vtable.display_status(lc,"we have been resumed..."); + call->state = LinphoneCallAVRunning; + lc->vtable.resumed_recv(lc,call); + linphone_core_start_media_streams(lc,call); + } + else if( (call->state != LinphoneCallPaused) && !strcmp(call->resultdesc->addr,"0.0.0.0")) + { + if(lc->vtable.display_status) + lc->vtable.display_status(lc,"we have been paused..."); + call->state = LinphoneCallPaused; + lc->vtable.paused_recv(lc,call); + if(call == linphone_core_get_current_call(lc)) + { + linphone_core_stop_media_streams(lc,call); + linphone_core_init_media_streams(lc,call); + } + } + else + { + if(call == linphone_core_get_current_call(lc)) + { + linphone_core_stop_media_streams(lc,call); + linphone_core_init_media_streams(lc,call); + } + linphone_connect_incoming(lc,call); + } } } @@ -276,7 +304,7 @@ static void call_terminated(SalOp *op, const char *from){ linphone_call_unref(call); } -static void call_failure(SalOp *op, SalError error, SalReason sr, const char *details){ +static void call_failure(SalOp *op, SalError error, SalReason sr, const char *details, int code){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); char *msg486=_("User is busy."); char *msg480=_("User is temporarily unavailable."); @@ -336,6 +364,8 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de lc->vtable.display_status(lc,_("Call failed.")); } } + if (lc->vtable.failure_recv) + lc->vtable.failure_recv(lc,call,code); if (lc->ringstream!=NULL) { ring_stop(lc->ringstream); lc->ringstream=NULL; @@ -415,8 +445,9 @@ static void dtmf_received(SalOp *op, char dtmf){ static void refer_received(Sal *sal, SalOp *op, const char *referto){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal); + LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); if (lc->vtable.refer_received){ - lc->vtable.refer_received(lc,referto); + lc->vtable.refer_received(lc,call,referto); if (op) sal_refer_accept(op); } } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index f9d3f29bf..d21b81cf1 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1574,6 +1574,8 @@ LinphoneAddress * linphone_core_interpret_url(LinphoneCore *lc, const char *url) lc->vtable.display_status(lc,_("Looking for telephone number destination...")); if (enum_lookup(enum_domain,&enumres)<0){ lc->vtable.display_status(lc,_("Could not resolve this number.")); + if(lc->vtable.failure_recv) + lc->vtable.failure_recv(lc,NULL,400); ms_free(enum_domain); return NULL; } @@ -2205,7 +2207,11 @@ int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *call) const char *contact=NULL; if (call==NULL){ - return -1; + //if just one call is present answer the only one ... + if(ms_list_size(linphone_core_get_calls(lc)) != 1) + return -1; + else + call = linphone_core_get_calls(lc)->data; } if (call->state==LinphoneCallAVRunning){ diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index fc735fd6c..5c250731f 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -398,6 +398,16 @@ typedef void (*InviteReceivedCb)(struct _LinphoneCore *lc, LinphoneCall *call); /** Callback prototype */ typedef void (*ByeReceivedCb)(struct _LinphoneCore *lc, LinphoneCall *call); /** Callback prototype */ +typedef void (*RingingReceivedCb)(struct _LinphoneCore *lc, LinphoneCall *call); +/** Callback prototype */ +typedef void (*ConnectedReceivedCb)(struct _LinphoneCore *lc, LinphoneCall *call); +/** Callback prototype */ +typedef void (*FailureReceivedCb)(struct _LinphoneCore *lc, LinphoneCall *call, int error_code); +/** Callback prototype */ +typedef void (*PausedReceivedCb)(struct _LinphoneCore *lc, LinphoneCall *call); +/** Callback prototype */ +typedef void (*ResumedReceivedCb)(struct _LinphoneCore *lc, LinphoneCall *call); +/** Callback prototype */ typedef void (*DisplayStatusCb)(struct _LinphoneCore *lc, const char *message); /** Callback prototype */ typedef void (*DisplayMessageCb)(struct _LinphoneCore *lc, const char *message); @@ -424,7 +434,7 @@ typedef void (*GeneralStateChange)(struct _LinphoneCore *lc, LinphoneGeneralStat /** Callback prototype */ typedef void (*DtmfReceived)(struct _LinphoneCore* lc, int dtmf); /** Callback prototype */ -typedef void (*ReferReceived)(struct _LinphoneCore *lc, const char *refer_to); +typedef void (*ReferReceived)(struct _LinphoneCore *lc, LinphoneCall *call, const char *refer_to); /** Callback prototype */ typedef void (*BuddyInfoUpdated)(struct _LinphoneCore *lc, LinphoneFriend *lf); @@ -437,6 +447,11 @@ typedef struct _LinphoneVTable ShowInterfaceCb show; /**< Notifies the application that it should show up*/ InviteReceivedCb inv_recv; /**< Notifies incoming calls */ ByeReceivedCb bye_recv; /**< Notify calls terminated by far end*/ + RingingReceivedCb ringing_recv; /**< Notify that the distant phone is ringing*/ + ConnectedReceivedCb connected_recv; /**< Notify that the distant phone answered the call*/ + FailureReceivedCb failure_recv; /**< Notify that the call failed*/ + PausedReceivedCb paused_recv; /**< Notify that the call failed*/ + ResumedReceivedCb resumed_recv; /**< Notify that the call failed*/ NotifyPresenceReceivedCb notify_presence_recv; /**< Notify received presence events*/ NewUnknownSubscriberCb new_unknown_subscriber; /**< Notify about unknown subscriber */ AuthInfoRequested auth_info_requested; /**< Ask the application some authentication information */ diff --git a/coreapi/sal.h b/coreapi/sal.h index 8aedd4487..7643ab7da 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -177,7 +177,7 @@ typedef void (*SalOnCallAccepted)(SalOp *op); typedef void (*SalOnCallAck)(SalOp *op); typedef void (*SalOnCallUpdated)(SalOp *op); typedef void (*SalOnCallTerminated)(SalOp *op, const char *from); -typedef void (*SalOnCallFailure)(SalOp *op, SalError error, SalReason reason, const char *details); +typedef void (*SalOnCallFailure)(SalOp *op, SalError error, SalReason reason, const char *details, int code); typedef void (*SalOnAuthRequested)(SalOp *op, const char *realm, const char *username); typedef void (*SalOnAuthSuccess)(SalOp *op, const char *realm, const char *username); typedef void (*SalOnRegisterSuccess)(SalOp *op, bool_t registered); diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index 7c4a24db7..94a51fa24 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -915,7 +915,7 @@ static void call_released(Sal *sal, eXosip_event_t *ev){ } op->cid=-1; if (op->did==-1) - sal->callbacks.call_failure(op,SalErrorNoResponse,SalReasonUnknown,NULL); + sal->callbacks.call_failure(op,SalErrorNoResponse,SalReasonUnknown,NULL, 487); } static int get_auth_data_from_response(osip_message_t *resp, const char **realm, const char **username){ @@ -1066,7 +1066,7 @@ static bool_t call_failure(Sal *sal, eXosip_event_t *ev){ sr=SalReasonUnknown; }else error=SalErrorNoResponse; } - sal->callbacks.call_failure(op,error,sr,reason); + sal->callbacks.call_failure(op,error,sr,reason,code); return TRUE; } diff --git a/gtk-glade/main.c b/gtk-glade/main.c index 2fd3f6d62..719ae5987 100644 --- a/gtk-glade/main.c +++ b/gtk-glade/main.c @@ -54,7 +54,7 @@ static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const ch static void linphone_gtk_display_question(LinphoneCore *lc, const char *question); static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl); static void linphone_gtk_general_state(LinphoneCore *lc, LinphoneGeneralState *gstate); -static void linphone_gtk_refer_received(LinphoneCore *lc, const char *refer_to); +static void linphone_gtk_refer_received(LinphoneCore *lc, LinphoneCall *call, const char *refer_to); static gboolean linphone_gtk_auto_answer(GtkWidget *incall_window); static LinphoneCoreVTable vtable={ @@ -1210,7 +1210,7 @@ void linphone_gtk_log_handler(OrtpLogLevel lev, const char *fmt, va_list args){ } -static void linphone_gtk_refer_received(LinphoneCore *lc, const char *refer_to){ +static void linphone_gtk_refer_received(LinphoneCore *lc, LinphoneCall *call, const char *refer_to){ GtkEntry * uri_bar =GTK_ENTRY(linphone_gtk_get_widget( linphone_gtk_get_main_window(), "uribar")); linphone_gtk_show_main_window(); diff --git a/mediastreamer2 b/mediastreamer2 index b340a76e9..5b8a7c368 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit b340a76e998c7dd2670372212b0bf14d7c59b987 +Subproject commit 5b8a7c368076733d478aa7e49149975915408483 From 26f0cd94c85a88f73738ffa432e8dea6cef9daf9 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 7 May 2010 21:53:02 +0200 Subject: [PATCH 07/45] enhance .gitignores --- .gitignore | 11 +++++++++++ mediastreamer2 | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 1473464cd..7de3a426a 100644 --- a/.gitignore +++ b/.gitignore @@ -31,4 +31,15 @@ msx264.iss linphone-install buddylookup-install msx264-install +*.tar.gz +intltool-extract.in +intltool-merge.in +intltool-update.in +INSTALL +Specfile +.anjuta/ +.anjuta_sym_db.db +coreapi/help/doxygen.dox +gtk-glade/version_date.h +share/linphone.desktop diff --git a/mediastreamer2 b/mediastreamer2 index 5b8a7c368..f315bd22f 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 5b8a7c368076733d478aa7e49149975915408483 +Subproject commit f315bd22ffbbe9a07d079c2859ea67e831f94e52 From 0741eb17a219b36c04c4f8e19969e03d691f3f8e Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 10 May 2010 15:27:06 +0200 Subject: [PATCH 08/45] keep sending streams when put on hold by remote --- coreapi/callbacks.c | 6 +++++- coreapi/linphonecall.c | 4 +++- mediastreamer2 | 2 +- oRTP | 2 +- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index cb9999a01..ff155b6dd 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -248,7 +248,8 @@ static void call_updated(SalOp *op){ lc->vtable.display_status(lc,"we have been resumed..."); call->state = LinphoneCallAVRunning; lc->vtable.resumed_recv(lc,call); - linphone_core_start_media_streams(lc,call); + //we have to keep sending when holded + //linphone_core_start_media_streams(lc,call); } else if( (call->state != LinphoneCallPaused) && !strcmp(call->resultdesc->addr,"0.0.0.0")) { @@ -256,11 +257,14 @@ static void call_updated(SalOp *op){ lc->vtable.display_status(lc,"we have been paused..."); call->state = LinphoneCallPaused; lc->vtable.paused_recv(lc,call); + //we have to keep sending when holded + /* if(call == linphone_core_get_current_call(lc)) { linphone_core_stop_media_streams(lc,call); linphone_core_init_media_streams(lc,call); } + */ } else { diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 5a85e7efa..060de0a0e 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -18,7 +18,9 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - +#ifdef WIN32 +#include +#endif #include "linphonecore.h" #include "sipsetup.h" #include "lpconfig.h" diff --git a/mediastreamer2 b/mediastreamer2 index f315bd22f..488263428 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit f315bd22ffbbe9a07d079c2859ea67e831f94e52 +Subproject commit 4882634280c82ca495d5bebec482d2744ddb7f61 diff --git a/oRTP b/oRTP index 92c452dcd..ba73b8155 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 92c452dcd38b26a0ce41d10be9a32d37f72a7d27 +Subproject commit ba73b8155b3a6aa64f8df95dee6b25ca9b95cbca From ce9a956c38ad2b5735053372d01c7f5e8029ab68 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 12 May 2010 10:01:48 +0200 Subject: [PATCH 09/45] make mediastreamer2 to the correct branch/version --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index bc6c0ed4c..d45f8e79e 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit bc6c0ed4c16db22c9d7cecec9d0c309c722e08ea +Subproject commit d45f8e79e37c1754e8f09c1f299cef1a57db66f6 From 1135f599f10a33ac7e1438129f1427eb51a483f0 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 21 May 2010 14:58:03 +0200 Subject: [PATCH 10/45] merge patch from aurel --- console/linphonec.c | 32 ++++++++++ coreapi/callbacks.c | 46 ++++++++++++-- coreapi/linphonecore.c | 132 +++++++++++++++++++++++++++++------------ coreapi/linphonecore.h | 10 +++- coreapi/sal_eXosip2.c | 8 ++- mediastreamer2 | 2 +- oRTP | 2 +- 7 files changed, 184 insertions(+), 48 deletions(-) diff --git a/console/linphonec.c b/console/linphonec.c index 86187ad7c..024075cf0 100644 --- a/console/linphonec.c +++ b/console/linphonec.c @@ -123,6 +123,8 @@ static void linphonec_display_url (LinphoneCore * lc, const char *something, con static void linphonec_display_warning (LinphoneCore * lc, const char *something); static void stub () {} static void linphonec_notify_received(LinphoneCore *lc,const char *from,const char *msg); +static void linphonec_ack_paused_received(LinphoneCore *lc, LinphoneCall *call); +static void linphonec_ack_resumed_received(LinphoneCore *lc, LinphoneCall *call); static void linphonec_notify_presence_received(LinphoneCore *lc,LinphoneFriend *fid); static void linphonec_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url); @@ -185,6 +187,8 @@ LinphoneCoreVTable linphonec_vtable .paused_recv = linphonec_paused_received, .resumed_recv = linphonec_resumed_received, .notify_recv = linphonec_notify_received, + .ack_paused_recv = linphonec_ack_paused_received, + .ack_resumed_recv = linphonec_ack_resumed_received, .notify_presence_recv = linphonec_notify_presence_received, .new_unknown_subscriber = linphonec_new_unknown_subscriber, .auth_info_requested = linphonec_prompt_for_auth, @@ -344,6 +348,34 @@ linphonec_notify_received(LinphoneCore *lc,const char *from,const char *msg) } } +/* + * Linphone core callback + */ +static void +linphonec_ack_paused_received(LinphoneCore *lc, LinphoneCall *call) +{ + char *from=linphone_call_get_remote_address_as_string(call); + if(from) + { + linphonec_out("the previous pause sent to %s has been acknowledged\n",from); + ms_free(from); + } +} + +/* + * Linphone core callback + */ +static void +linphonec_ack_resumed_received(LinphoneCore *lc, LinphoneCall *call) +{ + char *from=linphone_call_get_remote_address_as_string(call); + if(from) + { + linphonec_out("the previous resume sent to %s has been acknowledged\n",from); + ms_free(from); + } +} + /* * Linphone core callback */ diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 67611e2e3..1af84c194 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -37,6 +37,10 @@ static void linphone_connect_incoming(LinphoneCore *lc, LinphoneCall *call){ ring_stop(lc->ringstream); lc->ringstream=NULL; } + if(!linphone_core_in_call(lc)) + { + linphone_core_set_as_current_call(lc,call); + } if(call == linphone_core_get_current_call(lc)) linphone_core_start_media_streams(lc,call); } @@ -114,8 +118,15 @@ static void call_received(SalOp *h){ /* play the ring */ if (lc->sound_conf.ring_sndcard!=NULL && !linphone_core_in_call(lc)){ - ms_message("Starting local ring..."); - lc->ringstream=ring_start(lc->sound_conf.local_ring,2000,lc->sound_conf.ring_sndcard); + if(lc->ringstream==NULL) + { + ms_message("Starting local ring..."); + lc->ringstream=ring_start(lc->sound_conf.local_ring,2000,lc->sound_conf.ring_sndcard); + } + else + { + ms_message("the local ring is already started"); + } } call->state=LinphoneCallRinging; sal_call_notify_ringing(h); @@ -166,6 +177,11 @@ static void call_ringing(SalOp *h){ call->state=LinphoneCallRinging; } +/* + * could be reach : + * - when the call is accepted + * - when a request is accepted (pause, resume) + */ 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); @@ -174,7 +190,10 @@ static void call_accepted(SalOp *op){ return ; } if (call->state==LinphoneCallAVRunning){ - return ; /*already accepted*/ + ms_message("GET ACK of resume\n"); + if(lc->vtable.ack_resumed_recv) + lc->vtable.ack_resumed_recv(lc,call); + return ; //already accepted } if ((lc->audiostream!=NULL) && (lc->audiostream->ticker!=NULL)){ /*case where we accepted early media */ @@ -192,8 +211,18 @@ static void call_accepted(SalOp *op){ call->media_pending=FALSE; } if (call->resultdesc && !sal_media_description_empty(call->resultdesc)){ - gstate_new_state(lc, GSTATE_CALL_OUT_CONNECTED, NULL); - linphone_connect_incoming(lc,call); + //if we initiate a pause + if(call->state == LinphoneCallPaused) + { + ms_message("GET ACK of pause\n"); + if(lc->vtable.ack_paused_recv) + lc->vtable.ack_paused_recv(lc,call); + }//if there is an accepted incoming call + else + { + gstate_new_state(lc, GSTATE_CALL_OUT_CONNECTED, NULL); + linphone_connect_incoming(lc,call); + } }else{ /*send a bye*/ ms_error("Incompatible SDP offer received in 200Ok, need to abort the call"); @@ -289,7 +318,8 @@ static void call_terminated(SalOp *op, const char *from){ return; } ms_message("Current call terminated..."); - if (lc->ringstream!=NULL) { + //we stop the call only if we have this current call or if we are in call + if (lc->ringstream!=NULL && ( (ms_list_size(lc->calls) == 1) || linphone_core_in_call(lc) )) { ring_stop(lc->ringstream); lc->ringstream=NULL; } @@ -501,6 +531,10 @@ static void ping_reply(SalOp *op){ linphone_core_start_invite(call->core,call,NULL); } } + else + { + ms_warning("ping reply without call attached..."); + } } SalCallbacks linphone_sal_callbacks={ diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 5f7ae7afa..e45a1213c 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1359,9 +1359,22 @@ static void display_bandwidth(RtpSession *as, RtpSession *vs){ (vs!=NULL) ? (rtp_session_compute_send_bandwidth(vs)*1e-3) : 0); } -static void linphone_core_disconnected(LinphoneCore *lc){ - lc->vtable.display_warning(lc,_("Remote end seems to have disconnected, the call is going to be closed.")); - linphone_core_terminate_call(lc,NULL); +static void linphone_core_disconnected(LinphoneCore *lc, LinphoneCall *call){ + char temp[256]; + char *from; + if(call) + from = linphone_call_get_remote_address_as_string(call); + if(from) + { + snprintf(temp,sizeof(temp),"Remote end %s seems to have disconnected, the call is going to be closed.",from); + free(from); + } + else + { + snprintf(temp,sizeof(temp),"Remote end seems to have disconnected, the call is going to be closed."); + } + lc->vtable.display_warning(lc,temp); + linphone_core_terminate_call(lc,call);//TODO failure ?? } static void monitor_network_state(LinphoneCore *lc, time_t curtime){ @@ -1477,6 +1490,8 @@ static void linphone_core_do_plugin_tasks(LinphoneCore *lc){ * serialized with a mutex. **/ void linphone_core_iterate(LinphoneCore *lc){ + MSList *the_call; + LinphoneCall *call; int disconnect_timeout = linphone_core_get_nortp_timeout(lc); time_t curtime=time(NULL); int elapsed; @@ -1499,21 +1514,35 @@ void linphone_core_iterate(LinphoneCore *lc){ if (lc->auto_net_state_mon) monitor_network_state(lc,curtime); proxy_update(lc); - LinphoneCall *call = linphone_core_get_current_call(lc); - if(call){ + + //we have to iterate for each call + the_call = lc->calls; + while(the_call != NULL) + { + call = (LinphoneCall *)the_call->data; if (call->state==LinphoneCallPreEstablishing && (curtime-call->start_time>=2)){ - /*start the call even if the OPTIONS reply did not arrive*/ - linphone_core_start_invite(lc,call,NULL); - } - if (call->dir==LinphoneCallIncoming && call->state==LinphoneCallRinging){ - elapsed=curtime-call->start_time; - ms_message("incoming call ringing for %i seconds",elapsed); - if (elapsed>lc->sip_conf.inc_timeout){ - call->log->status=LinphoneCallMissed; - linphone_core_terminate_call(lc,NULL); + /*start the call even if the OPTIONS reply did not arrive*/ + linphone_core_start_invite(lc,call,NULL); } - }else if (call->state==LinphoneCallAVRunning){ - if (one_second_elapsed){ + if (call->dir==LinphoneCallIncoming && call->state==LinphoneCallRinging){ + elapsed=curtime-call->start_time; + ms_message("incoming call ringing for %i seconds",elapsed); + if (elapsed>lc->sip_conf.inc_timeout){ + call->log->status=LinphoneCallMissed; + linphone_core_terminate_call(lc,call); + } + } + + the_call = the_call->next; + }//end while + //and consider the current call + call = linphone_core_get_current_call(lc); + if(call) + { + if (call->state==LinphoneCallAVRunning) + { + if (one_second_elapsed) + { RtpSession *as=NULL,*vs=NULL; lc->prevtime=curtime; if (lc->audiostream!=NULL) @@ -1541,7 +1570,7 @@ void linphone_core_iterate(LinphoneCore *lc){ toggle_video_preview(lc,FALSE); } if (disconnected) - linphone_core_disconnected(lc); + linphone_core_disconnected(lc,call); linphone_core_do_plugin_tasks(lc); @@ -1749,7 +1778,9 @@ int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, LinphonePro ms_free(contact); } call->state=LinphoneCallInit; - linphone_core_init_media_streams(lc,call); + //TODO : should probably not be done here + if(! linphone_core_in_call(lc) ) + linphone_core_init_media_streams(lc,call); if (!lc->sip_conf.sdp_200_ack){ call->media_pending=TRUE; sal_call_set_local_media_description(call->op,call->localdesc); @@ -1852,7 +1883,6 @@ LinphoneCall * linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddr linphone_call_unref(call); return NULL; } - linphone_core_set_as_current_call(lc,call); if (dest_proxy!=NULL || lc->sip_conf.ping_with_options==FALSE){ err=linphone_core_start_invite(lc,call,dest_proxy); }else{ @@ -1904,6 +1934,9 @@ bool_t linphone_core_inc_invite_pending(LinphoneCore*lc){ } void linphone_core_init_media_streams(LinphoneCore *lc, LinphoneCall *call){ +#ifdef PRINTF_DEBUG + printf("%s(%d)\n",__FUNCTION__,__LINE__); +#endif SalMediaDescription *md=call->localdesc; lc->audiostream=audio_stream_new(md->streams[0].port,linphone_core_ipv6_enabled(lc)); if (linphone_core_echo_limiter_enabled(lc)){ @@ -2064,10 +2097,22 @@ static RtpProfile *make_profile(LinphoneCore *lc, const SalMediaDescription *md, } void linphone_core_start_media_streams(LinphoneCore *lc, LinphoneCall *call){ +#ifdef PRINTF_DEBUG + printf("%s(%d)\n",__FUNCTION__,__LINE__); +#endif LinphoneAddress *me=linphone_core_get_primary_contact_parsed(lc); const char *tool="linphone-" LINPHONE_VERSION; char *cname; int used_pt=-1; + if(lc->audiostream == NULL) + { + ms_warning("init media stream is needed before starting"); + linphone_core_init_media_streams(lc,call); + /* + * example of problem : + * 2 incomings calls, you answer and pause one, afterward if you try to answer the other call you will get SEGFAULT + */ + } /* adjust rtp jitter compensation. It must be at least the latency of the sound card */ int jitt_comp=MAX(lc->sound_conf.latency,lc->rtp_conf.audio_jitt_comp); @@ -2157,6 +2202,9 @@ void linphone_core_start_media_streams(LinphoneCore *lc, LinphoneCall *call){ } void linphone_core_stop_media_streams(LinphoneCore *lc, LinphoneCall *call){ +#ifdef PRINTF_DEBUG + printf("%s(%d)\n",__FUNCTION__,__LINE__); +#endif if (lc->audiostream!=NULL) { audio_stream_stop(lc->audiostream); lc->audiostream=NULL; @@ -2297,13 +2345,10 @@ int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *the_call) * @param lc The LinphoneCore **/ int linphone_core_terminate_all_calls(LinphoneCore *lc){ - MSList *calls; - - calls = lc->calls; - while(calls->next != NULL) + while(lc->calls) { - linphone_core_terminate_call(lc,(LinphoneCall *)calls->data); - calls = calls->next; + LinphoneCall *the_call = lc->calls->data; + linphone_core_terminate_call(lc,the_call); } ms_list_free(lc->calls); return -1; @@ -2370,10 +2415,15 @@ int linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *the_call) ms_error("The call asked to be paused was not the current on\n"); return -3; } - sal_call_hold(call->op,TRUE); + if(sal_call_hold(call->op,TRUE) != 0) + { + lc->vtable.display_warning(lc,_("Could not pause the call")); + } call->state = LinphoneCallPaused; linphone_core_unset_the_current_call(lc); linphone_core_stop_media_streams(lc,call); + //have to be done ... because if another call is incoming before this pause, you will get sound on the end point paused + linphone_core_init_media_streams(lc,call); lc->vtable.display_status(lc,_("Pause the current call")); return 0; } @@ -2407,13 +2457,21 @@ int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *the_call) return -2; } } + if(call->state == LinphoneCallInit || call->state == LinphoneCallPreEstablishing || call->state == LinphoneCallRinging ) + { + ms_warning("we cannot resume a call when the communication is not established"); + return -3; + } if(linphone_core_get_current_call(lc) != NULL) { ms_error("There is already a call in process pause or stop it first\n"); - return -3; + return -4; } linphone_core_init_media_streams(lc,call); - sal_call_hold(call->op,FALSE); + if(sal_call_hold(call->op,FALSE) != 0) + { + lc->vtable.display_warning(lc,_("Could not resume the call")); + } call->state = LinphoneCallAVRunning; linphone_core_set_as_current_call(lc,call); linphone_core_start_media_streams(lc,call); @@ -3544,18 +3602,18 @@ LpConfig *linphone_core_get_config(LinphoneCore *lc){ static void linphone_core_uninit(LinphoneCore *lc) { - if(linphone_core_get_calls_nb(lc)){ - int i; - linphone_core_terminate_all_calls(lc); - for(i=0;i<10;++i){ -#ifndef WIN32 - usleep(50000); + while(lc->calls) + { + LinphoneCall *the_call = lc->calls->data; + linphone_core_terminate_call(lc,the_call); + linphone_core_iterate(lc); +#ifdef WIN32 + Sleep(50000); #else - Sleep(50); + usleep(50000); #endif - linphone_core_iterate(lc); - } } + if (lc->friends) ms_list_for_each(lc->friends,(void (*)(void *))linphone_friend_close_subscriptions); gstate_new_state(lc, GSTATE_POWER_SHUTDOWN, NULL); diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 5c250731f..d7ac4abcc 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -408,6 +408,10 @@ typedef void (*PausedReceivedCb)(struct _LinphoneCore *lc, LinphoneCall *call); /** Callback prototype */ typedef void (*ResumedReceivedCb)(struct _LinphoneCore *lc, LinphoneCall *call); /** Callback prototype */ +typedef void (*AckPausedReceivedCb)(struct _LinphoneCore *lc, LinphoneCall *call); +/** Callback prototype */ +typedef void (*AckResumedReceivedCb)(struct _LinphoneCore *lc, LinphoneCall *call); +/** Callback prototype */ typedef void (*DisplayStatusCb)(struct _LinphoneCore *lc, const char *message); /** Callback prototype */ typedef void (*DisplayMessageCb)(struct _LinphoneCore *lc, const char *message); @@ -450,8 +454,10 @@ typedef struct _LinphoneVTable RingingReceivedCb ringing_recv; /**< Notify that the distant phone is ringing*/ ConnectedReceivedCb connected_recv; /**< Notify that the distant phone answered the call*/ FailureReceivedCb failure_recv; /**< Notify that the call failed*/ - PausedReceivedCb paused_recv; /**< Notify that the call failed*/ - ResumedReceivedCb resumed_recv; /**< Notify that the call failed*/ + PausedReceivedCb paused_recv; /**< Notify that the call has been paused*/ + ResumedReceivedCb resumed_recv; /**< Notify that the call has been resumed*/ + AckPausedReceivedCb ack_paused_recv;/**< Notify that the previous command pause sent to the call has been acknowledge*/ + AckResumedReceivedCb ack_resumed_recv;/**< Notify that the previous command resumed sent to the call has been acknowledge*/ NotifyPresenceReceivedCb notify_presence_recv; /**< Notify received presence events*/ NewUnknownSubscriberCb new_unknown_subscriber; /**< Notify about unknown subscriber */ AuthInfoRequested auth_info_requested; /**< Ask the application some authentication information */ diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index 94a51fa24..6091f18db 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -1427,6 +1427,9 @@ static void other_request_reply(Sal *sal,eXosip_event_t *ev){ } static bool_t process_event(Sal *sal, eXosip_event_t *ev){ +#ifdef PRINTF_DEBUG + printf("EVENT (%d)\n",ev->type); +#endif ms_message("linphone process event get a message %d\n",ev->type); switch(ev->type){ case EXOSIP_CALL_ANSWERED: @@ -1716,7 +1719,10 @@ int sal_call_hold(SalOp *h, bool_t holdon) int err=0; osip_message_t *reinvite; - eXosip_call_build_request(h->did,"INVITE",&reinvite); + if(eXosip_call_build_request(h->did,"INVITE",&reinvite) != OSIP_SUCCESS) + return -1; + if(reinvite==NULL) + return -2; osip_message_set_subject(reinvite,osip_strdup("Phone Call Hold")); osip_message_set_allow(reinvite, "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO"); if (h->base.root->session_expires!=0){ diff --git a/mediastreamer2 b/mediastreamer2 index d45f8e79e..57896d513 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit d45f8e79e37c1754e8f09c1f299cef1a57db66f6 +Subproject commit 57896d513f6fbf41fde3c777931ebc744e53e366 diff --git a/oRTP b/oRTP index ba73b8155..4ad63e9a1 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit ba73b8155b3a6aa64f8df95dee6b25ca9b95cbca +Subproject commit 4ad63e9a106aee8d9dfb675aa0532962f322609c From 3d99d13bf68e0864d540f3c91dfa7af3964a1920 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 25 May 2010 18:04:02 +0200 Subject: [PATCH 11/45] sound daemon: work in progress --- coreapi/linphonecore_utils.h | 50 +++++++++ coreapi/lsd.c | 198 +++++++++++++++++++++++++++++++++++ 2 files changed, 248 insertions(+) create mode 100644 coreapi/linphonecore_utils.h create mode 100644 coreapi/lsd.c diff --git a/coreapi/linphonecore_utils.h b/coreapi/linphonecore_utils.h new file mode 100644 index 000000000..1eeda5f3f --- /dev/null +++ b/coreapi/linphonecore_utils.h @@ -0,0 +1,50 @@ +/* +linphone +Copyright (C) 2010 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef LINPHONECORE_UTILS_H +#define LINPHONECORE_UTILS_H + +#ifdef IN_LINPHONE +#include "linphonecore.h" +#else +#include "linphone/linphonecore.h" +#endif + +typedef struct _LsdPlayer LsdPlayer; +typedef struct _LinphoneSoundDaemon LinphoneSoundDaemon; + +typedef void (*LsdEndOfPlayCallback)(LsdPlayer *p); + +LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname); + +LsdPlayer * linphone_sound_daemon_get_player(LinphoneSoundDaemon *lsd); +void linphone_sound_daemon_release_player(LinphoneSoundDaemon *lsd, LsdPlayer *lsdplayer); + +MSFilter *linphone_sound_daemon_get_proxy(LinphoneSoundDaemon *obj); + +void linphone_sound_daemon_destroy(LinphoneSoundDaemon *obj); + +void lsd_player_set_callback(LsdPlayer *p, LsdEndOfPlayCallback cb); +void lsd_player_set_user_pointer(LsdPlayer *p, void *up); +void *lsd_player_get_user_pointer(LsdPlayer *p); +int lsd_player_play(LsdPlayer *p, const char *filename); +int lsd_player_stop(LsdPlayer *p); +void lsd_player_enable_loop(LsdPlayer *p, bool_t loopmode); + +#endif diff --git a/coreapi/lsd.c b/coreapi/lsd.c new file mode 100644 index 000000000..d4f6dae48 --- /dev/null +++ b/coreapi/lsd.c @@ -0,0 +1,198 @@ +/* +linphone +Copyright (C) 2010 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/* Linphone Sound Daemon: is a lightweight utility to play sounds to speaker during a conversation. + This is useful for embedded platforms, where sound apis are not performant enough to allow + simultaneous sound access. +*/ + +#include "linphonecore_utils.h" +#include "mediastreamer2/mssndcard.h" +#include "mediastreamer2/msvolume.h" + + +#define MAX_BRANCHES 10 + + +struct _LsdPlayer{ + struct _LinphoneSoundDaemon *lsd; + MSFilter *player; + MSFilter *rateconv; + MSFilter *chanadapter; + MSFilter *volumectl; + LsdEndOfPlayCallback eop_cb; + void *user_data; + bool_t loopmode; +}; + +struct _LinphoneSoundDaemon { + int out_rate; + int out_nchans; + MSFilter *mixer; + MSFilter *soundout; + LsdPlayer branches[MAX_BRANCHES]; +}; + + +LsdPlayer *linphone_sound_daemon_get_player(LinphoneSoundDaemon *obj){ + int i; + for(i=0;ibranches[i]; + MSFilter *p=b->player; + int state; + ms_filter_call_method(p,MS_PLAYER_GET_STATE,&state); + if (state==MSPlayerClosed){ + return b; + } + } + ms_warning("No more free players !"); + return NULL; +} + +void linphone_sound_daemon_release_player(LinphoneSoundDaemon *obj, LsdPlayer * player){ + int state; + float gain=1; + ms_filter_call_method(player->player,MS_PLAYER_GET_STATE,&state); + if (state!=MSPlayerClosed){ + ms_filter_call_method(player->player,MS_PLAYER_CLOSE,&state); + } + ms_filter_call_method(player->volumectl,MS_VOLUME_SET_GAIN,&gain); +} + +int lsd_player_stop(LsdPlayer *p){ + ms_filter_call_method_noarg(p->player,MS_PLAYER_PAUSE); + return 0; +} + +MSFilter *linphone_sound_daemon_get_proxy(LinphoneSoundDaemon *obj); +void linphone_sound_daemon_destroy(LinphoneSoundDaemon *obj); + +static void lsd_player_init(LsdPlayer *p, MSConnectionPoint mixer, MSFilterId playerid, LinphoneSoundDaemon *lsd){ + MSConnectionHelper h; + p->player=ms_filter_new(playerid); + p->rateconv=ms_filter_new(MS_RESAMPLE_ID); + p->chanadapter=NULL; + p->volumectl=ms_filter_new(MS_VOLUME_ID); + + ms_connection_helper_start(&h); + ms_connection_helper_link(&h,p->player,-1,0); + ms_connection_helper_link(&h,p->rateconv,0,0); + ms_connection_helper_link(&h,p->chanadapter,0,0); + ms_connection_helper_link(&h,p->volumectl,0,0); + ms_connection_helper_link(&h,mixer.filter,mixer.pin,-1); + p->lsd=lsd; +} + +static void lsd_player_uninit(LsdPlayer *p, MSConnectionPoint mixer){ + MSConnectionHelper h; + + ms_connection_helper_start(&h); + ms_connection_helper_unlink (&h,p->player,-1,0); + ms_connection_helper_unlink(&h,p->rateconv,0,0); + ms_connection_helper_unlink(&h,p->chanadapter,0,0); + ms_connection_helper_unlink(&h,p->volumectl,0,0); + ms_connection_helper_unlink(&h,mixer.filter,mixer.pin,-1); + + ms_filter_destroy(p->player); + ms_filter_destroy(p->rateconv); + ms_filter_destroy(p->chanadapter); + ms_filter_destroy(p->volumectl); +} + +void lsd_player_set_callback(LsdPlayer *p, LsdEndOfPlayCallback cb){ + p->eop_cb=cb; +} + +void lsd_player_set_user_pointer(LsdPlayer *p, void *up){ + p->user_data=up; +} + +void *lsd_player_get_user_pointer(LsdPlayer *p){ + return p->user_data; +} + +static void lsd_player_on_eop(void * userdata, unsigned int id, void *arg){ +} + +int lsd_player_play(LsdPlayer *b, const char *filename ){ + int rate,chans; + int state; + LinphoneSoundDaemon *lsd=b->lsd; + + ms_filter_call_method(b->player,MS_PLAYER_GET_STATE,&state); + if (state!=MSPlayerClosed){ + ms_filter_call_method_noarg(b->player,MS_PLAYER_CLOSE); + } + + if (ms_filter_call_method(b->player,MS_PLAYER_OPEN,(void*)filename)!=0){ + return -1; + } + ms_filter_call_method(b->player,MS_FILTER_GET_SAMPLE_RATE,&rate); + ms_filter_call_method(b->player,MS_FILTER_GET_NCHANNELS,&chans); + ms_filter_set_notify_callback (b->player,lsd_player_on_eop,b); + + ms_filter_call_method(b->rateconv,MS_FILTER_SET_SAMPLE_RATE,&rate); + ms_filter_call_method(b->rateconv,MS_FILTER_SET_NCHANNELS,&chans); + ms_filter_call_method(b->rateconv,MS_FILTER_SET_OUTPUT_SAMPLE_RATE,&lsd->out_rate); + + ms_filter_call_method(b->chanadapter,MS_FILTER_SET_NCHANNELS,&chans); + ms_filter_call_method(b->chanadapter,MS_FILTER_SET_OUTPUT_NCHANNELS,&lsd->out_nchans); + return 0; +} + +int lsd_player_stop(LsdPlayer *p); +void lsd_player_enable_loop(LsdPlayer *p, bool_t loopmode); + +LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname){ + int i; + MSConnectionPoint mp; + LinphoneSoundDaemon *lsd; + MSSndCard *card=ms_snd_card_manager_get_card( + ms_snd_card_manager_get(), + cardname); + if (card==NULL){ + card=ms_snd_card_manager_get_default_playback_card ( + ms_snd_card_manager_get()); + if (card==NULL){ + ms_error("linphone_sound_daemon_new(): No playback soundcard available"); + return NULL; + } + } + + lsd=ms_new0(LinphoneSoundDaemon,1); + lsd->soundout=ms_snd_card_create_writer(card); + lsd->out_rate=44100; + lsd->out_nchans=2; + ms_filter_call_method(lsd->soundout,MS_FILTER_SET_SAMPLE_RATE,&lsd->out_rate); + ms_filter_call_method(lsd->soundout,MS_FILTER_SET_NCHANNELS,&lsd->out_nchans); + + mp.filter=lsd->filter; + mp.pin=0; + + lsd_player_init(&lsd->branches[0],mp,MS_ITC_SINK_ID,lsd); + for(i=1;ibranches[i],mp,MS_FILE_PLAYER_ID); + } + + return lsd; +} + + +#endif From 0c1555149a5f7d4a8eab7478453473ec115d5798 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 26 May 2010 23:33:02 +0200 Subject: [PATCH 12/45] work in progress --- coreapi/Makefile.am | 3 ++- coreapi/linphonecore_utils.h | 1 + coreapi/lsd.c | 44 +++++++++++++++++++++--------------- 3 files changed, 29 insertions(+), 19 deletions(-) diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index 014ae308e..66a2bf5f6 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -34,7 +34,8 @@ liblinphone_la_SOURCES=\ chat.c \ general_state.c \ sipsetup.c sipsetup.h \ - siplogin.c + siplogin.c \ + lsd.c linphonecore_utils.h liblinphone_la_LDFLAGS= -version-info $(LIBLINPHONE_SO_VERSION) -no-undefined diff --git a/coreapi/linphonecore_utils.h b/coreapi/linphonecore_utils.h index 1eeda5f3f..949cadaa6 100644 --- a/coreapi/linphonecore_utils.h +++ b/coreapi/linphonecore_utils.h @@ -46,5 +46,6 @@ void *lsd_player_get_user_pointer(LsdPlayer *p); int lsd_player_play(LsdPlayer *p, const char *filename); int lsd_player_stop(LsdPlayer *p); void lsd_player_enable_loop(LsdPlayer *p, bool_t loopmode); +void lsd_player_set_gain(LsdPlayer *p, float gain); #endif diff --git a/coreapi/lsd.c b/coreapi/lsd.c index d4f6dae48..34134d00d 100644 --- a/coreapi/lsd.c +++ b/coreapi/lsd.c @@ -24,7 +24,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "linphonecore_utils.h" #include "mediastreamer2/mssndcard.h" -#include "mediastreamer2/msvolume.h" +#include "mediastreamer2/msaudiomixer.h" +#include "mediastreamer2/mschanadapter.h" +#include "mediastreamer2/msfileplayer.h" + #define MAX_BRANCHES 10 @@ -35,10 +38,9 @@ struct _LsdPlayer{ MSFilter *player; MSFilter *rateconv; MSFilter *chanadapter; - MSFilter *volumectl; LsdEndOfPlayCallback eop_cb; + int mixer_pin; void *user_data; - bool_t loopmode; }; struct _LinphoneSoundDaemon { @@ -49,7 +51,6 @@ struct _LinphoneSoundDaemon { LsdPlayer branches[MAX_BRANCHES]; }; - LsdPlayer *linphone_sound_daemon_get_player(LinphoneSoundDaemon *obj){ int i; for(i=0;iplayer,MS_PLAYER_GET_STATE,&state); if (state!=MSPlayerClosed){ ms_filter_call_method(player->player,MS_PLAYER_CLOSE,&state); } - ms_filter_call_method(player->volumectl,MS_VOLUME_SET_GAIN,&gain); } int lsd_player_stop(LsdPlayer *p){ @@ -87,15 +87,14 @@ static void lsd_player_init(LsdPlayer *p, MSConnectionPoint mixer, MSFilterId pl MSConnectionHelper h; p->player=ms_filter_new(playerid); p->rateconv=ms_filter_new(MS_RESAMPLE_ID); - p->chanadapter=NULL; - p->volumectl=ms_filter_new(MS_VOLUME_ID); - + p->chanadapter=ms_filter_new(MS_CHANNEL_ADAPTER_ID); + ms_connection_helper_start(&h); ms_connection_helper_link(&h,p->player,-1,0); ms_connection_helper_link(&h,p->rateconv,0,0); ms_connection_helper_link(&h,p->chanadapter,0,0); - ms_connection_helper_link(&h,p->volumectl,0,0); ms_connection_helper_link(&h,mixer.filter,mixer.pin,-1); + p->mixer_pin=mixer.pin; p->lsd=lsd; } @@ -106,13 +105,11 @@ static void lsd_player_uninit(LsdPlayer *p, MSConnectionPoint mixer){ ms_connection_helper_unlink (&h,p->player,-1,0); ms_connection_helper_unlink(&h,p->rateconv,0,0); ms_connection_helper_unlink(&h,p->chanadapter,0,0); - ms_connection_helper_unlink(&h,p->volumectl,0,0); ms_connection_helper_unlink(&h,mixer.filter,mixer.pin,-1); ms_filter_destroy(p->player); ms_filter_destroy(p->rateconv); ms_filter_destroy(p->chanadapter); - ms_filter_destroy(p->volumectl); } void lsd_player_set_callback(LsdPlayer *p, LsdEndOfPlayCallback cb){ @@ -152,12 +149,25 @@ int lsd_player_play(LsdPlayer *b, const char *filename ){ ms_filter_call_method(b->rateconv,MS_FILTER_SET_OUTPUT_SAMPLE_RATE,&lsd->out_rate); ms_filter_call_method(b->chanadapter,MS_FILTER_SET_NCHANNELS,&chans); - ms_filter_call_method(b->chanadapter,MS_FILTER_SET_OUTPUT_NCHANNELS,&lsd->out_nchans); + ms_filter_call_method(b->chanadapter,MS_CHANNEL_ADAPTER_SET_OUTPUT_NCHANNELS,&lsd->out_nchans); return 0; } int lsd_player_stop(LsdPlayer *p); -void lsd_player_enable_loop(LsdPlayer *p, bool_t loopmode); + +void lsd_player_enable_loop(LsdPlayer *p, bool_t loopmode){ + if (ms_filter_get_id(p->player)==MS_FILE_PLAYER_ID){ + int arg=loopmode ? 0 : -1; + ms_filter_call_method(p->player,MS_FILE_PLAYER_LOOP,&arg); + } +} + +void lsd_player_set_gain(LsdPlayer *p, float gain){ + MSAudioMixerCtl gainctl; + gainctl.pin=p->mixer_pin; + gainctl.gain=gain; + ms_filter_call_method(p->lsd->mixer,MS_AUDIO_MIXER_SET_INPUT_GAIN,&gainctl); +} LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname){ int i; @@ -182,17 +192,15 @@ LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname){ ms_filter_call_method(lsd->soundout,MS_FILTER_SET_SAMPLE_RATE,&lsd->out_rate); ms_filter_call_method(lsd->soundout,MS_FILTER_SET_NCHANNELS,&lsd->out_nchans); - mp.filter=lsd->filter; + mp.filter=lsd->mixer; mp.pin=0; lsd_player_init(&lsd->branches[0],mp,MS_ITC_SINK_ID,lsd); for(i=1;ibranches[i],mp,MS_FILE_PLAYER_ID); + lsd_player_init(&lsd->branches[i],mp,MS_FILE_PLAYER_ID,lsd); } return lsd; } - -#endif From 96bbeb0a8501c6e2e21d6c544d3df0711f09f216 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 27 May 2010 11:33:47 +0200 Subject: [PATCH 13/45] work in progress, near code complete --- coreapi/linphonecore_utils.h | 2 +- coreapi/lsd.c | 59 ++++++++++++++++++++++++++++++++++-- 2 files changed, 57 insertions(+), 4 deletions(-) diff --git a/coreapi/linphonecore_utils.h b/coreapi/linphonecore_utils.h index 949cadaa6..a7f8cfaea 100644 --- a/coreapi/linphonecore_utils.h +++ b/coreapi/linphonecore_utils.h @@ -36,7 +36,7 @@ LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname); LsdPlayer * linphone_sound_daemon_get_player(LinphoneSoundDaemon *lsd); void linphone_sound_daemon_release_player(LinphoneSoundDaemon *lsd, LsdPlayer *lsdplayer); -MSFilter *linphone_sound_daemon_get_proxy(LinphoneSoundDaemon *obj); +struct _MSSndCard *linphone_sound_daemon_get_proxy_card(LinphoneSoundDaemon *obj); void linphone_sound_daemon_destroy(LinphoneSoundDaemon *obj); diff --git a/coreapi/lsd.c b/coreapi/lsd.c index 34134d00d..cb0f0af46 100644 --- a/coreapi/lsd.c +++ b/coreapi/lsd.c @@ -23,10 +23,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "linphonecore_utils.h" +#include "mediastreamer2/msticker.h" #include "mediastreamer2/mssndcard.h" #include "mediastreamer2/msaudiomixer.h" #include "mediastreamer2/mschanadapter.h" #include "mediastreamer2/msfileplayer.h" +#include "mediastreamer2/msitc.h" @@ -48,9 +50,31 @@ struct _LinphoneSoundDaemon { int out_nchans; MSFilter *mixer; MSFilter *soundout; + MSFilter *itcsink; + MSTicker *ticker; + MSSndCard *proxycard; LsdPlayer branches[MAX_BRANCHES]; }; +static MSFilter *create_writer(MSSndCard *c){ + LinphoneSoundDaemon *lsd=(LinphoneSoundDaemon*)c->data; + return lsd->itcsink; +} + +static MSSndCardDesc proxycard={ + "Linphone Sound Daemon", + /*detect*/ NULL, + /*init*/ NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + /*create_reader*/ NULL, + create_writer, + /*uninit,*/ +}; + LsdPlayer *linphone_sound_daemon_get_player(LinphoneSoundDaemon *obj){ int i; for(i=0;iplayer=ms_filter_new(playerid); @@ -187,10 +208,14 @@ LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname){ lsd=ms_new0(LinphoneSoundDaemon,1); lsd->soundout=ms_snd_card_create_writer(card); + lsd->mixer=ms_filter_new(MS_AUDIO_MIXER_ID); + lsd->itcsink=ms_filter_new(MS_ITC_SINK_ID); lsd->out_rate=44100; lsd->out_nchans=2; ms_filter_call_method(lsd->soundout,MS_FILTER_SET_SAMPLE_RATE,&lsd->out_rate); ms_filter_call_method(lsd->soundout,MS_FILTER_SET_NCHANNELS,&lsd->out_nchans); + ms_filter_call_method(lsd->mixer,MS_FILTER_SET_SAMPLE_RATE,&lsd->out_rate); + ms_filter_call_method(lsd->mixer,MS_FILTER_SET_NCHANNELS,&lsd->out_nchans); mp.filter=lsd->mixer; mp.pin=0; @@ -200,7 +225,35 @@ LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname){ mp.pin=i; lsd_player_init(&lsd->branches[i],mp,MS_FILE_PLAYER_ID,lsd); } + ms_filter_link(lsd->mixer,0,lsd->soundout,0); + lsd->ticker=ms_ticker_new(); + ms_ticker_attach(lsd->ticker,lsd->soundout); + + lsd->proxycard=ms_snd_card_new(&proxycard); + lsd->proxycard->data=lsd; + + ms_filter_call_method(lsd->itcsink,MS_ITC_SINK_CONNECT,lsd->branches[0].player); return lsd; } +void linphone_sound_daemon_destroy(LinphoneSoundDaemon *obj){ + int i; + MSConnectionPoint mp; + ms_ticker_detach(obj->ticker,obj->soundout); + mp.filter=obj->mixer; + for(i=0;ibranches[i],mp); + } + ms_ticker_destroy(obj->ticker); + ms_filter_destroy(obj->soundout); + ms_filter_destroy(obj->mixer); + ms_filter_destroy(obj->itcsink); +} + + + +MSSndCard *linphone_sound_daemon_get_proxy_card(LinphoneSoundDaemon *lsd){ + return lsd->proxycard; +} From 359bb6e0a2a217a03c51ace7e599502b6c00dc85 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 28 May 2010 14:15:27 +0200 Subject: [PATCH 14/45] code complete for linphone sound daemon --- coreapi/callbacks.c | 6 ++++-- coreapi/linphonecore.c | 8 +++++--- coreapi/linphonecore_utils.h | 15 ++++++--------- coreapi/lsd.c | 12 +++++++----- coreapi/private.h | 1 + 5 files changed, 23 insertions(+), 19 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index f15404dbf..a4ce8e341 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -100,8 +100,9 @@ static void call_received(SalOp *h){ /* play the ring */ if (lc->sound_conf.ring_sndcard!=NULL){ + MSSndCard *ringcard=lc->sound_conf.lsd_card ? lc->sound_conf.lsd_card : lc->sound_conf.ring_sndcard; ms_message("Starting local ring..."); - lc->ringstream=ring_start(lc->sound_conf.local_ring,2000,lc->sound_conf.ring_sndcard); + lc->ringstream=ring_start(lc->sound_conf.local_ring,2000,ringcard); } linphone_call_set_state(call,LCStateRinging); sal_call_notify_ringing(h); @@ -122,8 +123,9 @@ static void call_ringing(SalOp *h){ if (md==NULL){ if (lc->ringstream!=NULL) return; /*already ringing !*/ if (lc->sound_conf.play_sndcard!=NULL){ + MSSndCard *ringcard=lc->sound_conf.lsd_card ? lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard; ms_message("Remote ringing..."); - lc->ringstream=ring_start(lc->sound_conf.remote_ring,2000,lc->sound_conf.play_sndcard); + lc->ringstream=ring_start(lc->sound_conf.remote_ring,2000,ringcard); } }else{ /*accept early media */ diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index f62449e62..d6df2f81a 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -621,7 +621,7 @@ static void sound_config_read(LinphoneCore *lc) lp_config_get_int(lc->config,"sound","agc",0)); gain=lp_config_get_float(lc->config,"sound","soft_play_lev",0); - linphone_core_set_soft_play_level(lc,gain); + linphone_core_set_soft_play_level(lc,gain); } static void sip_config_read(LinphoneCore *lc) @@ -2240,7 +2240,8 @@ void linphone_core_start_media_streams(LinphoneCore *lc, LinphoneCall *call){ if (stream){ call->audio_profile=make_profile(lc,call->resultdesc,stream,&used_pt); if (!lc->use_files){ - MSSndCard *playcard=lc->sound_conf.play_sndcard; + MSSndCard *playcard=lc->sound_conf.lsd_card ? + lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard; MSSndCard *captcard=lc->sound_conf.capt_sndcard; if (playcard==NULL) { ms_warning("No card defined for playback !"); @@ -2820,7 +2821,8 @@ int linphone_core_preview_ring(LinphoneCore *lc, const char *ring,LinphoneCoreCb lc_callback_obj_init(&lc->preview_finished_cb,func,userdata); lc->preview_finished=0; if (lc->sound_conf.ring_sndcard!=NULL){ - lc->ringstream=ring_start_with_cb(ring,2000,lc->sound_conf.ring_sndcard,notify_end_of_ring,(void *)lc); + MSSndCard *ringcard=lc->sound_conf.lsd_card ? lc->sound_conf.lsd_card : lc->sound_conf.ring_sndcard; + lc->ringstream=ring_start_with_cb(ring,2000,ringcard,notify_end_of_ring,(void *)lc); } return 0; } diff --git a/coreapi/linphonecore_utils.h b/coreapi/linphonecore_utils.h index a7f8cfaea..0df37b800 100644 --- a/coreapi/linphonecore_utils.h +++ b/coreapi/linphonecore_utils.h @@ -31,15 +31,6 @@ typedef struct _LinphoneSoundDaemon LinphoneSoundDaemon; typedef void (*LsdEndOfPlayCallback)(LsdPlayer *p); -LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname); - -LsdPlayer * linphone_sound_daemon_get_player(LinphoneSoundDaemon *lsd); -void linphone_sound_daemon_release_player(LinphoneSoundDaemon *lsd, LsdPlayer *lsdplayer); - -struct _MSSndCard *linphone_sound_daemon_get_proxy_card(LinphoneSoundDaemon *obj); - -void linphone_sound_daemon_destroy(LinphoneSoundDaemon *obj); - void lsd_player_set_callback(LsdPlayer *p, LsdEndOfPlayCallback cb); void lsd_player_set_user_pointer(LsdPlayer *p, void *up); void *lsd_player_get_user_pointer(LsdPlayer *p); @@ -48,4 +39,10 @@ int lsd_player_stop(LsdPlayer *p); void lsd_player_enable_loop(LsdPlayer *p, bool_t loopmode); void lsd_player_set_gain(LsdPlayer *p, float gain); +LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname); +LsdPlayer * linphone_sound_daemon_get_player(LinphoneSoundDaemon *lsd); +void linphone_sound_daemon_release_player(LinphoneSoundDaemon *lsd, LsdPlayer *lsdplayer); +void linphone_core_use_sound_daemon(LinphoneCore *lc, LinphoneSoundDaemon *lsd); +void linphone_sound_daemon_destroy(LinphoneSoundDaemon *obj); + #endif diff --git a/coreapi/lsd.c b/coreapi/lsd.c index cb0f0af46..0ed782fe2 100644 --- a/coreapi/lsd.c +++ b/coreapi/lsd.c @@ -23,6 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "linphonecore_utils.h" +#include "private.h" #include "mediastreamer2/msticker.h" #include "mediastreamer2/mssndcard.h" #include "mediastreamer2/msaudiomixer.h" @@ -31,6 +32,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "mediastreamer2/msitc.h" +static struct _MSSndCard *linphone_sound_daemon_get_proxy_card(LinphoneSoundDaemon *obj); #define MAX_BRANCHES 10 @@ -77,7 +79,7 @@ static MSSndCardDesc proxycard={ LsdPlayer *linphone_sound_daemon_get_player(LinphoneSoundDaemon *obj){ int i; - for(i=0;ibranches[i]; MSFilter *p=b->player; int state; @@ -174,8 +176,6 @@ int lsd_player_play(LsdPlayer *b, const char *filename ){ return 0; } -int lsd_player_stop(LsdPlayer *p); - void lsd_player_enable_loop(LsdPlayer *p, bool_t loopmode){ if (ms_filter_get_id(p->player)==MS_FILE_PLAYER_ID){ int arg=loopmode ? 0 : -1; @@ -252,8 +252,10 @@ void linphone_sound_daemon_destroy(LinphoneSoundDaemon *obj){ ms_filter_destroy(obj->itcsink); } - - MSSndCard *linphone_sound_daemon_get_proxy_card(LinphoneSoundDaemon *lsd){ return lsd->proxycard; } + +void linphone_core_use_sound_daemon(LinphoneCore *lc, LinphoneSoundDaemon *lsd){ + lc->sound_conf.lsd_card=linphone_sound_daemon_get_proxy_card (lsd); +} diff --git a/coreapi/private.h b/coreapi/private.h index c3e2960a3..22286987e 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -293,6 +293,7 @@ typedef struct sound_config struct _MSSndCard * ring_sndcard; /* the playback sndcard currently used */ struct _MSSndCard * play_sndcard; /* the playback sndcard currently used */ struct _MSSndCard * capt_sndcard; /* the capture sndcard currently used */ + struct _MSSndCard * lsd_card; /* dummy playback card for Linphone Sound Daemon extension */ const char **cards; int latency; /* latency in samples of the current used sound device */ char rec_lev; From 626070658548bf44d57d65359bad2b97d33d7e00 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 28 May 2010 14:44:21 +0200 Subject: [PATCH 15/45] fix bug with sdp_answer not reset as it should. --- coreapi/sal_eXosip2.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index 32bd677a6..869d1934d 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -523,8 +523,11 @@ int sal_call_accept(SalOp * h){ if (h->sdp_offering) { set_sdp_from_desc(msg,h->base.local_media); }else{ - if (h->sdp_answer) + if (h->sdp_answer){ set_sdp(msg,h->sdp_answer); + sdp_message_free(h->sdp_answer); + h->sdp_answer=NULL; + } } }else{ ms_error("You are accepting a call but not defined any media capabilities !"); @@ -773,7 +776,11 @@ static void handle_reinvite(Sal *sal, eXosip_event_t *ev){ sdp_to_media_description(sdp,op->base.remote_media); sdp_message_free(sdp); sdp_process(op); - set_sdp(msg,op->sdp_answer); + if (op->sdp_answer!=NULL){ + set_sdp(msg,op->sdp_answer); + sdp_message_free(op->sdp_answer); + op->sdp_answer=NULL; + } }else { op->sdp_offering=TRUE; set_sdp_from_desc(msg,op->base.local_media); @@ -885,8 +892,11 @@ static void call_accepted(Sal *sal, eXosip_event_t *ev){ _osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free); osip_message_set_contact(msg,contact); } - if (op->sdp_answer) - set_sdp(msg,op->sdp_answer); + if (op->sdp_answer){ + set_sdp(msg,op->sdp_answer); + sdp_message_free(op->sdp_answer); + op->sdp_answer=NULL; + } eXosip_call_send_ack(ev->did,msg); sal->callbacks.call_accepted(op); } From 7fa19445c215e1146078e5dba8bc49bc942e35e9 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Sun, 30 May 2010 22:40:19 +0200 Subject: [PATCH 16/45] improved test with new event queue --- coreapi/Makefile.am | 5 ++ coreapi/linphonecore.c | 24 ++++++--- coreapi/linphonecore_utils.h | 4 +- coreapi/lsd.c | 19 ++++++- coreapi/private.h | 1 + coreapi/test_lsd.c | 102 +++++++++++++++++++++++++++++++++++ 6 files changed, 146 insertions(+), 9 deletions(-) create mode 100644 coreapi/test_lsd.c diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index 66a2bf5f6..44f7532a8 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -49,6 +49,11 @@ if BUILD_WIN32 liblinphone_la_LIBADD+=$(top_builddir)/oRTP/src/libortp.la endif +noinst_PROGRAMS=test_lsd + +test_lsd_SOURCES=test_lsd.c + +test_lsd_LDADD=liblinphone.la AM_CFLAGS=$(STRICT_OPTIONS) -DIN_LINPHONE \ $(ORTP_CFLAGS) \ diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index d6df2f81a..822dc169a 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -24,6 +24,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "mediastreamer2/mediastream.h" #include "mediastreamer2/msvolume.h" #include "mediastreamer2/msequalizer.h" +#include "mediastreamer2/mseventqueue.h" #include @@ -631,6 +632,11 @@ static void sip_config_read(LinphoneCore *lc) int port; int i,tmp; int ipv6; + + if (lp_config_get_int(lc->config,"sip","use_session_timers",0)==1){ + sal_use_session_timers(lc->sal,200); + } + port=lp_config_get_int(lc->config,"sip","use_info",0); linphone_core_set_use_info_for_dtmf(lc,port); @@ -641,7 +647,8 @@ static void sip_config_read(LinphoneCore *lc) if (ipv6==-1){ ipv6=0; if (host_has_ipv6_network()){ - lc->vtable.display_message(lc,_("Your machine appears to be connected to an IPv6 network. By default linphone always uses IPv4. Please update your configuration if you want to use IPv6")); + if (lc->vtable.display_message) + lc->vtable.display_message(lc,_("Your machine appears to be connected to an IPv6 network. By default linphone always uses IPv4. Please update your configuration if you want to use IPv6")); } } linphone_core_enable_ipv6(lc,ipv6); @@ -1078,6 +1085,10 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta #endif ms_init(); + /* create a mediastreamer2 event queue and set it as global */ + /* This allows to run event's callback in linphone_core_iterate() */ + lc->msevq=ms_event_queue_new(); + ms_set_global_event_queue(lc->msevq); lc->config=lp_config_new(config_path); if (factory_config_path) @@ -1086,9 +1097,7 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta lc->sal=sal_init(); sal_set_user_pointer(lc->sal,lc); sal_set_callbacks(lc->sal,&linphone_sal_callbacks); - if (lp_config_get_int(lc->config,"sip","use_session_timers",0)==1){ - sal_use_session_timers(lc->sal,200); - } + sip_setup_register_all(); sound_config_read(lc); net_config_read(lc); @@ -1101,8 +1110,9 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta lc->presence_mode=LINPHONE_STATUS_ONLINE; lc->max_call_logs=15; ui_config_read(lc); - lc->vtable.display_status(lc,_("Ready")); - gstate_new_state(lc, GSTATE_POWER_ON, NULL); + if (lc->vtable.display_status) + lc->vtable.display_status(lc,_("Ready")); + gstate_new_state(lc, GSTATE_POWER_ON, NULL); lc->auto_net_state_mon=lc->sip_conf.auto_net_state_mon; lc->ready=TRUE; @@ -1667,6 +1677,7 @@ void linphone_core_iterate(LinphoneCore *lc){ } sal_iterate(lc->sal); + ms_event_queue_pump(lc->msevq); if (lc->auto_net_state_mon) monitor_network_state(lc,curtime); proxy_update(lc); @@ -3593,6 +3604,7 @@ static void linphone_core_uninit(LinphoneCore *lc) lc->previewstream=NULL; } #endif + ms_event_queue_destroy(lc->msevq); /* save all config */ net_config_uninit(lc); sip_config_uninit(lc); diff --git a/coreapi/linphonecore_utils.h b/coreapi/linphonecore_utils.h index 0df37b800..43d6559bd 100644 --- a/coreapi/linphonecore_utils.h +++ b/coreapi/linphonecore_utils.h @@ -33,11 +33,13 @@ typedef void (*LsdEndOfPlayCallback)(LsdPlayer *p); void lsd_player_set_callback(LsdPlayer *p, LsdEndOfPlayCallback cb); void lsd_player_set_user_pointer(LsdPlayer *p, void *up); -void *lsd_player_get_user_pointer(LsdPlayer *p); +void *lsd_player_get_user_pointer(const LsdPlayer *p); int lsd_player_play(LsdPlayer *p, const char *filename); int lsd_player_stop(LsdPlayer *p); void lsd_player_enable_loop(LsdPlayer *p, bool_t loopmode); +bool_t lsd_player_loop_enabled(const LsdPlayer *p); void lsd_player_set_gain(LsdPlayer *p, float gain); +LinphoneSoundDaemon lsd_player_get_daemon(const LsdPlayer *p); LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname); LsdPlayer * linphone_sound_daemon_get_player(LinphoneSoundDaemon *lsd); diff --git a/coreapi/lsd.c b/coreapi/lsd.c index 0ed782fe2..2dd9898a5 100644 --- a/coreapi/lsd.c +++ b/coreapi/lsd.c @@ -45,6 +45,8 @@ struct _LsdPlayer{ LsdEndOfPlayCallback eop_cb; int mixer_pin; void *user_data; + bool_t loop; + bool_t pad[3]; }; struct _LinphoneSoundDaemon { @@ -86,6 +88,7 @@ LsdPlayer *linphone_sound_daemon_get_player(LinphoneSoundDaemon *obj){ ms_filter_call_method(p,MS_PLAYER_GET_STATE,&state); if (state==MSPlayerClosed){ lsd_player_set_gain(b,1); + lsd_player_enable_loop (b,FALSE); return b; } } @@ -118,6 +121,7 @@ static void lsd_player_init(LsdPlayer *p, MSConnectionPoint mixer, MSFilterId pl ms_connection_helper_link(&h,p->chanadapter,0,0); ms_connection_helper_link(&h,mixer.filter,mixer.pin,-1); p->mixer_pin=mixer.pin; + p->loop=FALSE; p->lsd=lsd; } @@ -143,11 +147,14 @@ void lsd_player_set_user_pointer(LsdPlayer *p, void *up){ p->user_data=up; } -void *lsd_player_get_user_pointer(LsdPlayer *p){ +void *lsd_player_get_user_pointer(const LsdPlayer *p){ return p->user_data; } static void lsd_player_on_eop(void * userdata, unsigned int id, void *arg){ + LsdPlayer *p=(LsdPlayer *)userdata; + if (p->eop_cb!=NULL) + p->eop_cb(p); } int lsd_player_play(LsdPlayer *b, const char *filename ){ @@ -161,6 +168,7 @@ int lsd_player_play(LsdPlayer *b, const char *filename ){ } if (ms_filter_call_method(b->player,MS_PLAYER_OPEN,(void*)filename)!=0){ + ms_warning("Could not play %s",filename); return -1; } ms_filter_call_method(b->player,MS_FILTER_GET_SAMPLE_RATE,&rate); @@ -173,6 +181,7 @@ int lsd_player_play(LsdPlayer *b, const char *filename ){ ms_filter_call_method(b->chanadapter,MS_FILTER_SET_NCHANNELS,&chans); ms_filter_call_method(b->chanadapter,MS_CHANNEL_ADAPTER_SET_OUTPUT_NCHANNELS,&lsd->out_nchans); + ms_filter_call_method_noarg (b->player,MS_PLAYER_START); return 0; } @@ -180,9 +189,14 @@ void lsd_player_enable_loop(LsdPlayer *p, bool_t loopmode){ if (ms_filter_get_id(p->player)==MS_FILE_PLAYER_ID){ int arg=loopmode ? 0 : -1; ms_filter_call_method(p->player,MS_FILE_PLAYER_LOOP,&arg); + p->loop=loopmode; } } +bool_t lsd_player_loop_enabled(const LsdPlayer *p){ + return p->loop; +} + void lsd_player_set_gain(LsdPlayer *p, float gain){ MSAudioMixerCtl gainctl; gainctl.pin=p->mixer_pin; @@ -220,7 +234,7 @@ LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname){ mp.filter=lsd->mixer; mp.pin=0; - lsd_player_init(&lsd->branches[0],mp,MS_ITC_SINK_ID,lsd); + lsd_player_init(&lsd->branches[0],mp,MS_ITC_SOURCE_ID,lsd); for(i=1;ibranches[i],mp,MS_FILE_PLAYER_ID,lsd); @@ -246,6 +260,7 @@ void linphone_sound_daemon_destroy(LinphoneSoundDaemon *obj){ mp.pin=i; lsd_player_uninit (&obj->branches[i],mp); } + ms_filter_unlink(obj->mixer,0,obj->soundout,0); ms_ticker_destroy(obj->ticker); ms_filter_destroy(obj->soundout); ms_filter_destroy(obj->mixer); diff --git a/coreapi/private.h b/coreapi/private.h index 22286987e..7a4c42052 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -371,6 +371,7 @@ struct _LinphoneCore struct _AudioStream *audiostream; /**/ struct _VideoStream *videostream; struct _VideoStream *previewstream; + struct _MSEventQueue *msevq; RtpTransport *a_rtp,*a_rtcp; MSList *bl_reqs; MSList *subscribers; /* unknown subscribers */ diff --git a/coreapi/test_lsd.c b/coreapi/test_lsd.c new file mode 100644 index 000000000..64b5d8a78 --- /dev/null +++ b/coreapi/test_lsd.c @@ -0,0 +1,102 @@ +/* +linphone +Copyright (C) 2010 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/* Linphone Sound Daemon: is a lightweight utility to play sounds to speaker during a conversation. + This is useful for embedded platforms, where sound apis are not performant enough to allow + simultaneous sound access. + + This file is a test program that plays several sound files and places a call simultatenously. +*/ + +#include "linphonecore_utils.h" + +static void play_finished(LsdPlayer *p){ + const char *filename=(const char *)lsd_player_get_user_pointer (p); + ms_message("Playing of %s is finished.",filename); + if (!lsd_player_loop_enabled (p)){ + linphone_sound_daemon_release_player (lsd_player_get_daemon(p)); + } +} + +static void wait_a_bit(LinphoneCore *lc, int seconds){ + time_t orig=time(NULL); + while(time(NULL)-orig1){ + linphone_core_invite(lc,argv[1]); + wait_a_bit(lc,10); + linphone_core_terminate_call(lc,NULL); + } + + linphone_core_destroy(lc); + linphone_sound_daemon_destroy(lsd); + return 0; +} From 9bd55d0b34286d55e89a9c2df61c774f1b4d53aa Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 31 May 2010 16:54:40 +0200 Subject: [PATCH 17/45] bugfixing in lsd. --- coreapi/callbacks.c | 6 +- coreapi/exevents.c | 1189 ---------------------------------- coreapi/linphonecore.c | 36 +- coreapi/linphonecore.h | 2 +- coreapi/linphonecore_utils.h | 2 +- coreapi/lsd.c | 8 +- coreapi/presence.c | 3 +- coreapi/test_lsd.c | 2 +- 8 files changed, 38 insertions(+), 1210 deletions(-) delete mode 100644 coreapi/exevents.c diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index a4ce8e341..6f86c9bbb 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -249,8 +249,10 @@ static void call_terminated(SalOp *op, const char *from){ lc->ringstream=NULL; } linphone_core_stop_media_streams(lc,lc->call); - lc->vtable.show(lc); - lc->vtable.display_status(lc,_("Call terminated.")); + if (lc->vtable.show!=NULL) + lc->vtable.show(lc); + if (lc->vtable.display_status!=NULL) + lc->vtable.display_status(lc,_("Call terminated.")); gstate_new_state(lc, GSTATE_CALL_END, NULL); if (lc->vtable.bye_recv!=NULL){ LinphoneAddress *addr=linphone_address_new(from); diff --git a/coreapi/exevents.c b/coreapi/exevents.c deleted file mode 100644 index 24e830905..000000000 --- a/coreapi/exevents.c +++ /dev/null @@ -1,1189 +0,0 @@ -/* -linphone -Copyright (C) 2000 Simon MORLAT (simon.morlat@free.fr) - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "exevents.h" -#include "linphonecore.h" -#include "private.h" -#include "mediastreamer2/mediastream.h" -#include -#include -#include - -static int linphone_answer_sdp(LinphoneCore *lc, eXosip_event_t *ev, sdp_message_t *sdp); - -static bool_t linphone_call_matches_event(LinphoneCall *call, eXosip_event_t *ev){ - return call->cid==ev->cid; -} - -static void linphone_call_proceeding(LinphoneCore *lc, eXosip_event_t *ev){ - if (lc->call==NULL || (lc->call->cid!=-1 && !linphone_call_matches_event(lc->call,ev)) ) { - ms_warning("This call has been canceled: call=%p, call->cid=%i, ev->cid=%i", - lc->call,lc->call?lc->call->cid:-1,ev->cid); - eXosip_lock(); - eXosip_call_terminate(ev->cid,ev->did); - eXosip_unlock(); - return; - } - lc->call->cid=ev->cid; - lc->call->did=ev->did; - lc->call->tid=ev->tid; -} - -static void linphone_connect_incoming(LinphoneCore *lc){ - lc->vtable.show(lc); - lc->vtable.display_status(lc,_("Connected.")); - lc->call->state=LCStateAVRunning; - if (lc->ringstream!=NULL){ - ring_stop(lc->ringstream); - lc->ringstream=NULL; - } - if (lc->audiostream->ticker!=NULL){ - /*case where we accepted early media */ - linphone_core_stop_media_streams(lc); - linphone_core_init_media_streams(lc); - } - linphone_core_start_media_streams(lc,lc->call); -} - -int linphone_call_accepted(LinphoneCore *lc, eXosip_event_t *ev) -{ - LinphoneCall *call=lc->call; - sdp_message_t *sdp; - const char *sdpanswer=NULL; - osip_message_t *msg=NULL; - int err; - if (call==NULL){ - ms_warning("No call to accept."); - return 0; - } - linphone_call_proceeding(lc,ev); - if (!linphone_call_matches_event(lc->call,ev)) return 0; - call->auth_pending=FALSE; - if (call->state==LCStateAVRunning){ - return 0; /*already accepted*/ - } - linphone_call_init_media_params(call); - sdp=eXosip_get_sdp_info(ev->response); - if (!lc->sip_conf.sdp_200_ack){ - err=0; - sdp_context_read_answer(call->sdpctx,sdp); - }else{ - /*we receive a 200OK with an sdp offer*/ - err=linphone_answer_sdp(lc,ev,sdp); - if (err==0) sdpanswer=call->sdpctx->answerstr; - } - if (err==0){ - gstate_new_state(lc, GSTATE_CALL_OUT_CONNECTED, NULL); - linphone_connect_incoming(lc); - } - /*send the ack once streams are started*/ - eXosip_call_build_ack(ev->did,&msg); - if (sdpanswer!=NULL) linphone_set_sdp(msg,sdpanswer); - eXosip_call_send_ack(ev->did,msg); - if (err!=0){ - /*send a bye*/ - ms_error("Incompatible SDP offer received in 200Ok, need to abort the call"); - linphone_core_terminate_call(lc,NULL); - } - sdp_message_free(sdp); - return 0; -} - - -int linphone_call_terminated(LinphoneCore *lc, eXosip_event_t *ev) -{ - /*stop ringing if necessary*/ - if (lc->call!=NULL){ - if (lc->call->cid!=ev->cid){ - /* this is not current call */ - ms_message("call %i terminated, this was not current call.",ev->cid); - return 0; - } - } - - ms_message("Current call terminated..."); - if (lc->ringstream!=NULL) { - ring_stop(lc->ringstream); - lc->ringstream=NULL; - } - linphone_core_stop_media_streams(lc); - lc->vtable.show(lc); - lc->vtable.display_status(lc,_("Call terminated.")); - gstate_new_state(lc, GSTATE_CALL_END, NULL); - if (lc->vtable.bye_recv!=NULL){ - char *from; - osip_from_to_str(ev->request->from,&from); - lc->vtable.bye_recv(lc,from); - osip_free(from); - } - if (lc->call!=NULL){ - linphone_call_destroy(lc->call); - lc->call=NULL; - } - return 0; -} - - -int linphone_call_released(LinphoneCore *lc, int cid){ - LinphoneCall *call=lc->call; - if (call!=NULL && call->cid==cid){ - - linphone_call_destroy(lc->call); - lc->call=NULL; - lc->vtable.display_status(lc,_("Could not reach destination.")); - gstate_new_state(lc, GSTATE_CALL_ERROR, NULL); - } - return 0; -} - -int linphone_call_failure(LinphoneCore *lc, eXosip_event_t *ev) -{ - const char *reason=""; - char *msg486=_("User is busy."); - char *msg480=_("User is temporarily unavailable."); - char *msg487=_("Request Cancelled."); - /*char *retrymsg=_("%s. Retry after %i minute(s).");*/ - char *msg600=_("User does not want to be disturbed."); - char *msg603=_("Call declined."); - char* tmpmsg=msg486; - int code; - LinphoneCall *call=lc->call; - - if (call){ - /*check that the faillure is related to this call, not an old one*/ - if (!linphone_call_matches_event(call,ev)) { - ms_warning("Failure reported for an old call."); - return 0; - } - } - - if (ev->response){ - code=osip_message_get_status_code(ev->response); - reason=osip_message_get_reason_phrase(ev->response); - }else code=-110; - lc->vtable.show(lc); - - switch(code) - { - case 401: - case 407: - if (lc->call!=NULL) - linphone_process_authentication(lc,ev); - return 0; - break; - case 400: - lc->vtable.display_status(lc,_("Bad request")); - break; - case 404: - lc->vtable.display_status(lc,_("User cannot be found at given address.")); - break; - case 415: - lc->vtable.display_status(lc,_("Remote user cannot support any of proposed codecs.")); - break; - case 422: - /*ignore: eXosip_automatic_action will do the job of retrying with a greater Session-Expires*/ - return 0; - break; - case 480: - tmpmsg=msg480; - case 486: - /* - msg_header_getbyname(msg,"retry-after",0,&retry); - if (retry!=NULL) - { - umsg=g_malloc(strlen(tmpmsg)+strlen(retrymsg)+13); - sprintf(umsg,retrymsg,tmpmsg,atoi(retry->hvalue)/60); - lc->vtable.display_message(lc,umsg); - ms_free(umsg); - }*/ - lc->vtable.display_message(lc,tmpmsg); - break; - case 487: /*request terminated*/ - lc->vtable.display_status(lc,msg487); - break; - case 600: - lc->vtable.display_message(lc,msg600); - break; - case 603: - lc->vtable.display_status(lc,msg603); - break; - case -110: /* time out, call leg is lost */ - lc->vtable.display_status(lc,_("Timeout.")); - break; - case -111: - lc->vtable.display_status(lc,_("Remote host was found but refused connection.")); - break; - - default: - if (code>0) - { - lc->vtable.display_status(lc,reason); - } - else ms_warning("failure_cb unknown code=%i\n",code); - } - if (lc->ringstream!=NULL) { - ring_stop(lc->ringstream); - lc->ringstream=NULL; - } - linphone_core_stop_media_streams(lc); - if (call!=NULL) { - linphone_call_destroy(call); - gstate_new_state(lc, GSTATE_CALL_ERROR, NULL); - lc->call=NULL; - } - return 0; -} - -extern sdp_handler_t linphone_sdphandler; - -static int linphone_answer_sdp(LinphoneCore *lc, eXosip_event_t *ev, sdp_message_t *sdp){ - int status=200; - sdp_context_t *ctx=NULL; - - ctx=lc->call->sdpctx; - /* get the result of the negociation */ - sdp_context_get_answer(ctx,sdp); - status=sdp_context_get_status(ctx); - - if (status==200){ - linphone_core_init_media_streams(lc); - return 0; - }else{ - if (status==-1) status=415; - } - return -1; -} - -int linphone_inc_new_call(LinphoneCore *lc, eXosip_event_t *ev) -{ - sdp_message_t *sdp=NULL; - osip_from_t *from_url=ev->request->from; - char *barmesg; - char *from; - char *to; - int err; - - osip_from_to_str(ev->request->from,&from); - osip_to_to_str(ev->request->to,&to); - - /* first check if we can answer successfully to this invite */ - if (lc->presence_mode!=LINPHONE_STATUS_ONLINE){ - ms_message("Not present !! presence mode : %d\n",lc->presence_mode); - eXosip_lock(); - if (lc->presence_mode==LINPHONE_STATUS_BUSY) - eXosip_call_send_answer(ev->tid,486,NULL); - else if (lc->presence_mode==LINPHONE_STATUS_AWAY - ||lc->presence_mode==LINPHONE_STATUS_BERIGHTBACK - ||lc->presence_mode==LINPHONE_STATUS_ONTHEPHONE - ||lc->presence_mode==LINPHONE_STATUS_OUTTOLUNCH - ||lc->presence_mode==LINPHONE_STATUS_OFFLINE) - eXosip_call_send_answer(ev->tid,480,NULL); - else if (lc->presence_mode==LINPHONE_STATUS_NOT_DISTURB) - eXosip_call_send_answer(ev->tid,480,NULL); - else if (lc->alt_contact!=NULL && lc->presence_mode==LINPHONE_STATUS_MOVED) - { - osip_message_t *msg; - eXosip_call_build_answer(ev->tid,302,&msg); - osip_message_set_contact(msg,lc->alt_contact); - eXosip_call_send_answer(ev->tid,302,msg); - } - else if (lc->alt_contact!=NULL && lc->presence_mode==LINPHONE_STATUS_ALT_SERVICE) - { - osip_message_t *msg; - eXosip_call_build_answer(ev->tid,380,&msg); - osip_message_set_contact(msg,lc->alt_contact); - eXosip_call_send_answer(ev->tid,380,msg); - } - else - eXosip_call_send_answer(ev->tid,486,NULL); - eXosip_unlock(); - goto end; - } - if (lc->call!=NULL){/*busy*/ - eXosip_lock(); - eXosip_call_send_answer(ev->tid,486,NULL); - eXosip_unlock(); - goto end; - } - lc->call=linphone_call_new_incoming(lc,linphone_address_new(from),linphone_address_new(to),ev); - - sdp=eXosip_get_sdp_info(ev->request); - if (sdp==NULL){ - ms_message("No sdp body in invite, 200-ack scheme"); - err=0; - }else{ - err=linphone_answer_sdp(lc,ev,sdp); - } - if (!err){ - char *tmp; - if (from_2char_without_params(from_url,&tmp)!=0){ - tmp=ms_strdup("Unknown user"); - } - gstate_new_state(lc, GSTATE_CALL_IN_INVITE, tmp); - barmesg=ortp_strdup_printf("%s %s",tmp,_("is contacting you.")); - lc->vtable.show(lc); - lc->vtable.display_status(lc,barmesg); - - /* play the ring */ - if (lc->sound_conf.ring_sndcard!=NULL){ - ms_message("Starting local ring..."); - lc->ringstream=ring_start(lc->sound_conf.local_ring,2000,lc->sound_conf.ring_sndcard); - } - linphone_call_set_state(lc->call,LCStateRinging); - eXosip_lock(); - eXosip_call_send_answer(ev->tid,180,NULL); - eXosip_unlock(); - - lc->vtable.inv_recv(lc,tmp); - ms_free(barmesg); - osip_free(tmp); - }else{ - ms_error("Error during sdp negociation. "); - eXosip_lock(); - eXosip_call_send_answer(ev->tid,415,NULL); - eXosip_unlock(); - linphone_call_destroy(lc->call); - lc->call=NULL; - } - end: - osip_free(from); - osip_free(to); - if (sdp) sdp_message_free(sdp); - return 0; -} - -void linphone_handle_ack(LinphoneCore *lc, eXosip_event_t *ev){ - sdp_message_t *sdp=eXosip_get_sdp_info(ev->ack); - if (sdp){ - sdp_context_read_answer(lc->call->sdpctx,sdp); - linphone_connect_incoming(lc); - sdp_message_free(sdp); - } -} - -void linphone_handle_reinvite(LinphoneCore *lc, eXosip_event_t *ev){ - sdp_message_t *sdp=eXosip_get_sdp_info(ev->request); - sdp_context_t *ctx; - LinphoneCall *call=lc->call; - char *answer; - int status; - if (sdp==NULL){ - ms_warning("No sdp in reinvite !"); - eXosip_lock(); - eXosip_call_send_answer(ev->tid,603,NULL); - eXosip_unlock(); - return; - } - ctx=call->sdpctx; - /* get the result of the negociation */ - linphone_call_init_media_params(call); - answer=sdp_context_get_answer(ctx,sdp); - status=sdp_context_get_status(ctx); - if (status==200){ - osip_message_t *msg=NULL; - linphone_core_stop_media_streams(lc); - linphone_core_init_media_streams(lc); - eXosip_lock(); - if (eXosip_call_build_answer(ev->tid,200,&msg)<0){ - ms_warning("Reinvite for closed call ?"); - eXosip_unlock(); - linphone_core_stop_media_streams(lc); - sdp_message_free(sdp); - return ; - } - answer=call->sdpctx->answerstr; /* takes the sdp already computed*/ - linphone_set_sdp(msg,answer); - eXosip_call_send_answer(ev->tid,200,msg); - eXosip_unlock(); - linphone_core_start_media_streams(lc,call); - }else{ - eXosip_lock(); - eXosip_call_send_answer(ev->tid,status,NULL); - eXosip_unlock(); - } - sdp_message_free(sdp); -} - -void linphone_do_automatic_redirect(LinphoneCore *lc, const char *contact){ - char *msg=ortp_strdup_printf(_("Redirected to %s..."),contact); - lc->vtable.display_status(lc,msg); - ms_free(msg); - if (lc->call!=NULL) linphone_call_destroy(lc->call); - lc->call=NULL; - linphone_core_invite(lc,contact); -} - -void linphone_call_redirected(LinphoneCore *lc, eXosip_event_t *ev){ - int code=osip_message_get_status_code(ev->response); - char *contact=NULL; - osip_contact_t *ct; - osip_message_get_contact(ev->response,0,&ct); - if (ct) osip_contact_to_str(ct,&contact); - switch(code){ - case 380: - lc->vtable.display_url(lc,_("User is not reachable at the moment but he invites you\nto contact him using the following alternate resource:"),contact); - if (lc->call!=NULL) linphone_call_destroy(lc->call); - lc->call=NULL; - break; - case 302: - linphone_do_automatic_redirect(lc,contact); - break; - } - if (contact) osip_free(contact); -} - - -/* these are the SdpHandler callbacks: we are called in to be aware of the content -of the SDP messages exchanged */ - -int linphone_set_audio_offer(sdp_context_t *ctx) -{ - LinphoneCall *call=(LinphoneCall*)sdp_context_get_user_pointer(ctx); - LinphoneCore *lc=call->core; - PayloadType *codec; - MSList *elem; - sdp_payload_t payload; - - - elem=lc->codecs_conf.audio_codecs; - while(elem!=NULL){ - codec=(PayloadType*) elem->data; - if (linphone_core_check_payload_type_usability(lc,codec) && - linphone_core_payload_type_enabled(lc,codec)){ - sdp_payload_init(&payload); - payload.a_rtpmap=ortp_strdup_printf("%s/%i/1",codec->mime_type,codec->clock_rate); - payload.pt=rtp_profile_get_payload_number_from_rtpmap(lc->local_profile,payload.a_rtpmap); - payload.localport=call->audio_params.natd_port > 0 ? - call->audio_params.natd_port : lc->rtp_conf.audio_rtp_port; - sdp_context_add_audio_payload(ctx,&payload); - ms_free(payload.a_rtpmap); - } - elem=ms_list_next(elem); - } - /* add telephone-event payload*/ - sdp_payload_init(&payload); - payload.pt=rtp_profile_get_payload_number_from_mime(lc->local_profile,"telephone-event"); - payload.a_rtpmap="telephone-event/8000"; - payload.a_fmtp="0-11"; - if (lc->dw_audio_bw>0) payload.b_as_bandwidth=lc->dw_audio_bw; - if (lc->down_ptime>0) { - payload.a_ptime=lc->down_ptime; - ms_message("ptime [%i]",payload.a_ptime); - } - sdp_context_add_audio_payload(ctx,&payload); - return 0; -} - -static int find_payload_type_number(RtpProfile *prof, PayloadType *pt){ - int candidate=-1,i; - PayloadType *it; - for(i=0;i<127;++i){ - it=rtp_profile_get_payload(prof,i); - if (it!=NULL && strcasecmp(pt->mime_type,it->mime_type)==0 - && (pt->clock_rate==it->clock_rate || pt->clock_rate<=0) ){ - if ( (pt->recv_fmtp && it->recv_fmtp && strcasecmp(pt->recv_fmtp,it->recv_fmtp)==0) || - (pt->recv_fmtp==NULL && it->recv_fmtp==NULL) ){ - /*exact match*/ - return i; - }else candidate=i; - } - } - if (candidate==-1) ms_fatal("Should not happen."); - return candidate; -} - -static int find_payload_type_number_best_match(RtpProfile *prof, const char *rtpmap, const char *fmtp){ - int localpt=rtp_profile_get_payload_number_from_rtpmap(prof,rtpmap); - PayloadType *pt; - char value[10]; - if (localpt<0) return -1; - pt=rtp_profile_get_payload(prof,localpt); - if (strcasecmp(pt->mime_type,"H264")==0){ - /*hack for H264: need to answer with same packetization-mode*/ - PayloadType tmp; - memset(&tmp,0,sizeof(tmp)); - tmp.mime_type="H264"; - tmp.clock_rate=pt->clock_rate; - if (fmtp && fmtp_get_value(fmtp,"packetization-mode",value,sizeof(value))){ - tmp.recv_fmtp=(atoi(value)==1) ? "packetization-mode=1" : NULL; - } - localpt=find_payload_type_number(prof,&tmp); - } - return localpt; -} - -int linphone_set_video_offer(sdp_context_t *ctx) -{ - LinphoneCall *call=(LinphoneCall*)sdp_context_get_user_pointer(ctx); - LinphoneCore *lc=call->core; - PayloadType *codec; - MSList *elem; - bool_t firsttime=TRUE; - - if (!linphone_core_video_enabled(lc)) return -1; - - for(elem=lc->codecs_conf.video_codecs;elem!=NULL;elem=ms_list_next(elem)){ - codec=(PayloadType*) elem->data; - if (linphone_core_check_payload_type_usability(lc,codec) && - linphone_core_payload_type_enabled(lc,codec)){ - sdp_payload_t payload; - sdp_payload_init(&payload); - payload.line=1; - payload.a_rtpmap=ortp_strdup_printf("%s/%i",codec->mime_type,codec->clock_rate); - payload.localport=call->video_params.natd_port>0 ? - call->video_params.natd_port : lc->rtp_conf.video_rtp_port; - payload.pt=find_payload_type_number(lc->local_profile,codec); - payload.a_fmtp=codec->recv_fmtp; - if(firsttime){ - firsttime=FALSE; - if (lc->dw_video_bw>0) - payload.b_as_bandwidth=lc->dw_video_bw; - } - sdp_context_add_video_payload(ctx,&payload); - ms_free(payload.a_rtpmap); - } - } - return 0; -} - -typedef enum { - Unsupported, - Supported, - SupportedAndValid /* valid= the presence of this codec is enough to make a call */ -}SupportLevel; - -SupportLevel linphone_payload_is_supported(LinphoneCore *lc, sdp_payload_t *payload,RtpProfile *local_profile,RtpProfile *dialog_profile, bool_t answering, PayloadType **local_payload_type) -{ - int localpt; - SupportLevel ret; - if (payload->a_rtpmap!=NULL){ - localpt=find_payload_type_number_best_match(local_profile,payload->a_rtpmap,payload->a_fmtp); - }else{ - localpt=payload->pt; - ms_warning("payload has no rtpmap."); - } - - if (localpt>=0 && localpt <128 ){ - /* this payload is understood, but does the user want to use it ?? */ - PayloadType *rtppayload; - rtppayload=rtp_profile_get_payload(local_profile,localpt); - if (rtppayload==NULL) { - ms_warning("strange error !!"); - return Unsupported; - } - *local_payload_type=rtppayload; - if (strcmp(rtppayload->mime_type,"telephone-event")!=0){ - if (answering && !linphone_core_check_payload_type_usability(lc,rtppayload) ){ - ms_warning("payload %s is not usable",rtppayload->mime_type); - return Unsupported; - } - if ( !linphone_core_payload_type_enabled(lc,rtppayload)) { - ms_warning("payload %s is not enabled.",rtppayload->mime_type); - return Unsupported; - } - ret=SupportedAndValid; - }else ret=Supported; - if (dialog_profile!=NULL){ - int dbw,ubw; - /* this payload is supported in our local rtp profile, so add it to the dialog rtp - profile */ - rtppayload=payload_type_clone(rtppayload); - if (rtp_profile_get_payload(dialog_profile,payload->pt)!=NULL){ - ms_error("Payload %s type already entered, should not happen !",rtppayload->mime_type); - } - rtp_profile_set_payload(dialog_profile,payload->pt,rtppayload); - /* add to the rtp payload type some other parameters (bandwidth) */ - if (rtppayload->type==PAYLOAD_VIDEO){ - dbw=lc->dw_video_bw; - ubw=lc->up_video_bw; - }else{ - dbw=lc->dw_audio_bw; - ubw=lc->up_audio_bw; - } - if (payload->b_as_bandwidth!=0){ - ms_message("Remote bandwidth constraint: %i",payload->b_as_bandwidth); - /*obey to remote bandwidth constraint AND our own upbandwidth constraint*/ - rtppayload->normal_bitrate=1000*get_min_bandwidth( - payload->b_as_bandwidth, ubw); - }else{ - /*limit to upload bandwidth if exist, else no limit*/ - if (ubw>0) rtppayload->normal_bitrate=1000*ubw; - else { - if (rtppayload->type!=PAYLOAD_VIDEO){ - rtppayload->normal_bitrate=-1; /*allow speex to use maximum bitrate*/ - } - } - } - if (payload->a_fmtp!=NULL){ - payload_type_set_send_fmtp(rtppayload,payload->a_fmtp); - } - payload->a_fmtp=rtppayload->recv_fmtp; - if (payload->a_ptime>0){ - char tmp[30]; - snprintf(tmp,sizeof(tmp),"ptime=%i",payload->a_ptime); - payload_type_append_send_fmtp(rtppayload,tmp); - ms_message("%s attribute added to fmtp",tmp); - } - } - return ret; - } - return Unsupported; -} - -int linphone_accept_audio_offer(sdp_context_t *ctx,sdp_payload_t *payload) -{ - RtpProfile *remote_profile; - StreamParams *params; - SupportLevel supported; - LinphoneCall *call=(LinphoneCall*)sdp_context_get_user_pointer(ctx); - LinphoneCore *lc=call->core; - PayloadType *lpt=NULL; - - params=&call->audio_params; - remote_profile=call->profile; - /* see if this codec is supported in our local rtp profile*/ - supported=linphone_payload_is_supported(lc,payload,lc->local_profile,remote_profile,TRUE,&lpt); - if (supported==Unsupported) { - ms_message("Refusing audio codec %i (%s)",payload->pt,payload->a_rtpmap); - return -1; - } - if (lc->sip_conf.only_one_codec && params->initialized){ - ms_message("Only one codec has to be accepted."); - return -1; - } - if (supported==SupportedAndValid) { - if (params->initialized==0){ - /* this is the first codec we accept, it is going to be used*/ - params->localport=lc->rtp_conf.audio_rtp_port; - payload->localport=params->natd_port>0 ? - params->natd_port : lc->rtp_conf.audio_rtp_port; - params->line=payload->line; - params->pt=payload->pt; /* remember the first payload accepted */ - if (payload->relay_host!=NULL){ - strncpy(params->remoteaddr,payload->relay_host,sizeof(params->remoteaddr)-1); - params->remoteport=payload->relay_port; - params->remotertcpport=payload->relay_port; - params->relay_session_id=payload->relay_session_id; - }else{ - strncpy(params->remoteaddr,payload->c_addr,sizeof(params->remoteaddr)-1); - params->remoteport=payload->remoteport; - params->remotertcpport=payload->remoteport+1; - } - params->initialized=1; - /* we can now update the allocated bandwidth for audio, and then video*/ - linphone_core_update_allocated_audio_bandwidth_in_call(lc,lpt); - /* give our download bandwidth constraint*/ - payload->b_as_bandwidth=(lc->dw_audio_bw>0) ? lc->dw_audio_bw : 0; - }else{ - /* refuse all other audio lines*/ - if(params->line!=payload->line) { - ms_message("Only one audio line can be accepted."); -#if !defined(_WIN32_WCE) - abort(); -#endif /*_WIN32_WCE*/ - return -1; - } - } - } - return 0; -} - -int linphone_accept_video_offer(sdp_context_t *ctx,sdp_payload_t *payload) -{ - LinphoneCall *call=(LinphoneCall*)sdp_context_get_user_pointer(ctx); - LinphoneCore *lc=call->core; - RtpProfile *remote_profile; - StreamParams *params; - SupportLevel supported; - PayloadType *lpt=NULL; - - if (!linphone_core_video_enabled(lc)) return -1; - - if (payload->remoteport==0) { - ms_message("Video stream refused by remote."); - return 0; - } - - params=&call->video_params; - remote_profile=call->profile; - /* see if this codec is supported in our local rtp profile*/ - supported=linphone_payload_is_supported(lc,payload,lc->local_profile,remote_profile,TRUE,&lpt); - if (supported==Unsupported) { - ms_message("Refusing video codec %i (%s)",payload->pt,payload->a_rtpmap); - return -1; - } - if (lc->sip_conf.only_one_codec && params->initialized){ - return -1; - } - if (supported==SupportedAndValid){ - if (params->initialized==0){ - /* this is the first codec we may accept*/ - params->localport=lc->rtp_conf.video_rtp_port; - payload->localport=params->natd_port>0 ? params->natd_port : lc->rtp_conf.video_rtp_port; - params->line=payload->line; - params->pt=payload->pt; /* remember the first payload accepted */ - if (payload->relay_host!=NULL){ - strncpy(params->remoteaddr,payload->relay_host,sizeof(params->remoteaddr)-1); - params->remoteport=payload->relay_port; - params->remotertcpport=payload->relay_port; - params->relay_session_id=payload->relay_session_id; - }else{ - strncpy(params->remoteaddr,payload->c_addr,sizeof(params->remoteaddr)-1); - params->remoteport=payload->remoteport; - params->remotertcpport=params->remoteport+1; - } - params->initialized=1; - payload->b_as_bandwidth=(lc->dw_video_bw>0) ? lc->dw_video_bw : 0; - }else{ - /* refuse all other video lines*/ - if(params->line!=payload->line) return -1; - } - } - return 0; -} - -int linphone_read_audio_answer(sdp_context_t *ctx,sdp_payload_t *payload) -{ - LinphoneCall *call=(LinphoneCall*)sdp_context_get_user_pointer(ctx); - LinphoneCore *lc=call->core; - StreamParams *params; - SupportLevel supported; - PayloadType *lpt=NULL; - - /* paranoid check: see if this codec is supported in our local rtp profile*/ - supported=linphone_payload_is_supported(lc, payload,lc->local_profile,call->profile,FALSE,&lpt); - if (supported==Unsupported) { - ms_warning("This remote sip phone did not answer properly to my sdp offer: rtpmap=%s",payload->a_rtpmap); - return 0; - } - if (supported==SupportedAndValid){ - params=&call->audio_params; - if (params->initialized==0){ - /* this is the first codec we accept, this is the one that is going to be used (at least for sending - data.*/ - params->localport=lc->rtp_conf.audio_rtp_port; - params->line=payload->line; - params->pt=payload->pt; /* remember the first payload accepted */ - if (payload->relay_host!=NULL){ - strncpy(params->remoteaddr,payload->relay_host,sizeof(params->remoteaddr)-1); - params->remoteport=payload->relay_port; - params->remotertcpport=payload->relay_port; - params->relay_session_id=payload->relay_session_id; - }else{ - strncpy(params->remoteaddr,payload->c_addr,sizeof(params->remoteaddr)-1); - params->remoteport=payload->remoteport; - params->remotertcpport=payload->remoteport+1; - } - params->initialized=1; - /* we can now update the allocated bandwidth for audio, and then video*/ - linphone_core_update_allocated_audio_bandwidth_in_call(lc,lpt); - } - } - return 0; -} - -int linphone_read_video_answer(sdp_context_t *ctx,sdp_payload_t *payload) -{ - LinphoneCall *call=(LinphoneCall*)sdp_context_get_user_pointer(ctx); - LinphoneCore *lc=call->core; - StreamParams *params; - SupportLevel supported; - PayloadType *lpt=NULL; - - /* paranoid check: see if this codec is supported in our local rtp profile*/ - supported=linphone_payload_is_supported(lc, payload,lc->local_profile,call->profile,FALSE,&lpt); - if (supported==Unsupported) { - ms_warning("This remote sip phone did not answer properly to my sdp offer: rtpmap=%s",payload->a_rtpmap); - return 0; - } - if (supported==SupportedAndValid){ - params=&call->video_params; - if (params->initialized==0){ - /* this is the first codec we may accept*/ - params->localport=lc->rtp_conf.video_rtp_port; - params->line=payload->line; - params->pt=payload->pt; /* remember the first payload accepted */ - if (payload->relay_host!=NULL){ - strncpy(params->remoteaddr,payload->relay_host,sizeof(params->remoteaddr)-1); - params->remoteport=payload->relay_port; - params->remotertcpport=payload->relay_port; - params->relay_session_id=payload->relay_session_id; - }else{ - strncpy(params->remoteaddr,payload->c_addr,sizeof(params->remoteaddr)-1); - params->remoteport=payload->remoteport; - params->remotertcpport=payload->remoteport+1; - } - params->initialized=1; - } - } - return 0; -} - -void linphone_call_ringing(LinphoneCore *lc, eXosip_event_t *ev){ - sdp_message_t *sdp=eXosip_get_sdp_info(ev->response); - LinphoneCall *call=lc->call; - - lc->vtable.display_status(lc,_("Remote ringing.")); - linphone_call_proceeding(lc,ev); - if (call==NULL) return; - if (sdp==NULL){ - if (lc->ringstream!=NULL) return; /*already ringing !*/ - if (lc->sound_conf.play_sndcard!=NULL){ - ms_message("Remote ringing..."); - lc->ringstream=ring_start(lc->sound_conf.remote_ring,2000,lc->sound_conf.play_sndcard); - } - }else{ - /*accept early media */ - StreamParams *audio_params; - if (call==NULL){ - ms_error("No call ?"); - goto end; - } - if (lc->audiostream->ticker!=NULL){ - /*streams already started */ - ms_message("Early media already started."); - goto end; - } - audio_params=&call->audio_params; - sdp_context_read_answer(lc->call->sdpctx,sdp); - lc->vtable.show(lc); - lc->vtable.display_status(lc,_("Early media.")); - gstate_new_state(lc, GSTATE_CALL_OUT_CONNECTED, NULL); - if (lc->ringstream!=NULL){ - ring_stop(lc->ringstream); - lc->ringstream=NULL; - } - ms_message("Doing early media..."); - linphone_core_start_media_streams(lc,call); - } - call->state=LCStateRinging; - goto end; - end: - sdp_message_free(sdp); - -} - -static void linphone_process_media_control_xml(LinphoneCore *lc, eXosip_event_t *ev){ - osip_body_t *body=NULL; - osip_message_get_body(ev->request,0,&body); - if (body && body->body!=NULL && - strstr(body->body,"picture_fast_update")){ - osip_message_t *ans=NULL; - ms_message("Receiving VFU request !"); -#ifdef VIDEO_ENABLED - if (lc->videostream) - video_stream_send_vfu(lc->videostream); -#endif - eXosip_call_build_answer(ev->tid,200,&ans); - if (ans) - eXosip_call_send_answer(ev->tid,200,ans); - } -} - -static void linphone_process_dtmf_relay(LinphoneCore *lc, eXosip_event_t *ev){ - osip_body_t *body=NULL; - osip_message_get_body(ev->request,0,&body); - if (body && body->body!=NULL){ - osip_message_t *ans=NULL; - const char *name=strstr(body->body,"Signal"); - if (name==NULL) name=strstr(body->body,"signal"); - if (name==NULL) { - ms_warning("Could not extract the dtmf name from the SIP INFO."); - }else{ - char tmp[2]; - name+=strlen("signal"); - if (sscanf(name," = %1s",tmp)==1){ - ms_message("Receiving dtmf %s via SIP INFO.",tmp); - if (lc->vtable.dtmf_received != NULL) - lc->vtable.dtmf_received(lc, tmp[0]); - } - } - - eXosip_call_build_answer(ev->tid,200,&ans); - if (ans) - eXosip_call_send_answer(ev->tid,200,ans); - } -} - -void linphone_call_message_new(LinphoneCore *lc, eXosip_event_t *ev){ - osip_message_t *ans=NULL; - if (ev->request){ - if (MSG_IS_INFO(ev->request)){ - osip_content_type_t *ct; - ct=osip_message_get_content_type(ev->request); - if (ct && ct->subtype){ - if (strcmp(ct->subtype,"media_control+xml")==0) - linphone_process_media_control_xml(lc,ev); - else if (strcmp(ct->subtype,"dtmf-relay")==0) - linphone_process_dtmf_relay(lc,ev); - else { - ms_message("Unhandled SIP INFO."); - /*send an "Not implemented" answer*/ - eXosip_call_build_answer(ev->tid,501,&ans); - if (ans) - eXosip_call_send_answer(ev->tid,501,ans); - } - }else{ - /*empty SIP INFO, probably to test we are alive. Send an empty answer*/ - eXosip_call_build_answer(ev->tid,200,&ans); - if (ans) - eXosip_call_send_answer(ev->tid,200,ans); - } - } - }else ms_warning("linphone_call_message_new: No request ?"); -} - -void linphone_registration_faillure(LinphoneCore *lc, eXosip_event_t *ev){ - int status_code=0; - char *msg; - const char *reason=NULL; - osip_uri_t *requri=osip_message_get_uri(ev->request); - char *ru; - LinphoneProxyConfig *cfg; - - if (ev->response){ - status_code=osip_message_get_status_code(ev->response); - reason=osip_message_get_reason_phrase(ev->response); - } - switch(status_code){ - case 401: - case 407: - linphone_process_authentication(lc,ev); - break; - default: - cfg=linphone_core_get_proxy_config_from_rid(lc,ev->rid); - /* if contact is up to date, process the failure, otherwise resend a new register with - updated contact first, just in case the faillure is due to incorrect contact */ - if (linphone_proxy_config_register_again_with_updated_contact(cfg,ev->request,ev->response)) - return; /*we are retrying with an updated contact*/ - linphone_proxy_config_process_authentication_failure(lc,status_code,ev); - osip_uri_to_str(requri,&ru); - msg=ortp_strdup_printf(_("Registration on %s failed: %s"),ru,(reason!=NULL) ? reason : _("no response timeout")); - lc->vtable.display_status(lc,msg); - gstate_new_state(lc, GSTATE_REG_FAILED, msg); - ms_free(msg); - osip_free(ru); - } -} - -void linphone_registration_success(LinphoneCore *lc,eXosip_event_t *ev){ - LinphoneProxyConfig *cfg; - osip_uri_t *requri=osip_message_get_uri(ev->request); - char *msg; - char *ru; - osip_header_t *h=NULL; - - cfg=linphone_core_get_proxy_config_from_rid(lc,ev->rid); - ms_return_if_fail(cfg!=NULL); - - osip_message_get_expires(ev->request,0,&h); - if (h!=NULL && atoi(h->hvalue)!=0){ - cfg->registered=TRUE; - linphone_proxy_config_register_again_with_updated_contact(cfg,ev->request,ev->response); - }else cfg->registered=FALSE; - - gstate_new_state(lc, GSTATE_REG_OK, NULL); - - osip_uri_to_str(requri,&ru); - if (cfg->registered) msg=ms_strdup_printf(_("Registration on %s successful."),ru); - else msg=ms_strdup_printf(_("Unregistration on %s done."),ru); - lc->vtable.display_status(lc,msg); - ms_free(msg); - osip_free(ru); -} - -static bool_t comes_from_local_if(osip_message_t *msg){ - osip_via_t *via=NULL; - osip_message_get_via(msg,0,&via); - if (via){ - const char *host; - host=osip_via_get_host(via); - if (strcmp(host,"127.0.0.1")==0 || strcmp(host,"::1")==0){ - osip_generic_param_t *param=NULL; - osip_via_param_get_byname(via,"received",¶m); - if (param==NULL) return TRUE; - if (param->gvalue && - (strcmp(param->gvalue,"127.0.0.1")==0 || strcmp(param->gvalue,"::1")==0)){ - return TRUE; - } - } - } - return FALSE; -} - -static void linphone_inc_update(LinphoneCore *lc, eXosip_event_t *ev){ - osip_message_t *msg=NULL; - ms_message("Processing incoming UPDATE"); - eXosip_lock(); - eXosip_message_build_answer(ev->tid,200,&msg); - if (msg!=NULL) - eXosip_message_send_answer(ev->tid,200,msg); - eXosip_unlock(); -} - -static void linphone_other_request(LinphoneCore *lc, eXosip_event_t *ev){ - ms_message("in linphone_other_request"); - if (ev->request==NULL) return; - if (strcmp(ev->request->sip_method,"MESSAGE")==0){ - linphone_core_text_received(lc,ev); - eXosip_message_send_answer(ev->tid,200,NULL); - }else if (strcmp(ev->request->sip_method,"OPTIONS")==0){ - osip_message_t *options=NULL; - eXosip_options_build_answer(ev->tid,200,&options); - osip_message_set_allow(options,"INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, SUBSCRIBE, NOTIFY, INFO"); - osip_message_set_accept(options,"application/sdp"); - eXosip_options_send_answer(ev->tid,200,options); - }else if (strcmp(ev->request->sip_method,"WAKEUP")==0 - && comes_from_local_if(ev->request)) { - eXosip_message_send_answer(ev->tid,200,NULL); - ms_message("Receiving WAKEUP request !"); - if (lc->vtable.show) - lc->vtable.show(lc); - }else if (strncmp(ev->request->sip_method, "REFER", 5) == 0){ - ms_message("Receiving REFER request !"); - if (comes_from_local_if(ev->request)) { - osip_header_t *h=NULL; - osip_message_header_get_byname(ev->request,"Refer-To",0,&h); - eXosip_message_send_answer(ev->tid,200,NULL); - if (h){ - if (lc->vtable.refer_received) - lc->vtable.refer_received(lc,h->hvalue); - } - - }else ms_warning("Ignored REFER not coming from this local loopback interface."); - }else if (strncmp(ev->request->sip_method, "UPDATE", 6) == 0){ - linphone_inc_update(lc,ev); - }else { - char *tmp=NULL; - size_t msglen=0; - osip_message_to_str(ev->request,&tmp,&msglen); - if (tmp){ - ms_message("Unsupported request received:\n%s",tmp); - osip_free(tmp); - } - /*answer with a 501 Not implemented*/ - eXosip_message_send_answer(ev->tid,501,NULL); - } -} - -void linphone_core_process_event(LinphoneCore *lc,eXosip_event_t *ev) -{ - switch(ev->type){ - case EXOSIP_CALL_ANSWERED: - ms_message("CALL_ANSWERED\n"); - linphone_call_accepted(lc,ev); - linphone_authentication_ok(lc,ev); - break; - case EXOSIP_CALL_CLOSED: - case EXOSIP_CALL_CANCELLED: - ms_message("CALL_CLOSED or CANCELLED\n"); - linphone_call_terminated(lc,ev); - break; - case EXOSIP_CALL_TIMEOUT: - case EXOSIP_CALL_NOANSWER: - ms_message("CALL_TIMEOUT or NOANSWER\n"); - linphone_call_failure(lc,ev); - break; - case EXOSIP_CALL_REQUESTFAILURE: - case EXOSIP_CALL_GLOBALFAILURE: - case EXOSIP_CALL_SERVERFAILURE: - ms_message("CALL_REQUESTFAILURE or GLOBALFAILURE or SERVERFAILURE\n"); - linphone_call_failure(lc,ev); - break; - case EXOSIP_CALL_INVITE: - ms_message("CALL_NEW\n"); - /* CALL_NEW is used twice in qos mode : - * when you receive invite (textinfo = "With QoS" or "Without QoS") - * and when you receive update (textinfo = "New Call") */ - linphone_inc_new_call(lc,ev); - break; - case EXOSIP_CALL_REINVITE: - linphone_handle_reinvite(lc,ev); - break; - case EXOSIP_CALL_ACK: - ms_message("CALL_ACK"); - linphone_handle_ack(lc,ev); - break; - case EXOSIP_CALL_REDIRECTED: - ms_message("CALL_REDIRECTED"); - linphone_call_redirected(lc,ev); - break; - case EXOSIP_CALL_PROCEEDING: - ms_message("CALL_PROCEEDING"); - linphone_call_proceeding(lc,ev); - break; - case EXOSIP_CALL_RINGING: - ms_message("CALL_RINGING"); - linphone_call_ringing(lc,ev); - break; - case EXOSIP_CALL_MESSAGE_NEW: - ms_message("EXOSIP_CALL_MESSAGE_NEW"); - linphone_call_message_new(lc,ev); - break; - case EXOSIP_CALL_MESSAGE_REQUESTFAILURE: - if (ev->did<0 && ev->response && - (ev->response->status_code==407 || ev->response->status_code==401)){ - eXosip_default_action(ev); - } - break; - case EXOSIP_IN_SUBSCRIPTION_NEW: - ms_message("CALL_SUBSCRIPTION_NEW or UPDATE"); - linphone_subscription_new(lc,ev); - break; - case EXOSIP_SUBSCRIPTION_UPDATE: - break; - case EXOSIP_SUBSCRIPTION_NOTIFY: - ms_message("CALL_SUBSCRIPTION_NOTIFY"); - linphone_notify_recv(lc,ev); - break; - case EXOSIP_SUBSCRIPTION_ANSWERED: - ms_message("EXOSIP_SUBSCRIPTION_ANSWERED, ev->sid=%i\n",ev->sid); - linphone_subscription_answered(lc,ev); - break; - case EXOSIP_SUBSCRIPTION_CLOSED: - ms_message("EXOSIP_SUBSCRIPTION_CLOSED\n"); - linphone_subscription_closed(lc,ev); - break; - case EXOSIP_CALL_RELEASED: - ms_message("CALL_RELEASED\n"); - linphone_call_released(lc, ev->cid); - break; - case EXOSIP_REGISTRATION_FAILURE: - ms_message("REGISTRATION_FAILURE\n"); - linphone_registration_faillure(lc,ev); - break; - case EXOSIP_REGISTRATION_SUCCESS: - linphone_authentication_ok(lc,ev); - linphone_registration_success(lc,ev); - break; - case EXOSIP_MESSAGE_NEW: - linphone_other_request(lc,ev); - break; - case EXOSIP_MESSAGE_REQUESTFAILURE: - if (ev->response && (ev->response->status_code == 407 || ev->response->status_code == 401)){ - /*the user is expected to have registered to the proxy, thus password is known*/ - eXosip_default_action(ev); - } - break; - default: - ms_message("Unhandled exosip event !"); - break; - } - eXosip_event_free(ev); -} diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 822dc169a..7aad0800f 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -313,7 +313,8 @@ void linphone_call_log_completed(LinphoneCallLog *calllog, LinphoneCall *call){ info=ortp_strdup_printf(ngettext("You have missed %i call.", "You have missed %i calls.", lc->missed_calls), lc->missed_calls); - lc->vtable.display_status(lc,info); + if (lc->vtable.display_status!=NULL) + lc->vtable.display_status(lc,info); ms_free(info); } else calllog->status=LinphoneCallAborted; @@ -1479,14 +1480,14 @@ void linphone_core_set_user_agent(const char *name, const char *ver){ * * @ingroup network_parameters **/ -void linphone_core_set_sip_port(LinphoneCore *lc,int port) +int linphone_core_set_sip_port(LinphoneCore *lc,int port) { const char *anyaddr; int err=0; - if (port==lc->sip_conf.sip_port) return; + if (port==lc->sip_conf.sip_port) return 0; lc->sip_conf.sip_port=port; - if (lc->sal==NULL) return; + if (lc->sal==NULL) return -1; if (lc->sip_conf.ipv6_enabled) anyaddr="::0"; @@ -1496,11 +1497,13 @@ void linphone_core_set_sip_port(LinphoneCore *lc,int port) if (err<0){ char *msg=ortp_strdup_printf("UDP port %i seems already in use ! Cannot initialize.",port); ms_warning(msg); - lc->vtable.display_warning(lc,msg); + if (lc->vtable.display_warning) + lc->vtable.display_warning(lc,msg); ms_free(msg); - return; + return -1; } apply_user_agent(lc); + return 0; } /** @@ -1541,7 +1544,8 @@ static void display_bandwidth(RtpSession *as, RtpSession *vs){ } static void linphone_core_disconnected(LinphoneCore *lc){ - lc->vtable.display_warning(lc,_("Remote end seems to have disconnected, the call is going to be closed.")); + if (lc->vtable.display_warning!=NULL) + lc->vtable.display_warning(lc,_("Remote end seems to have disconnected, the call is going to be closed.")); linphone_core_terminate_call(lc,NULL); } @@ -1754,9 +1758,11 @@ LinphoneAddress * linphone_core_interpret_url(LinphoneCore *lc, const char *url) LinphoneAddress *uri; if (is_enum(url,&enum_domain)){ - lc->vtable.display_status(lc,_("Looking for telephone number destination...")); + if (lc->vtable.display_status!=NULL) + lc->vtable.display_status(lc,_("Looking for telephone number destination...")); if (enum_lookup(enum_domain,&enumres)<0){ - lc->vtable.display_status(lc,_("Could not resolve this number.")); + if (lc->vtable.display_status!=NULL) + lc->vtable.display_status(lc,_("Could not resolve this number.")); ms_free(enum_domain); return NULL; } @@ -1944,12 +1950,14 @@ int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, LinphonePro sal_call_set_local_media_description(call->op,call->localdesc); } barmsg=ortp_strdup_printf("%s %s", _("Contacting"), real_url); - lc->vtable.display_status(lc,barmsg); + if (lc->vtable.display_status!=NULL) + lc->vtable.display_status(lc,barmsg); ms_free(barmsg); if (err<0){ ms_warning("Could not initiate call."); - lc->vtable.display_status(lc,_("could not call")); + if (lc->vtable.display_status!=NULL) + lc->vtable.display_status(lc,_("could not call")); linphone_core_stop_media_streams(lc,call); linphone_call_destroy(call); lc->call=NULL; @@ -2410,7 +2418,8 @@ int linphone_core_accept_call(LinphoneCore *lc, const char *url) sal_op_set_contact(call->op,contact); sal_call_accept(call->op); - lc->vtable.display_status(lc,_("Connected.")); + if (lc->vtable.display_status!=NULL) + lc->vtable.display_status(lc,_("Connected.")); gstate_new_state(lc, GSTATE_CALL_IN_CONNECTED, NULL); call->resultdesc=sal_call_get_final_media_description(call->op); if (call->resultdesc){ @@ -2444,7 +2453,8 @@ int linphone_core_terminate_call(LinphoneCore *lc, const char *url) lc->ringstream=NULL; } linphone_core_stop_media_streams(lc,call); - lc->vtable.display_status(lc,_("Call ended") ); + if (lc->vtable.display_status!=NULL) + lc->vtable.display_status(lc,_("Call ended") ); gstate_new_state(lc, GSTATE_CALL_END, NULL); linphone_call_destroy(call); return 0; diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 39606ae35..112f0ddaf 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -610,7 +610,7 @@ bool_t linphone_core_get_use_rfc2833_for_dtmf(LinphoneCore *lc); int linphone_core_get_sip_port(LinphoneCore *lc); -void linphone_core_set_sip_port(LinphoneCore *lc,int port); +int linphone_core_set_sip_port(LinphoneCore *lc,int port); ortp_socket_t linphone_core_get_sip_socket(LinphoneCore *lc); diff --git a/coreapi/linphonecore_utils.h b/coreapi/linphonecore_utils.h index 43d6559bd..b4f3643bb 100644 --- a/coreapi/linphonecore_utils.h +++ b/coreapi/linphonecore_utils.h @@ -39,7 +39,7 @@ int lsd_player_stop(LsdPlayer *p); void lsd_player_enable_loop(LsdPlayer *p, bool_t loopmode); bool_t lsd_player_loop_enabled(const LsdPlayer *p); void lsd_player_set_gain(LsdPlayer *p, float gain); -LinphoneSoundDaemon lsd_player_get_daemon(const LsdPlayer *p); +LinphoneSoundDaemon *lsd_player_get_daemon(const LsdPlayer *p); LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname); LsdPlayer * linphone_sound_daemon_get_player(LinphoneSoundDaemon *lsd); diff --git a/coreapi/lsd.c b/coreapi/lsd.c index 2dd9898a5..9759ed961 100644 --- a/coreapi/lsd.c +++ b/coreapi/lsd.c @@ -62,6 +62,8 @@ struct _LinphoneSoundDaemon { static MSFilter *create_writer(MSSndCard *c){ LinphoneSoundDaemon *lsd=(LinphoneSoundDaemon*)c->data; + lsd->itcsink=ms_filter_new(MS_ITC_SINK_ID); + ms_filter_call_method(lsd->itcsink,MS_ITC_SINK_CONNECT,lsd->branches[0].player); return lsd->itcsink; } @@ -104,6 +106,10 @@ void linphone_sound_daemon_release_player(LinphoneSoundDaemon *obj, LsdPlayer * } } +LinphoneSoundDaemon *lsd_player_get_daemon(const LsdPlayer *p){ + return p->lsd; +} + int lsd_player_stop(LsdPlayer *p){ ms_filter_call_method_noarg(p->player,MS_PLAYER_PAUSE); return 0; @@ -245,8 +251,6 @@ LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname){ lsd->proxycard=ms_snd_card_new(&proxycard); lsd->proxycard->data=lsd; - - ms_filter_call_method(lsd->itcsink,MS_ITC_SINK_CONNECT,lsd->branches[0].player); return lsd; } diff --git a/coreapi/presence.c b/coreapi/presence.c index 8d9d39474..c56861d9d 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -130,7 +130,8 @@ void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeState ss, Sal tmp=linphone_address_as_string(friend); lf->status=estatus; lf->subscribe_active=TRUE; - lc->vtable.notify_presence_recv(lc,(LinphoneFriend*)lf); + if (lc->vtable.notify_presence_recv) + lc->vtable.notify_presence_recv(lc,(LinphoneFriend*)lf); ms_free(tmp); }else{ ms_message("But this person is not part of our friend list, so we don't care."); diff --git a/coreapi/test_lsd.c b/coreapi/test_lsd.c index 64b5d8a78..930980f83 100644 --- a/coreapi/test_lsd.c +++ b/coreapi/test_lsd.c @@ -30,7 +30,7 @@ static void play_finished(LsdPlayer *p){ const char *filename=(const char *)lsd_player_get_user_pointer (p); ms_message("Playing of %s is finished.",filename); if (!lsd_player_loop_enabled (p)){ - linphone_sound_daemon_release_player (lsd_player_get_daemon(p)); + linphone_sound_daemon_release_player (lsd_player_get_daemon(p),p); } } From be086cd0fcd31f26071189ff55216efd9365101e Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 2 Jun 2010 11:51:43 +0200 Subject: [PATCH 18/45] linphone sound daemon now fully works --- coreapi/linphonecore.c | 3 --- coreapi/lsd.c | 43 +++++++++++++++++++++++++----------------- mediastreamer2 | 2 +- 3 files changed, 27 insertions(+), 21 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index ce01bfc01..ac10f2453 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2135,9 +2135,6 @@ static RtpProfile *make_profile(LinphoneCore *lc, const SalMediaDescription *md, } void linphone_core_start_media_streams(LinphoneCore *lc, LinphoneCall *call){ -#ifdef PRINTF_DEBUG - printf("%s(%d)\n",__FUNCTION__,__LINE__); -#endif LinphoneAddress *me=linphone_core_get_primary_contact_parsed(lc); const char *tool="linphone-" LINPHONE_VERSION; char *cname; diff --git a/coreapi/lsd.c b/coreapi/lsd.c index 9759ed961..ddb8667c2 100644 --- a/coreapi/lsd.c +++ b/coreapi/lsd.c @@ -54,7 +54,6 @@ struct _LinphoneSoundDaemon { int out_nchans; MSFilter *mixer; MSFilter *soundout; - MSFilter *itcsink; MSTicker *ticker; MSSndCard *proxycard; LsdPlayer branches[MAX_BRANCHES]; @@ -62,9 +61,9 @@ struct _LinphoneSoundDaemon { static MSFilter *create_writer(MSSndCard *c){ LinphoneSoundDaemon *lsd=(LinphoneSoundDaemon*)c->data; - lsd->itcsink=ms_filter_new(MS_ITC_SINK_ID); - ms_filter_call_method(lsd->itcsink,MS_ITC_SINK_CONNECT,lsd->branches[0].player); - return lsd->itcsink; + MSFilter *itcsink=ms_filter_new(MS_ITC_SINK_ID); + ms_filter_call_method(itcsink,MS_ITC_SINK_CONNECT,lsd->branches[0].player); + return itcsink; } static MSSndCardDesc proxycard={ @@ -163,10 +162,28 @@ static void lsd_player_on_eop(void * userdata, unsigned int id, void *arg){ p->eop_cb(p); } -int lsd_player_play(LsdPlayer *b, const char *filename ){ +static void lsd_player_configure(LsdPlayer *b){ int rate,chans; - int state; LinphoneSoundDaemon *lsd=b->lsd; + + if (ms_filter_get_id(b->player)==MS_ITC_SOURCE_ID) + ms_message("Configuring branch coming from audio call..."); + + ms_filter_call_method(b->player,MS_FILTER_GET_SAMPLE_RATE,&rate); + ms_filter_call_method(b->player,MS_FILTER_GET_NCHANNELS,&chans); + + + ms_filter_call_method(b->rateconv,MS_FILTER_SET_SAMPLE_RATE,&rate); + ms_filter_call_method(b->rateconv,MS_FILTER_SET_NCHANNELS,&chans); + ms_filter_call_method(b->rateconv,MS_FILTER_SET_OUTPUT_SAMPLE_RATE,&lsd->out_rate); + + ms_filter_call_method(b->chanadapter,MS_FILTER_SET_NCHANNELS,&chans); + ms_filter_call_method(b->chanadapter,MS_CHANNEL_ADAPTER_SET_OUTPUT_NCHANNELS,&lsd->out_nchans); + ms_message("player configured for rate=%i, channels=%i",rate,chans); +} + +int lsd_player_play(LsdPlayer *b, const char *filename ){ + int state; ms_filter_call_method(b->player,MS_PLAYER_GET_STATE,&state); if (state!=MSPlayerClosed){ @@ -177,16 +194,8 @@ int lsd_player_play(LsdPlayer *b, const char *filename ){ ms_warning("Could not play %s",filename); return -1; } - ms_filter_call_method(b->player,MS_FILTER_GET_SAMPLE_RATE,&rate); - ms_filter_call_method(b->player,MS_FILTER_GET_NCHANNELS,&chans); ms_filter_set_notify_callback (b->player,lsd_player_on_eop,b); - - ms_filter_call_method(b->rateconv,MS_FILTER_SET_SAMPLE_RATE,&rate); - ms_filter_call_method(b->rateconv,MS_FILTER_SET_NCHANNELS,&chans); - ms_filter_call_method(b->rateconv,MS_FILTER_SET_OUTPUT_SAMPLE_RATE,&lsd->out_rate); - - ms_filter_call_method(b->chanadapter,MS_FILTER_SET_NCHANNELS,&chans); - ms_filter_call_method(b->chanadapter,MS_CHANNEL_ADAPTER_SET_OUTPUT_NCHANNELS,&lsd->out_nchans); + lsd_player_configure(b); ms_filter_call_method_noarg (b->player,MS_PLAYER_START); return 0; } @@ -229,7 +238,6 @@ LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname){ lsd=ms_new0(LinphoneSoundDaemon,1); lsd->soundout=ms_snd_card_create_writer(card); lsd->mixer=ms_filter_new(MS_AUDIO_MIXER_ID); - lsd->itcsink=ms_filter_new(MS_ITC_SINK_ID); lsd->out_rate=44100; lsd->out_nchans=2; ms_filter_call_method(lsd->soundout,MS_FILTER_SET_SAMPLE_RATE,&lsd->out_rate); @@ -241,6 +249,8 @@ LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname){ mp.pin=0; lsd_player_init(&lsd->branches[0],mp,MS_ITC_SOURCE_ID,lsd); + ms_filter_set_notify_callback(lsd->branches[0].player,(MSFilterNotifyFunc)lsd_player_configure,&lsd->branches[0]); + ms_filter_enable_synchronous_notifcations (lsd->branches[0].player,TRUE); for(i=1;ibranches[i],mp,MS_FILE_PLAYER_ID,lsd); @@ -268,7 +278,6 @@ void linphone_sound_daemon_destroy(LinphoneSoundDaemon *obj){ ms_ticker_destroy(obj->ticker); ms_filter_destroy(obj->soundout); ms_filter_destroy(obj->mixer); - ms_filter_destroy(obj->itcsink); } MSSndCard *linphone_sound_daemon_get_proxy_card(LinphoneSoundDaemon *lsd){ diff --git a/mediastreamer2 b/mediastreamer2 index 6445a4897..7a9d0bf6b 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 6445a4897dfffc2331015e4a3a1dadc60d4a7261 +Subproject commit 7a9d0bf6b6be4ee0728db94bc0e1b661ee87e1d2 From f6537cb2b541f3904a1988bf781d399b6bf3e8a2 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 2 Jun 2010 14:18:07 +0200 Subject: [PATCH 19/45] fix release of call objects --- coreapi/callbacks.c | 22 +++++------- coreapi/linphonecall.c | 76 +++++++++++++++++++++++++++++++++++------- coreapi/linphonecore.c | 24 ++++++------- 3 files changed, 85 insertions(+), 37 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 4b53ffdad..31b5e723a 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -82,17 +82,11 @@ static void call_received(SalOp *h){ to=sal_op_get_to(h); call=linphone_call_new_incoming(lc,linphone_address_new(from),linphone_address_new(to),h); - if(linphone_core_add_call(lc,call)!= 0) - { - ms_warning("we cannot have more calls\n"); - sal_call_decline(h,SalReasonMedia,NULL); - linphone_call_unref(call); - return; - } + if(linphone_core_get_current_call(lc)!=NULL) //we are already in call just inform that an incoming call is going on { char temp[256]; - snprintf(temp,sizeof(temp),"A new incoming call from %s during call",from); + snprintf(temp,sizeof(temp)-1,"A new incoming call from %s during call",from); lc->vtable.display_status(lc,temp); } sal_call_set_local_media_description(h,call->localdesc); @@ -104,6 +98,8 @@ static void call_received(SalOp *h){ linphone_call_unref(call); return; } + /* the call is acceptable so we can now add it to our list */ + linphone_core_add_call(lc,call); from_parsed=linphone_address_new(sal_op_get_from(h)); linphone_address_clean(from_parsed); @@ -330,18 +326,19 @@ static void call_terminated(SalOp *op, const char *from){ lc->vtable.show(lc); if (lc->vtable.display_status!=NULL) lc->vtable.display_status(lc,_("Call terminated.")); - linphone_call_set_terminated(call); + call->state=LinphoneCallTerminated; gstate_new_state(lc, GSTATE_CALL_END, NULL); if (lc->vtable.bye_recv!=NULL){ LinphoneAddress *addr=linphone_address_new(from); char *tmp; linphone_address_clean(addr); tmp=linphone_address_as_string(addr); - lc->vtable.bye_recv(lc,call); + if (lc->vtable.bye_recv!=NULL) + lc->vtable.bye_recv(lc,call); ms_free(tmp); linphone_address_destroy(addr); } - linphone_call_unref(call); + linphone_call_set_terminated(call); } static void call_failure(SalOp *op, SalError error, SalReason sr, const char *details, int code){ @@ -413,10 +410,9 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de if(call == linphone_core_get_current_call(lc)) linphone_core_stop_media_streams(lc,call); if (call!=NULL) { - linphone_call_set_terminated(call); - linphone_call_unref(call);//TODO not an unref here ???//AUREL if (sr!=SalReasonDeclined) gstate_new_state(lc, GSTATE_CALL_ERROR, msg); else gstate_new_state(lc, GSTATE_CALL_END, NULL); + linphone_call_set_terminated(call); } } diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 26ece225b..ac165a629 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -151,20 +151,45 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro return call; } +/* this function is called internally to get rid of a call. + It performs the following tasks: + - remove the call from the internal list of calls + - unref the LinphoneCall object + - update the call logs accordingly +*/ + void linphone_call_set_terminated(LinphoneCall *call){ LinphoneCallStatus status=LinphoneCallAborted; + LinphoneCore *lc=call->core; + + if (ms_list_size(lc->calls)==0) + linphone_core_notify_all_friends(lc,lc->prev_mode); + + linphone_core_update_allocated_audio_bandwidth(lc); if (call->state==LinphoneCallAVRunning){ status=LinphoneCallSuccess; + } linphone_call_log_completed(call->log,call, status); call->state=LinphoneCallTerminated; + if (linphone_core_del_call(lc,call) != 0){ + ms_error("could not remove the call from the list !!!"); + } + if (call == linphone_core_get_current_call(lc)){ + ms_message("destroying the current call\n"); + linphone_core_unset_the_current_call(lc); + } + if (call->op!=NULL) { + /* so that we cannot have anymore upcalls for SAL + concerning this call*/ + sal_op_release(call->op); + call->op=NULL; + } + linphone_call_unref(call); } static void linphone_call_destroy(LinphoneCall *obj) { - linphone_core_notify_all_friends(obj->core,obj->core->prev_mode); - - linphone_core_update_allocated_audio_bandwidth(obj->core); if (obj->op!=NULL) { sal_op_release(obj->op); obj->op=NULL; @@ -180,40 +205,62 @@ static void linphone_call_destroy(LinphoneCall *obj) if (obj->ping_op) { sal_op_release(obj->ping_op); } - if(linphone_core_del_call(obj->core,obj) != 0) - { - ms_error("could not remove the call from the list !!!"); - } - if(obj == linphone_core_get_current_call(obj->core)) - { - ms_message("destroying the current call\n"); - linphone_core_unset_the_current_call(obj->core); - } ms_free(obj); } +/** + * @addtogroup calls + * @{ +**/ + +/** + * Increments the call 's reference count. + * An application that wishes to retain a pointer to call object + * must use this function to unsure the pointer remains + * valid. Once the application no more needs this pointer, + * it must call linphone_call_unref(). +**/ void linphone_call_ref(LinphoneCall *obj){ obj->refcnt++; } +/** + * Decrements the call object reference count. + * See linphone_call_ref(). +**/ void linphone_call_unref(LinphoneCall *obj){ obj->refcnt--; if (obj->refcnt==0) linphone_call_destroy(obj); } +/** + * Returns true if the call is paused. +**/ bool_t linphone_call_paused(LinphoneCall *call){ return call->state==LinphoneCallPaused; } +/** + * Returns the remote address associated to this call + * +**/ const LinphoneAddress * linphone_call_get_remote_address(const LinphoneCall *call){ return call->dir==LinphoneCallIncoming ? call->log->from : call->log->to; } +/** + * Returns the remote address associated to this call as a string. + * + * The result string must be freed by user using ms_free(). +**/ char *linphone_call_get_remote_address_as_string(const LinphoneCall *call){ return linphone_address_as_string(linphone_call_get_remote_address(call)); } +/** + * Retrieves the call's current state. +**/ LinphoneCallState linphone_call_get_state(const LinphoneCall *call){ return call->state; } @@ -241,3 +288,8 @@ void linphone_call_set_user_pointer(LinphoneCall *call, void *user_pointer) { call->user_pointer = user_pointer; } + +/** + * @} +**/ + diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index ac10f2453..a58061421 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1523,7 +1523,7 @@ static void linphone_core_do_plugin_tasks(LinphoneCore *lc){ * serialized with a mutex. **/ void linphone_core_iterate(LinphoneCore *lc){ - MSList *the_call; + MSList *calls; LinphoneCall *call; int disconnect_timeout = linphone_core_get_nortp_timeout(lc); time_t curtime=time(NULL); @@ -1550,10 +1550,13 @@ void linphone_core_iterate(LinphoneCore *lc){ proxy_update(lc); //we have to iterate for each call - the_call = lc->calls; - while(the_call != NULL) - { - call = (LinphoneCall *)the_call->data; + calls= lc->calls; + while(calls!= NULL){ + call = (LinphoneCall *)calls->data; + /* get immediately a reference to next one in case the one + we are going to examine is destroy and removed during + linphone_core_start_invite() */ + calls=calls->next; if (call->state==LinphoneCallPreEstablishing && (curtime-call->start_time>=2)){ /*start the call even if the OPTIONS reply did not arrive*/ linphone_core_start_invite(lc,call,NULL); @@ -1566,10 +1569,7 @@ void linphone_core_iterate(LinphoneCore *lc){ linphone_core_terminate_call(lc,call); } } - - the_call = the_call->next; - }//end while - //and consider the current call + } call = linphone_core_get_current_call(lc); if(call) { @@ -1840,7 +1840,7 @@ int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, LinphonePro lc->vtable.display_status(lc,_("could not call")); if(call == linphone_core_get_current_call(lc)) linphone_core_stop_media_streams(lc,call); - linphone_call_unref(call); + linphone_call_set_terminated (call); }else gstate_new_state(lc, GSTATE_CALL_OUT_INVITE, real_url); ms_free(real_url); ms_free(from); @@ -2377,7 +2377,6 @@ int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *the_call) lc->vtable.display_status(lc,_("Call ended") ); gstate_new_state(lc, GSTATE_CALL_END, NULL); linphone_call_set_terminated(call); - linphone_call_unref(call); return 0; } @@ -3788,6 +3787,7 @@ bool_t linphone_core_can_we_add_call(LinphoneCore *lc) { if(linphone_core_get_calls_nb(lc) < NB_MAX_CALLS) return TRUE; + ms_error("Maximum amount of simultaneous calls reached !"); return FALSE; } @@ -3828,7 +3828,7 @@ int linphone_core_add_call( LinphoneCore *lc, LinphoneCall *call) if(linphone_core_can_we_add_call(lc)) { MSList *the_calls = lc->calls; - the_calls = ms_list_append(the_calls,(void *)call); + the_calls = ms_list_append(the_calls,call); lc->calls = the_calls; return 0; } From d37e618afa2b3b5364c1e537149f5c6404afc6c1 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 2 Jun 2010 15:09:18 +0200 Subject: [PATCH 20/45] fix crash --- coreapi/callbacks.c | 1 + coreapi/linphonecore.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 8cb094121..eb2589c71 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -218,6 +218,7 @@ static void call_accepted(SalOp *op){ }//if there is an accepted incoming call else { + linphone_core_set_as_current_call (lc,call); gstate_new_state(lc, GSTATE_CALL_OUT_CONNECTED, NULL); linphone_connect_incoming(lc,call); } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index a58061421..277cbf13d 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -313,7 +313,7 @@ int linphone_core_get_current_call_duration(const LinphoneCore *lc){ const LinphoneAddress *linphone_core_get_current_call_remote_address(struct _LinphoneCore *lc){ LinphoneCall *call=linphone_core_get_current_call(lc); - if (call==NULL) return 0; + if (call==NULL) return NULL; return linphone_call_get_remote_address(call); } From 6cc2bfad9e51f2abc9f53bd4c394f0b13fad7cf8 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 14 Jun 2010 12:06:58 +0200 Subject: [PATCH 21/45] fix crash at termination --- coreapi/lsd.c | 6 +++++- coreapi/test_lsd.c | 5 +++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/coreapi/lsd.c b/coreapi/lsd.c index ddb8667c2..e216b8e88 100644 --- a/coreapi/lsd.c +++ b/coreapi/lsd.c @@ -285,5 +285,9 @@ MSSndCard *linphone_sound_daemon_get_proxy_card(LinphoneSoundDaemon *lsd){ } void linphone_core_use_sound_daemon(LinphoneCore *lc, LinphoneSoundDaemon *lsd){ - lc->sound_conf.lsd_card=linphone_sound_daemon_get_proxy_card (lsd); + if (lsd!=NULL){ + lc->sound_conf.lsd_card=linphone_sound_daemon_get_proxy_card (lsd); + }else { + lc->sound_conf.lsd_card=NULL; + } } diff --git a/coreapi/test_lsd.c b/coreapi/test_lsd.c index 930980f83..b34f51934 100644 --- a/coreapi/test_lsd.c +++ b/coreapi/test_lsd.c @@ -95,8 +95,9 @@ int main(int argc, char *argv[]){ wait_a_bit(lc,10); linphone_core_terminate_call(lc,NULL); } - - linphone_core_destroy(lc); + linphone_core_use_sound_daemon(lc,NULL); linphone_sound_daemon_destroy(lsd); + linphone_core_destroy(lc); + return 0; } From b448d5a9af1ebd6174540dd8f8222965a98670a2 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 14 Jun 2010 14:34:01 +0200 Subject: [PATCH 22/45] allow setting of output audio format in LinphoneSoundDaemon --- coreapi/linphonecore_utils.h | 2 +- coreapi/lsd.c | 6 +++--- coreapi/test_lsd.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/coreapi/linphonecore_utils.h b/coreapi/linphonecore_utils.h index b4f3643bb..7b62e972d 100644 --- a/coreapi/linphonecore_utils.h +++ b/coreapi/linphonecore_utils.h @@ -41,7 +41,7 @@ bool_t lsd_player_loop_enabled(const LsdPlayer *p); void lsd_player_set_gain(LsdPlayer *p, float gain); LinphoneSoundDaemon *lsd_player_get_daemon(const LsdPlayer *p); -LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname); +LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname, int rate, int nchannels); LsdPlayer * linphone_sound_daemon_get_player(LinphoneSoundDaemon *lsd); void linphone_sound_daemon_release_player(LinphoneSoundDaemon *lsd, LsdPlayer *lsdplayer); void linphone_core_use_sound_daemon(LinphoneCore *lc, LinphoneSoundDaemon *lsd); diff --git a/coreapi/lsd.c b/coreapi/lsd.c index e216b8e88..1599b074a 100644 --- a/coreapi/lsd.c +++ b/coreapi/lsd.c @@ -219,7 +219,7 @@ void lsd_player_set_gain(LsdPlayer *p, float gain){ ms_filter_call_method(p->lsd->mixer,MS_AUDIO_MIXER_SET_INPUT_GAIN,&gainctl); } -LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname){ +LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname, int rate, int nchannels){ int i; MSConnectionPoint mp; LinphoneSoundDaemon *lsd; @@ -238,8 +238,8 @@ LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname){ lsd=ms_new0(LinphoneSoundDaemon,1); lsd->soundout=ms_snd_card_create_writer(card); lsd->mixer=ms_filter_new(MS_AUDIO_MIXER_ID); - lsd->out_rate=44100; - lsd->out_nchans=2; + lsd->out_rate=rate; + lsd->out_nchans=nchannels; ms_filter_call_method(lsd->soundout,MS_FILTER_SET_SAMPLE_RATE,&lsd->out_rate); ms_filter_call_method(lsd->soundout,MS_FILTER_SET_NCHANNELS,&lsd->out_nchans); ms_filter_call_method(lsd->mixer,MS_FILTER_SET_SAMPLE_RATE,&lsd->out_rate); diff --git a/coreapi/test_lsd.c b/coreapi/test_lsd.c index b34f51934..c362aa4bc 100644 --- a/coreapi/test_lsd.c +++ b/coreapi/test_lsd.c @@ -51,7 +51,7 @@ int main(int argc, char *argv[]){ linphone_core_enable_logs(stdout); lc=linphone_core_new(&vtable,NULL,NULL,NULL); - lsd=linphone_sound_daemon_new (NULL); + lsd=linphone_sound_daemon_new (NULL,44100,1); linphone_core_use_sound_daemon(lc,lsd); From 567cec3c40fb15795c056c9fdb4370a115f21a34 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 14 Jun 2010 16:25:03 +0200 Subject: [PATCH 23/45] add linphone_sound_daemon_stop_all_players() --- coreapi/linphonecore_utils.h | 1 + coreapi/lsd.c | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/coreapi/linphonecore_utils.h b/coreapi/linphonecore_utils.h index 7b62e972d..7dbea33d7 100644 --- a/coreapi/linphonecore_utils.h +++ b/coreapi/linphonecore_utils.h @@ -44,6 +44,7 @@ LinphoneSoundDaemon *lsd_player_get_daemon(const LsdPlayer *p); LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname, int rate, int nchannels); LsdPlayer * linphone_sound_daemon_get_player(LinphoneSoundDaemon *lsd); void linphone_sound_daemon_release_player(LinphoneSoundDaemon *lsd, LsdPlayer *lsdplayer); +void linphone_sound_daemon_stop_all_players(LinphoneSoundDaemon *obj); void linphone_core_use_sound_daemon(LinphoneCore *lc, LinphoneSoundDaemon *lsd); void linphone_sound_daemon_destroy(LinphoneSoundDaemon *obj); diff --git a/coreapi/lsd.c b/coreapi/lsd.c index 1599b074a..a31592e9a 100644 --- a/coreapi/lsd.c +++ b/coreapi/lsd.c @@ -265,6 +265,13 @@ LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname, int rate, return lsd; } +void linphone_sound_daemon_stop_all_players(LinphoneSoundDaemon *obj){ + int i; + for(i=1;ibranches[i]); + } +} + void linphone_sound_daemon_destroy(LinphoneSoundDaemon *obj){ int i; MSConnectionPoint mp; @@ -272,6 +279,7 @@ void linphone_sound_daemon_destroy(LinphoneSoundDaemon *obj){ mp.filter=obj->mixer; for(i=0;ibranches[i]); lsd_player_uninit (&obj->branches[i],mp); } ms_filter_unlink(obj->mixer,0,obj->soundout,0); From 1a32d8f8a5497291aedf33f7d98c1f08498914af Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 14 Jun 2010 21:32:46 +0200 Subject: [PATCH 24/45] fix bug when call not closed when an invite is accepted with a 200Ok directly --- coreapi/linphonecore.c | 4 ++-- coreapi/sal_eXosip2.c | 12 ++++++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 6e0221ccb..51171d9f5 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2358,8 +2358,8 @@ int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *the_call) LinphoneCall *call; if (the_call == NULL){ call = linphone_core_get_current_call(lc); - if(call == NULL) - { + if(call == NULL){ + ms_warning("No currently active call to terminate !"); return -1; } } diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index 8214e2516..69f746642 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -644,9 +644,13 @@ int sal_call_send_dtmf(SalOp *h, char dtmf){ } int sal_call_terminate(SalOp *h){ + int err; eXosip_lock(); - eXosip_call_terminate(h->cid,h->did); + err=eXosip_call_terminate(h->cid,h->did); eXosip_unlock(); + if (err!=0){ + ms_warning("Exosip could not terminate the call: cid=%i did=%i", h->cid,h->did); + } sal_remove_call(h->base.root,h); h->cid=-1; return 0; @@ -845,7 +849,8 @@ static int call_proceeding(Sal *sal, eXosip_event_t *ev){ eXosip_unlock(); return -1; } - op->did=ev->did; + if (ev->did>0) + op->did=ev->did; op->tid=ev->tid; /* update contact if received and rport are set by the server @@ -879,6 +884,9 @@ static void call_accepted(Sal *sal, eXosip_event_t *ev){ ms_error("A closed call is accepted ?"); return; } + if (op->did==-1){ + op->did=ev->did; + } sdp=eXosip_get_sdp_info(ev->response); if (sdp){ op->base.remote_media=sal_media_description_new(); From 11a292a808306f8eed6dacda7422c14acafe214d Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 14 Jun 2010 22:44:56 +0200 Subject: [PATCH 25/45] add trace at daemon startup --- coreapi/lsd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/lsd.c b/coreapi/lsd.c index a31592e9a..84b5c3e84 100644 --- a/coreapi/lsd.c +++ b/coreapi/lsd.c @@ -261,7 +261,7 @@ LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname, int rate, lsd->proxycard=ms_snd_card_new(&proxycard); lsd->proxycard->data=lsd; - + ms_message("LinphoneSoundDaemon started with rate=%i, nchannels=%i",rate,nchannels); return lsd; } From 41c25722fbeed343dfb77420d69f0c73bd6ebd3c Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 15 Jun 2010 13:49:12 +0200 Subject: [PATCH 26/45] add linphonecore_utils.h to installed headers --- coreapi/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index 7044420ec..31094d71e 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -6,7 +6,7 @@ EXTRA_DIST=linphonecore_jni.cc ## Process this file with automake to produce Makefile.in linphone_includedir=$(includedir)/linphone -linphone_include_HEADERS=linphonecore.h ../config.h lpconfig.h sipsetup.h +linphone_include_HEADERS=linphonecore.h linphonecore_utils.h ../config.h lpconfig.h sipsetup.h INCLUDES = \ -I$(top_srcdir)\ From c3cf0f72e5e0978f4fc360ebb5831cc7c51e2527 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 16 Jun 2010 11:24:45 +0200 Subject: [PATCH 27/45] add linphone_sound_daemon_release_all_players() --- coreapi/linphonecore_utils.h | 1 + coreapi/lsd.c | 7 +++++++ mediastreamer2 | 2 +- oRTP | 2 +- 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecore_utils.h b/coreapi/linphonecore_utils.h index 7dbea33d7..8c29ef1af 100644 --- a/coreapi/linphonecore_utils.h +++ b/coreapi/linphonecore_utils.h @@ -45,6 +45,7 @@ LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname, int rate, LsdPlayer * linphone_sound_daemon_get_player(LinphoneSoundDaemon *lsd); void linphone_sound_daemon_release_player(LinphoneSoundDaemon *lsd, LsdPlayer *lsdplayer); void linphone_sound_daemon_stop_all_players(LinphoneSoundDaemon *obj); +void linphone_sound_daemon_release_all_players(LinphoneSoundDaemon *obj); void linphone_core_use_sound_daemon(LinphoneCore *lc, LinphoneSoundDaemon *lsd); void linphone_sound_daemon_destroy(LinphoneSoundDaemon *obj); diff --git a/coreapi/lsd.c b/coreapi/lsd.c index 84b5c3e84..3772c8911 100644 --- a/coreapi/lsd.c +++ b/coreapi/lsd.c @@ -272,6 +272,13 @@ void linphone_sound_daemon_stop_all_players(LinphoneSoundDaemon *obj){ } } +void linphone_sound_daemon_release_all_players(LinphoneSoundDaemon *obj){ + int i; + for(i=1;ibranches[i]); + } +} + void linphone_sound_daemon_destroy(LinphoneSoundDaemon *obj){ int i; MSConnectionPoint mp; diff --git a/mediastreamer2 b/mediastreamer2 index a2a611927..648bfcf64 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit a2a6119273226234ea7300742c34d46fa545fcd8 +Subproject commit 648bfcf647b2e358440507be6b5f17030f9a7212 diff --git a/oRTP b/oRTP index b9b53eede..18eccd4f3 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit b9b53eedef812b44762976617840c2b98fca62b9 +Subproject commit 18eccd4f3af64f3bd5293d635a1a169dc77c92ad From 7a8eea66e0ee7f68058ffd4a5c626b9b1f70a17a Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 17 Jun 2010 12:20:21 +0200 Subject: [PATCH 28/45] update mediastreamer2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 648bfcf64..17e879de8 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 648bfcf647b2e358440507be6b5f17030f9a7212 +Subproject commit 17e879de84d894df6a1875665594567c1cf43617 From d8b8bc5301babf4b73e26b5a314c1e7836e44f92 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 17 Jun 2010 15:58:19 +0200 Subject: [PATCH 29/45] add multicall to gstate callback --- console/linphonec.c | 4 +-- coreapi/callbacks.c | 39 +++++++++++++++++++------- coreapi/general_state.c | 57 ++++++++++++++++++------------------- coreapi/linphonecall.c | 10 ++++++- coreapi/linphonecore.c | 25 ++++++++++++----- coreapi/linphonecore.h | 62 ++++++++++++++++++++++------------------- coreapi/private.h | 5 +++- coreapi/proxy.c | 7 +++-- gtk-glade/main.c | 4 +-- mediastreamer2 | 2 +- 10 files changed, 132 insertions(+), 83 deletions(-) diff --git a/console/linphonec.c b/console/linphonec.c index 024075cf0..81218be29 100644 --- a/console/linphonec.c +++ b/console/linphonec.c @@ -132,7 +132,7 @@ static void linphonec_bye_received(LinphoneCore *lc, LinphoneCall *call); static void linphonec_text_received(LinphoneCore *lc, LinphoneChatRoom *cr, const char *from, const char *msg); static void linphonec_display_status (LinphoneCore * lc, const char *something); -static void linphonec_general_state (LinphoneCore * lc, LinphoneGeneralState *gstate); +static void linphonec_general_state (LinphoneCore * lc, LinphoneGeneralState *gstate, LinphoneGeneralStateContext gctx); static void linphonec_dtmf_received(LinphoneCore *lc, int dtmf); static void print_prompt(LinphoneCore *opm); void linphonec_out(const char *fmt,...); @@ -435,7 +435,7 @@ static void linphonec_dtmf_received(LinphoneCore *lc, int dtmf){ } static void -linphonec_general_state (LinphoneCore * lc, LinphoneGeneralState *gstate) +linphonec_general_state (LinphoneCore * lc, LinphoneGeneralState *gstate, LinphoneGeneralStateContext gctx) { if (show_general_state) { switch(gstate->new_state) { diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index eb2589c71..e37941f7f 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -52,6 +52,7 @@ static void call_received(SalOp *h){ const char *from,*to; char *tmp; LinphoneAddress *from_parsed; + LinphoneGeneralStateContext gctx; /* first check if we can answer successfully to this invite */ if (lc->presence_mode!=LINPHONE_STATUS_ONLINE){ @@ -105,7 +106,8 @@ static void call_received(SalOp *h){ linphone_address_clean(from_parsed); tmp=linphone_address_as_string(from_parsed); linphone_address_destroy(from_parsed); - gstate_new_state(lc, GSTATE_CALL_IN_INVITE, tmp); + gctx.call=call; + gstate_new_state(lc, GSTATE_CALL_IN_INVITE, gctx, tmp); barmesg=ortp_strdup_printf("%s %s%s",tmp,_("is contacting you"), (sal_call_autoanswer_asked(h)) ?_(" and asked autoanswer."):_(".")); if (lc->vtable.show) lc->vtable.show(lc); @@ -136,7 +138,11 @@ static void call_ringing(SalOp *h){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h)); LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(h); SalMediaDescription *md; + LinphoneGeneralStateContext gctx; + if (call==NULL) return; + gctx.call=call; + if (lc->vtable.display_status) lc->vtable.display_status(lc,_("Remote ringing.")); if (lc->vtable.ringing_recv) @@ -148,7 +154,8 @@ static void call_ringing(SalOp *h){ MSSndCard *ringcard=lc->sound_conf.lsd_card ? lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard; ms_message("Remote ringing..."); lc->ringstream=ring_start(lc->sound_conf.remote_ring,2000,ringcard); - gstate_new_state(lc, GSTATE_CALL_OUT_RINGING, NULL); + + gstate_new_state(lc, GSTATE_CALL_OUT_RINGING, gctx, NULL); } }else{ /*accept early media */ @@ -162,7 +169,7 @@ static void call_ringing(SalOp *h){ if (lc->vtable.show) lc->vtable.show(lc); if (lc->vtable.display_status) lc->vtable.display_status(lc,_("Early media.")); - gstate_new_state(lc, GSTATE_CALL_OUT_RINGING, NULL); + gstate_new_state(lc, GSTATE_CALL_OUT_RINGING, gctx, NULL); if (lc->ringstream!=NULL){ ring_stop(lc->ringstream); lc->ringstream=NULL; @@ -183,10 +190,12 @@ 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); + LinphoneGeneralStateContext gctx; if (call==NULL){ ms_warning("No call to accept."); return ; } + gctx.call=call; if (call->state==LinphoneCallAVRunning){ ms_message("GET ACK of resume\n"); if(lc->vtable.ack_resumed_recv) @@ -219,7 +228,7 @@ static void call_accepted(SalOp *op){ else { linphone_core_set_as_current_call (lc,call); - gstate_new_state(lc, GSTATE_CALL_OUT_CONNECTED, NULL); + gstate_new_state(lc, GSTATE_CALL_OUT_CONNECTED, gctx, NULL); linphone_connect_incoming(lc,call); } }else{ @@ -232,10 +241,12 @@ static void call_accepted(SalOp *op){ static void call_ack(SalOp *op){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); + LinphoneGeneralStateContext gctx; if (call==NULL){ ms_warning("No call to be ACK'd"); return ; } + gctx.call=call; if (call->media_pending){ if (lc->audiostream->ticker!=NULL){ /*case where we accepted early media */ @@ -251,7 +262,7 @@ static void call_ack(SalOp *op){ if (call->resultdesc) sal_media_description_ref(call->resultdesc); if (call->resultdesc && !sal_media_description_empty(call->resultdesc)){ - gstate_new_state(lc, GSTATE_CALL_IN_CONNECTED, NULL); + gstate_new_state(lc, GSTATE_CALL_IN_CONNECTED, gctx, NULL); linphone_connect_incoming(lc,call); }else{ /*send a bye*/ @@ -312,6 +323,8 @@ static void call_updated(SalOp *op){ static void call_terminated(SalOp *op, const char *from){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); + LinphoneGeneralStateContext gctx; + gctx.call=call; if (linphone_call_get_state(call)==LinphoneCallTerminated){ ms_warning("call_terminated: ignoring."); return; @@ -329,7 +342,7 @@ static void call_terminated(SalOp *op, const char *from){ if (lc->vtable.display_status!=NULL) lc->vtable.display_status(lc,_("Call terminated.")); call->state=LinphoneCallTerminated; - gstate_new_state(lc, GSTATE_CALL_END, NULL); + gstate_new_state(lc, GSTATE_CALL_END, gctx, NULL); if (lc->vtable.bye_recv!=NULL){ LinphoneAddress *addr=linphone_address_new(from); char *tmp; @@ -352,7 +365,9 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de char *msg603=_("Call declined."); char *msg=(char*)details; LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); + LinphoneGeneralStateContext gctx; + gctx.call=call; if (lc->vtable.show) lc->vtable.show(lc); if (error==SalErrorNoResponse){ @@ -412,8 +427,8 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de if(call == linphone_core_get_current_call(lc)) linphone_core_stop_media_streams(lc,call); if (call!=NULL) { - if (sr!=SalReasonDeclined) gstate_new_state(lc, GSTATE_CALL_ERROR, msg); - else gstate_new_state(lc, GSTATE_CALL_END, NULL); + if (sr!=SalReasonDeclined) gstate_new_state(lc, GSTATE_CALL_ERROR, gctx, msg); + else gstate_new_state(lc, GSTATE_CALL_END, gctx, NULL); linphone_call_set_terminated(call); } } @@ -450,8 +465,10 @@ static void register_success(SalOp *op, bool_t registered){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)sal_op_get_user_pointer(op); char *msg; + LinphoneGeneralStateContext gctx; + gctx.proxy=cfg; cfg->registered=registered; - gstate_new_state(lc, GSTATE_REG_OK, NULL); + gstate_new_state(lc, GSTATE_REG_OK,gctx, NULL); if (cfg->registered) msg=ms_strdup_printf(_("Registration on %s successful."),sal_op_get_proxy(op)); else msg=ms_strdup_printf(_("Unregistration on %s done."),sal_op_get_proxy(op)); if (lc->vtable.display_status) @@ -461,9 +478,11 @@ static void register_success(SalOp *op, bool_t registered){ static void register_failure(SalOp *op, SalError error, SalReason reason, const char *details){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); + LinphoneGeneralStateContext gctx; char *msg=ortp_strdup_printf(_("Registration on %s failed: %s"),sal_op_get_proxy(op),(details!=NULL) ? details : _("no response timeout")); if (lc->vtable.display_status) lc->vtable.display_status(lc,msg); - gstate_new_state(lc, GSTATE_REG_FAILED, msg); + gctx.proxy=(LinphoneProxyConfig*)sal_op_get_user_pointer (op); + gstate_new_state(lc, GSTATE_REG_FAILED, gctx, msg); ms_free(msg); } diff --git a/coreapi/general_state.c b/coreapi/general_state.c index 210037887..dc9e3e642 100644 --- a/coreapi/general_state.c +++ b/coreapi/general_state.c @@ -83,35 +83,36 @@ static void linphone_core_set_state(LinphoneCore *lc, gstate_group_t group, gsta void gstate_new_state(struct _LinphoneCore *lc, gstate_t new_state, + LinphoneGeneralStateContext gctx, const char *message) { - LinphoneGeneralState states_arg; - - /* determine the affected group */ - if (new_state < GSTATE_REG_NONE) - states_arg.group = GSTATE_GROUP_POWER; - else if (new_state < GSTATE_CALL_IDLE) - states_arg.group = GSTATE_GROUP_REG; - else - states_arg.group = GSTATE_GROUP_CALL; - - /* store the new state while remembering the old one */ - states_arg.new_state = new_state; - states_arg.old_state = linphone_core_get_state(lc,states_arg.group); - linphone_core_set_state(lc, states_arg.group,new_state); - states_arg.message = message; - - /*printf("gstate_new_state: %s\t-> %s\t(%s)\n", - _gstates_text[states_arg.old_state], - _gstates_text[states_arg.new_state], - message);*/ + LinphoneGeneralState states_arg; - /* call the virtual method */ - if (lc->vtable.general_state) - lc->vtable.general_state(lc, &states_arg); - - /* immediately proceed to idle state */ - if (new_state == GSTATE_CALL_END || - new_state == GSTATE_CALL_ERROR) - gstate_new_state(lc, GSTATE_CALL_IDLE, NULL); + /* determine the affected group */ + if (new_state < GSTATE_REG_NONE) + states_arg.group = GSTATE_GROUP_POWER; + else if (new_state < GSTATE_CALL_IDLE) + states_arg.group = GSTATE_GROUP_REG; + else + states_arg.group = GSTATE_GROUP_CALL; + + /* store the new state while remembering the old one */ + states_arg.new_state = new_state; + states_arg.old_state = linphone_core_get_state(lc,states_arg.group); + linphone_core_set_state(lc, states_arg.group,new_state); + states_arg.message = message; + + /*printf("gstate_new_state: %s\t-> %s\t(%s)\n", + _gstates_text[states_arg.old_state], + _gstates_text[states_arg.new_state], + message);*/ + + /* call the virtual method */ + if (lc->vtable.general_state) + lc->vtable.general_state(lc, &states_arg, gctx); + + /* immediately proceed to idle state */ + if (new_state == GSTATE_CALL_END || + new_state == GSTATE_CALL_ERROR) + gstate_new_state(lc, GSTATE_CALL_IDLE, gctx, NULL); } diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index ac165a629..c5c7f3eb1 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -166,7 +166,7 @@ void linphone_call_set_terminated(LinphoneCall *call){ linphone_core_notify_all_friends(lc,lc->prev_mode); linphone_core_update_allocated_audio_bandwidth(lc); - if (call->state==LinphoneCallAVRunning){ + if (call->state==LinphoneCallAVRunning || call->state==LinphoneCallPaused){ status=LinphoneCallSuccess; } @@ -289,6 +289,14 @@ void linphone_call_set_user_pointer(LinphoneCall *call, void *user_pointer) call->user_pointer = user_pointer; } +/** + * Returns the call log associated to this call. +**/ +LinphoneCallLog *linphone_call_get_call_log(const LinphoneCall *call){ + return call->log; +} + + /** * @} **/ diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 3423dd87c..c1922fe30 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -910,13 +910,14 @@ static void linphone_core_free_payload_types(void){ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vtable, const char *config_path, const char *factory_config_path, void * userdata) { + LinphoneGeneralStateContext gctx={0}; memset (lc, 0, sizeof (LinphoneCore)); lc->data=userdata; memcpy(&lc->vtable,vtable,sizeof(LinphoneCoreVTable)); gstate_initialize(lc); - gstate_new_state(lc, GSTATE_POWER_STARTUP, NULL); + gstate_new_state(lc, GSTATE_POWER_STARTUP, gctx, NULL); ortp_init(); linphone_core_assign_payload_type(&payload_type_pcmu8000,0,NULL); @@ -982,7 +983,7 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta ui_config_read(lc); if (lc->vtable.display_status) lc->vtable.display_status(lc,_("Ready")); - gstate_new_state(lc, GSTATE_POWER_ON, NULL); + gstate_new_state(lc, GSTATE_POWER_ON, gctx, NULL); lc->auto_net_state_mon=lc->sip_conf.auto_net_state_mon; lc->ready=TRUE; @@ -1902,6 +1903,7 @@ int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, LinphonePro char *contact; char *real_url,*barmsg; char *from; + LinphoneGeneralStateContext gctx; /*try to be best-effort in giving real local or routable contact address */ contact=get_fixed_contact(lc,call,dest_proxy); if (contact){ @@ -1936,7 +1938,10 @@ int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, LinphonePro if(call == linphone_core_get_current_call(lc)) linphone_core_stop_media_streams(lc,call); linphone_call_set_terminated (call); - }else gstate_new_state(lc, GSTATE_CALL_OUT_INVITE, real_url); + }else { + gctx.call=call; + gstate_new_state(lc, GSTATE_CALL_OUT_INVITE, gctx, real_url); + } ms_free(real_url); ms_free(from); return err; @@ -2406,6 +2411,7 @@ int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *call) { LinphoneProxyConfig *cfg=NULL; const char *contact=NULL; + LinphoneGeneralStateContext gctx; if (call==NULL){ //if just one call is present answer the only one ... @@ -2441,7 +2447,8 @@ int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *call) sal_call_accept(call->op); if (lc->vtable.display_status!=NULL) lc->vtable.display_status(lc,_("Connected.")); - gstate_new_state(lc, GSTATE_CALL_IN_CONNECTED, NULL); + gctx.call=call; + gstate_new_state(lc, GSTATE_CALL_IN_CONNECTED, gctx, NULL); call->resultdesc=sal_call_get_final_media_description(call->op); if (call->resultdesc){ sal_media_description_ref(call->resultdesc); @@ -2463,6 +2470,7 @@ int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *call) int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *the_call) { LinphoneCall *call; + LinphoneGeneralStateContext gctx; if (the_call == NULL){ call = linphone_core_get_current_call(lc); if(call == NULL){ @@ -2485,7 +2493,8 @@ int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *the_call) linphone_core_stop_media_streams(lc,call); if (lc->vtable.display_status!=NULL) lc->vtable.display_status(lc,_("Call ended") ); - gstate_new_state(lc, GSTATE_CALL_END, NULL); + gctx.call=call; + gstate_new_state(lc, GSTATE_CALL_END, gctx, NULL); linphone_call_set_terminated(call); return 0; } @@ -3816,6 +3825,7 @@ LpConfig *linphone_core_get_config(LinphoneCore *lc){ static void linphone_core_uninit(LinphoneCore *lc) { + LinphoneGeneralStateContext gctx; while(lc->calls) { LinphoneCall *the_call = lc->calls->data; @@ -3830,7 +3840,8 @@ static void linphone_core_uninit(LinphoneCore *lc) if (lc->friends) ms_list_for_each(lc->friends,(void (*)(void *))linphone_friend_close_subscriptions); - gstate_new_state(lc, GSTATE_POWER_SHUTDOWN, NULL); + gctx.call=NULL; + gstate_new_state(lc, GSTATE_POWER_SHUTDOWN, gctx, NULL); #ifdef VIDEO_ENABLED if (lc->previewstream!=NULL){ video_preview_stop(lc->previewstream); @@ -3857,7 +3868,7 @@ static void linphone_core_uninit(LinphoneCore *lc) linphone_core_free_payload_types(); ortp_exit(); - gstate_new_state(lc, GSTATE_POWER_OFF, NULL); + gstate_new_state(lc, GSTATE_POWER_OFF, gctx, NULL); } static void set_network_reachable(LinphoneCore* lc,bool_t isReachable){ diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index f9dc69e63..950be3a41 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -97,30 +97,6 @@ void linphone_address_destroy(LinphoneAddress *u); struct _SipSetupContext; -/** - * The LinphoneCall object represents a call issued or received by the LinphoneCore -**/ -struct _LinphoneCall; -typedef struct _LinphoneCall LinphoneCall; - -typedef enum _LinphoneCallState{ - LinphoneCallInit, - LinphoneCallPreEstablishing, - LinphoneCallRinging, - LinphoneCallAVRunning, - LinphoneCallPaused, - LinphoneCallTerminated -}LinphoneCallState; - -LinphoneCallState linphone_call_get_state(const LinphoneCall *call); -bool_t linphone_call_asked_to_autoanswer(LinphoneCall *call); -bool_t linphone_call_paused(LinphoneCall *call); -const LinphoneAddress * linphone_core_get_current_call_remote_address(struct _LinphoneCore *lc); -const LinphoneAddress * linphone_call_get_remote_address(const LinphoneCall *call); -char *linphone_call_get_remote_address_as_string(const LinphoneCall *call); -void linphone_call_ref(LinphoneCall *call); -void linphone_call_unref(LinphoneCall *call); - /** * Enum representing the direction of a call. @@ -178,6 +154,33 @@ const rtp_stats_t *linphone_call_log_get_local_stats(const LinphoneCallLog *cl); const rtp_stats_t *linphone_call_log_get_remote_stats(const LinphoneCallLog *cl); char * linphone_call_log_to_str(LinphoneCallLog *cl); + +/** + * The LinphoneCall object represents a call issued or received by the LinphoneCore +**/ +struct _LinphoneCall; +typedef struct _LinphoneCall LinphoneCall; + +typedef enum _LinphoneCallState{ + LinphoneCallInit, + LinphoneCallPreEstablishing, + LinphoneCallRinging, + LinphoneCallAVRunning, + LinphoneCallPaused, + LinphoneCallTerminated +}LinphoneCallState; + +LinphoneCallState linphone_call_get_state(const LinphoneCall *call); +bool_t linphone_call_asked_to_autoanswer(LinphoneCall *call); +bool_t linphone_call_paused(LinphoneCall *call); +const LinphoneAddress * linphone_core_get_current_call_remote_address(struct _LinphoneCore *lc); +const LinphoneAddress * linphone_call_get_remote_address(const LinphoneCall *call); +char *linphone_call_get_remote_address_as_string(const LinphoneCall *call); +void linphone_call_ref(LinphoneCall *call); +void linphone_call_unref(LinphoneCall *call); +LinphoneCallLog *linphone_call_get_call_log(const LinphoneCall *call); + + typedef enum{ LinphoneSPWait, LinphoneSPDeny, @@ -405,10 +408,11 @@ struct _LinphoneGeneralState { }; typedef struct _LinphoneGeneralState LinphoneGeneralState; -/* private: set a new state */ -void gstate_new_state(struct _LinphoneCore *lc, gstate_t new_state, const char *message); -/*private*/ -void gstate_initialize(struct _LinphoneCore *lc) ; + +typedef union _LinphoneGeneralStateContext{ + LinphoneCall *call; + LinphoneProxyConfig *proxy; +}LinphoneGeneralStateContext; /** * @addtogroup initializing @@ -458,7 +462,7 @@ typedef void (*CallLogUpdated)(struct _LinphoneCore *lc, struct _LinphoneCallLog /** Callback prototype */ typedef void (*TextMessageReceived)(struct _LinphoneCore *lc, LinphoneChatRoom *room, const char *from, const char *message); /** Callback prototype */ -typedef void (*GeneralStateChange)(struct _LinphoneCore *lc, LinphoneGeneralState *gstate); +typedef void (*GeneralStateChange)(struct _LinphoneCore *lc, LinphoneGeneralState *gstate, LinphoneGeneralStateContext ctx); /** Callback prototype */ typedef void (*DtmfReceived)(struct _LinphoneCore* lc, int dtmf); /** Callback prototype */ diff --git a/coreapi/private.h b/coreapi/private.h index 2a55b428f..818fc779e 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -55,7 +55,10 @@ #endif - +/* private: set a new state */ +void gstate_new_state(struct _LinphoneCore *lc, gstate_t new_state, LinphoneGeneralStateContext context, const char *message); +/*private*/ +void gstate_initialize(struct _LinphoneCore *lc); struct _LinphoneCall { diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 59d767303..3639520f4 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -259,7 +259,10 @@ static char *guess_contact_for_register(LinphoneProxyConfig *obj){ } static void linphone_proxy_config_register(LinphoneProxyConfig *obj){ + LinphoneGeneralStateContext gctx; const char *id_str; + + gctx.proxy=obj; if (obj->reg_identity!=NULL) id_str=obj->reg_identity; else id_str=linphone_core_get_primary_contact(obj->lc); if (obj->reg_sendregister){ @@ -272,9 +275,9 @@ static void linphone_proxy_config_register(LinphoneProxyConfig *obj){ ms_free(contact); sal_op_set_user_pointer(obj->op,obj); if (!sal_register(obj->op,obj->reg_proxy,obj->reg_identity,obj->expires)) { - gstate_new_state(obj->lc,GSTATE_REG_PENDING,NULL); + gstate_new_state(obj->lc,GSTATE_REG_PENDING, gctx, NULL); } else { - gstate_new_state(obj->lc,GSTATE_REG_FAILED,NULL); + gstate_new_state(obj->lc,GSTATE_REG_FAILED, gctx, NULL); } } } diff --git a/gtk-glade/main.c b/gtk-glade/main.c index 87db8fb2a..5ec4bdbcd 100644 --- a/gtk-glade/main.c +++ b/gtk-glade/main.c @@ -53,7 +53,7 @@ static void linphone_gtk_display_warning(LinphoneCore *lc, const char *warning); static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const char *url); static void linphone_gtk_display_question(LinphoneCore *lc, const char *question); static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl); -static void linphone_gtk_general_state(LinphoneCore *lc, LinphoneGeneralState *gstate); +static void linphone_gtk_general_state(LinphoneCore *lc, LinphoneGeneralState *gstate, LinphoneGeneralStateContext gctx); static void linphone_gtk_refer_received(LinphoneCore *lc, LinphoneCall *call, const char *refer_to); static gboolean linphone_gtk_auto_answer(GtkWidget *incall_window); @@ -879,7 +879,7 @@ static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl) if (w) linphone_gtk_call_log_update(w); } -static void linphone_gtk_general_state(LinphoneCore *lc, LinphoneGeneralState *gstate){ +static void linphone_gtk_general_state(LinphoneCore *lc, LinphoneGeneralState *gstate, LinphoneGeneralStateContext gctx){ switch(gstate->new_state){ case GSTATE_CALL_OUT_CONNECTED: case GSTATE_CALL_IN_CONNECTED: diff --git a/mediastreamer2 b/mediastreamer2 index 17e879de8..55e0624b5 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 17e879de84d894df6a1875665594567c1cf43617 +Subproject commit 55e0624b53e984eecc6b5a4eedef467456968886 From e6e6f38e0a512d2d47b9ccc7772902af2302a4ac Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 22 Jun 2010 10:41:10 +0200 Subject: [PATCH 30/45] minor fixes and improvement in dtmf notifications --- console/linphonec.c | 11 ++++++++--- coreapi/callbacks.c | 18 ++++++++++++++---- coreapi/linphonecore.c | 8 +++++--- coreapi/linphonecore.h | 2 +- mediastreamer2 | 2 +- 5 files changed, 29 insertions(+), 12 deletions(-) diff --git a/console/linphonec.c b/console/linphonec.c index 81218be29..f20305796 100644 --- a/console/linphonec.c +++ b/console/linphonec.c @@ -133,7 +133,7 @@ static void linphonec_text_received(LinphoneCore *lc, LinphoneChatRoom *cr, const char *from, const char *msg); static void linphonec_display_status (LinphoneCore * lc, const char *something); static void linphonec_general_state (LinphoneCore * lc, LinphoneGeneralState *gstate, LinphoneGeneralStateContext gctx); -static void linphonec_dtmf_received(LinphoneCore *lc, int dtmf); +static void linphonec_dtmf_received(LinphoneCore *lc, LinphoneCall *call, int dtmf); static void print_prompt(LinphoneCore *opm); void linphonec_out(const char *fmt,...); /*************************************************************************** @@ -429,9 +429,11 @@ linphonec_text_received(LinphoneCore *lc, LinphoneChatRoom *cr, } -static void linphonec_dtmf_received(LinphoneCore *lc, int dtmf){ - fprintf(stdout,"Receiving tone %c\n",dtmf); +static void linphonec_dtmf_received(LinphoneCore *lc, LinphoneCall *call, int dtmf){ + char *from=linphone_call_get_remote_address_as_string(call); + fprintf(stdout,"Receiving tone %c from %s\n",dtmf,from); fflush(stdout); + ms_free(from); } static void @@ -463,6 +465,9 @@ linphonec_general_state (LinphoneCore * lc, LinphoneGeneralState *gstate, Linpho case GSTATE_CALL_IDLE: printf("GSTATE_CALL_IDLE"); break; + case GSTATE_CALL_OUT_RINGING: + printf("GSTATE_CALL_OUT_RINGING"); + break; case GSTATE_CALL_OUT_INVITE: printf("GSTATE_CALL_OUT_INVITE"); break; diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index e37941f7f..48e2db005 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -100,8 +100,13 @@ static void call_received(SalOp *h){ return; } /* the call is acceptable so we can now add it to our list */ - linphone_core_add_call(lc,call); - + if(linphone_core_add_call(lc,call)!= 0) + { + ms_warning("we cannot handle anymore call\n"); + sal_call_decline(h,SalReasonMedia,NULL); + linphone_call_unref(call); + return; + } from_parsed=linphone_address_new(sal_op_get_from(h)); linphone_address_clean(from_parsed); tmp=linphone_address_as_string(from_parsed); @@ -227,7 +232,11 @@ static void call_accepted(SalOp *op){ }//if there is an accepted incoming call else { - linphone_core_set_as_current_call (lc,call); + /* + * Do not set the call as current here, + * because we can go through this function not only when an incoming call is accepted + */ + //linphone_core_set_as_current_call (lc,call); gstate_new_state(lc, GSTATE_CALL_OUT_CONNECTED, gctx, NULL); linphone_connect_incoming(lc,call); } @@ -496,8 +505,9 @@ static void vfu_request(SalOp *op){ static void dtmf_received(SalOp *op, char dtmf){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); + LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); if (lc->vtable.dtmf_received != NULL) - lc->vtable.dtmf_received(lc, dtmf); + lc->vtable.dtmf_received(lc, call, dtmf); } static void refer_received(Sal *sal, SalOp *op, const char *referto){ diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index c1922fe30..fa2e0815c 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1479,7 +1479,7 @@ static void display_bandwidth(RtpSession *as, RtpSession *vs){ static void linphone_core_disconnected(LinphoneCore *lc, LinphoneCall *call){ char temp[256]; - char *from; + char *from=NULL; if(call) from = linphone_call_get_remote_address_as_string(call); if(from) @@ -1493,7 +1493,9 @@ static void linphone_core_disconnected(LinphoneCore *lc, LinphoneCall *call){ } if (lc->vtable.display_warning!=NULL) lc->vtable.display_warning(lc,temp); - linphone_core_terminate_call(lc,call);//TODO failure ?? + if(lc->vtable.failure_recv) + lc->vtable.failure_recv(lc,call, 480);//480 Temporarily Unavailable + linphone_core_terminate_call(lc,call); } static void monitor_network_state(LinphoneCore *lc, time_t curtime){ @@ -2128,7 +2130,7 @@ static void linphone_core_dtmf_received(RtpSession* s, int dtmf, void* user_data return; } if (lc->vtable.dtmf_received != NULL) - lc->vtable.dtmf_received(lc, dtmf_tab[dtmf]); + lc->vtable.dtmf_received(lc, linphone_core_get_current_call(lc), dtmf_tab[dtmf]); } static void parametrize_equalizer(LinphoneCore *lc, AudioStream *st){ diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 950be3a41..703703a96 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -464,7 +464,7 @@ typedef void (*TextMessageReceived)(struct _LinphoneCore *lc, LinphoneChatRoom * /** Callback prototype */ typedef void (*GeneralStateChange)(struct _LinphoneCore *lc, LinphoneGeneralState *gstate, LinphoneGeneralStateContext ctx); /** Callback prototype */ -typedef void (*DtmfReceived)(struct _LinphoneCore* lc, int dtmf); +typedef void (*DtmfReceived)(struct _LinphoneCore* lc, LinphoneCall *call, int dtmf); /** Callback prototype */ typedef void (*ReferReceived)(struct _LinphoneCore *lc, LinphoneCall *call, const char *refer_to); /** Callback prototype */ diff --git a/mediastreamer2 b/mediastreamer2 index 55e0624b5..bc6cdb650 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 55e0624b53e984eecc6b5a4eedef467456968886 +Subproject commit bc6cdb650a9fc76d00380221eb0198ba4bb96812 From c7a2d74ea0799d6dc6b8a07e82523de351445f04 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 9 Aug 2010 10:28:46 +0200 Subject: [PATCH 31/45] merge --- mediastreamer2 | 1 + 1 file changed, 1 insertion(+) create mode 160000 mediastreamer2 diff --git a/mediastreamer2 b/mediastreamer2 new file mode 160000 index 000000000..4b5164714 --- /dev/null +++ b/mediastreamer2 @@ -0,0 +1 @@ +Subproject commit 4b5164714c2cf77a284f0213fc79e9b147e8563a From 725638c7bcb5617b3074341b95fcc8085576c984 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 9 Aug 2010 14:55:09 +0200 Subject: [PATCH 32/45] fix some bugs, cleanups --- configure.in | 9 ++++-- console/linphonec.c | 5 ---- coreapi/callbacks.c | 15 ++++------ coreapi/linphonecore.c | 14 +++------ coreapi/linphonecore.h | 61 ++++++++++++++++++++------------------- coreapi/sal.c | 21 ++++++++++++-- coreapi/sal.h | 14 +++++++-- coreapi/sal_eXosip2.c | 24 ++------------- coreapi/sal_eXosip2_sdp.c | 42 +++++++++++++++++++++++---- gtk-glade/incall_view.c | 3 -- gtk-glade/main.c | 6 ---- 11 files changed, 116 insertions(+), 98 deletions(-) diff --git a/configure.in b/configure.in index e7edf835e..6495ab0a6 100644 --- a/configure.in +++ b/configure.in @@ -1,6 +1,6 @@ dnl Process this file with autoconf to produce a configure script. -AC_INIT([linphone],[3.3.2],[linphone-developers@nongnu.org]) +AC_INIT([linphone],[3.3.99],[linphone-developers@nongnu.org]) AC_CANONICAL_SYSTEM dnl Source packaging numbers @@ -15,7 +15,12 @@ LINPHONE_VERSION=$LINPHONE_MAJOR_VERSION.$LINPHONE_MINOR_VERSION.${LINPHONE_MICR if test "$LINPHONE_EXTRA_VERSION" != "" ;then LINPHONE_VERSION=$LINPHONE_VERSION.${LINPHONE_EXTRA_VERSION} fi -LIBLINPHONE_SO_VERSION=`expr $LINPHONE_MINOR_VERSION + $LINPHONE_MAJOR_VERSION`:$LINPHONE_MICRO_VERSION:$LINPHONE_MINOR_VERSION + +LIBLINPHONE_SO_CURRENT=4 dnl increment this number when you add/change/remove an interface +LIBLINPHONE_SO_REVISION=0 dnl increment this number when you change source code, without changing interfaces; set to 0 when incrementing CURRENT +LIBLINPHONE_SO_AGE=0 dnl increment this number when you add an interface, set to 0 if you remove an interface + +LIBLINPHONE_SO_VERSION=$LIBLINPHONE_SO_CURRENT:$LIBLINPHONE_SO_REVISION:$LIBLINPHONE_SO_AGE AC_SUBST(LIBLINPHONE_SO_VERSION, $LIBLINPHONE_SO_VERSION) AC_SUBST(LINPHONE_VERSION) diff --git a/console/linphonec.c b/console/linphonec.c index f20305796..030477c74 100644 --- a/console/linphonec.c +++ b/console/linphonec.c @@ -194,13 +194,8 @@ LinphoneCoreVTable linphonec_vtable .auth_info_requested = linphonec_prompt_for_auth, .display_status = linphonec_display_status, .display_message=linphonec_display_something, -#ifdef VINCENT_MAURY_RSVP - /* the yes/no dialog box */ - .display_yes_no= (DisplayMessageCb) stub, -#endif .display_warning=linphonec_display_warning, .display_url=linphonec_display_url, - .display_question=(DisplayQuestionCb)stub, .text_received=linphonec_text_received, .general_state=linphonec_general_state, .dtmf_received=linphonec_dtmf_received, diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 36f21d5a5..a9d4e2c83 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -134,10 +134,9 @@ static void call_received(SalOp *h){ call->state=LinphoneCallRinging; sal_call_notify_ringing(h); #if !(__IPHONE_OS_VERSION_MIN_REQUIRED >= 40000) - linphone_core_init_media_streams(lc,lc->call); + linphone_core_init_media_streams(lc,call); #endif if (lc->vtable.inv_recv) lc->vtable.inv_recv(lc,call); -#endif ms_free(barmesg); ms_free(tmp); } @@ -205,7 +204,7 @@ static void call_accepted(SalOp *op){ } gctx.call=call; if (call->state==LinphoneCallAVRunning){ - ms_message("GET ACK of resume\n"); + ms_message("GET 200Ok of resume\n"); if(lc->vtable.ack_resumed_recv) lc->vtable.ack_resumed_recv(lc,call); return ; //already accepted @@ -226,20 +225,16 @@ static void call_accepted(SalOp *op){ call->media_pending=FALSE; } if (call->resultdesc && !sal_media_description_empty(call->resultdesc)){ - //if we initiate a pause + //if we initiated a pause if(call->state == LinphoneCallPaused) { - ms_message("GET ACK of pause\n"); + ms_message("GET 200Ok of pause\n"); if(lc->vtable.ack_paused_recv) lc->vtable.ack_paused_recv(lc,call); }//if there is an accepted incoming call else { - /* - * Do not set the call as current here, - * because we can go through this function not only when an incoming call is accepted - */ - //linphone_core_set_as_current_call (lc,call); + linphone_core_set_as_current_call (lc,call); gstate_new_state(lc, GSTATE_CALL_OUT_CONNECTED, gctx, NULL); linphone_connect_incoming(lc,call); } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 54b9d6d08..3da96b3c0 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3983,16 +3983,15 @@ int linphone_core_set_as_current_call(LinphoneCore *lc, LinphoneCall *call) return 0; } -/** - * Add the call in the LinphoneCall list - * - * @ingroup call_control -**/ + int linphone_core_add_call( LinphoneCore *lc, LinphoneCall *call) { if(linphone_core_can_we_add_call(lc)) { MSList *the_calls = lc->calls; + if (the_calls==NULL){ + lc->current_call=call; + } the_calls = ms_list_append(the_calls,call); lc->calls = the_calls; return 0; @@ -4000,11 +3999,6 @@ int linphone_core_add_call( LinphoneCore *lc, LinphoneCall *call) return -1; } -/** - * Add the call in the LinphoneCall list - * - * @ingroup call_control -**/ int linphone_core_del_call( LinphoneCore *lc, LinphoneCall *call) { MSList *it; diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 4d6fb8f6e..fb94db8db 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -179,7 +179,8 @@ char *linphone_call_get_remote_address_as_string(const LinphoneCall *call); void linphone_call_ref(LinphoneCall *call); void linphone_call_unref(LinphoneCall *call); LinphoneCallLog *linphone_call_get_call_log(const LinphoneCall *call); - +void *linphone_call_get_user_pointer(LinphoneCall *call); +void linphone_call_set_user_pointer(LinphoneCall *call, void *user_pointer); typedef enum{ LinphoneSPWait, @@ -378,26 +379,28 @@ typedef enum _gstate_group { } gstate_group_t; typedef enum _gstate { - /* states for GSTATE_GROUP_POWER */ - GSTATE_POWER_OFF = 0, /* initial state */ - GSTATE_POWER_STARTUP, - GSTATE_POWER_ON, - GSTATE_POWER_SHUTDOWN, - /* states for GSTATE_GROUP_REG */ - GSTATE_REG_NONE = 10, /* initial state */ - GSTATE_REG_OK, - GSTATE_REG_FAILED, - GSTATE_REG_PENDING, /* a registration request is ongoing*/ - /* states for GSTATE_GROUP_CALL */ - GSTATE_CALL_IDLE = 20, /* initial state */ - GSTATE_CALL_OUT_INVITE, - GSTATE_CALL_OUT_CONNECTED, - GSTATE_CALL_IN_INVITE, - GSTATE_CALL_IN_CONNECTED, - GSTATE_CALL_END, - GSTATE_CALL_ERROR, - GSTATE_INVALID, - GSTATE_CALL_OUT_RINGING /*remote ringing*/ + /* states for GSTATE_GROUP_POWER */ + GSTATE_POWER_OFF = 0, /* initial state */ + GSTATE_POWER_STARTUP, + GSTATE_POWER_ON, + GSTATE_POWER_SHUTDOWN, + /* states for GSTATE_GROUP_REG */ + GSTATE_REG_NONE = 10, /* initial state */ + GSTATE_REG_OK, + GSTATE_REG_FAILED, + GSTATE_REG_PENDING, /* a registration request is ongoing*/ + /* states for GSTATE_GROUP_CALL */ + GSTATE_CALL_IDLE = 20, /* initial state */ + GSTATE_CALL_OUT_INVITE, + GSTATE_CALL_OUT_CONNECTED, + GSTATE_CALL_IN_INVITE, + GSTATE_CALL_IN_CONNECTED, + GSTATE_CALL_END, + GSTATE_CALL_ERROR, + GSTATE_CALL_OUT_RINGING, /*remote ringing*/ + GSTATE_CALL_PAUSED, + GSTATE_CALL_RESUMED, + GSTATE_INVALID } gstate_t; struct _LinphoneGeneralState { @@ -476,7 +479,6 @@ typedef void (*BuddyInfoUpdated)(struct _LinphoneCore *lc, LinphoneFriend *lf); **/ typedef struct _LinphoneVTable { - ShowInterfaceCb show; /**< Notifies the application that it should show up*/ InviteReceivedCb inv_recv; /**< Notifies incoming calls */ ByeReceivedCb bye_recv; /**< Notify calls terminated by far end*/ RingingReceivedCb ringing_recv; /**< Notify that the distant phone is ringing*/ @@ -486,21 +488,21 @@ typedef struct _LinphoneVTable ResumedReceivedCb resumed_recv; /**< Notify that the call has been resumed*/ AckPausedReceivedCb ack_paused_recv;/**< Notify that the previous command pause sent to the call has been acknowledge*/ AckResumedReceivedCb ack_resumed_recv;/**< Notify that the previous command resumed sent to the call has been acknowledge*/ + GeneralStateChange general_state; /**< State notification callback */ NotifyPresenceReceivedCb notify_presence_recv; /**< Notify received presence events*/ NewUnknownSubscriberCb new_unknown_subscriber; /**< Notify about unknown subscriber */ AuthInfoRequested auth_info_requested; /**< Ask the application some authentication information */ - DisplayStatusCb display_status; /**< Callback that notifies various events with human readable text.*/ - DisplayMessageCb display_message;/**< Callback to display a message to the user */ - DisplayMessageCb display_warning;/** Callback to display a warning to the user */ - DisplayUrlCb display_url; - DisplayQuestionCb display_question; CallLogUpdated call_log_updated; /**< Notifies that call log list has been updated */ TextMessageReceived text_received; /**< A text message has been received */ - GeneralStateChange general_state; /**< State notification callback */ DtmfReceived dtmf_received; /**< A dtmf has been received received */ ReferReceived refer_received; /**< A refer was received */ BuddyInfoUpdated buddy_info_updated; /**< a LinphoneFriend's BuddyInfo has changed*/ NotifyReceivedCb notify_recv; /**< Other notifications*/ + DisplayStatusCb display_status; /**< Callback that notifies various events with human readable text.*/ + DisplayMessageCb display_message;/**< Callback to display a message to the user */ + DisplayMessageCb display_warning;/** Callback to display a warning to the user */ + DisplayUrlCb display_url; + ShowInterfaceCb show; /**< Notifies the application that it should show up*/ } LinphoneCoreVTable; /** @@ -875,7 +877,6 @@ int linphone_core_get_current_call_stats(LinphoneCore *lc, rtp_stats_t *local, r } #endif MSList *linphone_core_get_calls(LinphoneCore *lc); -void *linphone_call_get_user_pointer(LinphoneCall *call); -void linphone_call_set_user_pointer(LinphoneCall *call, void *user_pointer); + #endif diff --git a/coreapi/sal.c b/coreapi/sal.c index 750555016..84f3d412b 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -62,11 +62,28 @@ const SalStreamDescription *sal_media_description_find_stream(const SalMediaDesc return NULL; } -bool_t sal_media_description_empty(SalMediaDescription *md){ +bool_t sal_media_description_empty(const SalMediaDescription *md){ + int i; + for(i=0;instreams;++i){ + const SalStreamDescription *ss=&md->streams[i]; + if (ss->port!=0) return FALSE; + } + return TRUE; +} + +void sal_media_description_set_dir(SalMediaDescription *md, SalStreamDir stream_dir){ int i; for(i=0;instreams;++i){ SalStreamDescription *ss=&md->streams[i]; - if (ss->port!=0) return FALSE; + ss->dir=stream_dir; + } +} + +bool_t sal_media_description_has_dir(const SalMediaDescription *md, SalStreamDir stream_dir){ + int i; + for(i=0;instreams;++i){ + const SalStreamDescription *ss=&md->streams[i]; + if (ss->dir!=stream_dir) return FALSE; } return TRUE; } diff --git a/coreapi/sal.h b/coreapi/sal.h index c8ed11a49..fd3f6f21b 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -86,6 +86,13 @@ typedef enum{ SalProtoRtpSavp }SalMediaProto; +typedef enum{ + SalStreamSendRecv, + SalStreamSendOnly, + SalStreamRecvOnly, + SalStreamInactive +}SalStreamDir; + typedef struct SalEndpointCandidate{ char addr[64]; int port; @@ -102,7 +109,7 @@ typedef struct SalStreamDescription{ int bandwidth; int ptime; SalEndpointCandidate candidates[SAL_ENDPOINT_CANDIDATE_MAX]; - bool_t notsending; + SalStreamDir dir; } SalStreamDescription; #define SAL_MEDIA_DESCRIPTION_MAX_STREAMS 4 @@ -114,15 +121,16 @@ typedef struct SalMediaDescription{ int nstreams; int bandwidth; SalStreamDescription streams[SAL_MEDIA_DESCRIPTION_MAX_STREAMS]; - bool_t notsending; } SalMediaDescription; 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(SalMediaDescription *md); +bool_t sal_media_description_empty(const SalMediaDescription *md); +bool_t sal_media_description_has_dir(const SalMediaDescription *md, SalStreamDir dir); const SalStreamDescription *sal_media_description_find_stream(const SalMediaDescription *md, SalMediaProto proto, SalStreamType type); +void sal_media_description_set_dir(SalMediaDescription *md, SalStreamDir stream_dir); /*this structure must be at the first byte of the SalOp structure defined by implementors*/ typedef struct SalOpBase{ diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index 50454640c..923dfdf1b 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -421,19 +421,6 @@ static void set_sdp(osip_message_t *sip,sdp_message_t *msg){ osip_free(sdp); } -static void set_hold_status_to_desc(SalMediaDescription *desc, bool_t holdon) -{ - int i; - if(desc == NULL) - return; - desc->notsending = holdon; - for(i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) - { - if(desc->streams != NULL) - desc->streams[i].notsending = holdon;//Audio - } -} - static void set_sdp_from_desc(osip_message_t *sip, const SalMediaDescription *desc){ sdp_message_t *msg=media_description_to_sdp(desc); if (msg==NULL) { @@ -1482,9 +1469,6 @@ static void other_request_reply(Sal *sal,eXosip_event_t *ev){ } static bool_t process_event(Sal *sal, eXosip_event_t *ev){ -#ifdef PRINTF_DEBUG - printf("EVENT (%d)\n",ev->type); -#endif ms_message("linphone process event get a message %d\n",ev->type); switch(ev->type){ case EXOSIP_CALL_ANSWERED: @@ -1809,11 +1793,9 @@ int sal_call_hold(SalOp *h, bool_t holdon) { int err=0; - osip_message_t *reinvite; - if(eXosip_call_build_request(h->did,"INVITE",&reinvite) != OSIP_SUCCESS) + osip_message_t *reinvite=NULL; + if(eXosip_call_build_request(h->did,"INVITE",&reinvite) != OSIP_SUCCESS || reinvite==NULL) return -1; - if(reinvite==NULL) - return -2; osip_message_set_subject(reinvite,osip_strdup("Phone Call Hold")); osip_message_set_allow(reinvite, "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO"); if (h->base.root->session_expires!=0){ @@ -1823,7 +1805,7 @@ int sal_call_hold(SalOp *h, bool_t holdon) //add something to say that the distant sip phone will be in sendonly/sendrecv mode if (h->base.local_media){ h->sdp_offering=TRUE; - set_hold_status_to_desc(h->base.local_media,holdon); + sal_media_description_set_dir(h->base.local_media, holdon ? SalStreamSendOnly : SalStreamSendRecv); set_sdp_from_desc(reinvite,h->base.local_media); }else h->sdp_offering=FALSE; eXosip_lock(); diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c index 2c27c5236..7d63148af 100644 --- a/coreapi/sal_eXosip2_sdp.c +++ b/coreapi/sal_eXosip2_sdp.c @@ -106,6 +106,23 @@ static int _sdp_message_get_a_ptime(sdp_message_t *sdp, int mline){ return 0; } +static int _sdp_message_get_mline_dir(sdp_message_t *sdp, int mline){ + int i; + sdp_attribute_t *attr; + for (i=0;(attr=sdp_message_attribute_get(sdp,mline,i))!=NULL;i++){ + if (keywordcmp("sendrecv",attr->a_att_field)==0){ + return SalStreamSendRecv; + }else if (keywordcmp("sendonly",attr->a_att_field)==0){ + return SalStreamSendOnly; + }else if (keywordcmp("recvonly",attr->a_att_field)==0){ + return SalStreamSendOnly; + }else if (keywordcmp("inactive",attr->a_att_field)==0){ + return SalStreamInactive; + } + } + return SalStreamSendRecv; +} + static sdp_message_t *create_generic_sdp(const SalMediaDescription *desc) { sdp_message_t *local; @@ -121,7 +138,7 @@ static sdp_message_t *create_generic_sdp(const SalMediaDescription *desc) osip_strdup ("IN"), inet6 ? osip_strdup("IP6") : osip_strdup ("IP4"), osip_strdup (desc->addr)); sdp_message_s_name_set (local, osip_strdup ("A conversation")); - if(!desc->notsending) + if(!sal_media_description_has_dir (desc,SalStreamSendOnly)) { sdp_message_c_connection_add (local, -1, osip_strdup ("IN"), inet6 ? osip_strdup ("IP6") : osip_strdup ("IP4"), @@ -131,7 +148,7 @@ static sdp_message_t *create_generic_sdp(const SalMediaDescription *desc) { sdp_message_c_connection_add (local, -1, osip_strdup ("IN"), inet6 ? osip_strdup ("IP6") : osip_strdup ("IP4"), - inet6 ? osip_strdup ("0.0.0.0.0.0") : osip_strdup ("0.0.0.0"), NULL, NULL); + inet6 ? osip_strdup ("::0") : osip_strdup ("0.0.0.0"), NULL, NULL); } sdp_message_t_time_descr_add (local, osip_strdup ("0"), osip_strdup ("0")); if (desc->bandwidth>0) sdp_message_b_bandwidth_add (local, -1, osip_strdup ("AS"), @@ -167,6 +184,7 @@ static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription const char *mt=desc->type==SalAudio ? "audio" : "video"; const MSList *elem; const char *addr; + const char *dir="sendrecv"; int port; if (desc->candidates[0].addr[0]!='\0'){ addr=desc->candidates[0].addr; @@ -195,10 +213,21 @@ static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription for(elem=desc->payloads;elem!=NULL;elem=elem->next){ add_payload(msg, lineno, (PayloadType*)elem->data); } - if(desc->notsending)//to hold the distant SIP endpoint - sdp_message_a_attribute_add (msg, lineno, osip_strdup ("sendonly"),NULL); - else - sdp_message_a_attribute_add (msg, lineno, osip_strdup ("sendrecv"),NULL); + switch(desc->dir){ + case SalStreamSendRecv: + dir="sendrecv"; + break; + case SalStreamRecvOnly: + dir="recvonly"; + break; + case SalStreamSendOnly: + dir="sendonly"; + break; + case SalStreamInactive: + dir="inactive"; + break; + } + sdp_message_a_attribute_add (msg, lineno, osip_strdup (dir),NULL); } sdp_message_t *media_description_to_sdp(const SalMediaDescription *desc){ @@ -285,6 +314,7 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){ for(j=0;(sbw=sdp_message_bandwidth_get(msg,i,j))!=NULL;++j){ if (strcasecmp(sbw->b_bwtype,"AS")==0) stream->bandwidth=atoi(sbw->b_bandwidth); } + stream->dir=_sdp_message_get_mline_dir(msg,i); /* for each payload type */ for (j=0;((number=sdp_message_m_payload_get (msg, i,j)) != NULL); j++){ const char *rtpmap,*fmtp; diff --git a/gtk-glade/incall_view.c b/gtk-glade/incall_view.c index a17741ff4..2874da52a 100644 --- a/gtk-glade/incall_view.c +++ b/gtk-glade/incall_view.c @@ -213,11 +213,9 @@ void linphone_gtk_enable_mute_button(GtkToggleButton *button, gboolean sensitive } void linphone_gtk_draw_hold_button(GtkToggleButton *button, gboolean active){ - GtkWidget *status=linphone_gtk_get_widget(linphone_gtk_get_main_window(),"in_call_status"); if (active){ GtkWidget *image=create_pixmap("hold_off.png"); gtk_button_set_label(GTK_BUTTON(button),_("HoldOff")); - gtk_label_set_markup(GTK_LABEL(status),_("In call holded with")); if (image!=NULL) { gtk_button_set_image(GTK_BUTTON(button),image); gtk_widget_show(image); @@ -225,7 +223,6 @@ void linphone_gtk_draw_hold_button(GtkToggleButton *button, gboolean active){ }else{ GtkWidget *image=create_pixmap("hold_on.png"); gtk_button_set_label(GTK_BUTTON(button),_("HoldOn")); - gtk_label_set_markup(GTK_LABEL(status),_("In call with")); if (image!=NULL) { gtk_button_set_image(GTK_BUTTON(button),image); gtk_widget_show(image); diff --git a/gtk-glade/main.c b/gtk-glade/main.c index 5ec4bdbcd..56b572860 100644 --- a/gtk-glade/main.c +++ b/gtk-glade/main.c @@ -51,7 +51,6 @@ static void linphone_gtk_display_status(LinphoneCore *lc, const char *status); static void linphone_gtk_display_message(LinphoneCore *lc, const char *msg); static void linphone_gtk_display_warning(LinphoneCore *lc, const char *warning); static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const char *url); -static void linphone_gtk_display_question(LinphoneCore *lc, const char *question); static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl); static void linphone_gtk_general_state(LinphoneCore *lc, LinphoneGeneralState *gstate, LinphoneGeneralStateContext gctx); static void linphone_gtk_refer_received(LinphoneCore *lc, LinphoneCall *call, const char *refer_to); @@ -68,7 +67,6 @@ static LinphoneCoreVTable vtable={ .display_message=linphone_gtk_display_message, .display_warning=linphone_gtk_display_warning, .display_url=linphone_gtk_display_url, - .display_question=linphone_gtk_display_question, .call_log_updated=linphone_gtk_call_log_updated, .text_received=linphone_gtk_text_received, .general_state=linphone_gtk_general_state, @@ -870,10 +868,6 @@ static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const ch linphone_gtk_display_something(GTK_MESSAGE_INFO,richtext); } -static void linphone_gtk_display_question(LinphoneCore *lc, const char *question){ - linphone_gtk_display_something(GTK_MESSAGE_QUESTION,question); -} - static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl){ GtkWidget *w=(GtkWidget*)g_object_get_data(G_OBJECT(linphone_gtk_get_main_window()),"call_logs"); if (w) linphone_gtk_call_log_update(w); From 675f7bcd9ec3e8c7b2b931368816124b0cf61ae8 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 16 Aug 2010 17:08:28 +0200 Subject: [PATCH 33/45] major redesign of liblinphone in progress --- coreapi/Makefile.am | 1 - coreapi/callbacks.c | 246 ++++++---------- coreapi/friend.c | 52 ++-- coreapi/linphonecall.c | 430 +++++++++++++++++++++++++-- coreapi/linphonecore.c | 644 +++++++++++------------------------------ coreapi/linphonecore.h | 176 ++++------- coreapi/misc.c | 4 +- coreapi/presence.c | 20 +- coreapi/private.h | 37 +-- coreapi/proxy.c | 14 +- coreapi/sal_eXosip2.c | 8 +- mediastreamer2 | 2 +- 12 files changed, 788 insertions(+), 846 deletions(-) diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index 31094d71e..5ae7539e7 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -32,7 +32,6 @@ liblinphone_la_SOURCES=\ authentication.c \ lpconfig.c lpconfig.h \ chat.c \ - general_state.c \ linphonecall.c \ sipsetup.c sipsetup.h \ siplogin.c \ diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index a9d4e2c83..7c52c8327 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -30,19 +30,14 @@ static void linphone_connect_incoming(LinphoneCore *lc, LinphoneCall *call){ lc->vtable.show(lc); if (lc->vtable.display_status) lc->vtable.display_status(lc,_("Connected.")); - if (lc->vtable.connected_recv) - lc->vtable.connected_recv(lc,call); - call->state=LinphoneCallAVRunning; + linphone_call_set_state(call,LinphoneCallConnected,"Connected"); if (lc->ringstream!=NULL){ ring_stop(lc->ringstream); lc->ringstream=NULL; } - if(!linphone_core_in_call(lc)) - { - linphone_core_set_as_current_call(lc,call); - } - if(call == linphone_core_get_current_call(lc)) - linphone_core_start_media_streams(lc,call); + + linphone_call_start_media_streams(call); + linphone_call_set_state (call,LinphoneCallStreamsRunning,"Connected (streams running)"); } static void call_received(SalOp *h){ @@ -52,25 +47,20 @@ static void call_received(SalOp *h){ const char *from,*to; char *tmp; LinphoneAddress *from_parsed; - LinphoneGeneralStateContext gctx; /* first check if we can answer successfully to this invite */ - if (lc->presence_mode!=LINPHONE_STATUS_ONLINE){ - ms_message("Not present !! presence mode : %d\n",lc->presence_mode); - if (lc->presence_mode==LINPHONE_STATUS_BUSY) + if (lc->presence_mode==LinphoneStatusBusy || + lc->presence_mode==LinphoneStatusOffline || + lc->presence_mode==LinphoneStatusDoNotDisturb || + lc->presence_mode==LinphoneStatusMoved){ + if (lc->presence_mode==LinphoneStatusBusy ) sal_call_decline(h,SalReasonBusy,NULL); - else if (lc->presence_mode==LINPHONE_STATUS_AWAY - ||lc->presence_mode==LINPHONE_STATUS_BERIGHTBACK - ||lc->presence_mode==LINPHONE_STATUS_ONTHEPHONE - ||lc->presence_mode==LINPHONE_STATUS_OUTTOLUNCH - ||lc->presence_mode==LINPHONE_STATUS_OFFLINE) + else if (lc->presence_mode==LinphoneStatusOffline) sal_call_decline(h,SalReasonTemporarilyUnavailable,NULL); - else if (lc->presence_mode==LINPHONE_STATUS_NOT_DISTURB) + else if (lc->presence_mode==LinphoneStatusDoNotDisturb) sal_call_decline(h,SalReasonTemporarilyUnavailable,NULL); - else if (lc->alt_contact!=NULL && lc->presence_mode==LINPHONE_STATUS_MOVED) + else if (lc->alt_contact!=NULL && lc->presence_mode==LinphoneStatusMoved) sal_call_decline(h,SalReasonRedirect,lc->alt_contact); - else - sal_call_decline(h,SalReasonBusy,NULL); sal_op_release(h); return; } @@ -84,12 +74,6 @@ static void call_received(SalOp *h){ call=linphone_call_new_incoming(lc,linphone_address_new(from),linphone_address_new(to),h); - if(linphone_core_get_current_call(lc)!=NULL) //we are already in call just inform that an incoming call is going on - { - char temp[256]; - snprintf(temp,sizeof(temp)-1,"A new incoming call from %s during call",from); - lc->vtable.display_status(lc,temp); - } sal_call_set_local_media_description(h,call->localdesc); call->resultdesc=sal_call_get_final_media_description(h); if (call->resultdesc) @@ -111,8 +95,7 @@ static void call_received(SalOp *h){ linphone_address_clean(from_parsed); tmp=linphone_address_as_string(from_parsed); linphone_address_destroy(from_parsed); - gctx.call=call; - gstate_new_state(lc, GSTATE_CALL_IN_INVITE, gctx, tmp); + linphone_call_set_state(call,LinphoneCallIncomingProgress,"Incoming call"); barmesg=ortp_strdup_printf("%s %s%s",tmp,_("is contacting you"), (sal_call_autoanswer_asked(h)) ?_(" and asked autoanswer."):_(".")); if (lc->vtable.show) lc->vtable.show(lc); @@ -131,12 +114,10 @@ static void call_received(SalOp *h){ ms_message("the local ring is already started"); } } - call->state=LinphoneCallRinging; sal_call_notify_ringing(h); #if !(__IPHONE_OS_VERSION_MIN_REQUIRED >= 40000) - linphone_core_init_media_streams(lc,call); + linphone_call_init_media_streams(call); #endif - if (lc->vtable.inv_recv) lc->vtable.inv_recv(lc,call); ms_free(barmesg); ms_free(tmp); } @@ -145,15 +126,12 @@ static void call_ringing(SalOp *h){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h)); LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(h); SalMediaDescription *md; - LinphoneGeneralStateContext gctx; if (call==NULL) return; - gctx.call=call; if (lc->vtable.display_status) lc->vtable.display_status(lc,_("Remote ringing.")); - if (lc->vtable.ringing_recv) - lc->vtable.ringing_recv(lc,call); + md=sal_call_get_final_media_description(h); if (md==NULL){ if (lc->ringstream!=NULL) return; /*already ringing !*/ @@ -161,12 +139,11 @@ static void call_ringing(SalOp *h){ MSSndCard *ringcard=lc->sound_conf.lsd_card ? lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard; ms_message("Remote ringing..."); lc->ringstream=ring_start(lc->sound_conf.remote_ring,2000,ringcard); - - gstate_new_state(lc, GSTATE_CALL_OUT_RINGING, gctx, NULL); + linphone_call_set_state(call,LinphoneCallOutgoingRinging,"Remote ringing"); } }else{ /*accept early media */ - if (lc->audiostream && lc->audiostream->ticker!=NULL){ + if (call->audiostream && call->audiostream->ticker!=NULL){ /*streams already started */ ms_message("Early media already started."); return; @@ -176,17 +153,15 @@ static void call_ringing(SalOp *h){ if (lc->vtable.show) lc->vtable.show(lc); if (lc->vtable.display_status) lc->vtable.display_status(lc,_("Early media.")); - gstate_new_state(lc, GSTATE_CALL_OUT_RINGING, gctx, NULL); + linphone_call_set_state(call,LinphoneCallOutgoingEarlyMedia,"Early media"); if (lc->ringstream!=NULL){ ring_stop(lc->ringstream); lc->ringstream=NULL; } ms_message("Doing early media..."); - if(call == linphone_core_get_current_call(lc)) - linphone_core_start_media_streams(lc,call); + linphone_call_start_media_streams(call); call->media_pending=TRUE; } - call->state=LinphoneCallRinging; } /* @@ -197,25 +172,15 @@ 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); - LinphoneGeneralStateContext gctx; + if (call==NULL){ ms_warning("No call to accept."); return ; } - gctx.call=call; - if (call->state==LinphoneCallAVRunning){ - ms_message("GET 200Ok of resume\n"); - if(lc->vtable.ack_resumed_recv) - lc->vtable.ack_resumed_recv(lc,call); - return ; //already accepted - } - if ((lc->audiostream!=NULL) && (lc->audiostream->ticker!=NULL)){ - /*case where we accepted early media */ - if(call == linphone_core_get_current_call(lc)) - { - linphone_core_stop_media_streams(lc,call); - linphone_core_init_media_streams(lc,call); - } + if ((call->audiostream!=NULL) && (call->audiostream->ticker!=NULL)){ + /*case where we accepted early media or already in call*/ + linphone_call_stop_media_streams(call); + linphone_call_init_media_streams(call); } if (call->resultdesc) sal_media_description_unref(call->resultdesc); @@ -225,17 +190,12 @@ static void call_accepted(SalOp *op){ call->media_pending=FALSE; } if (call->resultdesc && !sal_media_description_empty(call->resultdesc)){ - //if we initiated a pause - if(call->state == LinphoneCallPaused) - { - ms_message("GET 200Ok of pause\n"); - if(lc->vtable.ack_paused_recv) - lc->vtable.ack_paused_recv(lc,call); - }//if there is an accepted incoming call - else - { - linphone_core_set_as_current_call (lc,call); - gstate_new_state(lc, GSTATE_CALL_OUT_CONNECTED, gctx, NULL); + if (call->state==LinphoneCallPausing || sal_media_description_has_dir(call->resultdesc,SalStreamSendOnly)){ + /*we initiated a pause*/ + linphone_call_set_state(call,LinphoneCallPaused,"Call paused"); + linphone_call_set_media_streams_dir (call,SalStreamSendOnly); + linphone_call_start_media_streams (call); + }else{ linphone_connect_incoming(lc,call); } }else{ @@ -248,20 +208,15 @@ static void call_accepted(SalOp *op){ static void call_ack(SalOp *op){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); - LinphoneGeneralStateContext gctx; if (call==NULL){ ms_warning("No call to be ACK'd"); return ; } - gctx.call=call; if (call->media_pending){ - if (lc->audiostream->ticker!=NULL){ + if (call->audiostream->ticker!=NULL){ /*case where we accepted early media */ - if(call == linphone_core_get_current_call(lc)) - { - linphone_core_stop_media_streams(lc,call); - linphone_core_init_media_streams(lc,call); - } + linphone_call_stop_media_streams(call); + linphone_call_init_media_streams(call); } if (call->resultdesc) sal_media_description_unref(call->resultdesc); @@ -269,17 +224,18 @@ static void call_ack(SalOp *op){ if (call->resultdesc) sal_media_description_ref(call->resultdesc); if (call->resultdesc && !sal_media_description_empty(call->resultdesc)){ - gstate_new_state(lc, GSTATE_CALL_IN_CONNECTED, gctx, NULL); linphone_connect_incoming(lc,call); }else{ /*send a bye*/ ms_error("Incompatible SDP response received in ACK, need to abort the call"); - linphone_core_terminate_call(lc,NULL); + linphone_core_abort_call(lc,call,"No codec intersection"); + return; } call->media_pending=FALSE; } } +/* this callback is called when an incoming re-INVITE modifies the session*/ static void call_updated(SalOp *op){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); @@ -291,37 +247,24 @@ static void call_updated(SalOp *op){ if (call->resultdesc && !sal_media_description_empty(call->resultdesc)) { - if( (call->state == LinphoneCallPaused) && strcmp(call->resultdesc->addr,"0.0.0.0")) - { + if (call->state==LinphoneCallPaused && + sal_media_description_has_dir(call->resultdesc,SalStreamSendRecv) && strcmp(call->resultdesc->addr,"0.0.0.0")!=0){ if(lc->vtable.display_status) - lc->vtable.display_status(lc,"we have been resumed..."); - call->state = LinphoneCallAVRunning; - lc->vtable.resumed_recv(lc,call); - //we have to keep sending when holded - //linphone_core_start_media_streams(lc,call); + lc->vtable.display_status(lc,_("We have been resumed...")); + linphone_call_set_state (call,LinphoneCallStreamsRunning,"Connected (streams running)"); + linphone_call_set_media_streams_dir (call,SalStreamSendRecv); } - else if( (call->state != LinphoneCallPaused) && !strcmp(call->resultdesc->addr,"0.0.0.0")) - { + else if(call->state==LinphoneCallStreamsRunning && + sal_media_description_has_dir(call->resultdesc,SalStreamRecvOnly) && !strcmp(call->resultdesc->addr,"0.0.0.0")){ if(lc->vtable.display_status) - lc->vtable.display_status(lc,"we have been paused..."); - call->state = LinphoneCallPaused; - lc->vtable.paused_recv(lc,call); - //we have to keep sending when holded - /* - if(call == linphone_core_get_current_call(lc)) - { - linphone_core_stop_media_streams(lc,call); - linphone_core_init_media_streams(lc,call); - } - */ + lc->vtable.display_status(lc,_("We are being paused...")); + linphone_call_set_state (call,LinphoneCallPaused,"Call paused"); + linphone_call_set_media_streams_dir (call,SalStreamRecvOnly); } else { - if(call == linphone_core_get_current_call(lc)) - { - linphone_core_stop_media_streams(lc,call); - linphone_core_init_media_streams(lc,call); - } + linphone_call_stop_media_streams (call); + linphone_call_init_media_streams (call); linphone_connect_incoming(lc,call); } } @@ -330,9 +273,8 @@ static void call_updated(SalOp *op){ static void call_terminated(SalOp *op, const char *from){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); - LinphoneGeneralStateContext gctx; - gctx.call=call; - if (linphone_call_get_state(call)==LinphoneCallTerminated){ + + if (linphone_call_get_state(call)==LinphoneCallEnd || linphone_call_get_state(call)==LinphoneCallError){ ms_warning("call_terminated: ignoring."); return; } @@ -342,25 +284,13 @@ static void call_terminated(SalOp *op, const char *from){ ring_stop(lc->ringstream); lc->ringstream=NULL; } - if(call == linphone_core_get_current_call(lc)) - linphone_core_stop_media_streams(lc,call); + linphone_call_stop_media_streams(call); if (lc->vtable.show!=NULL) lc->vtable.show(lc); if (lc->vtable.display_status!=NULL) lc->vtable.display_status(lc,_("Call terminated.")); - call->state=LinphoneCallTerminated; - gstate_new_state(lc, GSTATE_CALL_END, gctx, NULL); - if (lc->vtable.bye_recv!=NULL){ - LinphoneAddress *addr=linphone_address_new(from); - char *tmp; - linphone_address_clean(addr); - tmp=linphone_address_as_string(addr); - if (lc->vtable.bye_recv!=NULL) - lc->vtable.bye_recv(lc,call); - ms_free(tmp); - linphone_address_destroy(addr); - } - linphone_call_set_terminated(call); + + linphone_call_set_state(call, LinphoneCallEnd,"Call ended"); } static void call_failure(SalOp *op, SalError error, SalReason sr, const char *details, int code){ @@ -372,9 +302,12 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de char *msg603=_("Call declined."); const char *msg=details; LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); - LinphoneGeneralStateContext gctx; - gctx.call=call; + if (call==NULL){ + ms_warning("Call faillure reported on already cleaned call ?"); + return ; + } + if (lc->vtable.show) lc->vtable.show(lc); if (error==SalErrorNoResponse){ @@ -427,19 +360,15 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de lc->vtable.display_status(lc,_("Call failed.")); } } - if (lc->vtable.failure_recv) - lc->vtable.failure_recv(lc,call,code); + if (lc->ringstream!=NULL) { ring_stop(lc->ringstream); lc->ringstream=NULL; } - if(call == linphone_core_get_current_call(lc)) - linphone_core_stop_media_streams(lc,call); - if (call!=NULL) { - if (sr!=SalReasonDeclined) gstate_new_state(lc, GSTATE_CALL_ERROR, gctx, msg); - else gstate_new_state(lc, GSTATE_CALL_END, gctx, NULL); - linphone_call_set_terminated(call); - } + linphone_call_stop_media_streams (call); + if (sr!=SalReasonDeclined) linphone_call_set_state(call,LinphoneCallError,msg); + else linphone_call_set_state(call,LinphoneCallEnd,"Call declined."); + } static void auth_requested(SalOp *h, const char *realm, const char *username){ @@ -474,32 +403,47 @@ static void register_success(SalOp *op, bool_t registered){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)sal_op_get_user_pointer(op); char *msg; - LinphoneGeneralStateContext gctx; - gctx.proxy=cfg; + cfg->registered=registered; - gstate_new_state(lc, GSTATE_REG_OK,gctx, NULL); - if (cfg->registered) msg=ms_strdup_printf(_("Registration on %s successful."),sal_op_get_proxy(op)); - else msg=ms_strdup_printf(_("Unregistration on %s done."),sal_op_get_proxy(op)); - if (lc->vtable.display_status) + linphone_proxy_config_set_state(cfg, registered ? LinphoneRegistrationOk : LinphoneRegistrationCleared , + registered ? "Registration sucessful" : "Unregistration done"); + if (lc->vtable.display_status){ + if (cfg->registered) msg=ms_strdup_printf(_("Registration on %s successful."),sal_op_get_proxy(op)); + else msg=ms_strdup_printf(_("Unregistration on %s done."),sal_op_get_proxy(op)); lc->vtable.display_status(lc,msg); - ms_free(msg); + ms_free(msg); + } + } static void register_failure(SalOp *op, SalError error, SalReason reason, const char *details){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); - LinphoneGeneralStateContext gctx; - char *msg=ortp_strdup_printf(_("Registration on %s failed: %s"),sal_op_get_proxy(op),(details!=NULL) ? details : _("no response timeout")); - if (lc->vtable.display_status) lc->vtable.display_status(lc,msg); - gctx.proxy=(LinphoneProxyConfig*)sal_op_get_user_pointer (op); - gstate_new_state(lc, GSTATE_REG_FAILED, gctx, msg); - ms_free(msg); + LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)sal_op_get_user_pointer(op); + + if (cfg==NULL){ + ms_warning("Registration failed for unknown proxy config."); + return ; + } + if (details==NULL) + details=_("no response timeout"); + + if (lc->vtable.display_status) { + char *msg=ortp_strdup_printf(_("Registration on %s failed: %s"),sal_op_get_proxy(op),details ); + lc->vtable.display_status(lc,msg); + ms_free(msg); + } + linphone_proxy_config_set_state(cfg,LinphoneRegistrationFailed,details); } static void vfu_request(SalOp *op){ + LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer (op); #ifdef VIDEO_ENABLED - LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); - if (lc->videostream) - video_stream_send_vfu(lc->videostream); + if (call==NULL){ + ms_warning("VFU request but no call !"); + return ; + } + if (call->videostream) + video_stream_send_vfu(call->videostream); #endif } @@ -557,7 +501,7 @@ static void ping_reply(SalOp *op){ LinphoneCall *call=(LinphoneCall*) sal_op_get_user_pointer(op); ms_message("ping reply !"); if (call){ - if (call->state==LinphoneCallPreEstablishing){ + if (call->state==LinphoneCallOutgoingInit){ linphone_core_start_invite(call->core,call,NULL); } } diff --git a/coreapi/friend.c b/coreapi/friend.c index 7ba243741..1af7a4cb5 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -29,37 +29,37 @@ const char *linphone_online_status_to_string(LinphoneOnlineStatus ss){ const char *str=NULL; switch(ss){ - case LINPHONE_STATUS_ONLINE: + case LinphoneStatusOnline: str=_("Online"); break; - case LINPHONE_STATUS_BUSY: + case LinphoneStatusBusy: str=_("Busy"); break; - case LINPHONE_STATUS_BERIGHTBACK: + case LinphoneStatusBeRightBack: str=_("Be right back"); break; - case LINPHONE_STATUS_AWAY: + case LinphoneStatusAway: str=_("Away"); break; - case LINPHONE_STATUS_ONTHEPHONE: + case LinphoneStatusOnThePhone: str=_("On the phone"); break; - case LINPHONE_STATUS_OUTTOLUNCH: + case LinphoneStatusOutToLunch: str=_("Out to lunch"); break; - case LINPHONE_STATUS_NOT_DISTURB: + case LinphoneStatusDoNotDisturb: str=_("Do not disturb"); break; - case LINPHONE_STATUS_MOVED: + case LinphoneStatusMoved: str=_("Moved"); break; - case LINPHONE_STATUS_ALT_SERVICE: + case LinphoneStatusAltService: str=_("Using another messaging service"); break; - case LINPHONE_STATUS_OFFLINE: + case LinphoneStatusOffline: str=_("Offline"); break; - case LINPHONE_STATUS_PENDING: + case LinphoneStatusPending: str=_("Pending"); break; default: @@ -138,7 +138,7 @@ void __linphone_friend_do_subscribe(LinphoneFriend *fr){ }else from=linphone_core_get_primary_contact(fr->lc); if (fr->outsub==NULL){ /* people for which we don't have yet an answer should appear as offline */ - fr->status=LINPHONE_STATUS_OFFLINE; + fr->status=LinphoneStatusOffline; /* if (fr->lc->vtable.notify_recv) fr->lc->vtable.notify_recv(fr->lc,(LinphoneFriend*)fr); @@ -157,7 +157,7 @@ void __linphone_friend_do_subscribe(LinphoneFriend *fr){ LinphoneFriend * linphone_friend_new(){ LinphoneFriend *obj=ms_new0(LinphoneFriend,1); obj->pol=LinphoneSPAccept; - obj->status=LINPHONE_STATUS_OFFLINE; + obj->status=LinphoneStatusOffline; obj->subscribe=TRUE; return obj; } @@ -243,37 +243,37 @@ int linphone_friend_set_inc_subscribe_policy(LinphoneFriend *fr, LinphoneSubscri SalPresenceStatus linphone_online_status_to_sal(LinphoneOnlineStatus os){ switch(os){ - case LINPHONE_STATUS_OFFLINE: + case LinphoneStatusOffline: return SalPresenceOffline; break; - case LINPHONE_STATUS_ONLINE: + case LinphoneStatusOnline: return SalPresenceOnline; break; - case LINPHONE_STATUS_BUSY: + case LinphoneStatusBusy: return SalPresenceBusy; break; - case LINPHONE_STATUS_BERIGHTBACK: + case LinphoneStatusBeRightBack: return SalPresenceBerightback; break; - case LINPHONE_STATUS_AWAY: + case LinphoneStatusAway: return SalPresenceAway; break; - case LINPHONE_STATUS_ONTHEPHONE: + case LinphoneStatusOnThePhone: return SalPresenceOnthephone; break; - case LINPHONE_STATUS_OUTTOLUNCH: + case LinphoneStatusOutToLunch: return SalPresenceOuttolunch; break; - case LINPHONE_STATUS_NOT_DISTURB: + case LinphoneStatusDoNotDisturb: return SalPresenceDonotdisturb; break; - case LINPHONE_STATUS_MOVED: + case LinphoneStatusMoved: return SalPresenceMoved; break; - case LINPHONE_STATUS_ALT_SERVICE: + case LinphoneStatusAltService: return SalPresenceAltService; break; - case LINPHONE_STATUS_PENDING: + case LinphoneStatusPending: return SalPresenceOffline; break; default: @@ -347,7 +347,7 @@ void linphone_friend_apply(LinphoneFriend *fr, LinphoneCore *lc){ if (fr->inc_subscribe_pending){ switch(fr->pol){ case LinphoneSPWait: - linphone_friend_notify(fr,LINPHONE_STATUS_PENDING); + linphone_friend_notify(fr,LinphoneStatusPending); break; case LinphoneSPAccept: if (fr->lc!=NULL) @@ -356,7 +356,7 @@ void linphone_friend_apply(LinphoneFriend *fr, LinphoneCore *lc){ } break; case LinphoneSPDeny: - linphone_friend_notify(fr,LINPHONE_STATUS_OFFLINE); + linphone_friend_notify(fr,LinphoneStatusOffline); break; } fr->inc_subscribe_pending=FALSE; diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index c5c7f3eb1..0a3807442 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -27,6 +27,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "private.h" +#include "mediastreamer2/mediastream.h" +#include "mediastreamer2/msvolume.h" +#include "mediastreamer2/msequalizer.h" + static MSList *make_codec_list(LinphoneCore *lc, const MSList *codecs, bool_t only_one_codec){ @@ -43,17 +47,17 @@ static MSList *make_codec_list(LinphoneCore *lc, const MSList *codecs, bool_t on } static SalMediaDescription *create_local_media_description(LinphoneCore *lc, - const char *localip, const char *username, bool_t only_one_codec){ + LinphoneCall *call, const char *username, bool_t only_one_codec){ MSList *l; PayloadType *pt; SalMediaDescription *md=sal_media_description_new(); md->nstreams=1; - strncpy(md->addr,localip,sizeof(md->addr)); + strncpy(md->addr,call->localip,sizeof(md->addr)); strncpy(md->username,username,sizeof(md->username)); md->bandwidth=linphone_core_get_download_bandwidth(lc); /*set audio capabilities */ - strncpy(md->streams[0].addr,localip,sizeof(md->streams[0].addr)); - md->streams[0].port=linphone_core_get_audio_port(lc); + strncpy(md->streams[0].addr,call->localip,sizeof(md->streams[0].addr)); + md->streams[0].port=call->audio_port; md->streams[0].proto=SalProtoRtpAvp; md->streams[0].type=SalAudio; md->streams[0].ptime=lc->net_conf.down_ptime; @@ -67,7 +71,7 @@ static SalMediaDescription *create_local_media_description(LinphoneCore *lc, if (linphone_core_video_enabled (lc)){ md->nstreams++; - md->streams[1].port=linphone_core_get_video_port(lc); + md->streams[1].port=call->video_port; md->streams[1].proto=SalProtoRtpAvp; md->streams[1].type=SalVideo; l=make_codec_list(lc,lc->codecs_conf.video_codecs,only_one_codec); @@ -78,15 +82,43 @@ static SalMediaDescription *create_local_media_description(LinphoneCore *lc, return md; } +static int find_port_offset(LinphoneCore *lc){ + int offset; + MSList *elem; + int audio_port; + bool_t already_used=FALSE; + for(offset=0;offset<100;++offset){ + audio_port=linphone_core_get_audio_port (lc)+offset; + already_used=FALSE; + for(elem=lc->calls;elem!=NULL;elem=elem->next){ + LinphoneCall *call=(LinphoneCall*)elem->data; + if (call->audio_port==audio_port) { + already_used=TRUE; + break; + } + } + if (!already_used) break; + } + if (offset==100){ + ms_error("Could not find any free port !"); + return -1; + } + return offset; +} + static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){ + int port_offset; call->refcnt=1; - call->state=LinphoneCallInit; + call->state=LinphoneCallIdle; call->start_time=time(NULL); call->media_start_time=0; call->log=linphone_call_log_new(call, from, to); - linphone_core_notify_all_friends(call->core,LINPHONE_STATUS_ONTHEPHONE); - if (linphone_core_get_firewall_policy(call->core)==LINPHONE_POLICY_USE_STUN) - linphone_core_run_stun_tests(call->core,call); + linphone_core_notify_all_friends(call->core,LinphoneStatusOnThePhone); + port_offset=find_port_offset (call->core); + if (port_offset==-1) return; + call->audio_port=linphone_core_get_audio_port(call->core)+port_offset; + call->video_port=linphone_core_get_video_port(call->core)+port_offset; + } static void discover_mtu(LinphoneCore *lc, const char *remote){ @@ -110,9 +142,11 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr sal_op_set_user_pointer(call->op,call); call->core=lc; linphone_core_get_local_ip(lc,linphone_address_get_domain(to),call->localip); - call->localdesc=create_local_media_description (lc,call->localip, - linphone_address_get_username(from),FALSE); linphone_call_init_common(call,from,to); + call->localdesc=create_local_media_description (lc,call, + linphone_address_get_username(from),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)); return call; } @@ -143,9 +177,11 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro linphone_address_clean(from); linphone_core_get_local_ip(lc,linphone_address_get_domain(from),call->localip); - call->localdesc=create_local_media_description (lc,call->localip, - linphone_address_get_username(me),lc->sip_conf.only_one_codec); 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); + 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)); linphone_address_destroy(me); return call; @@ -158,27 +194,26 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro - update the call logs accordingly */ -void linphone_call_set_terminated(LinphoneCall *call){ +static void linphone_call_set_terminated(LinphoneCall *call){ LinphoneCallStatus status=LinphoneCallAborted; LinphoneCore *lc=call->core; - - if (ms_list_size(lc->calls)==0) - linphone_core_notify_all_friends(lc,lc->prev_mode); linphone_core_update_allocated_audio_bandwidth(lc); - if (call->state==LinphoneCallAVRunning || call->state==LinphoneCallPaused){ + if (call->state==LinphoneCallEnd){ status=LinphoneCallSuccess; } linphone_call_log_completed(call->log,call, status); - call->state=LinphoneCallTerminated; if (linphone_core_del_call(lc,call) != 0){ - ms_error("could not remove the call from the list !!!"); + ms_error("Could not remove the call from the list !!!"); } - if (call == linphone_core_get_current_call(lc)){ - ms_message("destroying the current call\n"); - linphone_core_unset_the_current_call(lc); + if (call == lc->current_call){ + ms_message("Resetting the current call"); + lc->current_call=NULL; } + if (ms_list_size(lc->calls)==0) + linphone_core_notify_all_friends(lc,lc->presence_mode); + if (call->op!=NULL) { /* so that we cannot have anymore upcalls for SAL concerning this call*/ @@ -188,6 +223,17 @@ void linphone_call_set_terminated(LinphoneCall *call){ linphone_call_unref(call); } +void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message){ + LinphoneCore *lc=call->core; + if (call->state!=cstate){ + call->state=cstate; + if (lc->vtable.call_state_changed) + lc->vtable.call_state_changed(lc,call,cstate,message); + } + if (call->state==LinphoneCallEnd || call->state==LinphoneCallError) + linphone_call_set_terminated (call); +} + static void linphone_call_destroy(LinphoneCall *obj) { if (obj->op!=NULL) { @@ -234,13 +280,6 @@ void linphone_call_unref(LinphoneCall *obj){ linphone_call_destroy(obj); } -/** - * Returns true if the call is paused. -**/ -bool_t linphone_call_paused(LinphoneCall *call){ - return call->state==LinphoneCallPaused; -} - /** * Returns the remote address associated to this call * @@ -301,3 +340,334 @@ LinphoneCallLog *linphone_call_get_call_log(const LinphoneCall *call){ * @} **/ + +#ifdef TEST_EXT_RENDERER +static void rendercb(void *data, const MSPicture *local, const MSPicture *remote){ + ms_message("rendercb, local buffer=%p, remote buffer=%p", + local ? local->planes[0] : NULL, remote? remote->planes[0] : NULL); +} +#endif + +void linphone_call_init_media_streams(LinphoneCall *call){ + LinphoneCore *lc=call->core; + SalMediaDescription *md=call->localdesc; + AudioStream *audiostream; + + call->audiostream=audiostream=audio_stream_new(md->streams[0].port,linphone_core_ipv6_enabled(lc)); + if (linphone_core_echo_limiter_enabled(lc)){ + const char *type=lp_config_get_string(lc->config,"sound","el_type","mic"); + if (strcasecmp(type,"mic")==0) + audio_stream_enable_echo_limiter(audiostream,ELControlMic); + else if (strcasecmp(type,"full")==0) + audio_stream_enable_echo_limiter(audiostream,ELControlFull); + } + audio_stream_enable_gain_control(audiostream,TRUE); + if (linphone_core_echo_cancellation_enabled(lc)){ + int len,delay,framesize; + len=lp_config_get_int(lc->config,"sound","ec_tail_len",0); + delay=lp_config_get_int(lc->config,"sound","ec_delay",0); + framesize=lp_config_get_int(lc->config,"sound","ec_framesize",0); + audio_stream_set_echo_canceller_params(audiostream,len,delay,framesize); + } + audio_stream_enable_automatic_gain_control(audiostream,linphone_core_agc_enabled(lc)); + { + int enabled=lp_config_get_int(lc->config,"sound","noisegate",0); + audio_stream_enable_noise_gate(audiostream,enabled); + } + if (lc->a_rtp) + rtp_session_set_transports(audiostream->session,lc->a_rtp,lc->a_rtcp); + +#ifdef VIDEO_ENABLED + if ((lc->video_conf.display || lc->video_conf.capture) && md->streams[1].port>0){ + call->videostream=video_stream_new(md->streams[1].port,linphone_core_ipv6_enabled(lc)); +#ifdef TEST_EXT_RENDERER + video_stream_set_render_callback(call->videostream,rendercb,NULL); +#endif + } +#else + lc->videostream=NULL; +#endif +} + + +static int dtmf_tab[16]={'0','1','2','3','4','5','6','7','8','9','*','#','A','B','C','D'}; + +static void linphone_core_dtmf_received(RtpSession* s, int dtmf, void* user_data){ + LinphoneCore* lc = (LinphoneCore*)user_data; + if (dtmf<0 || dtmf>15){ + ms_warning("Bad dtmf value %i",dtmf); + return; + } + if (lc->vtable.dtmf_received != NULL) + lc->vtable.dtmf_received(lc, linphone_core_get_current_call(lc), dtmf_tab[dtmf]); +} + +static void parametrize_equalizer(LinphoneCore *lc, AudioStream *st){ + if (st->equalizer){ + MSFilter *f=st->equalizer; + int enabled=lp_config_get_int(lc->config,"sound","eq_active",0); + const char *gains=lp_config_get_string(lc->config,"sound","eq_gains",NULL); + ms_filter_call_method(f,MS_EQUALIZER_SET_ACTIVE,&enabled); + if (enabled){ + if (gains){ + do{ + int bytes; + MSEqualizerGain g; + if (sscanf(gains,"%f:%f:%f %n",&g.frequency,&g.gain,&g.width,&bytes)==3){ + ms_message("Read equalizer gains: %f(~%f) --> %f",g.frequency,g.width,g.gain); + ms_filter_call_method(f,MS_EQUALIZER_SET_GAIN,&g); + gains+=bytes; + }else break; + }while(1); + } + } + } +} + + +static void post_configure_audio_streams(LinphoneCall*call){ + AudioStream *st=call->audiostream; + LinphoneCore *lc=call->core; + float mic_gain=lp_config_get_float(lc->config,"sound","mic_gain",1); + float thres = 0; + float recv_gain; + float ng_thres=lp_config_get_float(lc->config,"sound","ng_thres",0.05); + 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) + audio_stream_set_mic_gain(st,mic_gain); + call->audio_muted=FALSE; + + recv_gain = lc->sound_conf.soft_play_lev; + if (recv_gain != 0) { + linphone_core_set_playback_gain_db (lc,recv_gain); + } + if (st->volsend){ + ms_filter_call_method(st->volsend,MS_VOLUME_REMOVE_DC,&dc_removal); + } + if (linphone_core_echo_limiter_enabled(lc)){ + float speed=lp_config_get_float(lc->config,"sound","el_speed",-1); + thres=lp_config_get_float(lc->config,"sound","el_thres",-1); + float force=lp_config_get_float(lc->config,"sound","el_force",-1); + int sustain=lp_config_get_int(lc->config,"sound","el_sustain",-1); + MSFilter *f=NULL; + if (st->el_type!=ELInactive){ + f=st->volsend; + if (speed==-1) speed=0.03; + if (force==-1) force=25; + ms_filter_call_method(f,MS_VOLUME_SET_EA_SPEED,&speed); + ms_filter_call_method(f,MS_VOLUME_SET_EA_FORCE,&force); + if (thres!=-1) + ms_filter_call_method(f,MS_VOLUME_SET_EA_THRESHOLD,&thres); + if (sustain!=-1) + ms_filter_call_method(f,MS_VOLUME_SET_EA_SUSTAIN,&sustain); + } + } + + if (st->volsend){ + ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_thres); + ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&ng_floorgain); + } + if (st->volrecv){ + /* parameters for a limited noise-gate effect, using echo limiter threshold */ + float floorgain = 1/mic_gain; + ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&thres); + ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&floorgain); + } + parametrize_equalizer(lc,st); + if (lc->vtable.dtmf_received!=NULL){ + /* replace by our default action*/ + audio_stream_play_received_dtmfs(call->audiostream,FALSE); + rtp_session_signal_connect(call->audiostream->session,"telephone-event",(RtpCallback)linphone_core_dtmf_received,(unsigned long)lc); + } +} + + + + +static RtpProfile *make_profile(LinphoneCore *lc, const SalMediaDescription *md, const SalStreamDescription *desc, int *used_pt){ + int bw; + const MSList *elem; + RtpProfile *prof=rtp_profile_new("Call profile"); + bool_t first=TRUE; + int remote_bw=0; + *used_pt=-1; + + for(elem=desc->payloads;elem!=NULL;elem=elem->next){ + PayloadType *pt=(PayloadType*)elem->data; + + if (first) { + if (desc->type==SalAudio){ + linphone_core_update_allocated_audio_bandwidth_in_call(lc,pt); + } + *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-=lc->audio_bw; + } + } + + if (desc->type==SalAudio){ + bw=get_min_bandwidth(lc->up_audio_bw,remote_bw); + }else bw=get_min_bandwidth(lc->up_video_bw,remote_bw); + if (bw>0) pt->normal_bitrate=bw*1000; + else if (desc->type==SalAudio){ + pt->normal_bitrate=-1; + } + if (desc->ptime>0){ + char tmp[40]; + snprintf(tmp,sizeof(tmp),"ptime=%i",desc->ptime); + payload_type_append_send_fmtp(pt,tmp); + } + rtp_profile_set_payload(prof,payload_type_get_number(pt),pt); + } + return prof; +} + +void linphone_call_start_media_streams(LinphoneCall *call){ + 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 !"); + return; + } + /* adjust rtp jitter compensation. It must be at least the latency of the sound card */ + int jitt_comp=MAX(lc->sound_conf.latency,lc->rtp_conf.audio_jitt_comp); + + if (call->media_start_time==0) call->media_start_time=time(NULL); + + cname=linphone_address_as_string_uri_only(me); + { + const SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc, + SalProtoRtpAvp,SalAudio); + if (stream && stream->port!=0){ + call->audio_profile=make_profile(lc,call->resultdesc,stream,&used_pt); + if (!lc->use_files){ + MSSndCard *playcard=lc->sound_conf.lsd_card ? + lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard; + MSSndCard *captcard=lc->sound_conf.capt_sndcard; + if (playcard==NULL) { + ms_warning("No card defined for playback !"); + goto end; + } + if (captcard==NULL) { + ms_warning("No card defined for capture !"); + goto end; + } + audio_stream_start_now( + call->audiostream, + call->audio_profile, + stream->addr[0]!='\0' ? stream->addr : call->resultdesc->addr, + stream->port, + stream->port+1, + used_pt, + jitt_comp, + playcard, + captcard, + linphone_core_echo_cancellation_enabled(lc)); + }else{ + audio_stream_start_with_files( + call->audiostream, + call->audio_profile, + stream->addr[0]!='\0' ? stream->addr : call->resultdesc->addr, + stream->port, + stream->port+1, + used_pt, + 100, + lc->play_file, + lc->rec_file); + } + post_configure_audio_streams(call); + audio_stream_set_rtcp_information(call->audiostream, cname, tool); + }else ms_warning("No audio stream defined ?"); + } +#ifdef VIDEO_ENABLED + { + const SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc, + SalProtoRtpAvp,SalVideo); + /* shutdown preview */ + if (lc->previewstream!=NULL) { + video_preview_stop(lc->previewstream); + lc->previewstream=NULL; + } + if (stream && stream->port!=0 && (lc->video_conf.display || lc->video_conf.capture)) { + const char *addr=stream->addr[0]!='\0' ? stream->addr : call->resultdesc->addr; + call->video_profile=make_profile(lc,call->resultdesc,stream,&used_pt); + video_stream_set_sent_video_size(call->videostream,linphone_core_get_preferred_video_size(lc)); + video_stream_enable_self_view(call->videostream,lc->video_conf.selfview); + if (lc->video_conf.display && lc->video_conf.capture) + video_stream_start(call->videostream, + call->video_profile, addr, stream->port, + stream->port+1, + used_pt, jitt_comp, lc->video_conf.device); + else if (lc->video_conf.display) + video_stream_recv_only_start(call->videostream, + call->video_profile, addr, stream->port, + used_pt, jitt_comp); + else if (lc->video_conf.capture) + video_stream_send_only_start(call->videostream, + call->video_profile, addr, stream->port, + stream->port+1, + used_pt, jitt_comp, lc->video_conf.device); + video_stream_set_rtcp_information(call->videostream, cname,tool); + }else{ + ms_warning("No valid video stream defined."); + } + } +#endif + goto end; + end: + ms_free(cname); + linphone_address_destroy(me); +} + + + +static void linphone_call_log_fill_stats(LinphoneCallLog *log, AudioStream *st){ + audio_stream_get_local_rtp_stats (st,&log->local_stats); +} + +void linphone_call_stop_media_streams(LinphoneCall *call){ + LinphoneCore *lc=call->core; + if (call->audiostream!=NULL) { + linphone_call_log_fill_stats (call->log,call->audiostream); + audio_stream_stop(call->audiostream); + call->audiostream=NULL; + } +#ifdef VIDEO_ENABLED + if (call->videostream!=NULL){ + if (lc->video_conf.display && lc->video_conf.capture) + video_stream_stop(call->videostream); + else if (lc->video_conf.display) + video_stream_recv_only_stop(call->videostream); + else if (lc->video_conf.capture) + video_stream_send_only_stop(call->videostream); + call->videostream=NULL; + } + +#endif + if (call->audio_profile){ + rtp_profile_clear_all(call->audio_profile); + rtp_profile_destroy(call->audio_profile); + call->audio_profile=NULL; + } + if (call->video_profile){ + rtp_profile_clear_all(call->video_profile); + rtp_profile_destroy(call->video_profile); + call->video_profile=NULL; + } +} + +void linphone_call_set_media_streams_dir(LinphoneCall *call, SalStreamDir dir){ +} + diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 3da96b3c0..20f28384c 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -21,13 +21,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "sipsetup.h" #include "lpconfig.h" #include "private.h" -#include "mediastreamer2/mediastream.h" -#include "mediastreamer2/msvolume.h" -#include "mediastreamer2/msequalizer.h" -#include "mediastreamer2/mseventqueue.h" #include - +#include "mediastreamer2/mediastream.h" +#include "mediastreamer2/mseventqueue.h" +#include "mediastreamer2/msvolume.h" +#include "mediastreamer2/msequalizer.h" #ifdef INET6 #ifndef WIN32 @@ -907,18 +906,21 @@ static void linphone_core_free_payload_types(void){ linphone_payload_types=NULL; } +void linphone_core_set_state(LinphoneCore *lc, LinphoneGlobalState gstate, const char *message){ + if (lc->vtable.global_state_changed){ + lc->vtable.global_state_changed(lc,gstate,message); + } +} + static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vtable, const char *config_path, const char *factory_config_path, void * userdata) { - LinphoneGeneralStateContext gctx={0}; memset (lc, 0, sizeof (LinphoneCore)); lc->data=userdata; memcpy(&lc->vtable,vtable,sizeof(LinphoneCoreVTable)); - gstate_initialize(lc); - gstate_new_state(lc, GSTATE_POWER_STARTUP, gctx, NULL); - + linphone_core_set_state(lc,LinphoneGlobalStartup,"Starting up"); ortp_init(); linphone_core_assign_payload_type(&payload_type_pcmu8000,0,NULL); linphone_core_assign_payload_type(&payload_type_gsm,3,NULL); @@ -977,13 +979,12 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta sip_config_read(lc); /* this will start eXosip*/ video_config_read(lc); //autoreplier_config_init(&lc->autoreplier_conf); - lc->prev_mode=LINPHONE_STATUS_ONLINE; - lc->presence_mode=LINPHONE_STATUS_ONLINE; + lc->presence_mode=LinphoneStatusOnline; lc->max_call_logs=15; ui_config_read(lc); if (lc->vtable.display_status) lc->vtable.display_status(lc,_("Ready")); - gstate_new_state(lc, GSTATE_POWER_ON, gctx, NULL); + linphone_core_set_state(lc,LinphoneGlobalOn,"Ready"); lc->auto_net_state_mon=lc->sip_conf.auto_net_state_mon; lc->ready=TRUE; @@ -1068,7 +1069,7 @@ int linphone_core_set_primary_contact(LinphoneCore *lc, const char *contact) /*result must be an array of chars at least LINPHONE_IPADDR_SIZE */ void linphone_core_get_local_ip(LinphoneCore *lc, const char *dest, char *result){ - if (linphone_core_get_firewall_policy(lc)==LINPHONE_POLICY_USE_NAT_ADDRESS + if (linphone_core_get_firewall_policy(lc)==LinphonePolicyUseNatAddress && linphone_core_get_nat_address(lc)!=NULL){ strncpy(result,linphone_core_get_nat_address(lc),LINPHONE_IPADDR_SIZE); return; @@ -1493,9 +1494,7 @@ static void linphone_core_disconnected(LinphoneCore *lc, LinphoneCall *call){ snprintf(temp,sizeof(temp),"Remote end seems to have disconnected, the call is going to be closed."); } if (lc->vtable.display_warning!=NULL) - lc->vtable.display_warning(lc,temp); - if(lc->vtable.failure_recv) - lc->vtable.failure_recv(lc,call, 480);//480 Temporarily Unavailable + lc->vtable.display_warning(lc,temp); linphone_core_terminate_call(lc,call); } @@ -1656,11 +1655,11 @@ void linphone_core_iterate(LinphoneCore *lc){ we are going to examine is destroy and removed during linphone_core_start_invite() */ calls=calls->next; - if (call->state==LinphoneCallPreEstablishing && (curtime-call->start_time>=2)){ + if (call->state==LinphoneCallOutgoingInit && (curtime-call->start_time>=2)){ /*start the call even if the OPTIONS reply did not arrive*/ linphone_core_start_invite(lc,call,NULL); } - if (call->dir==LinphoneCallIncoming && call->state==LinphoneCallRinging){ + if (call->dir==LinphoneCallIncoming && call->state==LinphoneCallOutgoingRinging){ elapsed=curtime-call->start_time; ms_message("incoming call ringing for %i seconds",elapsed); if (elapsed>lc->sip_conf.inc_timeout){ @@ -1672,28 +1671,28 @@ void linphone_core_iterate(LinphoneCore *lc){ call = linphone_core_get_current_call(lc); if(call) { - if (call->state==LinphoneCallAVRunning) + if (call->state==LinphoneCallConnected) { if (one_second_elapsed) { RtpSession *as=NULL,*vs=NULL; lc->prevtime=curtime; - if (lc->audiostream!=NULL) - as=lc->audiostream->session; - if (lc->videostream!=NULL) - vs=lc->videostream->session; + if (call->audiostream!=NULL) + as=call->audiostream->session; + if (call->videostream!=NULL) + vs=call->videostream->session; display_bandwidth(as,vs); } #ifdef VIDEO_ENABLED - if (lc->videostream!=NULL) - video_stream_iterate(lc->videostream); + if (call->videostream!=NULL) + video_stream_iterate(call->videostream); #endif - if (lc->audiostream!=NULL && disconnect_timeout>0) - disconnected=!audio_stream_alive(lc->audiostream,disconnect_timeout); + if (call->audiostream!=NULL && disconnect_timeout>0) + disconnected=!audio_stream_alive(call->audiostream,disconnect_timeout); } } if (linphone_core_video_preview_enabled(lc)){ - if (lc->previewstream==NULL) + if (lc->previewstream==NULL && lc->calls==NULL) toggle_video_preview(lc,TRUE); #ifdef VIDEO_ENABLED else video_stream_iterate(lc->previewstream); @@ -1739,8 +1738,6 @@ LinphoneAddress * linphone_core_interpret_url(LinphoneCore *lc, const char *url) if (enum_lookup(enum_domain,&enumres)<0){ if (lc->vtable.display_status!=NULL) lc->vtable.display_status(lc,_("Could not resolve this number.")); - if(lc->vtable.failure_recv) - lc->vtable.failure_recv(lc,NULL,400); ms_free(enum_domain); return NULL; } @@ -1857,7 +1854,7 @@ static char *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , LinphonePr const char *localip=call->localip; /* first use user's supplied ip address if asked*/ - if (linphone_core_get_firewall_policy(lc)==LINPHONE_POLICY_USE_NAT_ADDRESS){ + if (linphone_core_get_firewall_policy(lc)==LinphonePolicyUseNatAddress){ ctt=linphone_core_get_primary_contact_parsed(lc); return ms_strdup_printf("sip:%s@%s",linphone_address_get_username(ctt), linphone_core_get_nat_address(lc)); @@ -1906,17 +1903,16 @@ int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, LinphonePro char *contact; char *real_url,*barmsg; char *from; - LinphoneGeneralStateContext gctx; + /*try to be best-effort in giving real local or routable contact address */ contact=get_fixed_contact(lc,call,dest_proxy); if (contact){ sal_op_set_contact(call->op, contact); ms_free(contact); } - call->state=LinphoneCallInit; + //TODO : should probably not be done here - if(! linphone_core_in_call(lc) ) - linphone_core_init_media_streams(lc,call); + linphone_call_init_media_streams(call); if (!lc->sip_conf.sdp_200_ack){ call->media_pending=TRUE; sal_call_set_local_media_description(call->op,call->localdesc); @@ -1935,15 +1931,12 @@ int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, LinphonePro ms_free(barmsg); if (err<0){ - ms_warning("Could not initiate call."); if (lc->vtable.display_status!=NULL) - lc->vtable.display_status(lc,_("could not call")); - if(call == linphone_core_get_current_call(lc)) - linphone_core_stop_media_streams(lc,call); - linphone_call_set_terminated (call); + lc->vtable.display_status(lc,_("Could not call")); + linphone_call_stop_media_streams(call); + linphone_call_set_state(call,LinphoneCallError,"Call failed"); }else { - gctx.call=call; - gstate_new_state(lc, GSTATE_CALL_OUT_INVITE, gctx, real_url); + linphone_call_set_state(call,LinphoneCallOutgoingProgress,"Outgoing call in progress"); } ms_free(real_url); ms_free(from); @@ -2028,7 +2021,7 @@ LinphoneCall * linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddr err=linphone_core_start_invite(lc,call,dest_proxy); }else{ /*defer the start of the call after the OPTIONS ping*/ - call->state=LinphoneCallPreEstablishing; + linphone_call_set_state (call,LinphoneCallOutgoingInit,"Starting outgoing call"); call->ping_op=sal_op_new(lc->sal); sal_ping(call->ping_op,from,real_url); sal_op_set_user_pointer(call->ping_op,call); @@ -2074,334 +2067,6 @@ bool_t linphone_core_inc_invite_pending(LinphoneCore*lc){ return FALSE; } -#ifdef TEST_EXT_RENDERER -static void rendercb(void *data, const MSPicture *local, const MSPicture *remote){ - ms_message("rendercb, local buffer=%p, remote buffer=%p", - local ? local->planes[0] : NULL, remote? remote->planes[0] : NULL); -} -#endif - -void linphone_core_init_media_streams(LinphoneCore *lc, LinphoneCall *call){ -#ifdef PRINTF_DEBUG - printf("%s(%d)\n",__FUNCTION__,__LINE__); -#endif - SalMediaDescription *md=call->localdesc; - lc->audiostream=audio_stream_new(md->streams[0].port,linphone_core_ipv6_enabled(lc)); - if (linphone_core_echo_limiter_enabled(lc)){ - const char *type=lp_config_get_string(lc->config,"sound","el_type","mic"); - if (strcasecmp(type,"mic")==0) - audio_stream_enable_echo_limiter(lc->audiostream,ELControlMic); - else if (strcasecmp(type,"full")==0) - audio_stream_enable_echo_limiter(lc->audiostream,ELControlFull); - } - audio_stream_enable_gain_control(lc->audiostream,TRUE); - if (linphone_core_echo_cancellation_enabled(lc)){ - int len,delay,framesize; - len=lp_config_get_int(lc->config,"sound","ec_tail_len",0); - delay=lp_config_get_int(lc->config,"sound","ec_delay",0); - framesize=lp_config_get_int(lc->config,"sound","ec_framesize",0); - audio_stream_set_echo_canceller_params(lc->audiostream,len,delay,framesize); - } - audio_stream_enable_automatic_gain_control(lc->audiostream,linphone_core_agc_enabled(lc)); - { - int enabled=lp_config_get_int(lc->config,"sound","noisegate",0); - audio_stream_enable_noise_gate(lc->audiostream,enabled); - } - if (lc->a_rtp) - rtp_session_set_transports(lc->audiostream->session,lc->a_rtp,lc->a_rtcp); - -#ifdef VIDEO_ENABLED - if ((lc->video_conf.display || lc->video_conf.capture) && md->streams[1].port>0){ - lc->videostream=video_stream_new(md->streams[1].port,linphone_core_ipv6_enabled(lc)); -#ifdef TEST_EXT_RENDERER - video_stream_set_render_callback(lc->videostream,rendercb,NULL); -#endif - } -#else - lc->videostream=NULL; -#endif -} - -static int dtmf_tab[16]={'0','1','2','3','4','5','6','7','8','9','*','#','A','B','C','D'}; - -static void linphone_core_dtmf_received(RtpSession* s, int dtmf, void* user_data){ - LinphoneCore* lc = (LinphoneCore*)user_data; - if (dtmf<0 || dtmf>15){ - ms_warning("Bad dtmf value %i",dtmf); - return; - } - if (lc->vtable.dtmf_received != NULL) - lc->vtable.dtmf_received(lc, linphone_core_get_current_call(lc), dtmf_tab[dtmf]); -} - -static void parametrize_equalizer(LinphoneCore *lc, AudioStream *st){ - if (st->equalizer){ - MSFilter *f=st->equalizer; - int enabled=lp_config_get_int(lc->config,"sound","eq_active",0); - const char *gains=lp_config_get_string(lc->config,"sound","eq_gains",NULL); - ms_filter_call_method(f,MS_EQUALIZER_SET_ACTIVE,&enabled); - if (enabled){ - if (gains){ - do{ - int bytes; - MSEqualizerGain g; - if (sscanf(gains,"%f:%f:%f %n",&g.frequency,&g.gain,&g.width,&bytes)==3){ - ms_message("Read equalizer gains: %f(~%f) --> %f",g.frequency,g.width,g.gain); - ms_filter_call_method(f,MS_EQUALIZER_SET_GAIN,&g); - gains+=bytes; - }else break; - }while(1); - } - } - } -} - -static void post_configure_audio_streams(LinphoneCore *lc){ - AudioStream *st=lc->audiostream; - float mic_gain=lp_config_get_float(lc->config,"sound","mic_gain",1); - float thres = 0; - float recv_gain; - float ng_thres=lp_config_get_float(lc->config,"sound","ng_thres",0.05); - 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) - audio_stream_set_mic_gain(st,mic_gain); - lc->audio_muted=FALSE; - - recv_gain = lc->sound_conf.soft_play_lev; - if (recv_gain != 0) { - linphone_core_set_playback_gain_db (lc,recv_gain); - } - if (st->volsend){ - ms_filter_call_method(st->volsend,MS_VOLUME_REMOVE_DC,&dc_removal); - } - if (linphone_core_echo_limiter_enabled(lc)){ - float speed=lp_config_get_float(lc->config,"sound","el_speed",-1); - thres=lp_config_get_float(lc->config,"sound","el_thres",-1); - float force=lp_config_get_float(lc->config,"sound","el_force",-1); - int sustain=lp_config_get_int(lc->config,"sound","el_sustain",-1); - MSFilter *f=NULL; - if (st->el_type!=ELInactive){ - f=st->volsend; - if (speed==-1) speed=0.03; - if (force==-1) force=25; - ms_filter_call_method(f,MS_VOLUME_SET_EA_SPEED,&speed); - ms_filter_call_method(f,MS_VOLUME_SET_EA_FORCE,&force); - if (thres!=-1) - ms_filter_call_method(f,MS_VOLUME_SET_EA_THRESHOLD,&thres); - if (sustain!=-1) - ms_filter_call_method(f,MS_VOLUME_SET_EA_SUSTAIN,&sustain); - } - } - - if (st->volsend){ - ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_thres); - ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&ng_floorgain); - } - if (st->volrecv){ - /* parameters for a limited noise-gate effect, using echo limiter threshold */ - float floorgain = 1/mic_gain; - ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&thres); - ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&floorgain); - } - parametrize_equalizer(lc,st); - if (lc->vtable.dtmf_received!=NULL){ - /* replace by our default action*/ - audio_stream_play_received_dtmfs(lc->audiostream,FALSE); - rtp_session_signal_connect(lc->audiostream->session,"telephone-event",(RtpCallback)linphone_core_dtmf_received,(unsigned long)lc); - } -} - -static RtpProfile *make_profile(LinphoneCore *lc, const SalMediaDescription *md, const SalStreamDescription *desc, int *used_pt){ - int bw; - const MSList *elem; - RtpProfile *prof=rtp_profile_new("Call profile"); - bool_t first=TRUE; - int remote_bw=0; - *used_pt=-1; - - for(elem=desc->payloads;elem!=NULL;elem=elem->next){ - PayloadType *pt=(PayloadType*)elem->data; - - if (first) { - if (desc->type==SalAudio){ - linphone_core_update_allocated_audio_bandwidth_in_call(lc,pt); - } - *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-=lc->audio_bw; - } - } - - if (desc->type==SalAudio){ - bw=get_min_bandwidth(lc->up_audio_bw,remote_bw); - }else bw=get_min_bandwidth(lc->up_video_bw,remote_bw); - if (bw>0) pt->normal_bitrate=bw*1000; - else if (desc->type==SalAudio){ - pt->normal_bitrate=-1; - } - if (desc->ptime>0){ - char tmp[40]; - snprintf(tmp,sizeof(tmp),"ptime=%i",desc->ptime); - payload_type_append_send_fmtp(pt,tmp); - } - rtp_profile_set_payload(prof,payload_type_get_number(pt),pt); - } - return prof; -} - -void linphone_core_start_media_streams(LinphoneCore *lc, LinphoneCall *call){ - LinphoneAddress *me=linphone_core_get_primary_contact_parsed(lc); - const char *tool="linphone-" LINPHONE_VERSION; - char *cname; - int used_pt=-1; - if(lc->audiostream == NULL) - { - ms_warning("init media stream is needed before starting"); - linphone_core_init_media_streams(lc,call); - /* - * example of problem : - * 2 incomings calls, you answer and pause one, afterward if you try to answer the other call you will get SEGFAULT - */ - } - /* adjust rtp jitter compensation. It must be at least the latency of the sound card */ - int jitt_comp=MAX(lc->sound_conf.latency,lc->rtp_conf.audio_jitt_comp); - - if (call->media_start_time==0) call->media_start_time=time(NULL); - - cname=linphone_address_as_string_uri_only(me); - { - const SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc, - SalProtoRtpAvp,SalAudio); - if (stream && stream->port!=0){ - call->audio_profile=make_profile(lc,call->resultdesc,stream,&used_pt); - if (!lc->use_files){ - MSSndCard *playcard=lc->sound_conf.lsd_card ? - lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard; - MSSndCard *captcard=lc->sound_conf.capt_sndcard; - if (playcard==NULL) { - ms_warning("No card defined for playback !"); - goto end; - } - if (captcard==NULL) { - ms_warning("No card defined for capture !"); - goto end; - } - audio_stream_start_now( - lc->audiostream, - call->audio_profile, - stream->addr[0]!='\0' ? stream->addr : call->resultdesc->addr, - stream->port, - stream->port+1, - used_pt, - jitt_comp, - playcard, - captcard, - linphone_core_echo_cancellation_enabled(lc)); - }else{ - audio_stream_start_with_files( - lc->audiostream, - call->audio_profile, - stream->addr[0]!='\0' ? stream->addr : call->resultdesc->addr, - stream->port, - stream->port+1, - used_pt, - 100, - lc->play_file, - lc->rec_file); - } - post_configure_audio_streams(lc); - audio_stream_set_rtcp_information(lc->audiostream, cname, tool); - }else ms_warning("No audio stream defined ?"); - } -#ifdef VIDEO_ENABLED - { - const SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc, - SalProtoRtpAvp,SalVideo); - /* shutdown preview */ - if (lc->previewstream!=NULL) { - video_preview_stop(lc->previewstream); - lc->previewstream=NULL; - } - if (stream && stream->port!=0 && (lc->video_conf.display || lc->video_conf.capture)) { - const char *addr=stream->addr[0]!='\0' ? stream->addr : call->resultdesc->addr; - call->video_profile=make_profile(lc,call->resultdesc,stream,&used_pt); - video_stream_set_sent_video_size(lc->videostream,linphone_core_get_preferred_video_size(lc)); - video_stream_enable_self_view(lc->videostream,lc->video_conf.selfview); - if (lc->video_conf.display && lc->video_conf.capture) - video_stream_start(lc->videostream, - call->video_profile, addr, stream->port, - stream->port+1, - used_pt, jitt_comp, lc->video_conf.device); - else if (lc->video_conf.display) - video_stream_recv_only_start(lc->videostream, - call->video_profile, addr, stream->port, - used_pt, jitt_comp); - else if (lc->video_conf.capture) - video_stream_send_only_start(lc->videostream, - call->video_profile, addr, stream->port, - stream->port+1, - used_pt, jitt_comp, lc->video_conf.device); - video_stream_set_rtcp_information(lc->videostream, cname,tool); - }else{ - ms_warning("No valid video stream defined."); - } - } -#endif - goto end; - end: - ms_free(cname); - linphone_address_destroy(me); - call->state=LinphoneCallAVRunning; -} - -static void linphone_call_log_fill_stats(LinphoneCallLog *log, AudioStream *st){ - audio_stream_get_local_rtp_stats (st,&log->local_stats); -} - -void linphone_core_stop_media_streams(LinphoneCore *lc, LinphoneCall *call){ -#ifdef PRINTF_DEBUG - printf("%s(%d)\n",__FUNCTION__,__LINE__); -#endif - if (lc->audiostream!=NULL) { - linphone_call_log_fill_stats (call->log,lc->audiostream); - audio_stream_stop(lc->audiostream); - lc->audiostream=NULL; - } -#ifdef VIDEO_ENABLED - if (lc->videostream!=NULL){ - if (lc->video_conf.display && lc->video_conf.capture) - video_stream_stop(lc->videostream); - else if (lc->video_conf.display) - video_stream_recv_only_stop(lc->videostream); - else if (lc->video_conf.capture) - video_stream_send_only_stop(lc->videostream); - lc->videostream=NULL; - } - if (linphone_core_video_preview_enabled(lc)){ - if (lc->previewstream==NULL){ - lc->previewstream=video_preview_start(lc->video_conf.device, lc->video_conf.vsize); - } - } -#endif - if (call->audio_profile){ - rtp_profile_clear_all(call->audio_profile); - rtp_profile_destroy(call->audio_profile); - call->audio_profile=NULL; - } - if (call->video_profile){ - rtp_profile_clear_all(call->video_profile); - rtp_profile_destroy(call->video_profile); - call->video_profile=NULL; - } -} /** * Accept an incoming call. @@ -2421,7 +2086,6 @@ int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *call) { LinphoneProxyConfig *cfg=NULL; const char *contact=NULL; - LinphoneGeneralStateContext gctx; if (call==NULL){ //if just one call is present answer the only one ... @@ -2431,11 +2095,23 @@ int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *call) call = linphone_core_get_calls(lc)->data; } - if (call->state==LinphoneCallAVRunning){ + if (call->state==LinphoneCallConnected){ /*call already accepted*/ return -1; } + /*can accept a new call only if others are on hold */ + { + MSList *elem; + for(elem=lc->calls;elem!=NULL;elem=elem->next){ + LinphoneCall *c=(LinphoneCall*)elem->data; + if (c!=call && (c->state!=LinphoneCallPaused || c->state!=LinphoneCallPausing)){ + ms_warning("Cannot accept this call as another one is running, pause it before."); + return -1; + } + } + } + /*stop ringing */ if (lc->ringstream!=NULL) { ms_message("stop ringing"); @@ -2454,23 +2130,37 @@ int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *call) if (contact) sal_op_set_contact(call->op,contact); #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 40000 - linphone_core_init_media_streams(lc,call); + linphone_call_init_media_streams(call); #endif sal_call_accept(call->op); if (lc->vtable.display_status!=NULL) lc->vtable.display_status(lc,_("Connected.")); - gctx.call=call; - gstate_new_state(lc, GSTATE_CALL_IN_CONNECTED, gctx, NULL); + 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); sal_media_description_ref(call->resultdesc); - if(call == linphone_core_get_current_call(lc)) - linphone_core_start_media_streams(lc, call); }else call->media_pending=TRUE; ms_message("call answered."); return 0; } +int linphone_core_abort_call(LinphoneCore *lc, LinphoneCall *call, const char *error){ + sal_call_terminate(call->op); + + /*stop ringing*/ + if (lc->ringstream!=NULL) { + ring_stop(lc->ringstream); + lc->ringstream=NULL; + } + linphone_call_stop_media_streams(call); + if (lc->vtable.display_status!=NULL) + lc->vtable.display_status(lc,_("Call aborted") ); + linphone_call_set_state(call,LinphoneCallError,error); + return 0; +} + + /** * Terminates a call. * @@ -2482,7 +2172,6 @@ int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *call) int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *the_call) { LinphoneCall *call; - LinphoneGeneralStateContext gctx; if (the_call == NULL){ call = linphone_core_get_current_call(lc); if(call == NULL){ @@ -2501,13 +2190,10 @@ int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *the_call) ring_stop(lc->ringstream); lc->ringstream=NULL; } - if(call == linphone_core_get_current_call(lc)) - linphone_core_stop_media_streams(lc,call); + linphone_call_stop_media_streams(call); if (lc->vtable.display_status!=NULL) lc->vtable.display_status(lc,_("Call ended") ); - gctx.call=call; - gstate_new_state(lc, GSTATE_CALL_END, gctx, NULL); - linphone_call_set_terminated(call); + linphone_call_set_state(call,LinphoneCallEnd,"Call terminated"); return 0; } @@ -2551,11 +2237,9 @@ bool_t linphone_core_in_call(const LinphoneCore *lc){ * * @ingroup call_control **/ -LinphoneCall *linphone_core_get_current_call(LinphoneCore *lc) +LinphoneCall *linphone_core_get_current_call(const LinphoneCore *lc) { - if(lc->current_call != NULL) - return lc->current_call; - return NULL; + return lc->current_call; } /** @@ -2579,25 +2263,23 @@ int linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *the_call) } else { - ms_error("LinphoneCall was null\n"); - return -2; + ms_error("LinphoneCall was null"); + return -1; } } if(linphone_core_get_current_call(lc) != call) { - ms_error("The call asked to be paused was not the current on\n"); - return -3; + ms_error("The call asked to be paused was not the current on"); + return -1; } - if(sal_call_hold(call->op,TRUE) != 0) + if (sal_call_hold(call->op,TRUE) != 0) { - lc->vtable.display_warning(lc,_("Could not pause the call")); + if (lc->vtable.display_warning) + lc->vtable.display_warning(lc,_("Could not pause the call")); } - call->state = LinphoneCallPaused; - linphone_core_unset_the_current_call(lc); - linphone_core_stop_media_streams(lc,call); - //have to be done ... because if another call is incoming before this pause, you will get sound on the end point paused - linphone_core_init_media_streams(lc,call); - lc->vtable.display_status(lc,_("Pause the current call")); + linphone_call_set_state(call,LinphoneCallPausing,"Pausing call"); + if (lc->vtable.display_status) + lc->vtable.display_status(lc,_("Pausing the current call...")); return 0; } @@ -2608,7 +2290,7 @@ int linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *the_call) **/ int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *the_call) { - char temp[255]; + char temp[255]={0}; LinphoneCall *call = the_call; if(lc == NULL) { @@ -2630,26 +2312,25 @@ int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *the_call) return -2; } } - if(call->state == LinphoneCallInit || call->state == LinphoneCallPreEstablishing || call->state == LinphoneCallRinging ) + if(call->state!=LinphoneCallPaused ) { ms_warning("we cannot resume a call when the communication is not established"); - return -3; + return -1; } if(linphone_core_get_current_call(lc) != NULL) { ms_error("There is already a call in process pause or stop it first\n"); - return -4; + return -1; } - linphone_core_init_media_streams(lc,call); if(sal_call_hold(call->op,FALSE) != 0) { lc->vtable.display_warning(lc,_("Could not resume the call")); } - call->state = LinphoneCallAVRunning; + linphone_call_set_state (call,LinphoneCallResuming,"Resuming"); linphone_core_set_as_current_call(lc,call); - linphone_core_start_media_streams(lc,call); - snprintf(temp,sizeof(temp),"Resume the call with %s",linphone_call_get_remote_address_as_string(call)); - lc->vtable.display_status(lc,temp); + snprintf(temp,sizeof(temp)-1,"Resuming the call with %s",linphone_call_get_remote_address_as_string(call)); + if (lc->vtable.display_status) + lc->vtable.display_status(lc,temp); return 0; } @@ -2746,7 +2427,6 @@ void linphone_core_set_presence_info(LinphoneCore *lc,int minutes_away, */ linphone_core_send_publish(lc,presence_mode); } - lc->prev_mode=lc->presence_mode; lc->presence_mode=presence_mode; } @@ -2802,10 +2482,15 @@ void linphone_core_set_ring_level(LinphoneCore *lc, int level){ **/ void linphone_core_set_playback_gain_db (LinphoneCore *lc, float gaindb){ float gain=gaindb; - lc->sound_conf.soft_play_lev=gaindb; - AudioStream *st=lc->audiostream; - if (!st) return; /*just return*/ + LinphoneCall *call=linphone_core_get_current_call (lc); + AudioStream *st; + lc->sound_conf.soft_play_lev=gaindb; + + if (call==NULL || (st=call->audiostream)==NULL){ + ms_message("linphone_core_set_playback_gain_db(): no active call."); + return; + } if (st->volrecv){ ms_filter_call_method(st->volrecv,MS_VOLUME_SET_DB_GAIN,&gain); }else ms_warning("Could not apply gain: gain control wasn't activated."); @@ -2817,13 +2502,7 @@ void linphone_core_set_playback_gain_db (LinphoneCore *lc, float gaindb){ * @ingroup media_parameters **/ float linphone_core_get_playback_gain_db(LinphoneCore *lc) { - float gain=0; - AudioStream *st=lc->audiostream; - if (st->volrecv){ - ms_filter_call_method(st->volrecv,MS_VOLUME_GET_GAIN_DB,&gain); - }else ms_warning("Could not get gain: gain control wasn't activated."); - - return gain; + return lc->sound_conf.soft_play_lev; } /** @@ -3128,39 +2807,46 @@ bool_t linphone_core_echo_limiter_enabled(const LinphoneCore *lc){ * @ingroup media_parameters **/ void linphone_core_mute_mic(LinphoneCore *lc, bool_t val){ - if (lc->audiostream!=NULL){ - audio_stream_set_mic_gain(lc->audiostream, - (val==TRUE) ? 0 : 1.0); // REVISIT: take mic_gain value - if ( linphone_core_get_rtp_no_xmit_on_audio_mute(lc) ){ - audio_stream_mute_rtp(lc->audiostream,val); - } - lc->audio_muted=val; + LinphoneCall *call=linphone_core_get_current_call(lc); + if (call==NULL){ + ms_warning("linphone_core_mute_mic(): No current call !"); + return; + } + if (call->audiostream!=NULL){ + audio_stream_set_mic_gain(call->audiostream, + (val==TRUE) ? 0 : lp_config_get_float(lc->config,"sound","mic_gain",1)); + if ( linphone_core_get_rtp_no_xmit_on_audio_mute(lc) ){ + audio_stream_mute_rtp(call->audiostream,val); + } + call->audio_muted=val; } } bool_t linphone_core_is_mic_muted(LinphoneCore *lc) { float gain=1.0; - if (lc->audiostream && lc->audiostream->volsend){ - ms_filter_call_method(lc->audiostream->volsend,MS_VOLUME_GET_GAIN,&gain); + 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; -} - -// returns audio mute status for active stream -bool_t linphone_core_is_audio_muted(LinphoneCore *lc){ - if( lc->audiostream != NULL ) - return (lc->audio_muted); - return FALSE; + return gain==0 || call->audio_muted; } // returns rtp transmission status for an active stream // if audio is muted and config parameter rtp_no_xmit_on_audio_mute // was set on then rtp transmission is also muted bool_t linphone_core_is_rtp_muted(LinphoneCore *lc){ - if( (lc->audiostream != NULL) && - linphone_core_get_rtp_no_xmit_on_audio_mute(lc)){ - return lc->audio_muted; + LinphoneCall *call=linphone_core_get_current_call(lc); + if (call==NULL){ + ms_warning("linphone_core_is_mic_muted(): No current call !"); + return FALSE; + } + if( linphone_core_get_rtp_no_xmit_on_audio_mute(lc)){ + return call->audio_muted; } return FALSE; } @@ -3184,12 +2870,17 @@ bool_t linphone_core_agc_enabled(const LinphoneCore *lc){ **/ void linphone_core_send_dtmf(LinphoneCore *lc, char dtmf) { + LinphoneCall *call=linphone_core_get_current_call(lc); + if (call==NULL){ + ms_warning("linphone_core_send_dtmf(): no active call"); + return; + } /*By default we send DTMF RFC2833 if we do not have enabled SIP_INFO but we can also send RFC2833 and SIP_INFO*/ if (linphone_core_get_use_rfc2833_for_dtmf(lc)!=0 || linphone_core_get_use_info_for_dtmf(lc)==0) { /* In Band DTMF */ - if (lc->audiostream!=NULL){ - audio_stream_send_dtmf(lc->audiostream,dtmf); + if (call->audiostream!=NULL){ + audio_stream_send_dtmf(call->audiostream,dtmf); } else { @@ -3198,10 +2889,6 @@ void linphone_core_send_dtmf(LinphoneCore *lc, char dtmf) } if (linphone_core_get_use_info_for_dtmf(lc)!=0){ /* Out of Band DTMF (use INFO method) */ - LinphoneCall *call=linphone_core_get_current_call(lc); - if (call==NULL){ - return; - } sal_call_send_dtmf(call->op,dtmf); } } @@ -3281,17 +2968,15 @@ void linphone_core_clear_call_logs(LinphoneCore *lc){ static void toggle_video_preview(LinphoneCore *lc, bool_t val){ #ifdef VIDEO_ENABLED - if (lc->videostream==NULL){ - if (val){ - if (lc->previewstream==NULL){ - lc->previewstream=video_preview_start(lc->video_conf.device, - lc->video_conf.vsize); - } - }else{ - if (lc->previewstream!=NULL){ - video_preview_stop(lc->previewstream); - lc->previewstream=NULL; - } + if (val){ + if (lc->previewstream==NULL){ + lc->previewstream=video_preview_start(lc->video_conf.device, + lc->video_conf.vsize); + } + }else{ + if (lc->previewstream!=NULL){ + video_preview_stop(lc->previewstream); + lc->previewstream=NULL; } } #endif @@ -3360,10 +3045,11 @@ bool_t linphone_core_video_preview_enabled(const LinphoneCore *lc){ * This function works at any time, including during calls. **/ void linphone_core_enable_self_view(LinphoneCore *lc, bool_t val){ + LinphoneCall *call=linphone_core_get_current_call (lc); lc->video_conf.selfview=val; #ifdef VIDEO_ENABLED - if (lc->videostream){ - video_stream_enable_self_view(lc->videostream,val); + if (call && call->videostream){ + video_stream_enable_self_view(call->videostream,val); } #endif } @@ -3422,12 +3108,13 @@ const char *linphone_core_get_video_device(const LinphoneCore *lc){ int linphone_core_set_static_picture(LinphoneCore *lc, const char *path) { #ifdef VIDEO_ENABLED VideoStream *vs = NULL; + LinphoneCall *call=linphone_core_get_current_call (lc); /* Select the video stream from the call in the first place */ - if (lc && lc->videostream) { - vs = lc->videostream; + if (call && call->videostream) { + vs = call->videostream; } /* If not in call, select the video stream from the preview */ - if (vs == NULL && lc && lc->previewstream) { + if (vs == NULL && lc->previewstream) { vs = lc->previewstream; } @@ -3457,8 +3144,9 @@ int linphone_core_set_static_picture(LinphoneCore *lc, const char *path) { **/ unsigned long linphone_core_get_native_video_window_id(const LinphoneCore *lc){ #ifdef VIDEO_ENABLED - if (lc->videostream) - return video_stream_get_native_window_id(lc->videostream); + LinphoneCall *call=linphone_core_get_current_call (lc); + if (call->videostream) + return video_stream_get_native_window_id(call->videostream); if (lc->previewstream) return video_stream_get_native_window_id(lc->previewstream); #endif @@ -3561,26 +3249,28 @@ void linphone_core_use_files(LinphoneCore *lc, bool_t yesno){ } void linphone_core_set_play_file(LinphoneCore *lc, const char *file){ + LinphoneCall *call=linphone_core_get_current_call(lc); if (lc->play_file!=NULL){ ms_free(lc->play_file); lc->play_file=NULL; } if (file!=NULL) { lc->play_file=ms_strdup(file); - if (lc->audiostream->ticker) - audio_stream_play(lc->audiostream,file); + if (call && call->audiostream && call->audiostream->ticker) + audio_stream_play(call->audiostream,file); } } void linphone_core_set_record_file(LinphoneCore *lc, const char *file){ + LinphoneCall *call=linphone_core_get_current_call(lc); if (lc->rec_file!=NULL){ ms_free(lc->rec_file); lc->rec_file=NULL; } if (file!=NULL) { lc->rec_file=ms_strdup(file); - if (lc->audiostream) - audio_stream_record(lc->audiostream,file); + if (call && call->audiostream) + audio_stream_record(call->audiostream,file); } } @@ -3656,9 +3346,9 @@ void linphone_core_set_audio_transports(LinphoneCore *lc, RtpTransport *rtp, Rtp int linphone_core_get_current_call_stats(LinphoneCore *lc, rtp_stats_t *local, rtp_stats_t *remote){ LinphoneCall *call=linphone_core_get_current_call (lc); if (call!=NULL){ - if (lc->audiostream!=NULL){ + if (call->audiostream!=NULL){ memset(remote,0,sizeof(*remote)); - audio_stream_get_local_rtp_stats (lc->audiostream,local); + audio_stream_get_local_rtp_stats (call->audiostream,local); return 0; } } @@ -3837,7 +3527,6 @@ LpConfig *linphone_core_get_config(LinphoneCore *lc){ static void linphone_core_uninit(LinphoneCore *lc) { - LinphoneGeneralStateContext gctx; while(lc->calls) { LinphoneCall *the_call = lc->calls->data; @@ -3852,8 +3541,7 @@ static void linphone_core_uninit(LinphoneCore *lc) if (lc->friends) ms_list_for_each(lc->friends,(void (*)(void *))linphone_friend_close_subscriptions); - gctx.call=NULL; - gstate_new_state(lc, GSTATE_POWER_SHUTDOWN, gctx, NULL); + linphone_core_set_state(lc,LinphoneGlobalShutdown,"Shutting down"); #ifdef VIDEO_ENABLED if (lc->previewstream!=NULL){ video_preview_stop(lc->previewstream); @@ -3880,7 +3568,7 @@ static void linphone_core_uninit(LinphoneCore *lc) linphone_core_free_payload_types(); ortp_exit(); - gstate_new_state(lc, GSTATE_POWER_OFF, gctx, NULL); + linphone_core_set_state(lc,LinphoneGlobalOff,"Off"); } static void set_network_reachable(LinphoneCore* lc,bool_t isReachable){ @@ -4033,6 +3721,12 @@ static PayloadType* find_payload_type_from_list(const char* type, int rate,const return NULL; } +/** + * Get payload type from mime type and clock rate + * @ingroup media_parameters + * This function searches in audio and video codecs for the given payload type name and clockrate. + * Returns NULL if not found. + */ PayloadType* linphone_core_find_payload_type(LinphoneCore* lc, const char* type, int rate) { PayloadType* result = find_payload_type_from_list(type, rate, linphone_core_get_audio_codecs(lc)); if (result) { @@ -4043,6 +3737,6 @@ PayloadType* linphone_core_find_payload_type(LinphoneCore* lc, const char* type, return result; } } - //not found + /*not found*/ return NULL; } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index fb94db8db..774dcc817 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -161,18 +161,9 @@ char * linphone_call_log_to_str(LinphoneCallLog *cl); struct _LinphoneCall; typedef struct _LinphoneCall LinphoneCall; -typedef enum _LinphoneCallState{ - LinphoneCallInit, - LinphoneCallPreEstablishing, - LinphoneCallRinging, - LinphoneCallAVRunning, - LinphoneCallPaused, - LinphoneCallTerminated -}LinphoneCallState; -LinphoneCallState linphone_call_get_state(const LinphoneCall *call); +enum _LinphoneCallState linphone_call_get_state(const LinphoneCall *call); bool_t linphone_call_asked_to_autoanswer(LinphoneCall *call); -bool_t linphone_call_paused(LinphoneCall *call); const LinphoneAddress * linphone_core_get_current_call_remote_address(struct _LinphoneCore *lc); const LinphoneAddress * linphone_call_get_remote_address(const LinphoneCall *call); char *linphone_call_get_remote_address_as_string(const LinphoneCall *call); @@ -189,18 +180,18 @@ typedef enum{ }LinphoneSubscribePolicy; typedef enum _LinphoneOnlineStatus{ - LINPHONE_STATUS_OFFLINE, - LINPHONE_STATUS_ONLINE, - LINPHONE_STATUS_BUSY, - LINPHONE_STATUS_BERIGHTBACK, - LINPHONE_STATUS_AWAY, - LINPHONE_STATUS_ONTHEPHONE, - LINPHONE_STATUS_OUTTOLUNCH, - LINPHONE_STATUS_NOT_DISTURB, - LINPHONE_STATUS_MOVED, - LINPHONE_STATUS_ALT_SERVICE, - LINPHONE_STATUS_PENDING, - LINPHONE_STATUS_END + LinphoneStatusOffline, + LinphoneStatusOnline, + LinphoneStatusBusy, + LinphoneStatusBeRightBack, + LinphoneStatusAway, + LinphoneStatusOnThePhone, + LinphoneStatusOutToLunch, + LinphoneStatusDoNotDisturb, + LinphoneStatusMoved, + LinphoneStatusAltService, + LinphoneStatusPending, + LinphoneStatusEnd }LinphoneOnlineStatus; const char *linphone_online_status_to_string(LinphoneOnlineStatus ss); @@ -371,86 +362,59 @@ void linphone_chat_room_destroy(LinphoneChatRoom *cr); void linphone_chat_room_set_user_data(LinphoneChatRoom *cr, void * ud); void * linphone_chat_room_get_user_data(LinphoneChatRoom *cr); -/* describes the different groups of states */ -typedef enum _gstate_group { - GSTATE_GROUP_POWER, - GSTATE_GROUP_REG, - GSTATE_GROUP_CALL -} gstate_group_t; +typedef enum _LinphoneCallState{ + LinphoneCallIdle, + LinphoneCallIncomingProgress, + LinphoneCallOutgoingInit, + LinphoneCallOutgoingProgress, + LinphoneCallOutgoingRinging, + LinphoneCallOutgoingEarlyMedia, + LinphoneCallConnected, + LinphoneCallStreamsRunning, + LinphoneCallPausing, + LinphoneCallPaused, + LinphoneCallResuming, + LinphoneCallRefered, + LinphoneCallError, + LinphoneCallEnd, +} LinphoneCallState; -typedef enum _gstate { - /* states for GSTATE_GROUP_POWER */ - GSTATE_POWER_OFF = 0, /* initial state */ - GSTATE_POWER_STARTUP, - GSTATE_POWER_ON, - GSTATE_POWER_SHUTDOWN, - /* states for GSTATE_GROUP_REG */ - GSTATE_REG_NONE = 10, /* initial state */ - GSTATE_REG_OK, - GSTATE_REG_FAILED, - GSTATE_REG_PENDING, /* a registration request is ongoing*/ - /* states for GSTATE_GROUP_CALL */ - GSTATE_CALL_IDLE = 20, /* initial state */ - GSTATE_CALL_OUT_INVITE, - GSTATE_CALL_OUT_CONNECTED, - GSTATE_CALL_IN_INVITE, - GSTATE_CALL_IN_CONNECTED, - GSTATE_CALL_END, - GSTATE_CALL_ERROR, - GSTATE_CALL_OUT_RINGING, /*remote ringing*/ - GSTATE_CALL_PAUSED, - GSTATE_CALL_RESUMED, - GSTATE_INVALID -} gstate_t; +typedef enum _LinphoneGlobalState{ + LinphoneGlobalOff, + LinphoneGlobalStartup, + LinphoneGlobalOn, + LinphoneGlobalShutdown +}LinphoneGlobalState; -struct _LinphoneGeneralState { - gstate_t old_state; - gstate_t new_state; - gstate_group_t group; - const char *message; -}; -typedef struct _LinphoneGeneralState LinphoneGeneralState; - - -typedef union _LinphoneGeneralStateContext{ - LinphoneCall *call; - LinphoneProxyConfig *proxy; -}LinphoneGeneralStateContext; +typedef enum _LinphoneRegistrationState{ + LinphoneRegistrationNone, + LinphoneRegistrationProgress, + LinphoneRegistrationOk, + LinphoneRegistrationCleared, + LinphoneRegistrationFailed +}LinphoneRegistrationState; /** * @addtogroup initializing * @{ **/ + +/**Call state notification callback prototype*/ +typedef void (*LinphoneGlobalStateCb)(struct _LinphoneCore *lc, LinphoneGlobalState gstate, const char *message); +/**Call state notification callback prototype*/ +typedef void (*LinphoneCallStateCb)(struct _LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *message); +/**Registration state notification callback prototype*/ +typedef void (*LinphoneRegistrationStateCb)(struct _LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneCallState cstate, const char *message); /** Callback prototype */ typedef void (*ShowInterfaceCb)(struct _LinphoneCore *lc); /** Callback prototype */ -typedef void (*InviteReceivedCb)(struct _LinphoneCore *lc, LinphoneCall *call); -/** Callback prototype */ -typedef void (*ByeReceivedCb)(struct _LinphoneCore *lc, LinphoneCall *call); -/** Callback prototype */ -typedef void (*RingingReceivedCb)(struct _LinphoneCore *lc, LinphoneCall *call); -/** Callback prototype */ -typedef void (*ConnectedReceivedCb)(struct _LinphoneCore *lc, LinphoneCall *call); -/** Callback prototype */ -typedef void (*FailureReceivedCb)(struct _LinphoneCore *lc, LinphoneCall *call, int error_code); -/** Callback prototype */ -typedef void (*PausedReceivedCb)(struct _LinphoneCore *lc, LinphoneCall *call); -/** Callback prototype */ -typedef void (*ResumedReceivedCb)(struct _LinphoneCore *lc, LinphoneCall *call); -/** Callback prototype */ -typedef void (*AckPausedReceivedCb)(struct _LinphoneCore *lc, LinphoneCall *call); -/** Callback prototype */ -typedef void (*AckResumedReceivedCb)(struct _LinphoneCore *lc, LinphoneCall *call); -/** Callback prototype */ typedef void (*DisplayStatusCb)(struct _LinphoneCore *lc, const char *message); /** Callback prototype */ typedef void (*DisplayMessageCb)(struct _LinphoneCore *lc, const char *message); /** Callback prototype */ typedef void (*DisplayUrlCb)(struct _LinphoneCore *lc, const char *message, const char *url); /** Callback prototype */ -typedef void (*DisplayQuestionCb)(struct _LinphoneCore *lc, const char *message); -/** Callback prototype */ typedef void (*LinphoneCoreCbFunc)(struct _LinphoneCore *lc,void * user_data); /** Callback prototype */ typedef void (*NotifyReceivedCb)(struct _LinphoneCore *lc, const char *from, const char *msg); @@ -465,8 +429,6 @@ typedef void (*CallLogUpdated)(struct _LinphoneCore *lc, struct _LinphoneCallLog /** Callback prototype */ typedef void (*TextMessageReceived)(struct _LinphoneCore *lc, LinphoneChatRoom *room, const char *from, const char *message); /** Callback prototype */ -typedef void (*GeneralStateChange)(struct _LinphoneCore *lc, LinphoneGeneralState *gstate, LinphoneGeneralStateContext ctx); -/** Callback prototype */ typedef void (*DtmfReceived)(struct _LinphoneCore* lc, LinphoneCall *call, int dtmf); /** Callback prototype */ typedef void (*ReferReceived)(struct _LinphoneCore *lc, LinphoneCall *call, const char *refer_to); @@ -475,20 +437,12 @@ typedef void (*BuddyInfoUpdated)(struct _LinphoneCore *lc, LinphoneFriend *lf); /** * This structure holds all callbacks that the application should implement. - * + * None is mandatory. **/ -typedef struct _LinphoneVTable -{ - InviteReceivedCb inv_recv; /**< Notifies incoming calls */ - ByeReceivedCb bye_recv; /**< Notify calls terminated by far end*/ - RingingReceivedCb ringing_recv; /**< Notify that the distant phone is ringing*/ - ConnectedReceivedCb connected_recv; /**< Notify that the distant phone answered the call*/ - FailureReceivedCb failure_recv; /**< Notify that the call failed*/ - PausedReceivedCb paused_recv; /**< Notify that the call has been paused*/ - ResumedReceivedCb resumed_recv; /**< Notify that the call has been resumed*/ - AckPausedReceivedCb ack_paused_recv;/**< Notify that the previous command pause sent to the call has been acknowledge*/ - AckResumedReceivedCb ack_resumed_recv;/**< Notify that the previous command resumed sent to the call has been acknowledge*/ - GeneralStateChange general_state; /**< State notification callback */ +typedef struct _LinphoneVTable{ + LinphoneGlobalStateCb global_state_changed; /**vtable.display_status(lc,_("Stun lookup in progress...")); /*create the two audio and video RTP sockets, and send STUN message to our stun server */ - sock1=create_socket(linphone_core_get_audio_port(lc)); + sock1=create_socket(call->audio_port); if (sock1<0) return; if (video_enabled){ - sock2=create_socket(linphone_core_get_video_port(lc)); + sock2=create_socket(call->video_port); if (sock2<0) return ; } sendStunRequest(sock1,(struct sockaddr*)&ss,ss_len,11,TRUE); diff --git a/coreapi/presence.c b/coreapi/presence.c index c56861d9d..57e764c38 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -92,36 +92,36 @@ void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeState ss, Sal char *tmp; LinphoneFriend *lf; LinphoneAddress *friend=NULL; - LinphoneOnlineStatus estatus=LINPHONE_STATUS_OFFLINE; + LinphoneOnlineStatus estatus=LinphoneStatusOffline; switch(sal_status){ case SalPresenceOffline: - estatus=LINPHONE_STATUS_OFFLINE; + estatus=LinphoneStatusOffline; break; case SalPresenceOnline: - estatus=LINPHONE_STATUS_ONLINE; + estatus=LinphoneStatusOnline; break; case SalPresenceBusy: - estatus=LINPHONE_STATUS_BUSY; + estatus=LinphoneStatusBusy; break; case SalPresenceBerightback: - estatus=LINPHONE_STATUS_AWAY; + estatus=LinphoneStatusBeRightBack; break; case SalPresenceAway: - estatus=LINPHONE_STATUS_AWAY; + estatus=LinphoneStatusAway; break; case SalPresenceOnthephone: - estatus=LINPHONE_STATUS_ONTHEPHONE; + estatus=LinphoneStatusOnThePhone; break; case SalPresenceOuttolunch: - estatus=LINPHONE_STATUS_OUTTOLUNCH; + estatus=LinphoneStatusOutToLunch; break; case SalPresenceDonotdisturb: - estatus=LINPHONE_STATUS_BUSY; + estatus=LinphoneStatusDoNotDisturb; break; case SalPresenceMoved: case SalPresenceAltService: - estatus=LINPHONE_STATUS_AWAY; + estatus=LinphoneStatusMoved; break; } lf=linphone_find_friend_by_out_subscribe(lc->friends,op); diff --git a/coreapi/private.h b/coreapi/private.h index 818fc779e..28caaaf9d 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -54,12 +54,6 @@ #endif #endif - -/* private: set a new state */ -void gstate_new_state(struct _LinphoneCore *lc, gstate_t new_state, LinphoneGeneralStateContext context, const char *message); -/*private*/ -void gstate_initialize(struct _LinphoneCore *lc); - struct _LinphoneCall { struct _LinphoneCore *core; @@ -76,28 +70,32 @@ struct _LinphoneCall time_t media_start_time; /*time at which it was accepted, media streams established*/ LinphoneCallState state; int refcnt; - bool_t media_pending; void * user_pointer; + int audio_port; + int video_port; + struct _AudioStream *audiostream; /**/ + struct _VideoStream *videostream; + bool_t media_pending; + bool_t audio_muted; }; LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to); LinphoneCall * linphone_call_new_incoming(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op); -void linphone_call_set_terminated(LinphoneCall *call); +void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message); /* private: */ LinphoneCallLog * linphone_call_log_new(LinphoneCall *call, LinphoneAddress *local, LinphoneAddress * remote); void linphone_call_log_completed(LinphoneCallLog *calllog, LinphoneCall *call, LinphoneCallStatus status); void linphone_call_log_destroy(LinphoneCallLog *cl); - -void linphone_core_init_media_streams(LinphoneCore *lc, LinphoneCall *call); - void linphone_auth_info_write_config(struct _LpConfig *config, LinphoneAuthInfo *obj, int pos); void linphone_core_update_proxy_register(LinphoneCore *lc); void linphone_core_refresh_subscribes(LinphoneCore *lc); +int linphone_core_abort_call(LinphoneCore *lc, LinphoneCall *call, const char *error); int linphone_proxy_config_send_publish(LinphoneProxyConfig *cfg, LinphoneOnlineStatus os); +void linphone_proxy_config_set_state(LinphoneProxyConfig *cfg, LinphoneRegistrationState rstate, const char *message); int linphone_online_status_to_eXosip(LinphoneOnlineStatus os); void linphone_friend_close_subscriptions(LinphoneFriend *lf); @@ -172,8 +170,11 @@ 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_core_start_media_streams(LinphoneCore *lc, struct _LinphoneCall *call); -void linphone_core_stop_media_streams(LinphoneCore *lc, struct _LinphoneCall *call); +void linphone_call_init_media_streams(LinphoneCall *call); +void linphone_call_start_media_streams(LinphoneCall *call); +void linphone_call_set_media_streams_dir(LinphoneCall *call, SalStreamDir dir); +void linphone_call_stop_media_streams(LinphoneCall *call); + const char * linphone_core_get_identity(LinphoneCore *lc); const char * linphone_core_get_route(LinphoneCore *lc); bool_t linphone_core_is_in_communication_with(LinphoneCore *lc, const char *to); @@ -372,8 +373,6 @@ struct _LinphoneCore MSList *chatrooms; int max_call_logs; int missed_calls; - struct _AudioStream *audiostream; /**/ - struct _VideoStream *videostream; struct _VideoStream *previewstream; struct _MSEventQueue *msevq; RtpTransport *a_rtp,*a_rtcp; @@ -381,7 +380,6 @@ struct _LinphoneCore MSList *subscribers; /* unknown subscribers */ int minutes_away; LinphoneOnlineStatus presence_mode; - LinphoneOnlineStatus prev_mode; char *alt_contact; void *data; char *play_file; @@ -392,9 +390,6 @@ struct _LinphoneCore int dw_video_bw; int up_video_bw; int audio_bw; - gstate_t gstate_power; - gstate_t gstate_reg; - gstate_t gstate_call; LinphoneWaitingCallback wait_cb; void *wait_ctx; bool_t use_files; @@ -404,16 +399,16 @@ struct _LinphoneCore bool_t preview_finished; bool_t auto_net_state_mon; bool_t network_reachable; - bool_t audio_muted; }; bool_t linphone_core_can_we_add_call(LinphoneCore *lc); int linphone_core_add_call( LinphoneCore *lc, LinphoneCall *call); int linphone_core_del_call( LinphoneCore *lc, LinphoneCall *call); int linphone_core_set_as_current_call(LinphoneCore *lc, LinphoneCall *call); -int linphone_core_unset_the_current_call(LinphoneCore *lc); int linphone_core_get_calls_nb(const LinphoneCore *lc); +void linphone_core_set_state(LinphoneCore *lc, LinphoneGlobalState gstate, const char *message); + #define HOLD_OFF (0) #define HOLD_ON (1) diff --git a/coreapi/proxy.c b/coreapi/proxy.c index e4870c781..848c8e4df 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -262,10 +262,8 @@ static char *guess_contact_for_register(LinphoneProxyConfig *obj){ } static void linphone_proxy_config_register(LinphoneProxyConfig *obj){ - LinphoneGeneralStateContext gctx; const char *id_str; - gctx.proxy=obj; if (obj->reg_identity!=NULL) id_str=obj->reg_identity; else id_str=linphone_core_get_primary_contact(obj->lc); if (obj->reg_sendregister){ @@ -277,10 +275,10 @@ static void linphone_proxy_config_register(LinphoneProxyConfig *obj){ sal_op_set_contact(obj->op,contact); ms_free(contact); sal_op_set_user_pointer(obj->op,obj); - if (!sal_register(obj->op,obj->reg_proxy,obj->reg_identity,obj->expires)) { - gstate_new_state(obj->lc,GSTATE_REG_PENDING, gctx, NULL); + if (sal_register(obj->op,obj->reg_proxy,obj->reg_identity,obj->expires)==0) { + linphone_proxy_config_set_state(obj,LinphoneRegistrationProgress,"Registration in progress"); } else { - gstate_new_state(obj->lc,GSTATE_REG_FAILED, gctx, NULL); + linphone_proxy_config_set_state(obj,LinphoneRegistrationFailed,"Registration failed"); } } } @@ -799,6 +797,12 @@ void * linphone_proxy_config_get_user_data(LinphoneProxyConfig *cr) { return cr->user_data; } +void linphone_proxy_config_set_state(LinphoneProxyConfig *cfg, LinphoneRegistrationState state, const char *message){ + LinphoneCore *lc=cfg->lc; + if (lc && lc->vtable.registration_state_changed){ + lc->vtable.registration_state_changed(lc,cfg,state,message); + } +} diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index 923dfdf1b..ec0b7aff8 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -1782,13 +1782,9 @@ int sal_address_get_port_int(const SalAddress *uri) { } } -/** +/* * Send a re-Invite used to hold the current call - * - * @ingroup call_control - * @param lc the LinphoneCore object - * @param url the destination of the call (sip address). -**/ +*/ int sal_call_hold(SalOp *h, bool_t holdon) { int err=0; diff --git a/mediastreamer2 b/mediastreamer2 index 4b5164714..04be0f4c3 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 4b5164714c2cf77a284f0213fc79e9b147e8563a +Subproject commit 04be0f4c3eac2d30828963b3617497bb9337e3bc From 5de380f508c7c38fc059875d574be6d13bc19430 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 17 Aug 2010 15:20:00 +0200 Subject: [PATCH 34/45] multicall again --- console/commands.c | 91 ++++++++------- console/linphonec.c | 248 ++++++++-------------------------------- coreapi/callbacks.c | 38 +++--- coreapi/linphonecall.c | 125 ++++++++++++-------- coreapi/linphonecore.c | 147 ++++++------------------ coreapi/linphonecore.h | 12 +- coreapi/offeranswer.c | 9 ++ coreapi/private.h | 1 + gtk-glade/friendlist.c | 28 ++--- gtk-glade/incall_view.c | 19 ++- gtk-glade/main.c | 64 +++++------ gtk-glade/propertybox.c | 12 +- mediastreamer2 | 2 +- 13 files changed, 310 insertions(+), 486 deletions(-) diff --git a/console/commands.c b/console/commands.c index 9f10a4831..2f07bbdad 100644 --- a/console/commands.c +++ b/console/commands.c @@ -407,19 +407,20 @@ lpc_cmd_call(LinphoneCore *lc, char *args) } if(!strcmp(args,"show")) { - MSList *calls = linphone_core_get_calls(lc); + const MSList *calls = linphone_core_get_calls(lc); if(calls) { - MSList *p_calls = calls; + const MSList *p_calls = calls; linphonec_out("\t\t\t\t\r\n"); while(p_calls != NULL) { + char *tmp=linphone_call_get_remote_address_as_string(p_calls->data); linphonec_out("%s\t\t\t%s\r\n", - linphone_call_get_remote_address_as_string(p_calls->data), + tmp, (((LinphoneCall *)p_calls->data)==linphone_core_get_current_call(lc))?"yes":"no"); p_calls = p_calls->next; + ms_free(tmp); } - ms_list_free(calls); } else { @@ -639,7 +640,7 @@ lpc_cmd_nat(LinphoneCore *lc, char *args) } nat = linphone_core_get_nat_address(lc); - use = linphone_core_get_firewall_policy(lc)==LINPHONE_POLICY_USE_NAT_ADDRESS; + use = linphone_core_get_firewall_policy(lc)==LinphonePolicyUseNatAddress; linphonec_out("Nat address: %s%s\n", nat ? nat : "unspecified" , use ? "" : " (disabled - use 'firewall nat' to enable)"); return 1; @@ -660,7 +661,7 @@ lpc_cmd_stun(LinphoneCore *lc, char *args) } stun = linphone_core_get_stun_server(lc); - use = linphone_core_get_firewall_policy(lc)==LINPHONE_POLICY_USE_STUN; + use = linphone_core_get_firewall_policy(lc)==LinphonePolicyUseStun; linphonec_out("Stun server: %s%s\n", stun ? stun : "unspecified" , use? "" : " (disabled - use 'firewall stun' to enable)"); return 1; @@ -677,7 +678,7 @@ lpc_cmd_firewall(LinphoneCore *lc, char *args) { if (strcmp(args,"none")==0) { - linphone_core_set_firewall_policy(lc,LINPHONE_POLICY_NO_FIREWALL); + linphone_core_set_firewall_policy(lc,LinphonePolicyNoFirewall); } else if (strcmp(args,"stun")==0) { @@ -687,7 +688,7 @@ lpc_cmd_firewall(LinphoneCore *lc, char *args) linphonec_out("No stun server address is defined, use 'stun
' first\n"); return 1; } - linphone_core_set_firewall_policy(lc,LINPHONE_POLICY_USE_STUN); + linphone_core_set_firewall_policy(lc,LinphonePolicyUseStun); } else if (strcmp(args,"nat")==0) { @@ -697,19 +698,19 @@ lpc_cmd_firewall(LinphoneCore *lc, char *args) linphonec_out("No nat address is defined, use 'nat
' first"); return 1; } - linphone_core_set_firewall_policy(lc,LINPHONE_POLICY_USE_NAT_ADDRESS); + linphone_core_set_firewall_policy(lc,LinphonePolicyUseNatAddress); } } switch(linphone_core_get_firewall_policy(lc)) { - case LINPHONE_POLICY_NO_FIREWALL: + case LinphonePolicyNoFirewall: linphonec_out("No firewall\n"); break; - case LINPHONE_POLICY_USE_STUN: + case LinphonePolicyUseStun: linphonec_out("Using stun server %s to discover firewall address\n", setting ? setting : linphone_core_get_stun_server(lc)); break; - case LINPHONE_POLICY_USE_NAT_ADDRESS: + case LinphonePolicyUseNatAddress: linphonec_out("Using supplied nat address %s.\n", setting ? setting : linphone_core_get_nat_address(lc)); break; } @@ -1229,7 +1230,7 @@ static int lpc_cmd_resume(LinphoneCore *lc, char *args){ else { int returned = 0; - MSList *calls = linphone_core_get_calls(lc); + const MSList *calls = linphone_core_get_calls(lc); if(ms_list_size(calls) == 1) { if(linphone_core_resume_call(lc,calls->data) < 0) @@ -1241,7 +1242,6 @@ static int lpc_cmd_resume(LinphoneCore *lc, char *args){ { returned = 1; } - ms_list_free(calls); return returned; } } @@ -1775,31 +1775,31 @@ static int lpc_cmd_status(LinphoneCore *lc, char *args) } else if (strstr(args,"hook")) { - gstate_t call_state=linphone_core_get_state(lc,GSTATE_GROUP_CALL); -/* - if (!cfg || !linphone_proxy_config_is_registered(cfg)){ - linphonec_out("unregistered\n"); - return 1; - } - */ + LinphoneCall *call=linphone_core_get_current_call (lc); + LinphoneCallState call_state=LinphoneCallIdle; + if (call) call_state=linphone_call_get_state(call); + switch(call_state){ - case GSTATE_CALL_OUT_INVITE: + case LinphoneCallOutgoingInit: + case LinphoneCallOutgoingProgress: linphonec_out("hook=dialing\n"); break; - case GSTATE_CALL_IDLE: + case LinphoneCallIdle: linphonec_out("hook=offhook\n"); break; - case GSTATE_CALL_OUT_CONNECTED: - linphonec_out("Call out, hook=%s duration=%i, muted=%s rtp-xmit-muted=%s\n", linphonec_get_callee(), + case LinphoneCallStreamsRunning: + case LinphoneCallConnected: + if (linphone_call_get_dir(call)==LinphoneCallOutgoing){ + linphonec_out("Call out, hook=%s duration=%i, muted=%s rtp-xmit-muted=%s\n", linphonec_get_callee(), linphone_core_get_current_call_duration(lc), - lc->audio_muted ? "yes" : "no", + linphone_core_is_mic_muted (lc) ? "yes" : "no", linphone_core_is_rtp_muted(lc) ? "yes" : "no"); - break; - case GSTATE_CALL_IN_CONNECTED: - linphonec_out("hook=answered duration=%i\n" , - linphone_core_get_current_call_duration(lc)); + }else{ + linphonec_out("hook=answered duration=%i\n" , + linphone_core_get_current_call_duration(lc)); + } break; - case GSTATE_CALL_IN_INVITE: + case LinphoneCallIncomingReceived: linphonec_out("Incoming call from %s\n",linphonec_get_caller()); break; default: @@ -2048,22 +2048,21 @@ static int lpc_cmd_unmute_mic(LinphoneCore *lc, char *args){ static int lpc_cmd_rtp_no_xmit_on_audio_mute(LinphoneCore *lc, char *args) { - bool_t rtp_xmit_off=FALSE; - char *status; - gstate_t call_state=linphone_core_get_state(lc,GSTATE_GROUP_CALL); + bool_t rtp_xmit_off=FALSE; + char *status; - if(args){ - if(strstr(args,"1"))rtp_xmit_off=TRUE; - if(call_state == GSTATE_CALL_IDLE) - linphone_core_set_rtp_no_xmit_on_audio_mute(lc,rtp_xmit_off); - else - linphonec_out("nortp-on-audio-mute: call in progress - cannot change state\n"); - } - rtp_xmit_off=linphone_core_get_rtp_no_xmit_on_audio_mute(lc); - if(rtp_xmit_off)status="off"; - else status="on"; - linphonec_out("rtp transmit %s when audio muted\n",status); - return 1; + if(args){ + if(strstr(args,"1"))rtp_xmit_off=TRUE; + if(linphone_core_get_current_call (lc)==NULL) + linphone_core_set_rtp_no_xmit_on_audio_mute(lc,rtp_xmit_off); + else + linphonec_out("nortp-on-audio-mute: call in progress - cannot change state\n"); + } + rtp_xmit_off=linphone_core_get_rtp_no_xmit_on_audio_mute(lc); + if (rtp_xmit_off) status="off"; + else status="on"; + linphonec_out("rtp transmit %s when audio muted\n",status); + return 1; } diff --git a/console/linphonec.c b/console/linphonec.c index 030477c74..c00d87632 100644 --- a/console/linphonec.c +++ b/console/linphonec.c @@ -112,27 +112,21 @@ static char **linephonec_readline_completion(const char *text, #endif /* These are callback for linphone core */ -static void linphonec_call_received(LinphoneCore *lc, LinphoneCall *call); -static void linphonec_paused_received(LinphoneCore *lc, LinphoneCall *call); -static void linphonec_resumed_received(LinphoneCore *lc, LinphoneCall *call); static void linphonec_prompt_for_auth(LinphoneCore *lc, const char *realm, const char *username); -static void linphonec_display_refer (LinphoneCore * lc,LinphoneCall *call, const char *refer_to); +static void linphonec_display_refer (LinphoneCore * lc, const char *refer_to); static void linphonec_display_something (LinphoneCore * lc, const char *something); static void linphonec_display_url (LinphoneCore * lc, const char *something, const char *url); static void linphonec_display_warning (LinphoneCore * lc, const char *something); -static void stub () {} static void linphonec_notify_received(LinphoneCore *lc,const char *from,const char *msg); -static void linphonec_ack_paused_received(LinphoneCore *lc, LinphoneCall *call); -static void linphonec_ack_resumed_received(LinphoneCore *lc, LinphoneCall *call); + static void linphonec_notify_presence_received(LinphoneCore *lc,LinphoneFriend *fid); static void linphonec_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url); -static void linphonec_bye_received(LinphoneCore *lc, LinphoneCall *call); + static void linphonec_text_received(LinphoneCore *lc, LinphoneChatRoom *cr, const char *from, const char *msg); static void linphonec_display_status (LinphoneCore * lc, const char *something); -static void linphonec_general_state (LinphoneCore * lc, LinphoneGeneralState *gstate, LinphoneGeneralStateContext gctx); static void linphonec_dtmf_received(LinphoneCore *lc, LinphoneCall *call, int dtmf); static void print_prompt(LinphoneCore *opm); void linphonec_out(const char *fmt,...); @@ -175,37 +169,6 @@ static ortp_pipe_t server_sock; #endif /*_WIN32_WCE*/ -LinphoneCoreVTable linphonec_vtable -#if !defined (_MSC_VER) -= { - .show =(ShowInterfaceCb) stub, - .inv_recv = linphonec_call_received, - .bye_recv = linphonec_bye_received, - .ringing_recv = (RingingReceivedCb) stub, - .connected_recv = (ConnectedReceivedCb) stub, - .failure_recv = (FailureReceivedCb) stub, - .paused_recv = linphonec_paused_received, - .resumed_recv = linphonec_resumed_received, - .notify_recv = linphonec_notify_received, - .ack_paused_recv = linphonec_ack_paused_received, - .ack_resumed_recv = linphonec_ack_resumed_received, - .notify_presence_recv = linphonec_notify_presence_received, - .new_unknown_subscriber = linphonec_new_unknown_subscriber, - .auth_info_requested = linphonec_prompt_for_auth, - .display_status = linphonec_display_status, - .display_message=linphonec_display_something, - .display_warning=linphonec_display_warning, - .display_url=linphonec_display_url, - .text_received=linphonec_text_received, - .general_state=linphonec_general_state, - .dtmf_received=linphonec_dtmf_received, - .refer_received=linphonec_display_refer -} -#endif /*_WIN32_WCE*/ -; - - - /*************************************************************************** * * Linphone core callbacks @@ -216,10 +179,9 @@ LinphoneCoreVTable linphonec_vtable * Linphone core callback */ static void -linphonec_display_refer (LinphoneCore * lc,LinphoneCall *call, const char *refer_to) +linphonec_display_refer (LinphoneCore * lc, const char *refer_to) { - fprintf (stdout, "The distant end point asked to transfer the call to %s,don't forget to terminate the call if not\n%s", refer_to,prompt); - fflush(stdout); + linphonec_out("Receiving out of call refer to %s", refer_to); } /* @@ -261,49 +223,6 @@ linphonec_display_url (LinphoneCore * lc, const char *something, const char *url fprintf (stdout, "%s : %s\n", something, url); } - -/* - * Linphone core callback - */ -static void -linphonec_call_received(LinphoneCore *lc, LinphoneCall *call) -{ - char *from=linphone_call_get_remote_address_as_string(call); - linphonec_set_caller(from); - ms_free(from); - if ( auto_answer) { - answer_call=TRUE; - } -} -/* - * Linphone core callback - */ -static void -linphonec_paused_received(LinphoneCore *lc, LinphoneCall *call) -{ - char *from=linphone_call_get_remote_address_as_string(call); - if(from) - { - linphonec_out("the call from %s have been paused\n",from); - ms_free(from); - } -} -/* - * Linphone core callback - */ -static void -linphonec_resumed_received(LinphoneCore *lc, LinphoneCall *call) -{ - char *from=linphone_call_get_remote_address_as_string(call); - if(from) - { - linphonec_out("the call from %s have been resumed\n",from); - ms_free(from); - } -} - - - /* * Linphone core callback */ @@ -343,33 +262,6 @@ linphonec_notify_received(LinphoneCore *lc,const char *from,const char *msg) } } -/* - * Linphone core callback - */ -static void -linphonec_ack_paused_received(LinphoneCore *lc, LinphoneCall *call) -{ - char *from=linphone_call_get_remote_address_as_string(call); - if(from) - { - linphonec_out("the previous pause sent to %s has been acknowledged\n",from); - ms_free(from); - } -} - -/* - * Linphone core callback - */ -static void -linphonec_ack_resumed_received(LinphoneCore *lc, LinphoneCall *call) -{ - char *from=linphone_call_get_remote_address_as_string(call); - if(from) - { - linphonec_out("the previous resume sent to %s has been acknowledged\n",from); - ms_free(from); - } -} /* * Linphone core callback @@ -397,18 +289,33 @@ linphonec_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, } -/* - * Linphone core callback - */ -static void -linphonec_bye_received(LinphoneCore *lc, LinphoneCall *call) -{ - // Should change prompt back to original maybe - - // printing this is unneeded as we'd get a "Communication ended" - // message trough display_status callback anyway +static void linphonec_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState st, const char *msg){ char *from=linphone_call_get_remote_address_as_string(call); - printf("Bye received from %s\n", from); + switch(st){ + case LinphoneCallEnd: + printf("Call with %s ended.\n", from); + break; + case LinphoneCallResuming: + printf("Resuming call with %s.\n", from); + break; + case LinphoneCallStreamsRunning: + printf("Media streams established with %s.\n", from); + break; + case LinphoneCallPausing: + printf("Pausing call with %s.\n", from); + break; + case LinphoneCallPaused: + printf("Call with %s is now paused.\n", from); + break; + case LinphoneCallIncomingReceived: + linphonec_set_caller(from); + if ( auto_answer) { + answer_call=TRUE; + } + break; + default: + break; + } ms_free(from); } @@ -431,64 +338,6 @@ static void linphonec_dtmf_received(LinphoneCore *lc, LinphoneCall *call, int dt ms_free(from); } -static void -linphonec_general_state (LinphoneCore * lc, LinphoneGeneralState *gstate, LinphoneGeneralStateContext gctx) -{ - if (show_general_state) { - switch(gstate->new_state) { - case GSTATE_POWER_OFF: - printf("GSTATE_POWER_OFF"); - break; - case GSTATE_POWER_STARTUP: - printf("GSTATE_POWER_STARTUP"); - break; - case GSTATE_POWER_ON: - printf("GSTATE_POWER_ON"); - break; - case GSTATE_POWER_SHUTDOWN: - printf("GSTATE_POWER_SHUTDOWN"); - break; - case GSTATE_REG_NONE: - printf("GSTATE_REG_NONE"); - break; - case GSTATE_REG_OK: - printf("GSTATE_REG_OK"); - break; - case GSTATE_REG_FAILED: - printf("GSTATE_REG_FAILED"); - break; - case GSTATE_CALL_IDLE: - printf("GSTATE_CALL_IDLE"); - break; - case GSTATE_CALL_OUT_RINGING: - printf("GSTATE_CALL_OUT_RINGING"); - break; - case GSTATE_CALL_OUT_INVITE: - printf("GSTATE_CALL_OUT_INVITE"); - break; - case GSTATE_CALL_OUT_CONNECTED: - printf("GSTATE_CALL_OUT_CONNECTED"); - break; - case GSTATE_CALL_IN_INVITE: - printf("GSTATE_CALL_IN_INVITE"); - break; - case GSTATE_CALL_IN_CONNECTED: - printf("GSTATE_CALL_IN_CONNECTED"); - break; - case GSTATE_CALL_END: - printf("GSTATE_CALL_END"); - break; - case GSTATE_CALL_ERROR: - printf("GSTATE_CALL_ERROR"); - break; - default: - printf("GSTATE_UNKNOWN_%d",gstate->new_state); - } - if (gstate->message) printf(" %s", gstate->message); - printf("\n"); - } -} - static char received_prompt[PROMPT_MAX_LEN]; static ms_mutex_t prompt_mutex; static bool_t have_prompt=FALSE; @@ -668,6 +517,8 @@ bool_t linphonec_get_autoanswer(){ return auto_answer; } +LinphoneCoreVTable linphonec_vtable={0}; + /***************************************************************************/ /* * Main @@ -693,31 +544,24 @@ char **convert_args_to_ascii(int argc, _TCHAR **wargv){ int _tmain(int argc, _TCHAR* wargv[]) { char **argv=convert_args_to_ascii(argc,wargv); trace_level=6; - linphonec_vtable.show =(ShowInterfaceCb) stub; - linphonec_vtable.inv_recv = linphonec_call_received; - linphonec_vtable.bye_recv = linphonec_bye_received; - linphonec_vtable.notify_presence_recv = linphonec_notify_received; - linphonec_vtable.new_unknown_subscriber = linphonec_new_unknown_subscriber; - linphonec_vtable.auth_info_requested = linphonec_prompt_for_auth; - linphonec_vtable.display_status = linphonec_display_status; - linphonec_vtable.display_message=linphonec_display_something; -#ifdef VINCENT_MAURY_RSVP - /* the yes/no dialog box */ - linphonec_vtable.display_yes_no= (DisplayMessageCb) stub; -#endif - linphonec_vtable.display_warning=linphonec_display_warning; - linphonec_vtable.display_url=linphonec_display_url; - linphonec_vtable.display_question=(DisplayQuestionCb)stub; - linphonec_vtable.text_received=linphonec_text_received; - linphonec_vtable.general_state=linphonec_general_state; - linphonec_vtable.dtmf_received=linphonec_dtmf_received; #else int main (int argc, char *argv[]) { #endif - - + linphonec_vtable.call_state_changed=linphonec_call_state_changed; + linphonec_vtable.notify_presence_recv = linphonec_notify_presence_received; + linphonec_vtable.new_unknown_subscriber = linphonec_new_unknown_subscriber; + linphonec_vtable.auth_info_requested = linphonec_prompt_for_auth; + linphonec_vtable.display_status = linphonec_display_status; + linphonec_vtable.display_message=linphonec_display_something; + linphonec_vtable.display_warning=linphonec_display_warning; + linphonec_vtable.display_url=linphonec_display_url; + linphonec_vtable.text_received=linphonec_text_received; + linphonec_vtable.dtmf_received=linphonec_dtmf_received; + linphonec_vtable.refer_received=linphonec_display_refer; + linphonec_vtable.notify_recv=linphonec_notify_received; + if (! linphonec_init(argc, argv) ) exit(EXIT_FAILURE); linphonec_main_loop (linphonec, sipAddr); diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 7c52c8327..597aeb0c8 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -95,7 +95,7 @@ static void call_received(SalOp *h){ linphone_address_clean(from_parsed); tmp=linphone_address_as_string(from_parsed); linphone_address_destroy(from_parsed); - linphone_call_set_state(call,LinphoneCallIncomingProgress,"Incoming call"); + linphone_call_set_state(call,LinphoneCallIncomingReceived,"Incoming call"); barmesg=ortp_strdup_printf("%s %s%s",tmp,_("is contacting you"), (sal_call_autoanswer_asked(h)) ?_(" and asked autoanswer."):_(".")); if (lc->vtable.show) lc->vtable.show(lc); @@ -190,10 +190,16 @@ static void call_accepted(SalOp *op){ call->media_pending=FALSE; } if (call->resultdesc && !sal_media_description_empty(call->resultdesc)){ - if (call->state==LinphoneCallPausing || sal_media_description_has_dir(call->resultdesc,SalStreamSendOnly)){ + if (sal_media_description_has_dir(call->resultdesc,SalStreamSendOnly)){ /*we initiated a pause*/ + 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); + lc->vtable.display_status(lc,msg); + ms_free(tmp); + ms_free(msg); + } linphone_call_set_state(call,LinphoneCallPaused,"Call paused"); - linphone_call_set_media_streams_dir (call,SalStreamSendOnly); linphone_call_start_media_streams (call); }else{ linphone_connect_incoming(lc,call); @@ -252,21 +258,17 @@ static void call_updated(SalOp *op){ if(lc->vtable.display_status) lc->vtable.display_status(lc,_("We have been resumed...")); linphone_call_set_state (call,LinphoneCallStreamsRunning,"Connected (streams running)"); - linphone_call_set_media_streams_dir (call,SalStreamSendRecv); } else if(call->state==LinphoneCallStreamsRunning && sal_media_description_has_dir(call->resultdesc,SalStreamRecvOnly) && !strcmp(call->resultdesc->addr,"0.0.0.0")){ if(lc->vtable.display_status) lc->vtable.display_status(lc,_("We are being paused...")); linphone_call_set_state (call,LinphoneCallPaused,"Call paused"); - linphone_call_set_media_streams_dir (call,SalStreamRecvOnly); - } - else - { - linphone_call_stop_media_streams (call); - linphone_call_init_media_streams (call); - linphone_connect_incoming(lc,call); } + + linphone_call_stop_media_streams (call); + linphone_call_init_media_streams (call); + linphone_connect_incoming(lc,call); } } @@ -457,9 +459,17 @@ static void dtmf_received(SalOp *op, char dtmf){ static void refer_received(Sal *sal, SalOp *op, const char *referto){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal); LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); - if (lc->vtable.refer_received){ - lc->vtable.refer_received(lc,call,referto); - if (op) sal_refer_accept(op); + if (call){ + linphone_call_set_state(call,LinphoneCallRefered,"Refered"); + if (lc->vtable.display_status){ + char *msg=ms_strdup_printf(_("We are transferred to %s"),referto); + lc->vtable.display_status(lc,msg); + ms_free(msg); + } + sal_refer_accept(op); + }else if (lc->vtable.refer_received){ + lc->vtable.refer_received(lc,referto); + sal_refer_accept(op); } } diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 0a3807442..17df0e52a 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -335,6 +335,16 @@ LinphoneCallLog *linphone_call_get_call_log(const LinphoneCall *call){ return call->log; } +/** + * Returns the refer-to uri (if the call received was transfered). +**/ +const char *linphone_call_get_refer_to(const LinphoneCall *call){ + return call->refer_to; +} + +LinphoneCallDir linphone_call_get_dir(const LinphoneCall *call){ + return call->log->dir; +} /** * @} @@ -550,21 +560,35 @@ void linphone_call_start_media_streams(LinphoneCall *call){ { const SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc, SalProtoRtpAvp,SalAudio); - if (stream && stream->port!=0){ + if (stream){ + MSSndCard *playcard=lc->sound_conf.lsd_card ? + lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard; + MSSndCard *captcard=lc->sound_conf.capt_sndcard; + const char *playfile=lc->play_file; + const char *recfile=lc->rec_file; call->audio_profile=make_profile(lc,call->resultdesc,stream,&used_pt); - if (!lc->use_files){ - MSSndCard *playcard=lc->sound_conf.lsd_card ? - lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard; - MSSndCard *captcard=lc->sound_conf.capt_sndcard; + if (used_pt!=-1){ if (playcard==NULL) { ms_warning("No card defined for playback !"); - goto end; } if (captcard==NULL) { ms_warning("No card defined for capture !"); - goto end; } - audio_stream_start_now( + ms_message("streamdir is %i",stream->dir); + /*Replace soundcard filters by inactive file players or recorders + when placed in recvonly or sendonly mode*/ + if (stream->port==0 || stream->dir==SalStreamRecvOnly){ + captcard=NULL; + playfile=NULL; + }else if (stream->dir==SalStreamSendOnly){ + playcard=NULL; + captcard=NULL; + recfile=NULL; + } + /*if playfile are supplied don't use soundcards*/ + if (playfile) captcard=NULL; + if (recfile) playcard=NULL; + audio_stream_start_full( call->audiostream, call->audio_profile, stream->addr[0]!='\0' ? stream->addr : call->resultdesc->addr, @@ -572,54 +596,63 @@ void linphone_call_start_media_streams(LinphoneCall *call){ stream->port+1, used_pt, jitt_comp, + playfile, + recfile, playcard, captcard, linphone_core_echo_cancellation_enabled(lc)); - }else{ - audio_stream_start_with_files( - call->audiostream, - call->audio_profile, - stream->addr[0]!='\0' ? stream->addr : call->resultdesc->addr, - stream->port, - stream->port+1, - used_pt, - 100, - lc->play_file, - lc->rec_file); - } - post_configure_audio_streams(call); - audio_stream_set_rtcp_information(call->audiostream, cname, tool); - }else ms_warning("No audio stream defined ?"); + post_configure_audio_streams(call); + audio_stream_set_rtcp_information(call->audiostream, cname, tool); + }else ms_warning("No audio stream accepted ?"); + } } #ifdef VIDEO_ENABLED { const SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc, SalProtoRtpAvp,SalVideo); + used_pt=-1; /* shutdown preview */ if (lc->previewstream!=NULL) { video_preview_stop(lc->previewstream); lc->previewstream=NULL; } - if (stream && stream->port!=0 && (lc->video_conf.display || lc->video_conf.capture)) { + if (stream) { const char *addr=stream->addr[0]!='\0' ? stream->addr : call->resultdesc->addr; call->video_profile=make_profile(lc,call->resultdesc,stream,&used_pt); - video_stream_set_sent_video_size(call->videostream,linphone_core_get_preferred_video_size(lc)); - video_stream_enable_self_view(call->videostream,lc->video_conf.selfview); - if (lc->video_conf.display && lc->video_conf.capture) - video_stream_start(call->videostream, - call->video_profile, addr, stream->port, - stream->port+1, - used_pt, jitt_comp, lc->video_conf.device); - else if (lc->video_conf.display) - video_stream_recv_only_start(call->videostream, - call->video_profile, addr, stream->port, - used_pt, jitt_comp); - else if (lc->video_conf.capture) - video_stream_send_only_start(call->videostream, - call->video_profile, addr, stream->port, - stream->port+1, - used_pt, jitt_comp, lc->video_conf.device); - video_stream_set_rtcp_information(call->videostream, cname,tool); + if (used_pt!=-1){ + VideoStreamDir dir=VideoStreamSendRecv; + MSWebCam *cam=lc->video_conf.device; + bool_t is_inactive=FALSE; + + video_stream_set_sent_video_size(call->videostream,linphone_core_get_preferred_video_size(lc)); + video_stream_enable_self_view(call->videostream,lc->video_conf.selfview); + + if (stream->dir==SalStreamSendOnly && lc->video_conf.capture ){ + cam=ms_web_cam_manager_get_cam(ms_web_cam_manager_get(),"Static picture"); + dir=VideoStreamSendOnly; + }else if (stream->dir==SalStreamRecvOnly && lc->video_conf.display ){ + dir=VideoStreamRecvOnly; + }else if (stream->dir==SalStreamSendRecv){ + if (lc->video_conf.display && lc->video_conf.capture) + dir=VideoStreamSendRecv; + else if (lc->video_conf.display) + dir=VideoStreamRecvOnly; + else + dir=VideoStreamSendOnly; + }else{ + ms_warning("video stream is inactive."); + /*either inactive or incompatible with local capabilities*/ + is_inactive=TRUE; + } + if (!is_inactive){ + video_stream_set_direction (call->videostream, dir); + video_stream_start(call->videostream, + call->video_profile, addr, stream->port, + stream->port+1, + used_pt, jitt_comp, cam); + video_stream_set_rtcp_information(call->videostream, cname,tool); + } + }else ms_warning("No video stream accepted."); }else{ ms_warning("No valid video stream defined."); } @@ -638,7 +671,6 @@ static void linphone_call_log_fill_stats(LinphoneCallLog *log, AudioStream *st){ } void linphone_call_stop_media_streams(LinphoneCall *call){ - LinphoneCore *lc=call->core; if (call->audiostream!=NULL) { linphone_call_log_fill_stats (call->log,call->audiostream); audio_stream_stop(call->audiostream); @@ -646,12 +678,7 @@ void linphone_call_stop_media_streams(LinphoneCall *call){ } #ifdef VIDEO_ENABLED if (call->videostream!=NULL){ - if (lc->video_conf.display && lc->video_conf.capture) - video_stream_stop(call->videostream); - else if (lc->video_conf.display) - video_stream_recv_only_stop(call->videostream); - else if (lc->video_conf.capture) - video_stream_send_only_stop(call->videostream); + video_stream_stop(call->videostream); call->videostream=NULL; } @@ -668,6 +695,4 @@ void linphone_call_stop_media_streams(LinphoneCall *call){ } } -void linphone_call_set_media_streams_dir(LinphoneCall *call, SalStreamDir dir){ -} diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 20f28384c..0c5420d66 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1980,11 +1980,13 @@ LinphoneCall * linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddr LinphoneCall *call; if (linphone_core_in_call(lc)){ - lc->vtable.display_warning(lc,_("Sorry, you have to pause or stop the current call first !")); + if (lc->vtable.display_warning) + lc->vtable.display_warning(lc,_("Sorry, you have to pause or stop the current call first !")); return NULL; } if(!linphone_core_can_we_add_call(lc)){ - lc->vtable.display_warning(lc,_("Sorry, we have reached the maximum number of simultaneous calls")); + if (lc->vtable.display_warning) + lc->vtable.display_warning(lc,_("Sorry, we have reached the maximum number of simultaneous calls")); return NULL; } linphone_core_get_default_proxy(lc,&proxy); @@ -2013,10 +2015,12 @@ LinphoneCall * linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddr if(linphone_core_add_call(lc,call)!= 0) { - ms_warning("we had a problem in adding the call into the invite ... weird\n"); + ms_warning("we had a problem in adding the call into the invite ... weird"); linphone_call_unref(call); return NULL; } + /* this call becomes now the current one*/ + lc->current_call=call; if (dest_proxy!=NULL || lc->sip_conf.ping_with_options==FALSE){ err=linphone_core_start_invite(lc,call,dest_proxy); }else{ @@ -2089,12 +2093,17 @@ int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *call) if (call==NULL){ //if just one call is present answer the only one ... - if(ms_list_size(linphone_core_get_calls(lc)) != 1) + if(linphone_core_get_calls_nb (lc) != 1) return -1; else - call = linphone_core_get_calls(lc)->data; + call = (LinphoneCall*)linphone_core_get_calls(lc)->data; } + if (lc->current_call){ + ms_warning("Cannot accept this call, there is already one running."); + return -1; + } + if (call->state==LinphoneCallConnected){ /*call already accepted*/ return -1; @@ -2119,10 +2128,6 @@ int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *call) ms_message("ring stopped"); lc->ringstream=NULL; } - if(linphone_core_set_as_current_call(lc,call)!=0) - { - ms_message("another call is already in process\n"); - } linphone_core_get_default_proxy(lc,&cfg); /*try to be best-effort in giving real local or routable contact address*/ @@ -2135,6 +2140,7 @@ int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *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){ @@ -2214,13 +2220,17 @@ int linphone_core_terminate_all_calls(LinphoneCore *lc){ } /** - * Returns the calls MSList + * Returns the current list of calls. + * + * Note that this list is read-only and might be changed by the core after a function call to linphone_core_iterate(). + * Similarly the LinphoneCall objects inside it might be destroyed without prior notice. + * To hold references to LinphoneCall object into your program, you must use linphone_call_ref(). * * @ingroup call_control **/ -MSList *linphone_core_get_calls(LinphoneCore *lc) +const MSList *linphone_core_get_calls(LinphoneCore *lc) { - return ms_list_copy(lc->calls); + return lc->calls; } /** @@ -2250,23 +2260,7 @@ LinphoneCall *linphone_core_get_current_call(const LinphoneCore *lc) int linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *the_call) { LinphoneCall *call = the_call; - if(lc == NULL) - { - ms_error("LinphoneCore was null\n"); - return -1; - } - if(call == NULL) - { - if(linphone_core_in_call(lc)) - { - call = linphone_core_get_current_call(lc); - } - else - { - ms_error("LinphoneCall was null"); - return -1; - } - } + if(linphone_core_get_current_call(lc) != call) { ms_error("The call asked to be paused was not the current on"); @@ -2280,6 +2274,7 @@ int linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *the_call) linphone_call_set_state(call,LinphoneCallPausing,"Pausing call"); if (lc->vtable.display_status) lc->vtable.display_status(lc,_("Pausing the current call...")); + lc->current_call=NULL; return 0; } @@ -2292,46 +2287,24 @@ int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *the_call) { char temp[255]={0}; LinphoneCall *call = the_call; - if(lc == NULL) - { - ms_error("LinphoneCore was null\n"); - return -1; - } - if(call == NULL) - { - MSList *calls = linphone_core_get_calls(lc); - if(ms_list_size(calls) == 1) - { - call = ((LinphoneCall *)calls->data); - ms_list_free(calls); - } - else - { - ms_error("LinphoneCall was null\n"); - ms_list_free(calls); - return -2; - } - } - if(call->state!=LinphoneCallPaused ) - { + + if(call->state!=LinphoneCallPaused ){ ms_warning("we cannot resume a call when the communication is not established"); return -1; } - if(linphone_core_get_current_call(lc) != NULL) - { - ms_error("There is already a call in process pause or stop it first\n"); + if(linphone_core_get_current_call(lc) != NULL){ + if (lc->vtable.display_warning) + lc->vtable.display_warning(lc,_("There is already a call in process, pause or stop it first.")); return -1; } - if(sal_call_hold(call->op,FALSE) != 0) - { - lc->vtable.display_warning(lc,_("Could not resume the call")); + if(sal_call_hold(call->op,FALSE) != 0){ + return -1; } linphone_call_set_state (call,LinphoneCallResuming,"Resuming"); - linphone_core_set_as_current_call(lc,call); snprintf(temp,sizeof(temp)-1,"Resuming the call with %s",linphone_call_get_remote_address_as_string(call)); if (lc->vtable.display_status) lc->vtable.display_status(lc,temp); - + lc->current_call=call; return 0; } @@ -3145,7 +3118,7 @@ int linphone_core_set_static_picture(LinphoneCore *lc, const char *path) { unsigned long linphone_core_get_native_video_window_id(const LinphoneCore *lc){ #ifdef VIDEO_ENABLED LinphoneCall *call=linphone_core_get_current_call (lc); - if (call->videostream) + if (call && call->videostream) return video_stream_get_native_window_id(call->videostream); if (lc->previewstream) return video_stream_get_native_window_id(lc->previewstream); @@ -3617,18 +3590,8 @@ void linphone_core_destroy(LinphoneCore *lc){ * * @ingroup call_control **/ -int linphone_core_get_calls_nb(const LinphoneCore *lc) -{ - int returned; - if(lc->calls == NULL) - { - returned = 0; - } - else - { - returned = ms_list_size(lc->calls); - } - return returned; +int linphone_core_get_calls_nb(const LinphoneCore *lc){ + return ms_list_size(lc->calls);; } /** @@ -3644,44 +3607,12 @@ bool_t linphone_core_can_we_add_call(LinphoneCore *lc) return FALSE; } -/** - * Unset the current call - * - * @ingroup call_control -**/ -int linphone_core_unset_the_current_call(LinphoneCore *lc) -{ - if(lc->current_call == NULL) - return -1; - lc->current_call = NULL; - ms_message("Current call unset\n"); - return 0; -} - -/** - * Set the call in parameter as the new current call - * - * @ingroup call_control -**/ -int linphone_core_set_as_current_call(LinphoneCore *lc, LinphoneCall *call) -{ - if(lc->current_call != NULL) - return -1; - lc->current_call = call; - return 0; -} - int linphone_core_add_call( LinphoneCore *lc, LinphoneCall *call) { if(linphone_core_can_we_add_call(lc)) { - MSList *the_calls = lc->calls; - if (the_calls==NULL){ - lc->current_call=call; - } - the_calls = ms_list_append(the_calls,call); - lc->calls = the_calls; + lc->calls = ms_list_append(lc->calls,call); return 0; } return -1; @@ -3690,12 +3621,8 @@ int linphone_core_add_call( LinphoneCore *lc, LinphoneCall *call) int linphone_core_del_call( LinphoneCore *lc, LinphoneCall *call) { MSList *it; - MSList *the_calls = lc->calls; - if(call == linphone_core_get_current_call(lc)) - { - linphone_core_unset_the_current_call(lc); - } + it=ms_list_find(the_calls,call); if (it) { diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 774dcc817..a1ed9d317 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -167,9 +167,11 @@ bool_t linphone_call_asked_to_autoanswer(LinphoneCall *call); const LinphoneAddress * linphone_core_get_current_call_remote_address(struct _LinphoneCore *lc); const LinphoneAddress * linphone_call_get_remote_address(const LinphoneCall *call); char *linphone_call_get_remote_address_as_string(const LinphoneCall *call); +LinphoneCallDir linphone_call_get_dir(const LinphoneCall *call); void linphone_call_ref(LinphoneCall *call); void linphone_call_unref(LinphoneCall *call); LinphoneCallLog *linphone_call_get_call_log(const LinphoneCall *call); +const char *linphone_call_get_refer_to(const LinphoneCall *call); void *linphone_call_get_user_pointer(LinphoneCall *call); void linphone_call_set_user_pointer(LinphoneCall *call, void *user_pointer); @@ -364,7 +366,7 @@ void * linphone_chat_room_get_user_data(LinphoneChatRoom *cr); typedef enum _LinphoneCallState{ LinphoneCallIdle, - LinphoneCallIncomingProgress, + LinphoneCallIncomingReceived, LinphoneCallOutgoingInit, LinphoneCallOutgoingProgress, LinphoneCallOutgoingRinging, @@ -431,7 +433,7 @@ typedef void (*TextMessageReceived)(struct _LinphoneCore *lc, LinphoneChatRoom * /** Callback prototype */ typedef void (*DtmfReceived)(struct _LinphoneCore* lc, LinphoneCall *call, int dtmf); /** Callback prototype */ -typedef void (*ReferReceived)(struct _LinphoneCore *lc, LinphoneCall *call, const char *refer_to); +typedef void (*ReferReceived)(struct _LinphoneCore *lc, const char *refer_to); /** Callback prototype */ typedef void (*BuddyInfoUpdated)(struct _LinphoneCore *lc, LinphoneFriend *lf); @@ -449,7 +451,7 @@ typedef struct _LinphoneVTable{ CallLogUpdated call_log_updated; /**< Notifies that call log list has been updated */ TextMessageReceived text_received; /**< A text message has been received */ DtmfReceived dtmf_received; /**< A dtmf has been received received */ - ReferReceived refer_received; /**< A refer was received */ + ReferReceived refer_received; /**< An out of call refer was received */ BuddyInfoUpdated buddy_info_updated; /**< a LinphoneFriend's BuddyInfo has changed*/ NotifyReceivedCb notify_recv; /**< Other notifications*/ DisplayStatusCb display_status; /**< Callback that notifies various events with human readable text.*/ @@ -813,10 +815,12 @@ void linphone_core_set_audio_transports(LinphoneCore *lc, RtpTransport *rtp, Rtp int linphone_core_get_current_call_stats(LinphoneCore *lc, rtp_stats_t *local, rtp_stats_t *remote); +const MSList *linphone_core_get_calls(LinphoneCore *lc); + #ifdef __cplusplus } #endif -MSList *linphone_core_get_calls(LinphoneCore *lc); + #endif diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index d69a22ddd..efd44552d 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -85,6 +85,8 @@ static void initiate_outgoing(const SalStreamDescription *local_offer, result->payloads=match_payloads(local_offer->payloads,remote_answer->payloads); result->proto=local_offer->proto; result->type=local_offer->type; + result->dir=local_offer->dir; + if (result->payloads && !only_telephone_event(result->payloads)){ strcpy(result->addr,remote_answer->addr); result->port=remote_answer->port; @@ -102,6 +104,13 @@ static void initiate_incoming(const SalStreamDescription *local_cap, result->payloads=match_payloads(local_cap->payloads,remote_offer->payloads); result->proto=local_cap->proto; result->type=local_cap->type; + if (remote_offer->dir==SalStreamSendOnly) + result->dir=SalStreamRecvOnly; + else if (remote_offer->dir==SalStreamRecvOnly){ + result->dir=SalStreamSendOnly; + }else if (remote_offer->dir==SalStreamInactive){ + result->dir=SalStreamInactive; + }else result->dir=SalStreamSendRecv; if (result->payloads && !only_telephone_event(result->payloads)){ strcpy(result->addr,local_cap->addr); result->port=local_cap->port; diff --git a/coreapi/private.h b/coreapi/private.h index 28caaaf9d..e5d0e9055 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -75,6 +75,7 @@ struct _LinphoneCall int video_port; struct _AudioStream *audiostream; /**/ struct _VideoStream *videostream; + char *refer_to; bool_t media_pending; bool_t audio_muted; }; diff --git a/gtk-glade/friendlist.c b/gtk-glade/friendlist.c index d4fddf871..3805057c3 100644 --- a/gtk-glade/friendlist.c +++ b/gtk-glade/friendlist.c @@ -39,18 +39,18 @@ typedef struct _status_picture_tab_t{ } status_picture_tab_t; status_picture_tab_t status_picture_tab[]={ - { LINPHONE_STATUS_ONLINE, "status-green.png" }, - { LINPHONE_STATUS_BUSY, "status-orange.png" }, - { LINPHONE_STATUS_BERIGHTBACK, "status-orange.png" }, - { LINPHONE_STATUS_AWAY, "status-orange.png" }, - { LINPHONE_STATUS_ONTHEPHONE, "status-orange.png" }, - { LINPHONE_STATUS_OUTTOLUNCH, "status-orange.png" }, - { LINPHONE_STATUS_NOT_DISTURB, "status-red.png" }, - { LINPHONE_STATUS_MOVED, "status-orange.png" }, - { LINPHONE_STATUS_ALT_SERVICE, "status-orange.png" }, - { LINPHONE_STATUS_OFFLINE, "status-offline.png" }, - { LINPHONE_STATUS_PENDING, "status-offline.png" }, - { LINPHONE_STATUS_END, NULL }, + { LinphoneStatusOnline, "status-green.png" }, + { LinphoneStatusBusy, "status-orange.png" }, + { LinphoneStatusBeRightBack, "status-orange.png" }, + { LinphoneStatusAway, "status-orange.png" }, + { LinphoneStatusOnThePhone, "status-orange.png" }, + { LinphoneStatusOutToLunch, "status-orange.png" }, + { LinphoneStatusDoNotDisturb, "status-red.png" }, + { LinphoneStatusMoved, "status-orange.png" }, + { LinphoneStatusAltService, "status-orange.png" }, + { LinphoneStatusOffline, "status-offline.png" }, + { LinphoneStatusPending, "status-offline.png" }, + { LinphoneStatusEnd, NULL }, }; static GdkPixbuf *create_status_picture(LinphoneOnlineStatus ss){ @@ -132,7 +132,7 @@ static GtkWidget * create_presence_menu(){ GdkPixbuf *pbuf; status_picture_tab_t *t; for(t=status_picture_tab;t->img!=NULL;++t){ - if (t->status==LINPHONE_STATUS_PENDING){ + if (t->status==LinphoneStatusPending){ continue; } menu_item=gtk_image_menu_item_new_with_label(linphone_online_status_to_string(t->status)); @@ -317,7 +317,7 @@ void linphone_gtk_show_friends(void){ continue; } } - if (!online_only || (linphone_friend_get_status(lf)!=LINPHONE_STATUS_OFFLINE)){ + if (!online_only || (linphone_friend_get_status(lf)!=LinphoneStatusOffline)){ BuddyInfo *bi; if (name==NULL || name[0]=='\0') display=uri; gtk_list_store_append(store,&iter); diff --git a/gtk-glade/incall_view.c b/gtk-glade/incall_view.c index 2874da52a..4d60d6309 100644 --- a/gtk-glade/incall_view.c +++ b/gtk-glade/incall_view.c @@ -231,22 +231,29 @@ void linphone_gtk_draw_hold_button(GtkToggleButton *button, gboolean active){ } void linphone_gtk_hold_toggled(GtkToggleButton *button){ - GtkWidget *mw=linphone_gtk_get_main_window(); gboolean active=gtk_toggle_button_get_active(button); + if(active) { - linphone_core_pause_call(linphone_gtk_get_core(),NULL); - gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"terminate_call"),FALSE); + LinphoneCall *call=linphone_core_get_current_call (linphone_gtk_get_core()); + if (call==NULL) return; + linphone_core_pause_call(linphone_gtk_get_core(),call); } else { - linphone_core_resume_call(linphone_gtk_get_core(),NULL); - gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"terminate_call"),TRUE); + const MSList *calls=linphone_core_get_calls(linphone_gtk_get_core()); + if (calls==NULL) return; + if (ms_list_size(calls)>1){ + g_warning("Simultaneously calls not yet implemented in gtk ui."); + return; + } + /*we are supposed to have only one */ + linphone_core_resume_call(linphone_gtk_get_core(),(LinphoneCall*)calls->data); } linphone_gtk_draw_hold_button(button,active); } void linphone_gtk_enable_hold_button(GtkToggleButton *button, gboolean sensitive){ gtk_widget_set_sensitive(GTK_WIDGET(button),sensitive); - linphone_gtk_hold_toggled(button); + linphone_gtk_draw_hold_button(button,FALSE); } diff --git a/gtk-glade/main.c b/gtk-glade/main.c index 56b572860..d5a1b0997 100644 --- a/gtk-glade/main.c +++ b/gtk-glade/main.c @@ -43,7 +43,6 @@ static GtkWidget *the_ui=NULL; static void linphone_gtk_show(LinphoneCore *lc); static void linphone_gtk_inv_recv(LinphoneCore *lc, LinphoneCall *call); -static void linphone_gtk_bye_recv(LinphoneCore *lc, LinphoneCall *call); static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid); static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url); static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username); @@ -52,27 +51,10 @@ static void linphone_gtk_display_message(LinphoneCore *lc, const char *msg); static void linphone_gtk_display_warning(LinphoneCore *lc, const char *warning); static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const char *url); static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl); -static void linphone_gtk_general_state(LinphoneCore *lc, LinphoneGeneralState *gstate, LinphoneGeneralStateContext gctx); -static void linphone_gtk_refer_received(LinphoneCore *lc, LinphoneCall *call, const char *refer_to); +static void linphone_gtk_refer_received(LinphoneCore *lc, const char *refer_to); +static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cs, const char *msg); static gboolean linphone_gtk_auto_answer(GtkWidget *incall_window); -static LinphoneCoreVTable vtable={ - .show=linphone_gtk_show, - .inv_recv=linphone_gtk_inv_recv, - .bye_recv=linphone_gtk_bye_recv, - .notify_presence_recv=linphone_gtk_notify_recv, - .new_unknown_subscriber=linphone_gtk_new_unknown_subscriber, - .auth_info_requested=linphone_gtk_auth_info_requested, - .display_status=linphone_gtk_display_status, - .display_message=linphone_gtk_display_message, - .display_warning=linphone_gtk_display_warning, - .display_url=linphone_gtk_display_url, - .call_log_updated=linphone_gtk_call_log_updated, - .text_received=linphone_gtk_text_received, - .general_state=linphone_gtk_general_state, - .refer_received=linphone_gtk_refer_received, - .buddy_info_updated=linphone_gtk_buddy_info_updated -}; static gboolean verbose=0; static gboolean auto_answer = 0; @@ -209,6 +191,22 @@ static const char *linphone_gtk_get_factory_config_file(){ static void linphone_gtk_init_liblinphone(const char *config_file, const char *factory_config_file) { + LinphoneCoreVTable vtable={0}; + + vtable.call_state_changed=linphone_gtk_call_state_changed; + vtable.show=linphone_gtk_show; + vtable.notify_presence_recv=linphone_gtk_notify_recv; + vtable.new_unknown_subscriber=linphone_gtk_new_unknown_subscriber; + vtable.auth_info_requested=linphone_gtk_auth_info_requested; + vtable.display_status=linphone_gtk_display_status; + vtable.display_message=linphone_gtk_display_message; + vtable.display_warning=linphone_gtk_display_warning; + vtable.display_url=linphone_gtk_display_url; + vtable.call_log_updated=linphone_gtk_call_log_updated; + vtable.text_received=linphone_gtk_text_received; + vtable.refer_received=linphone_gtk_refer_received; + vtable.buddy_info_updated=linphone_gtk_buddy_info_updated; + linphone_core_set_user_agent("Linphone", LINPHONE_VERSION); the_core=linphone_core_new(&vtable,config_file,factory_config_file,NULL); linphone_core_set_waiting_callback(the_core,linphone_gtk_wait,NULL); @@ -641,7 +639,9 @@ void linphone_gtk_uri_bar_activate(GtkWidget *w){ void linphone_gtk_terminate_call(GtkWidget *button){ - linphone_core_terminate_call(linphone_gtk_get_core(),NULL); + const MSList *elem=linphone_core_get_calls(linphone_gtk_get_core()); + if (elem==NULL) return; + linphone_core_terminate_call(linphone_gtk_get_core(),(LinphoneCall*)elem->data); } void linphone_gtk_decline_call(GtkWidget *button){ @@ -729,10 +729,6 @@ static void linphone_gtk_inv_recv(LinphoneCore *lc, LinphoneCall *call){ ms_free(from); } -static void linphone_gtk_bye_recv(LinphoneCore *lc, LinphoneCall *call){ - -} - static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid){ linphone_gtk_show_friends(); } @@ -873,22 +869,24 @@ static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl) if (w) linphone_gtk_call_log_update(w); } -static void linphone_gtk_general_state(LinphoneCore *lc, LinphoneGeneralState *gstate, LinphoneGeneralStateContext gctx){ - switch(gstate->new_state){ - case GSTATE_CALL_OUT_CONNECTED: - case GSTATE_CALL_IN_CONNECTED: +static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cs, const char *msg){ + switch(cs){ + case LinphoneCallConnected: if (linphone_gtk_use_in_call_view()) linphone_gtk_in_call_view_set_in_call(); linphone_gtk_enable_mute_button( GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"main_mute")), TRUE); break; - case GSTATE_CALL_ERROR: - linphone_gtk_call_terminated(gstate->message); + case LinphoneCallError: + linphone_gtk_call_terminated(msg); break; - case GSTATE_CALL_END: + case LinphoneCallEnd: linphone_gtk_call_terminated(NULL); break; + case LinphoneCallIncomingReceived: + linphone_gtk_inv_recv (lc,call); + break; default: break; } @@ -1204,7 +1202,7 @@ void linphone_gtk_log_handler(OrtpLogLevel lev, const char *fmt, va_list args){ } -static void linphone_gtk_refer_received(LinphoneCore *lc, LinphoneCall *call, const char *refer_to){ +static void linphone_gtk_refer_received(LinphoneCore *lc, const char *refer_to){ GtkEntry * uri_bar =GTK_ENTRY(linphone_gtk_get_widget( linphone_gtk_get_main_window(), "uribar")); linphone_gtk_show_main_window(); diff --git a/gtk-glade/propertybox.c b/gtk-glade/propertybox.c index bab3e3af6..be4073fb9 100644 --- a/gtk-glade/propertybox.c +++ b/gtk-glade/propertybox.c @@ -119,17 +119,17 @@ void linphone_gtk_video_port_changed(GtkWidget *w){ void linphone_gtk_no_firewall_toggled(GtkWidget *w){ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) - linphone_core_set_firewall_policy(linphone_gtk_get_core(),LINPHONE_POLICY_NO_FIREWALL); + linphone_core_set_firewall_policy(linphone_gtk_get_core(),LinphonePolicyNoFirewall); } void linphone_gtk_use_nat_address_toggled(GtkWidget *w){ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) - linphone_core_set_firewall_policy(linphone_gtk_get_core(),LINPHONE_POLICY_USE_NAT_ADDRESS); + linphone_core_set_firewall_policy(linphone_gtk_get_core(),LinphonePolicyUseNatAddress); } void linphone_gtk_use_stun_toggled(GtkWidget *w){ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) - linphone_core_set_firewall_policy(linphone_gtk_get_core(),LINPHONE_POLICY_USE_STUN); + linphone_core_set_firewall_policy(linphone_gtk_get_core(),LinphonePolicyUseStun); } void linphone_gtk_mtu_changed(GtkWidget *w){ @@ -762,13 +762,13 @@ void linphone_gtk_show_parameters(void){ if (tmp) gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(pb,"stun_server")),tmp); pol=linphone_core_get_firewall_policy(lc); switch(pol){ - case LINPHONE_POLICY_NO_FIREWALL: + case LinphonePolicyNoFirewall: gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"no_nat")),TRUE); break; - case LINPHONE_POLICY_USE_NAT_ADDRESS: + case LinphonePolicyUseNatAddress: gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"use_nat_address")),TRUE); break; - case LINPHONE_POLICY_USE_STUN: + case LinphonePolicyUseStun: gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"use_stun")),TRUE); break; } diff --git a/mediastreamer2 b/mediastreamer2 index 04be0f4c3..236222b3f 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 04be0f4c3eac2d30828963b3617497bb9337e3bc +Subproject commit 236222b3f08baf502742b6c75633f50e3a14917f From 0ec655d063160fed946505b27048e5cd998b7fda Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 17 Aug 2010 15:42:16 +0200 Subject: [PATCH 35/45] fix compilation bug with video disabled --- coreapi/linphonecore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 0c5420d66..7e8572461 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3018,9 +3018,9 @@ bool_t linphone_core_video_preview_enabled(const LinphoneCore *lc){ * This function works at any time, including during calls. **/ void linphone_core_enable_self_view(LinphoneCore *lc, bool_t val){ +#ifdef VIDEO_ENABLED LinphoneCall *call=linphone_core_get_current_call (lc); lc->video_conf.selfview=val; -#ifdef VIDEO_ENABLED if (call && call->videostream){ video_stream_enable_self_view(call->videostream,val); } From c18cff36d523be5745a5e3e225e9162a7a1ff050 Mon Sep 17 00:00:00 2001 From: smorlat Date: Tue, 17 Aug 2010 15:46:39 +0200 Subject: [PATCH 36/45] fix compilation problems without video --- coreapi/callbacks.c | 2 +- coreapi/linphonecall.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 597aeb0c8..5def5557f 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -438,8 +438,8 @@ static void register_failure(SalOp *op, SalError error, SalReason reason, const } static void vfu_request(SalOp *op){ - LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer (op); #ifdef VIDEO_ENABLED + LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer (op); if (call==NULL){ ms_warning("VFU request but no call !"); return ; diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 17df0e52a..fbb4f0212 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -395,7 +395,7 @@ void linphone_call_init_media_streams(LinphoneCall *call){ #endif } #else - lc->videostream=NULL; + call->videostream=NULL; #endif } From 7a02fb5ab108913bd2d19224b71c4c74601e7f8c Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 17 Aug 2010 16:16:58 +0200 Subject: [PATCH 37/45] fix bugs --- coreapi/callbacks.c | 13 +++++++++---- coreapi/linphonecore.c | 1 + oRTP | 2 +- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 5def5557f..b1ef86656 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -189,6 +189,11 @@ static void call_accepted(SalOp *op){ sal_media_description_ref(call->resultdesc); call->media_pending=FALSE; } + 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)){ /*we initiated a pause*/ @@ -200,14 +205,14 @@ static void call_accepted(SalOp *op){ ms_free(msg); } linphone_call_set_state(call,LinphoneCallPaused,"Call paused"); - linphone_call_start_media_streams (call); }else{ - linphone_connect_incoming(lc,call); - } + linphone_call_set_state(call,LinphoneCallStreamsRunning,"Connected (streams running)"); + } + linphone_call_start_media_streams (call); }else{ /*send a bye*/ ms_error("Incompatible SDP offer received in 200Ok, need to abort the call"); - linphone_core_terminate_call(lc,NULL); + linphone_core_abort_call(lc,call,"No codec intersection"); } } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 7e8572461..6cf8725f3 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2145,6 +2145,7 @@ int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *call) call->resultdesc=sal_call_get_final_media_description(call->op); if (call->resultdesc){ linphone_call_start_media_streams(call); + linphone_call_set_state(call,LinphoneCallStreamsRunning,"Connected (streams running)"); sal_media_description_ref(call->resultdesc); }else call->media_pending=TRUE; ms_message("call answered."); diff --git a/oRTP b/oRTP index 534074027..a08462074 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 534074027a2163694ce6f8a520f0d6f6ac82b15d +Subproject commit a084620745b1b1c81ec93501ffbb3de373f7c8c9 From 6129ecf51bc65180b05d39b2200be8dc787a9cb0 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 17 Aug 2010 16:23:33 +0200 Subject: [PATCH 38/45] bugfix --- coreapi/callbacks.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index b1ef86656..aa8bf3f30 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -26,18 +26,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. static void linphone_connect_incoming(LinphoneCore *lc, LinphoneCall *call){ - if (lc->vtable.show) - lc->vtable.show(lc); - if (lc->vtable.display_status) - lc->vtable.display_status(lc,_("Connected.")); - linphone_call_set_state(call,LinphoneCallConnected,"Connected"); if (lc->ringstream!=NULL){ ring_stop(lc->ringstream); lc->ringstream=NULL; } - linphone_call_start_media_streams(call); - linphone_call_set_state (call,LinphoneCallStreamsRunning,"Connected (streams running)"); } static void call_received(SalOp *h){ @@ -208,7 +201,7 @@ static void call_accepted(SalOp *op){ }else{ linphone_call_set_state(call,LinphoneCallStreamsRunning,"Connected (streams running)"); } - linphone_call_start_media_streams (call); + linphone_connect_incoming (lc,call); }else{ /*send a bye*/ ms_error("Incompatible SDP offer received in 200Ok, need to abort the call"); @@ -236,6 +229,7 @@ static void call_ack(SalOp *op){ sal_media_description_ref(call->resultdesc); if (call->resultdesc && !sal_media_description_empty(call->resultdesc)){ linphone_connect_incoming(lc,call); + linphone_call_set_state (call,LinphoneCallStreamsRunning,"Connected (streams running)"); }else{ /*send a bye*/ ms_error("Incompatible SDP response received in ACK, need to abort the call"); @@ -273,7 +267,7 @@ static void call_updated(SalOp *op){ linphone_call_stop_media_streams (call); linphone_call_init_media_streams (call); - linphone_connect_incoming(lc,call); + linphone_call_start_media_streams (call); } } From 9d37f3591a1f2691dc94d24adf53096ec0beea90 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 18 Aug 2010 11:24:38 +0200 Subject: [PATCH 39/45] fix illegal characters in presence xml --- coreapi/sal_eXosip2_presence.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/coreapi/sal_eXosip2_presence.c b/coreapi/sal_eXosip2_presence.c index 9be8a698f..a38fdf91b 100644 --- a/coreapi/sal_eXosip2_presence.c +++ b/coreapi/sal_eXosip2_presence.c @@ -176,9 +176,9 @@ static void add_presence_body(osip_message_t *notify, SalPresenceStatus online_s #endif char *contact_info; - osip_contact_t *ct=NULL; - osip_message_get_contact(notify,0,&ct); - osip_contact_to_str(ct,&contact_info); + osip_from_t *from=NULL; + from=osip_message_get_from(notify); + osip_uri_to_str(from->url,&contact_info); #ifdef SUPPORT_MSN From d32da0079d0faaff34ffc4b641daed3152573e59 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 20 Aug 2010 16:33:11 +0200 Subject: [PATCH 40/45] many bugfixes and improvements for multicall --- console/commands.c | 289 +++++++++++++++++++++++------------------ console/linphonec.c | 51 ++++++-- console/linphonec.h | 2 + coreapi/callbacks.c | 45 ++++++- coreapi/linphonecall.c | 35 ++++- coreapi/linphonecore.c | 60 ++++++--- coreapi/linphonecore.h | 5 +- coreapi/private.h | 3 +- coreapi/sal.h | 5 +- coreapi/sal_eXosip2.c | 38 +++--- mediastreamer2 | 2 +- oRTP | 2 +- po/POTFILES.in | 2 + 13 files changed, 332 insertions(+), 207 deletions(-) diff --git a/console/commands.c b/console/commands.c index 2f07bbdad..c3e1e472f 100644 --- a/console/commands.c +++ b/console/commands.c @@ -56,13 +56,14 @@ extern char *lpc_strip_blanks(char *input); static int lpc_cmd_help(LinphoneCore *, char *); static int lpc_cmd_proxy(LinphoneCore *, char *); static int lpc_cmd_call(LinphoneCore *, char *); +static int lpc_cmd_calls(LinphoneCore *, char *); static int lpc_cmd_chat(LinphoneCore *, char *); static int lpc_cmd_answer(LinphoneCore *, char *); static int lpc_cmd_autoanswer(LinphoneCore *, char *); static int lpc_cmd_terminate(LinphoneCore *, char *); static int lpc_cmd_call_logs(LinphoneCore *, char *); static int lpc_cmd_ipv6(LinphoneCore *, char *); -static int lpc_cmd_refer(LinphoneCore *, char *); +static int lpc_cmd_transfer(LinphoneCore *, char *); static int lpc_cmd_quit(LinphoneCore *, char *); static int lpc_cmd_nat(LinphoneCore *, char *); static int lpc_cmd_stun(LinphoneCore *, char *); @@ -131,7 +132,10 @@ LPC_COMMAND commands[] = { { "help", lpc_cmd_help, "Print commands help", NULL }, { "call", lpc_cmd_call, "Call a SIP uri", "'call ' \t: initiate a call to the specified destination.\n" - "'call show' \t: show all the current calls status.\n" + "'call show' \t: show all the current calls with their id and status.\n" + }, + { "calls", lpc_cmd_calls, "Show all the current calls with their id and status.\n", + NULL }, { "chat", lpc_cmd_chat, "Chat with a SIP uri", "'chat \"message\"' " @@ -139,12 +143,12 @@ LPC_COMMAND commands[] = { }, { "terminate", lpc_cmd_terminate, "Terminate a call", "'terminate' : Terminate the current call\n" - "'terminate ' : Terminate the call with remote address\n" + "'terminate ' : Terminate the call with supplied id\n" "'terminate ' : Terminate all the current calls\n" }, { "answer", lpc_cmd_answer, "Answer a call", "'answer' : Answer the current incoming call\n" - "'answer ' : Answer the call with remote address\n" + "'answer ' : Answer the call with given id\n" }, { "autoanswer", lpc_cmd_autoanswer, "Show/set auto-answer mode", "'autoanswer' \t: show current autoanswer mode\n" @@ -177,10 +181,10 @@ LPC_COMMAND commands[] = { "'ipv6 enable' : enable the use of the ipv6 network.\n" "'ipv6 disable' : do not use ipv6 network." }, - { "refer", lpc_cmd_refer, - "Refer the current call to the specified destination.", - "'refer ' or 'r ' " - ": refer the current call to the specified destination." + { "transfer", lpc_cmd_transfer, + "Transfer a call to a specified destination.", + "'transfer ' : transfers the current active call to the destination sip-uri" + "'transfer ': transfers the call with 'id' to the destination sip-uri" }, { "nat", lpc_cmd_nat, "Set nat address", "'nat' : show nat settings.\n" @@ -245,7 +249,7 @@ LPC_COMMAND commands[] = { "'pause' : pause the current call\n"}, { "resume", lpc_cmd_resume, "resume a call", "'resume' : resume the unique call\n" - "'resume ' : hold off the call with cid \n"}, + "'resume ' : hold off the call with given id\n"}, { "mute", lpc_cmd_mute_mic, "Mute microphone and suspend voice transmission."}, { "unmute", lpc_cmd_unmute_mic, @@ -398,6 +402,35 @@ lpc_cmd_help(LinphoneCore *lc, char *arg) static char callee_name[256]={0}; static char caller_name[256]={0}; +static const char *get_call_status(LinphoneCall *call){ + switch(linphone_call_get_state(call)){ + case LinphoneCallPaused: + if (linphone_call_get_refer_to (call)!=NULL){ + return "Paused (transfered)"; + }else{ + return "Paused"; + } + break; + case LinphoneCallIncomingReceived: + return "Pending"; + break; + case LinphoneCallOutgoingInit: + case LinphoneCallOutgoingProgress: + return "Dialing out"; + break; + case LinphoneCallOutgoingEarlyMedia: + case LinphoneCallOutgoingRinging: + return "Remote ringing"; + break; + default: + if (linphone_call_has_transfer_pending(call)){ + return "Running (transfer pending)"; + }else + return "Running"; + } + return ""; +} + static int lpc_cmd_call(LinphoneCore *lc, char *args) { @@ -405,36 +438,14 @@ lpc_cmd_call(LinphoneCore *lc, char *args) { return 0; } - if(!strcmp(args,"show")) - { - const MSList *calls = linphone_core_get_calls(lc); - if(calls) - { - const MSList *p_calls = calls; - linphonec_out("\t\t\t\t\r\n"); - while(p_calls != NULL) - { - char *tmp=linphone_call_get_remote_address_as_string(p_calls->data); - linphonec_out("%s\t\t\t%s\r\n", - tmp, - (((LinphoneCall *)p_calls->data)==linphone_core_get_current_call(lc))?"yes":"no"); - p_calls = p_calls->next; - ms_free(tmp); - } - } - else - { - linphonec_out("No active call.\n"); - } - } - else { + LinphoneCall *call; if ( linphone_core_in_call(lc) ) { linphonec_out("Terminate or hold on the current call first.\n"); return 1; } - if ( NULL == linphone_core_invite(lc, args) ) + if ( NULL == (call=linphone_core_invite(lc, args)) ) { linphonec_out("Error from linphone_core_invite.\n"); } @@ -446,6 +457,32 @@ lpc_cmd_call(LinphoneCore *lc, char *args) return 1; } +static int +lpc_cmd_calls(LinphoneCore *lc, char *args){ + const MSList *calls = linphone_core_get_calls(lc); + if(calls) + { + const MSList *p_calls = calls; + linphonec_out("ID\t\tDestination\t\t\t\tStatus\n---------------------------------------------------------------------\n"); + while(p_calls != NULL) + { + LinphoneCall *call=(LinphoneCall*)p_calls->data; + char *tmp=linphone_call_get_remote_address_as_string(call); + linphonec_out("%li\t%s\t\t\t%s\r\n", + (long)linphone_call_get_user_pointer (call), + tmp, + get_call_status(call)); + p_calls = p_calls->next; + ms_free(tmp); + } + }else + { + linphonec_out("No active call.\n"); + } + return 1; +} + + static int lpc_cmd_chat(LinphoneCore *lc, char *args) { @@ -488,12 +525,34 @@ void linphonec_set_caller(const char *caller){ } static int -lpc_cmd_refer(LinphoneCore *lc, char *args) +lpc_cmd_transfer(LinphoneCore *lc, char *args) { - if (args) - linphone_core_refer(lc, linphone_core_get_current_call(lc), args); - else{ - linphonec_out("refer needs an argument\n"); + if (args){ + LinphoneCall *call; + const char *refer_to=NULL; + char arg1[256]={0}; + char arg2[266]={0}; + int n=sscanf(args,"%s %s",arg1,arg2); + if (n==1 || isalpha(*arg1)){ + call=linphone_core_get_current_call(lc); + if (call==NULL && linphone_core_get_calls_nb (lc)==1){ + call=(LinphoneCall*)linphone_core_get_calls(lc)->data; + } + refer_to=args; + if (call==NULL){ + linphonec_out("No active call, please specify a call id among the ones listed by 'calls' command.\n"); + return 0; + } + }else{ + long id=atoi(arg1); + refer_to=args+strlen(arg1)+1; + call=linphonec_get_call(id); + if (call==NULL) return 0; + } + linphone_core_transfer_call(lc, call, refer_to); + }else{ + linphonec_out("Transfer command requires at least one argument\n"); + return 0; } return 1; } @@ -501,96 +560,64 @@ lpc_cmd_refer(LinphoneCore *lc, char *args) static int lpc_cmd_terminate(LinphoneCore *lc, char *args) { - char *arg1 = args; - char *arg2 = NULL; - char *ptr = args; - + if (linphone_core_get_calls(lc)==NULL){ + linphonec_out("No active calls"); + return 1; + } if (!args) { - if(linphone_core_in_call(lc)) - { - if ( -1 == linphone_core_terminate_call(lc, linphone_core_get_current_call(lc)) ) - { - linphonec_out("Could not stop the active call.\n"); - } - } - else - { - linphonec_out("No active call.\n"); + if ( -1 == linphone_core_terminate_call(lc, NULL) ){ + linphonec_out("Could not stop the active call.\n"); } return 1; } - /* Isolate first and second arg */ - while(*ptr && !isspace(*ptr)) ++ptr; - if ( *ptr ) - { - *ptr='\0'; - arg2=ptr+1; - while(*arg2 && isspace(*arg2)) ++arg2; - } - if (arg1 != 0) - { - if(strcmp(arg1,"all")==0) - { - linphonec_out("We are going to stop all the calls.\n"); - return (linphone_core_terminate_all_calls(lc)==0)?1:0; - } - else - { - char the_remote_address[255]; - int n = sscanf(arg1, "%s", the_remote_address); - if (n == 1) - { - if ( -1 == linphone_core_terminate_call(lc,linphone_core_get_call_by_remote_address(lc,the_remote_address))) - { - linphonec_out("Cannot stop the call with %s.\n",the_remote_address); - } - return 1; + if(strcmp(args,"all")==0){ + linphonec_out("We are going to stop all the calls.\n"); + linphone_core_terminate_all_calls(lc); + return 1; + }else{ + /*the argument is a linphonec call id */ + long id=atoi(args); + LinphoneCall *call=linphonec_get_call(id); + if (call){ + if (linphone_core_terminate_call(lc,call)==-1){ + linphonec_out("Could not stop the call with id %li",id); } - } + }else return 0; + return 1; } return 0; } static int -lpc_cmd_answer(LinphoneCore *lc, char *args) -{ - char *arg1 = args; - char *arg2 = NULL; - char *ptr = args; - +lpc_cmd_answer(LinphoneCore *lc, char *args){ if (!args) { - //if just one call is present answer the only one in passing NULL to the linphone_core_accept_call ... - if ( -1 == linphone_core_accept_call(lc, NULL) ) - { - linphonec_out("No incoming call.\n"); + int nb=ms_list_size(linphone_core_get_calls(lc)); + if (nb==1){ + //if just one call is present answer the only one in passing NULL to the linphone_core_accept_call ... + if ( -1 == linphone_core_accept_call(lc, NULL) ) + { + linphonec_out("Fail to accept incoming call\n"); + } + }else if (nb==0){ + linphonec_out("There are no calls to answer.\n"); + }else{ + linphonec_out("Multiple calls in progress, please specify call id.\n"); + return 0; } return 1; - } - - // Isolate first and second arg - while(*ptr && !isspace(*ptr)) ++ptr; - if ( *ptr ) - { - *ptr='\0'; - arg2=ptr+1; - while(*arg2 && isspace(*arg2)) ++arg2; - } - if (arg1 != 0) - { - char the_remote_address[256]; - int n = sscanf(arg1, "%s", the_remote_address); - if (n == 1) - { - if ( -1 == linphone_core_accept_call(lc, linphone_core_get_call_by_remote_address(lc,the_remote_address)) ) - { - linphonec_out("Cannot answer the call from %s.\n",the_remote_address); + }else{ + long id; + if (sscanf(args,"%li",&id)==1){ + LinphoneCall *call=linphonec_get_call (id); + if (linphone_core_accept_call (lc,call)==-1){ + linphonec_out("Fail to accept call %i\n",id); } - return 1; - } + }else return 0; + return 1; } return 0; } @@ -1209,40 +1236,42 @@ static int lpc_cmd_resume(LinphoneCore *lc, char *args){ if(linphone_core_in_call(lc)) { linphonec_out("There is already a call in process pause or stop it first"); + return 1; } if (args) { - char the_remote_address[255]; - int n = sscanf(args, "%s", the_remote_address); - if (n == 1) - { - if(linphone_core_resume_call(lc,linphone_core_get_call_by_remote_address(lc,the_remote_address)) < 0) - { - linphonec_out("There was a problem to resume the call check the remote address you gave %s\n",args); - return 0; - } - else + long id; + int n = sscanf(args, "%li", &id); + if (n == 1){ + LinphoneCall *call=linphonec_get_call (id); + if (call){ + if(linphone_core_resume_call(lc,call)==-1) + { + linphonec_out("There was a problem to resume the call check the remote address you gave %s\n",args); + return 1; + } + }else { return 1; } - } + }else return 0; } else { - int returned = 0; const MSList *calls = linphone_core_get_calls(lc); - if(ms_list_size(calls) == 1) + int nbcalls=ms_list_size(calls); + if( nbcalls == 1) { if(linphone_core_resume_call(lc,calls->data) < 0) { - linphonec_out("There was a problem to resume the unique call \n"); - returned = 0; + linphonec_out("There was a problem to resume the unique call.\n"); } - else - { - returned = 1; - } - return returned; + return 1; + }else if (nbcalls==0){ + linphonec_out("There is no calls at this time.\n"); + return 1; + }else{ + linphonec_out("There are %i calls at this time, please specify call id as given with 'calls' command.\n"); } } return 0; diff --git a/console/linphonec.c b/console/linphonec.c index c00d87632..df86abb8f 100644 --- a/console/linphonec.c +++ b/console/linphonec.c @@ -118,7 +118,7 @@ static void linphonec_display_refer (LinphoneCore * lc, const char *refer_to); static void linphonec_display_something (LinphoneCore * lc, const char *something); static void linphonec_display_url (LinphoneCore * lc, const char *something, const char *url); static void linphonec_display_warning (LinphoneCore * lc, const char *something); -static void linphonec_notify_received(LinphoneCore *lc,const char *from,const char *msg); +static void linphonec_notify_received(LinphoneCore *lc, LinphoneCall *call, const char *from,const char *event); static void linphonec_notify_presence_received(LinphoneCore *lc,LinphoneFriend *fid); static void linphonec_new_unknown_subscriber(LinphoneCore *lc, @@ -169,6 +169,24 @@ static ortp_pipe_t server_sock; #endif /*_WIN32_WCE*/ +void linphonec_call_identify(LinphoneCall* call){ + static long callid=1; + linphone_call_set_user_pointer (call,(void*)callid); + callid++; +} + +LinphoneCall *linphonec_get_call(long id){ + const MSList *elem=linphone_core_get_calls(linphonec); + for (;elem!=NULL;elem=elem->next){ + LinphoneCall *call=(LinphoneCall*)elem->data; + if (linphone_call_get_user_pointer (call)==(void*)id){ + return call; + } + } + linphonec_out("Sorry, no call with id %i exists at this time.",id); + return NULL; +} + /*************************************************************************** * * Linphone core callbacks @@ -252,13 +270,12 @@ linphonec_prompt_for_auth(LinphoneCore *lc, const char *realm, const char *usern * Linphone core callback */ static void -linphonec_notify_received(LinphoneCore *lc,const char *from,const char *msg) +linphonec_notify_received(LinphoneCore *lc, LinphoneCall *call, const char *from,const char *event) { - printf("Notify type %s from %s\n", msg, from); - if(!strcmp(msg,"refer")) + if(!strcmp(event,"refer")) { - printf("The distant SIP end point get the refer we can close the call\n"); - linphonec_parse_command_line(linphonec, "terminate"); + linphonec_out("The distand endpoint %s of call %li has been transfered, you can safely close the call.\n", + from,(long)linphone_call_get_user_pointer (call)); } } @@ -291,27 +308,34 @@ linphonec_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, static void linphonec_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState st, const char *msg){ char *from=linphone_call_get_remote_address_as_string(call); + long id=(long)linphone_call_get_user_pointer (call); switch(st){ case LinphoneCallEnd: - printf("Call with %s ended.\n", from); + linphonec_out("Call %i with %s ended.\n", id, from); break; case LinphoneCallResuming: - printf("Resuming call with %s.\n", from); + linphonec_out("Resuming call %i with %s.\n", id, from); break; case LinphoneCallStreamsRunning: - printf("Media streams established with %s.\n", from); + linphonec_out("Media streams established with %s for call %i.\n", from,id); break; case LinphoneCallPausing: - printf("Pausing call with %s.\n", from); + linphonec_out("Pausing call %i with %s.\n", id, from); break; case LinphoneCallPaused: - printf("Call with %s is now paused.\n", from); + linphonec_out("Call %i with %s is now paused.\n", id, from); break; case LinphoneCallIncomingReceived: + linphonec_call_identify(call); + id=(long)linphone_call_get_user_pointer (call); linphonec_set_caller(from); if ( auto_answer) { answer_call=TRUE; } + linphonec_out("Receiving new incoming call from %s, assigned id %i", from,id); + break; + case LinphoneCallOutgoingInit: + linphonec_call_identify(call); break; default: break; @@ -682,11 +706,10 @@ void linphonec_main_loop_exit(void){ void linphonec_finish(int exit_status) { - printf("Terminating...\n"); + linphonec_out("Terminating...\n"); /* Terminate any pending call */ - linphonec_parse_command_line(linphonec, "terminate"); - linphonec_command_finished(); + linphone_core_terminate_all_calls(linphonec); #ifdef HAVE_READLINE linphonec_finish_readline(); #endif diff --git a/console/linphonec.h b/console/linphonec.h index 90b6f6842..235aa5e97 100644 --- a/console/linphonec.h +++ b/console/linphonec.h @@ -112,6 +112,8 @@ void linphonec_set_autoanswer(bool_t enabled); bool_t linphonec_get_autoanswer(); void linphonec_command_finished(void); void linphonec_set_caller(const char *caller); +LinphoneCall *linphonec_get_call(long id); +void linphonec_call_identify(LinphoneCall* call); #endif /* def LINPHONEC_H */ diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index aa8bf3f30..6d0cd8b8f 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -95,8 +95,8 @@ static void call_received(SalOp *h){ if (lc->vtable.display_status) lc->vtable.display_status(lc,barmesg); - /* play the ring */ - if (lc->sound_conf.ring_sndcard!=NULL && !linphone_core_in_call(lc)){ + /* play the ring if this is the only call*/ + if (lc->sound_conf.ring_sndcard!=NULL && ms_list_size(lc->calls)==1){ if(lc->ringstream==NULL){ MSSndCard *ringcard=lc->sound_conf.lsd_card ?lc->sound_conf.lsd_card : lc->sound_conf.ring_sndcard; ms_message("Starting local ring..."); @@ -106,6 +106,8 @@ static void call_received(SalOp *h){ { ms_message("the local ring is already started"); } + }else{ + /*TODO : play a tone within the context of the current call */ } sal_call_notify_ringing(h); #if !(__IPHONE_OS_VERSION_MIN_REQUIRED >= 40000) @@ -198,6 +200,16 @@ 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)){ + /*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); + char *msg=ms_strdup_printf(_("Call answered by %s - on hold."),tmp); + lc->vtable.display_status(lc,msg); + ms_free(tmp); + ms_free(msg); + } + linphone_call_set_state(call,LinphoneCallPaused,"Call paused"); }else{ linphone_call_set_state(call,LinphoneCallStreamsRunning,"Connected (streams running)"); } @@ -241,7 +253,7 @@ static void call_ack(SalOp *op){ } /* this callback is called when an incoming re-INVITE modifies the session*/ -static void call_updated(SalOp *op){ +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); if (call->resultdesc) @@ -254,6 +266,13 @@ static void call_updated(SalOp *op){ { if (call->state==LinphoneCallPaused && sal_media_description_has_dir(call->resultdesc,SalStreamSendRecv) && strcmp(call->resultdesc->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!"); + /*we are actively running another call, reject with a busy*/ + sal_call_decline (op,SalReasonBusy,NULL); + return; + } if(lc->vtable.display_status) lc->vtable.display_status(lc,_("We have been resumed...")); linphone_call_set_state (call,LinphoneCallStreamsRunning,"Connected (streams running)"); @@ -263,12 +282,18 @@ static void call_updated(SalOp *op){ if(lc->vtable.display_status) lc->vtable.display_status(lc,_("We are being paused...")); linphone_call_set_state (call,LinphoneCallPaused,"Call paused"); + if (lc->current_call!=call){ + ms_error("Inconsitency detected: current call is %p but call %p is being paused !",lc->current_call,call); + } + lc->current_call=NULL; } - + /*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); } + if (lc->current_call==NULL) linphone_core_start_pending_refered_calls (lc); } static void call_terminated(SalOp *op, const char *from){ @@ -459,12 +484,18 @@ static void refer_received(Sal *sal, SalOp *op, const char *referto){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal); LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); if (call){ + if (call->refer_to!=NULL){ + ms_free(call->refer_to); + } + call->refer_to=ms_strdup(referto); + call->refer_pending=TRUE; linphone_call_set_state(call,LinphoneCallRefered,"Refered"); if (lc->vtable.display_status){ char *msg=ms_strdup_printf(_("We are transferred to %s"),referto); lc->vtable.display_status(lc,msg); ms_free(msg); } + if (lc->current_call==NULL) linphone_core_start_pending_refered_calls (lc); sal_refer_accept(op); }else if (lc->vtable.refer_received){ lc->vtable.refer_received(lc,referto); @@ -479,10 +510,10 @@ static void text_received(Sal *sal, const char *from, const char *msg){ static void notify(SalOp *op, const char *from, const char *msg){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); - + LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer (op); ms_message("get a %s notify from %s",msg,from); if(lc->vtable.notify_recv) - lc->vtable.notify_recv(lc,from,msg); + lc->vtable.notify_recv(lc,call,from,msg); } static void notify_presence(SalOp *op, SalSubscribeState ss, SalPresenceStatus status, const char *msg){ @@ -525,7 +556,7 @@ SalCallbacks linphone_sal_callbacks={ call_ringing, call_accepted, call_ack, - call_updated, + call_updating, call_terminated, call_failure, auth_requested, diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index fbb4f0212..871d00e57 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -87,7 +87,7 @@ static int find_port_offset(LinphoneCore *lc){ MSList *elem; int audio_port; bool_t already_used=FALSE; - for(offset=0;offset<100;++offset){ + for(offset=0;offset<100;offset+=2){ audio_port=linphone_core_get_audio_port (lc)+offset; already_used=FALSE; for(elem=lc->calls;elem!=NULL;elem=elem->next){ @@ -204,13 +204,17 @@ static void linphone_call_set_terminated(LinphoneCall *call){ } linphone_call_log_completed(call->log,call, status); - if (linphone_core_del_call(lc,call) != 0){ - ms_error("Could not remove the call from the list !!!"); - } + if (call == lc->current_call){ ms_message("Resetting the current call"); lc->current_call=NULL; + linphone_core_start_pending_refered_calls(lc); } + + if (linphone_core_del_call(lc,call) != 0){ + ms_error("Could not remove the call from the list !!!"); + } + if (ms_list_size(lc->calls)==0) linphone_core_notify_all_friends(lc,lc->presence_mode); @@ -226,7 +230,11 @@ static void linphone_call_set_terminated(LinphoneCall *call){ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message){ LinphoneCore *lc=call->core; if (call->state!=cstate){ - call->state=cstate; + if (cstate!=LinphoneCallRefered){ + /*LinphoneCallRefered is rather an event, not a state. + Indeed it does not change the state of the call (still paused or running)*/ + call->state=cstate; + } if (lc->vtable.call_state_changed) lc->vtable.call_state_changed(lc,call,cstate,message); } @@ -251,6 +259,9 @@ static void linphone_call_destroy(LinphoneCall *obj) if (obj->ping_op) { sal_op_release(obj->ping_op); } + if (obj->refer_to){ + ms_free(obj->refer_to); + } ms_free(obj); } @@ -336,7 +347,7 @@ LinphoneCallLog *linphone_call_get_call_log(const LinphoneCall *call){ } /** - * Returns the refer-to uri (if the call received was transfered). + * Returns the refer-to uri (if the call was transfered). **/ const char *linphone_call_get_refer_to(const LinphoneCall *call){ return call->refer_to; @@ -346,6 +357,18 @@ LinphoneCallDir linphone_call_get_dir(const LinphoneCall *call){ return call->log->dir; } +/** + * Returns true if this calls has received a transfer that has not been + * executed yet. + * Pending transfers are executed when this call is being paused or closed, + * locally or by remote endpoint. + * If the call is already paused while receiving the transfer request, the + * transfer immediately occurs. +**/ +bool_t linphone_call_has_transfer_pending(const LinphoneCall *call){ + return call->refer_pending; +} + /** * @} **/ diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 6cf8725f3..38f69d23d 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1671,25 +1671,22 @@ void linphone_core_iterate(LinphoneCore *lc){ call = linphone_core_get_current_call(lc); if(call) { - if (call->state==LinphoneCallConnected) + if (one_second_elapsed) { - if (one_second_elapsed) - { - RtpSession *as=NULL,*vs=NULL; - lc->prevtime=curtime; - if (call->audiostream!=NULL) - as=call->audiostream->session; - if (call->videostream!=NULL) - vs=call->videostream->session; - display_bandwidth(as,vs); - } -#ifdef VIDEO_ENABLED + RtpSession *as=NULL,*vs=NULL; + lc->prevtime=curtime; + if (call->audiostream!=NULL) + as=call->audiostream->session; if (call->videostream!=NULL) - video_stream_iterate(call->videostream); -#endif - if (call->audiostream!=NULL && disconnect_timeout>0) - disconnected=!audio_stream_alive(call->audiostream,disconnect_timeout); + vs=call->videostream->session; + display_bandwidth(as,vs); } +#ifdef VIDEO_ENABLED + if (call->videostream!=NULL) + video_stream_iterate(call->videostream); +#endif + if (call->audiostream!=NULL && disconnect_timeout>0) + disconnected=!audio_stream_alive(call->audiostream,disconnect_timeout); } if (linphone_core_video_preview_enabled(lc)){ if (lc->previewstream==NULL && lc->calls==NULL) @@ -1835,6 +1832,19 @@ bool_t linphone_core_is_in_communication_with(LinphoneCore *lc, const char *to) return returned; } +void linphone_core_start_pending_refered_calls(LinphoneCore *lc){ + MSList *elem; + for(elem=lc->calls;elem!=NULL;elem=elem->next){ + LinphoneCall *call=(LinphoneCall*)elem->data; + if (call->refer_pending){ + ms_message("Starting new call to refered address %s",call->refer_to); + call->refer_pending=FALSE; + linphone_core_invite(lc,call->refer_to); + break; + } + } +} + LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const LinphoneAddress *uri){ const MSList *elem; LinphoneProxyConfig *found_cfg=NULL; @@ -2036,7 +2046,13 @@ LinphoneCall * linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddr return call; } -int linphone_core_refer(LinphoneCore *lc, LinphoneCall *call, const char *url) +/** + * Performs a simple call transfer to the specified destination. + * + * The remote endpoint is expected to issue a new call to the specified destination. + * The current call remains active and thus can be later paused or terminated. +**/ +int linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall *call, const char *url) { char *real_url=NULL; LinphoneAddress *real_parsed_url=linphone_core_interpret_url(lc,url); @@ -2053,6 +2069,7 @@ int linphone_core_refer(LinphoneCore *lc, LinphoneCall *call, const char *url) real_url=linphone_address_as_string (real_parsed_url); sal_refer(call->op,real_url); ms_free(real_url); + linphone_address_destroy(real_parsed_url); return 0; } @@ -2114,7 +2131,7 @@ int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *call) MSList *elem; for(elem=lc->calls;elem!=NULL;elem=elem->next){ LinphoneCall *c=(LinphoneCall*)elem->data; - if (c!=call && (c->state!=LinphoneCallPaused || c->state!=LinphoneCallPausing)){ + if (c!=call && (c->state!=LinphoneCallPaused)){ ms_warning("Cannot accept this call as another one is running, pause it before."); return -1; } @@ -2181,8 +2198,10 @@ int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *the_call) LinphoneCall *call; if (the_call == NULL){ call = linphone_core_get_current_call(lc); - if(call == NULL){ - ms_warning("No currently active call to terminate !"); + if (ms_list_size(lc->calls)==1){ + call=(LinphoneCall*)lc->calls->data; + }else{ + ms_warning("No unique call to terminate !"); return -1; } } @@ -2276,6 +2295,7 @@ int linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *the_call) if (lc->vtable.display_status) lc->vtable.display_status(lc,_("Pausing the current call...")); lc->current_call=NULL; + linphone_core_start_pending_refered_calls(lc); return 0; } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index a1ed9d317..d0c680d92 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -172,6 +172,7 @@ void linphone_call_ref(LinphoneCall *call); void linphone_call_unref(LinphoneCall *call); 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); void *linphone_call_get_user_pointer(LinphoneCall *call); void linphone_call_set_user_pointer(LinphoneCall *call, void *user_pointer); @@ -419,7 +420,7 @@ typedef void (*DisplayUrlCb)(struct _LinphoneCore *lc, const char *message, cons /** Callback prototype */ typedef void (*LinphoneCoreCbFunc)(struct _LinphoneCore *lc,void * user_data); /** Callback prototype */ -typedef void (*NotifyReceivedCb)(struct _LinphoneCore *lc, const char *from, const char *msg); +typedef void (*NotifyReceivedCb)(struct _LinphoneCore *lc, LinphoneCall *call, const char *from, const char *event); /** Callback prototype */ typedef void (*NotifyPresenceReceivedCb)(struct _LinphoneCore *lc, LinphoneFriend * fid); /** Callback prototype */ @@ -509,7 +510,7 @@ LinphoneCall * linphone_core_invite(LinphoneCore *lc, const char *url); LinphoneCall * linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddress *addr); -int linphone_core_refer(LinphoneCore *lc, LinphoneCall *call, const char *url); +int linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall *call, const char *refer_to); bool_t linphone_core_inc_invite_pending(LinphoneCore*lc); diff --git a/coreapi/private.h b/coreapi/private.h index e5d0e9055..cb3ff78e2 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -76,6 +76,7 @@ struct _LinphoneCall struct _AudioStream *audiostream; /**/ struct _VideoStream *videostream; char *refer_to; + bool_t refer_pending; bool_t media_pending; bool_t audio_muted; }; @@ -184,7 +185,7 @@ void linphone_core_update_progress(LinphoneCore *lc, const char *purpose, float void linphone_core_stop_waiting(LinphoneCore *lc); int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, LinphoneProxyConfig *dest_proxy); - +void linphone_core_start_pending_refered_calls(LinphoneCore *lc); extern SalCallbacks linphone_sal_callbacks; diff --git a/coreapi/sal.h b/coreapi/sal.h index fd3f6f21b..7c6c7867b 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -187,7 +187,7 @@ typedef void (*SalOnCallReceived)(SalOp *op); typedef void (*SalOnCallRinging)(SalOp *op); typedef void (*SalOnCallAccepted)(SalOp *op); typedef void (*SalOnCallAck)(SalOp *op); -typedef void (*SalOnCallUpdated)(SalOp *op); +typedef void (*SalOnCallUpdating)(SalOp *op);/*< Called when a reINVITE is received*/ typedef void (*SalOnCallTerminated)(SalOp *op, const char *from); typedef void (*SalOnCallFailure)(SalOp *op, SalError error, SalReason reason, const char *details, int code); typedef void (*SalOnAuthRequested)(SalOp *op, const char *realm, const char *username); @@ -210,7 +210,7 @@ typedef struct SalCallbacks{ SalOnCallRinging call_ringing; SalOnCallAccepted call_accepted; SalOnCallAck call_ack; - SalOnCallUpdated call_updated; + SalOnCallUpdating call_updating; SalOnCallTerminated call_terminated; SalOnCallFailure call_failure; SalOnAuthRequested auth_requested; @@ -273,6 +273,7 @@ void *sal_op_get_user_pointer(const SalOp *op); int sal_call_set_local_media_description(SalOp *h, SalMediaDescription *desc); int sal_call(SalOp *h, const char *from, const char *to); int sal_call_notify_ringing(SalOp *h); +/*accept an incoming call or, during a call accept a reINVITE*/ 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); diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index ec0b7aff8..8e4afe22e 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -284,8 +284,8 @@ void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs){ ctx->callbacks.call_failure=(SalOnCallFailure)unimplemented_stub; if (ctx->callbacks.call_terminated==NULL) ctx->callbacks.call_terminated=(SalOnCallTerminated)unimplemented_stub; - if (ctx->callbacks.call_updated==NULL) - ctx->callbacks.call_updated=(SalOnCallUpdated)unimplemented_stub; + if (ctx->callbacks.call_updating==NULL) + ctx->callbacks.call_updating=(SalOnCallUpdating)unimplemented_stub; if (ctx->callbacks.auth_requested==NULL) ctx->callbacks.auth_requested=(SalOnAuthRequested)unimplemented_stub; if (ctx->callbacks.auth_success==NULL) @@ -773,35 +773,27 @@ static void handle_reinvite(Sal *sal, eXosip_event_t *ev){ sal_media_description_unref(op->base.remote_media); op->base.remote_media=NULL; } - eXosip_lock(); - eXosip_call_build_answer(ev->tid,200,&msg); - eXosip_unlock(); - if (msg==NULL) return; - if (op->base.root->session_expires!=0){ - if (op->supports_session_timers) osip_message_set_supported(msg, "timer"); - } - if (op->base.contact){ - _osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free); - osip_message_set_contact(msg,op->base.contact); + if (op->result){ + sal_media_description_unref(op->result); + op->result=NULL; } if (sdp){ op->sdp_offering=FALSE; op->base.remote_media=sal_media_description_new(); sdp_to_media_description(sdp,op->base.remote_media); sdp_message_free(sdp); - sdp_process(op); - if (op->sdp_answer!=NULL){ - set_sdp(msg,op->sdp_answer); - sdp_message_free(op->sdp_answer); - op->sdp_answer=NULL; - } + sal->callbacks.call_updating(op); }else { op->sdp_offering=TRUE; - set_sdp_from_desc(msg,op->base.local_media); + eXosip_lock(); + eXosip_call_build_answer(ev->tid,200,&msg); + if (msg!=NULL){ + set_sdp_from_desc(msg,op->base.local_media); + eXosip_call_send_answer(ev->tid,200,msg); + } + eXosip_unlock(); } - eXosip_lock(); - eXosip_call_send_answer(ev->tid,200,msg); - eXosip_unlock(); + } static void handle_ack(Sal *sal, eXosip_event_t *ev){ @@ -820,7 +812,7 @@ static void handle_ack(Sal *sal, eXosip_event_t *ev){ sdp_message_free(sdp); } if (op->reinvite){ - sal->callbacks.call_updated(op); + if (sdp) sal->callbacks.call_updating(op); op->reinvite=FALSE; }else{ sal->callbacks.call_ack(op); diff --git a/mediastreamer2 b/mediastreamer2 index 236222b3f..6cc9076b9 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 236222b3f08baf502742b6c75633f50e3a14917f +Subproject commit 6cc9076b9cc4d6b88e7a0b93e6abdd1ad881e832 diff --git a/oRTP b/oRTP index a08462074..d2a8cb089 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit a084620745b1b1c81ec93501ffbb3de373f7c8c9 +Subproject commit d2a8cb0890c7547703a092c839c55db10449ef92 diff --git a/po/POTFILES.in b/po/POTFILES.in index 2b0f2734f..3fcfbdd20 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -72,3 +72,5 @@ mediastreamer2/src/audiomixer.c mediastreamer2/src/chanadapt.c mediastreamer2/src/itc.c mediastreamer2/src/extdisplay.c +mediastreamer2/src/msiounit.c + From 8a5c5626e3696e4818d9ecd4b66302f3a712405a Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 23 Aug 2010 15:15:51 +0200 Subject: [PATCH 41/45] fix bug with calls without ping not beeing identified by linphonec --- console/commands.c | 8 ++------ coreapi/linphonecore.c | 2 +- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/console/commands.c b/console/commands.c index c3e1e472f..9efc054e7 100644 --- a/console/commands.c +++ b/console/commands.c @@ -1245,15 +1245,11 @@ static int lpc_cmd_resume(LinphoneCore *lc, char *args){ if (n == 1){ LinphoneCall *call=linphonec_get_call (id); if (call){ - if(linphone_core_resume_call(lc,call)==-1) - { + if(linphone_core_resume_call(lc,call)==-1){ linphonec_out("There was a problem to resume the call check the remote address you gave %s\n",args); - return 1; } - }else - { - return 1; } + return 1; }else return 0; } else diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 38f69d23d..82d77c6ab 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2031,11 +2031,11 @@ LinphoneCall * linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddr } /* this call becomes now the current one*/ lc->current_call=call; + linphone_call_set_state (call,LinphoneCallOutgoingInit,"Starting outgoing call"); if (dest_proxy!=NULL || lc->sip_conf.ping_with_options==FALSE){ err=linphone_core_start_invite(lc,call,dest_proxy); }else{ /*defer the start of the call after the OPTIONS ping*/ - linphone_call_set_state (call,LinphoneCallOutgoingInit,"Starting outgoing call"); call->ping_op=sal_op_new(lc->sal); sal_ping(call->ping_op,from,real_url); sal_op_set_user_pointer(call->ping_op,call); From 370d0ff8b0514d26951fde3ff12ab6e4df72be17 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 25 Aug 2010 14:26:23 +0200 Subject: [PATCH 42/45] workaround for stupid phone using "G729A" submime type. --- coreapi/offeranswer.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index efd44552d..22901242a 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -29,7 +29,10 @@ static PayloadType * find_payload_type_best_match(const MSList *l, const Payload for (elem=l;elem!=NULL;elem=elem->next){ pt=(PayloadType*)elem->data; - if (strcasecmp(pt->mime_type,refpt->mime_type)==0 && pt->clock_rate==refpt->clock_rate){ + /* the compare between G729 and G729A is for some stupid uncompliant phone*/ + if (strcasecmp(pt->mime_type,refpt->mime_type)==0 || + ((strcasecmp(pt->mime_type, "G729") == 0 && strcasecmp(refpt->mime_type, "G729A") == 0 )) + && pt->clock_rate==refpt->clock_rate){ candidate=pt; /*good candidate, check fmtp for H264 */ if (strcasecmp(pt->mime_type,"H264")==0){ From 1e15e24d8db0e3bca1ebf70d3fb291c61c16110e Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 25 Aug 2010 14:26:45 +0200 Subject: [PATCH 43/45] allow playing audio file during hold on --- configure.in | 2 +- coreapi/linphonecall.c | 6 ++++-- coreapi/linphonecore.c | 16 ++++++++++++++++ 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/configure.in b/configure.in index 6495ab0a6..cda24af91 100644 --- a/configure.in +++ b/configure.in @@ -1,6 +1,6 @@ dnl Process this file with autoconf to produce a configure script. -AC_INIT([linphone],[3.3.99],[linphone-developers@nongnu.org]) +AC_INIT([linphone],[3.3.99.1],[linphone-developers@nongnu.org]) AC_CANONICAL_SYSTEM dnl Source packaging numbers diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 871d00e57..089923126 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -609,8 +609,10 @@ void linphone_call_start_media_streams(LinphoneCall *call){ recfile=NULL; } /*if playfile are supplied don't use soundcards*/ - if (playfile) captcard=NULL; - if (recfile) playcard=NULL; + if (lc->use_files) { + captcard=NULL; + playcard=NULL; + } audio_stream_start_full( call->audiostream, call->audio_profile, diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 82d77c6ab..cede342dc 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3238,10 +3238,19 @@ MSVideoSize linphone_core_get_preferred_video_size(LinphoneCore *lc){ return lc->video_conf.vsize; } +/** + * Ask the core to stream audio from and to files, instead of using the soundcard. +**/ void linphone_core_use_files(LinphoneCore *lc, bool_t yesno){ lc->use_files=yesno; } +/** + * Sets a wav file to be played when putting somebody on hold, + * or when files are used instead of soundcards (see linphone_core_use_files()). + * + * The file must be a 16 bit linear wav file. +**/ void linphone_core_set_play_file(LinphoneCore *lc, const char *file){ LinphoneCall *call=linphone_core_get_current_call(lc); if (lc->play_file!=NULL){ @@ -3255,6 +3264,13 @@ void linphone_core_set_play_file(LinphoneCore *lc, const char *file){ } } + +/** + * Sets a wav file where incoming stream is to be recorded, + * when files are used instead of soundcards (see linphone_core_use_files()). + * + * The file must be a 16 bit linear wav file. +**/ void linphone_core_set_record_file(LinphoneCore *lc, const char *file){ LinphoneCall *call=linphone_core_get_current_call(lc); if (lc->rec_file!=NULL){ From 51147aee3c481148836649454fd4615dda087c30 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 25 Aug 2010 15:22:14 +0200 Subject: [PATCH 44/45] integration of g722 codec --- coreapi/offeranswer.c | 4 ++-- mediastreamer2 | 2 +- oRTP | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index 22901242a..6bd21863c 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -30,8 +30,8 @@ static PayloadType * find_payload_type_best_match(const MSList *l, const Payload for (elem=l;elem!=NULL;elem=elem->next){ pt=(PayloadType*)elem->data; /* the compare between G729 and G729A is for some stupid uncompliant phone*/ - if (strcasecmp(pt->mime_type,refpt->mime_type)==0 || - ((strcasecmp(pt->mime_type, "G729") == 0 && strcasecmp(refpt->mime_type, "G729A") == 0 )) + if ( (strcasecmp(pt->mime_type,refpt->mime_type)==0 || + (strcasecmp(pt->mime_type, "G729") == 0 && strcasecmp(refpt->mime_type, "G729A") == 0 )) && pt->clock_rate==refpt->clock_rate){ candidate=pt; /*good candidate, check fmtp for H264 */ diff --git a/mediastreamer2 b/mediastreamer2 index 6cc9076b9..030250c16 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 6cc9076b9cc4d6b88e7a0b93e6abdd1ad881e832 +Subproject commit 030250c162f546af5b1c2b97e51a71d81a73679b diff --git a/oRTP b/oRTP index d2a8cb089..6bc540160 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit d2a8cb0890c7547703a092c839c55db10449ef92 +Subproject commit 6bc540160a8729f63f6074b958161bc696e78f93 From f6d765bc22972a44e7a80f39d36a4efc2847df0a Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 26 Aug 2010 12:10:12 +0200 Subject: [PATCH 45/45] implements playing of dtmfs outside of any call --- console/commands.c | 1 + coreapi/callbacks.c | 10 ++++++++ coreapi/linphonecore.c | 52 +++++++++++++++++++++++++++++++++++++++++- coreapi/linphonecore.h | 3 +++ coreapi/private.h | 1 + gtk-glade/main.c | 8 +++---- mediastreamer2 | 2 +- 7 files changed, 71 insertions(+), 6 deletions(-) diff --git a/console/commands.c b/console/commands.c index 9efc054e7..2fd9b5401 100644 --- a/console/commands.c +++ b/console/commands.c @@ -296,6 +296,7 @@ linphonec_parse_command_line(LinphoneCore *lc, char *cl) while ( isdigit(*cl) || *cl == '#' || *cl == '*' ) { linphone_core_send_dtmf(lc, *cl); + linphone_core_play_dtmf (lc,*cl,100); ms_sleep(1); // be nice ++cl; } diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 6d0cd8b8f..aad80a60d 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -97,6 +97,11 @@ static void call_received(SalOp *h){ /* play the ring if this is the only call*/ if (lc->sound_conf.ring_sndcard!=NULL && ms_list_size(lc->calls)==1){ + if (lc->ringstream && lc->dmfs_playing_start_time!=0){ + ring_stop(lc->ringstream); + lc->ringstream=NULL; + lc->dmfs_playing_start_time=0; + } if(lc->ringstream==NULL){ MSSndCard *ringcard=lc->sound_conf.lsd_card ?lc->sound_conf.lsd_card : lc->sound_conf.ring_sndcard; ms_message("Starting local ring..."); @@ -129,6 +134,11 @@ static void call_ringing(SalOp *h){ md=sal_call_get_final_media_description(h); if (md==NULL){ + if (lc->ringstream && lc->dmfs_playing_start_time!=0){ + ring_stop(lc->ringstream); + lc->ringstream=NULL; + lc->dmfs_playing_start_time=0; + } if (lc->ringstream!=NULL) return; /*already ringing !*/ if (lc->sound_conf.play_sndcard!=NULL){ MSSndCard *ringcard=lc->sound_conf.lsd_card ? lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard; diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index cede342dc..5f388860b 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -27,6 +27,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "mediastreamer2/mseventqueue.h" #include "mediastreamer2/msvolume.h" #include "mediastreamer2/msequalizer.h" +#include "mediastreamer2/dtmfgen.h" #ifdef INET6 #ifndef WIN32 @@ -1641,6 +1642,13 @@ void linphone_core_iterate(LinphoneCore *lc){ lc_callback_obj_invoke(&lc->preview_finished_cb,lc); } + if (lc->ringstream && lc->dmfs_playing_start_time!=0 + && (curtime-lc->dmfs_playing_start_time)>5){ + ring_stop(lc->ringstream); + lc->ringstream=NULL; + lc->dmfs_playing_start_time=0; + } + sal_iterate(lc->sal); ms_event_queue_pump(lc->msevq); if (lc->auto_net_state_mon) monitor_network_state(lc,curtime); @@ -1671,7 +1679,7 @@ void linphone_core_iterate(LinphoneCore *lc){ call = linphone_core_get_current_call(lc); if(call) { - if (one_second_elapsed) + if (call->state==LinphoneCallStreamsRunning && one_second_elapsed) { RtpSession *as=NULL,*vs=NULL; lc->prevtime=curtime; @@ -3284,6 +3292,48 @@ void linphone_core_set_record_file(LinphoneCore *lc, const char *file){ } } +static MSFilter *get_dtmf_gen(LinphoneCore *lc){ + LinphoneCall *call=linphone_core_get_current_call (lc); + if (call){ + AudioStream *stream=call->audiostream; + if (stream){ + return stream->dtmfgen; + } + } + if (lc->ringstream==NULL){ + MSSndCard *ringcard=lc->sound_conf.lsd_card ?lc->sound_conf.lsd_card : lc->sound_conf.ring_sndcard; + lc->ringstream=ring_start(NULL,0,ringcard); + lc->dmfs_playing_start_time=time(NULL); + }else{ + if (lc->dmfs_playing_start_time!=0) + lc->dmfs_playing_start_time=time(NULL); + } + return lc->ringstream->gendtmf; +} + +/** + * Plays a dtmf to the local user. +**/ +void linphone_core_play_dtmf(LinphoneCore *lc, char dtmf, int duration_ms){ + MSFilter *f=get_dtmf_gen(lc); + if (f==NULL){ + ms_error("No dtmf generator at this time !"); + return; + } + if (duration_ms>0) + ms_filter_call_method(f, MS_DTMF_GEN_PLAY, &dtmf); + else ms_filter_call_method(f, MS_DTMF_GEN_START, &dtmf); +} + +/** + * Stops playing a dtmf started by linphone_core_play_dtmf(). +**/ +void linphone_core_stop_dtmf(LinphoneCore *lc){ + MSFilter *f=get_dtmf_gen(lc); + ms_filter_call_method_noarg (f, MS_DTMF_GEN_STOP); +} + + /** * Retrieves the user pointer that was given to linphone_core_new() * diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index d0c680d92..e67da5209 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -769,6 +769,9 @@ void linphone_core_use_files(LinphoneCore *lc, bool_t yesno); void linphone_core_set_play_file(LinphoneCore *lc, const char *file); void linphone_core_set_record_file(LinphoneCore *lc, const char *file); +void linphone_core_play_dtmf(LinphoneCore *lc, char dtmf, int duration_ms); +void linphone_core_stop_dtmf(LinphoneCore *lc); + int linphone_core_get_current_call_duration(const LinphoneCore *lc); const LinphoneAddress *linphone_core_get_remote_address(LinphoneCore *lc); diff --git a/coreapi/private.h b/coreapi/private.h index cb3ff78e2..bbb48d0cb 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -367,6 +367,7 @@ struct _LinphoneCore MSList *friends; MSList *auth_info; struct _RingStream *ringstream; + time_t dmfs_playing_start_time; LCCallbackObj preview_finished_cb; LinphoneCall *current_call; /* the current call */ MSList *calls; /* all the processed calls */ diff --git a/gtk-glade/main.c b/gtk-glade/main.c index d5a1b0997..ddae9ff90 100644 --- a/gtk-glade/main.c +++ b/gtk-glade/main.c @@ -997,12 +997,12 @@ void linphone_gtk_load_identities(void){ static void linphone_gtk_dtmf_clicked(GtkButton *button){ const char *label=gtk_button_get_label(button); + GtkWidget *uri_bar=linphone_gtk_get_widget(gtk_widget_get_toplevel(GTK_WIDGET(button)),"uribar"); + int pos=-1; + gtk_editable_insert_text(GTK_EDITABLE(uri_bar),label,1,&pos); + linphone_core_play_dtmf (linphone_gtk_get_core(),label[0],100); if (linphone_core_in_call(linphone_gtk_get_core())){ linphone_core_send_dtmf(linphone_gtk_get_core(),label[0]); - }else{ - GtkWidget *uri_bar=linphone_gtk_get_widget(gtk_widget_get_toplevel(GTK_WIDGET(button)),"uribar"); - int pos=-1; - gtk_editable_insert_text(GTK_EDITABLE(uri_bar),label,1,&pos); } } diff --git a/mediastreamer2 b/mediastreamer2 index 030250c16..332d79209 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 030250c162f546af5b1c2b97e51a71d81a73679b +Subproject commit 332d79209b333bd8ded5b16a7b9dcfe2c0aedc63