3 Copyright (C) 2010 Simon MORLAT (simon.morlat@free.fr)
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 #include "linphonecore.h"
25 #include "mediastreamer2/mediastream.h"
28 static void register_failure(SalOp *op, SalError error, SalReason reason, const char *details);
30 static void linphone_connect_incoming(LinphoneCore *lc, LinphoneCall *call){
31 if (lc->ringstream!=NULL){
32 ring_stop(lc->ringstream);
35 linphone_call_start_media_streams(call);
38 static bool_t is_duplicate_call(LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to){
40 for(elem=lc->calls;elem!=NULL;elem=elem->next){
41 LinphoneCall *call=(LinphoneCall*)elem->data;
42 if (linphone_address_weak_equal(call->log->from,from) &&
43 linphone_address_weak_equal(call->log->to, to)){
50 static void call_received(SalOp *h){
51 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h));
56 LinphoneAddress *from_parsed;
57 LinphoneAddress *from_addr, *to_addr;
58 const char * early_media=linphone_core_get_remote_ringback_tone (lc);
60 /* first check if we can answer successfully to this invite */
61 if (lc->presence_mode==LinphoneStatusBusy ||
62 lc->presence_mode==LinphoneStatusOffline ||
63 lc->presence_mode==LinphoneStatusDoNotDisturb ||
64 lc->presence_mode==LinphoneStatusMoved){
65 if (lc->presence_mode==LinphoneStatusBusy )
66 sal_call_decline(h,SalReasonBusy,NULL);
67 else if (lc->presence_mode==LinphoneStatusOffline)
68 sal_call_decline(h,SalReasonTemporarilyUnavailable,NULL);
69 else if (lc->presence_mode==LinphoneStatusDoNotDisturb)
70 sal_call_decline(h,SalReasonTemporarilyUnavailable,NULL);
71 else if (lc->alt_contact!=NULL && lc->presence_mode==LinphoneStatusMoved)
72 sal_call_decline(h,SalReasonRedirect,lc->alt_contact);
76 if (!linphone_core_can_we_add_call(lc)){/*busy*/
77 sal_call_decline(h,SalReasonBusy,NULL);
81 from=sal_op_get_from(h);
83 from_addr=linphone_address_new(from);
84 to_addr=linphone_address_new(to);
86 if (is_duplicate_call(lc,from_addr,to_addr)){
87 ms_warning("Receiving duplicated call, refusing this one.");
88 sal_call_decline(h,SalReasonBusy,NULL);
89 linphone_address_destroy(from_addr);
90 linphone_address_destroy(to_addr);
94 call=linphone_call_new_incoming(lc,from_addr,to_addr,h);
95 sal_call_set_local_media_description(h,call->localdesc);
96 call->resultdesc=sal_call_get_final_media_description(h);
98 sal_media_description_ref(call->resultdesc);
99 if (call->resultdesc && sal_media_description_empty(call->resultdesc)){
100 sal_call_decline(h,SalReasonMedia,NULL);
101 linphone_call_unref(call);
106 /* the call is acceptable so we can now add it to our list */
107 linphone_core_add_call(lc,call);
109 from_parsed=linphone_address_new(sal_op_get_from(h));
110 linphone_address_clean(from_parsed);
111 tmp=linphone_address_as_string(from_parsed);
112 linphone_address_destroy(from_parsed);
113 linphone_call_set_state(call,LinphoneCallIncomingReceived,"Incoming call");
114 barmesg=ortp_strdup_printf("%s %s%s",tmp,_("is contacting you"),
115 (sal_call_autoanswer_asked(h)) ?_(" and asked autoanswer."):_("."));
116 if (lc->vtable.show) lc->vtable.show(lc);
117 if (lc->vtable.display_status)
118 lc->vtable.display_status(lc,barmesg);
120 /* play the ring if this is the only call*/
121 if (lc->sound_conf.ring_sndcard!=NULL && ms_list_size(lc->calls)==1){
122 lc->current_call=call;
123 if (lc->ringstream && lc->dmfs_playing_start_time!=0){
124 ring_stop(lc->ringstream);
126 lc->dmfs_playing_start_time=0;
128 if(lc->ringstream==NULL){
129 MSSndCard *ringcard=lc->sound_conf.lsd_card ?lc->sound_conf.lsd_card : lc->sound_conf.ring_sndcard;
130 ms_message("Starting local ring...");
131 lc->ringstream=ring_start(lc->sound_conf.local_ring,2000,ringcard);
135 ms_message("the local ring is already started");
138 /*TODO : play a tone within the context of the current call */
140 sal_call_notify_ringing(h,early_media!=NULL);
141 #if !(__IPHONE_OS_VERSION_MIN_REQUIRED >= 40000)
142 linphone_call_init_media_streams(call);
143 if (early_media!=NULL){
144 linphone_call_start_early_media (call);
151 static void call_ringing(SalOp *h){
152 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h));
153 LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(h);
154 SalMediaDescription *md;
156 if (call==NULL) return;
158 if (lc->vtable.display_status)
159 lc->vtable.display_status(lc,_("Remote ringing."));
161 md=sal_call_get_final_media_description(h);
163 if (lc->ringstream && lc->dmfs_playing_start_time!=0){
164 ring_stop(lc->ringstream);
166 lc->dmfs_playing_start_time=0;
168 if (lc->ringstream!=NULL) return; /*already ringing !*/
169 if (lc->sound_conf.play_sndcard!=NULL){
170 MSSndCard *ringcard=lc->sound_conf.lsd_card ? lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard;
171 ms_message("Remote ringing...");
172 lc->ringstream=ring_start(lc->sound_conf.remote_ring,2000,ringcard);
173 linphone_call_set_state(call,LinphoneCallOutgoingRinging,"Remote ringing");
176 /*accept early media */
177 if (call->audiostream && call->audiostream->ticker!=NULL){
178 /*streams already started */
179 ms_message("Early media already started.");
182 sal_media_description_ref(md);
184 if (lc->vtable.show) lc->vtable.show(lc);
185 if (lc->vtable.display_status)
186 lc->vtable.display_status(lc,_("Early media."));
187 linphone_call_set_state(call,LinphoneCallOutgoingEarlyMedia,"Early media");
188 if (lc->ringstream!=NULL){
189 ring_stop(lc->ringstream);
192 ms_message("Doing early media...");
193 linphone_call_start_media_streams(call);
194 call->media_pending=TRUE;
200 * - when the call is accepted
201 * - when a request is accepted (pause, resume)
203 static void call_accepted(SalOp *op){
204 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
205 LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
208 ms_warning("No call to accept.");
211 if ((call->audiostream!=NULL) && (call->audiostream->ticker!=NULL)){
212 /*case where we accepted early media or already in call*/
213 linphone_call_stop_media_streams(call);
215 if (call->audiostream==NULL){
216 linphone_call_init_media_streams(call);
218 if (call->resultdesc)
219 sal_media_description_unref(call->resultdesc);
220 call->resultdesc=sal_call_get_final_media_description(op);
221 if (call->resultdesc){
222 sal_media_description_ref(call->resultdesc);
223 call->media_pending=FALSE;
225 if (call->state==LinphoneCallOutgoingProgress ||
226 call->state==LinphoneCallOutgoingRinging ||
227 call->state==LinphoneCallOutgoingEarlyMedia){
228 linphone_call_set_state(call,LinphoneCallConnected,"Connected");
230 if (call->resultdesc && !sal_media_description_empty(call->resultdesc)){
231 if (sal_media_description_has_dir(call->resultdesc,SalStreamSendOnly) ||
232 sal_media_description_has_dir(call->resultdesc,SalStreamInactive)){
233 if (lc->vtable.display_status){
234 char *tmp=linphone_call_get_remote_address_as_string (call);
235 char *msg=ms_strdup_printf(_("Call with %s is paused."),tmp);
236 lc->vtable.display_status(lc,msg);
240 linphone_call_set_state(call,LinphoneCallPaused,"Call paused");
241 }else if (sal_media_description_has_dir(call->resultdesc,SalStreamRecvOnly)){
242 /*we are put on hold when the call is initially accepted */
243 if (lc->vtable.display_status){
244 char *tmp=linphone_call_get_remote_address_as_string (call);
245 char *msg=ms_strdup_printf(_("Call answered by %s - on hold."),tmp);
246 lc->vtable.display_status(lc,msg);
250 linphone_call_set_state(call,LinphoneCallPaused,"Call paused");
252 if (lc->vtable.display_status){
253 lc->vtable.display_status(lc,_("Call answered - connected."));
255 linphone_call_set_state(call,LinphoneCallStreamsRunning,"Connected (streams running)");
257 linphone_connect_incoming (lc,call);
260 ms_error("Incompatible SDP offer received in 200Ok, need to abort the call");
261 linphone_core_abort_call(lc,call,"No codec intersection");
265 static void call_ack(SalOp *op){
266 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
267 LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
269 ms_warning("No call to be ACK'd");
272 if (call->media_pending){
273 if (call->audiostream->ticker!=NULL){
274 /*case where we accepted early media */
275 linphone_call_stop_media_streams(call);
276 linphone_call_init_media_streams(call);
278 if (call->resultdesc)
279 sal_media_description_unref(call->resultdesc);
280 call->resultdesc=sal_call_get_final_media_description(op);
281 if (call->resultdesc)
282 sal_media_description_ref(call->resultdesc);
283 if (call->resultdesc && !sal_media_description_empty(call->resultdesc)){
284 linphone_connect_incoming(lc,call);
285 linphone_call_set_state (call,LinphoneCallStreamsRunning,"Connected (streams running)");
288 ms_error("Incompatible SDP response received in ACK, need to abort the call");
289 linphone_core_abort_call(lc,call,"No codec intersection");
292 call->media_pending=FALSE;
296 /* this callback is called when an incoming re-INVITE modifies the session*/
297 static void call_updating(SalOp *op){
298 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
299 LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
300 LinphoneCallState prevstate=LinphoneCallIdle;
302 if (call->resultdesc)
303 sal_media_description_unref(call->resultdesc);
304 call->resultdesc=sal_call_get_final_media_description(op);
305 if (call->resultdesc)
306 sal_media_description_ref(call->resultdesc);
308 if (call->resultdesc && !sal_media_description_empty(call->resultdesc))
310 if ((call->state==LinphoneCallPausedByRemote || call->state==LinphoneCallPaused) &&
311 sal_media_description_has_dir(call->resultdesc,SalStreamSendRecv) && strcmp(call->resultdesc->addr,"0.0.0.0")!=0){
312 /*make sure we can be resumed */
313 if (lc->current_call!=NULL && lc->current_call!=call){
314 ms_warning("Attempt to be resumed but already in call with somebody else!");
315 /*we are actively running another call, reject with a busy*/
316 sal_call_decline (op,SalReasonBusy,NULL);
319 if(lc->vtable.display_status)
320 lc->vtable.display_status(lc,_("We have been resumed..."));
321 linphone_call_set_state (call,LinphoneCallStreamsRunning,"Connected (streams running)");
323 else if(call->state==LinphoneCallStreamsRunning &&
324 ( sal_media_description_has_dir(call->resultdesc,SalStreamRecvOnly)
325 || sal_media_description_has_dir(call->resultdesc,SalStreamInactive)
326 || strcmp(call->resultdesc->addr,"0.0.0.0")==0)){
327 if(lc->vtable.display_status)
328 lc->vtable.display_status(lc,_("We are being paused..."));
329 linphone_call_set_state (call,LinphoneCallPausedByRemote,"Call paused by remote");
330 if (lc->current_call!=call){
331 ms_error("Inconsitency detected: current call is %p but call %p is being paused !",lc->current_call,call);
334 prevstate=call->state;
335 linphone_call_set_state(call, LinphoneCallUpdatedByRemote,"Call updated by remote");
337 /*accept the modification (sends a 200Ok)*/
339 linphone_call_stop_media_streams (call);
340 linphone_call_init_media_streams (call);
341 linphone_call_start_media_streams (call);
342 if (prevstate!=LinphoneCallIdle){
343 linphone_call_set_state (call,prevstate,"Connected (streams running)");
346 if (lc->current_call==NULL) linphone_core_start_pending_refered_calls (lc);
349 static void call_terminated(SalOp *op, const char *from){
350 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
351 LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
353 if (call==NULL) return;
355 if (linphone_call_get_state(call)==LinphoneCallEnd || linphone_call_get_state(call)==LinphoneCallError){
356 ms_warning("call_terminated: ignoring.");
359 ms_message("Current call terminated...");
360 //we stop the call only if we have this current call or if we are in call
361 if (lc->ringstream!=NULL && ( (ms_list_size(lc->calls) == 1) || linphone_core_in_call(lc) )) {
362 ring_stop(lc->ringstream);
365 linphone_call_stop_media_streams(call);
366 if (lc->vtable.show!=NULL)
368 if (lc->vtable.display_status!=NULL)
369 lc->vtable.display_status(lc,_("Call terminated."));
371 linphone_call_set_state(call, LinphoneCallEnd,"Call ended");
374 static void call_failure(SalOp *op, SalError error, SalReason sr, const char *details, int code){
375 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
376 char *msg486=_("User is busy.");
377 char *msg480=_("User is temporarily unavailable.");
378 /*char *retrymsg=_("%s. Retry after %i minute(s).");*/
379 char *msg600=_("User does not want to be disturbed.");
380 char *msg603=_("Call declined.");
381 const char *msg=details;
382 LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
385 ms_warning("Call faillure reported on already cleaned call ?");
389 if (lc->vtable.show) lc->vtable.show(lc);
391 if (error==SalErrorNoResponse){
392 msg=_("No response.");
393 if (lc->vtable.display_status)
394 lc->vtable.display_status(lc,msg);
395 }else if (error==SalErrorProtocol){
396 msg=details ? details : _("Protocol error.");
397 if (lc->vtable.display_status)
398 lc->vtable.display_status(lc, msg);
399 }else if (error==SalErrorFailure){
401 case SalReasonDeclined:
403 if (lc->vtable.display_status)
404 lc->vtable.display_status(lc,msg603);
408 if (lc->vtable.display_status)
409 lc->vtable.display_status(lc,msg486);
411 case SalReasonRedirect:
413 if (lc->vtable.display_status)
414 lc->vtable.display_status(lc,msg);
416 case SalReasonTemporarilyUnavailable:
418 if (lc->vtable.display_status)
419 lc->vtable.display_status(lc,msg480);
421 case SalReasonNotFound:
423 if (lc->vtable.display_status)
424 lc->vtable.display_status(lc,msg);
426 case SalReasonDoNotDisturb:
428 if (lc->vtable.display_status)
429 lc->vtable.display_status(lc,msg600);
432 msg=_("No common codecs");
433 if (lc->vtable.display_status)
434 lc->vtable.display_status(lc,msg);
437 if (lc->vtable.display_status)
438 lc->vtable.display_status(lc,_("Call failed."));
442 if (lc->ringstream!=NULL) {
443 ring_stop(lc->ringstream);
446 linphone_call_stop_media_streams (call);
447 if (sr!=SalReasonDeclined) linphone_call_set_state(call,LinphoneCallError,msg);
448 else linphone_call_set_state(call,LinphoneCallEnd,"Call declined.");
452 static void auth_requested(SalOp *h, const char *realm, const char *username){
453 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h));
454 LinphoneAuthInfo *ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,realm,username);
455 ms_message("auth_requested() for realm=%s, username=%s",realm,username);
456 if (ai && (ai->works || ai->usecount<3)){
458 sai.username=ai->username;
459 sai.userid=ai->userid;
461 sai.password=ai->passwd;
462 ms_message("auth_requested(): authenticating realm=%s, username=%s",realm,username);
463 sal_op_authenticate(h,&sai);
466 if (ai && ai->works==FALSE) {
467 register_failure(h, SalErrorFailure, SalReasonForbidden, _("Authentication failure"));
469 if (lc->vtable.auth_info_requested)
470 lc->vtable.auth_info_requested(lc,realm,username);
474 static void auth_success(SalOp *h, const char *realm, const char *username){
475 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h));
476 LinphoneAuthInfo *ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,realm,username);
478 ms_message("%s/%s authentication works.",realm,username);
483 static void register_success(SalOp *op, bool_t registered){
484 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
485 LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)sal_op_get_user_pointer(op);
488 cfg->registered=registered;
489 linphone_proxy_config_set_error(cfg,LinphoneErrorNone);
490 linphone_proxy_config_set_state(cfg, registered ? LinphoneRegistrationOk : LinphoneRegistrationCleared ,
491 registered ? "Registration sucessful" : "Unregistration done");
492 if (lc->vtable.display_status){
493 if (cfg->registered) msg=ms_strdup_printf(_("Registration on %s successful."),sal_op_get_proxy(op));
494 else msg=ms_strdup_printf(_("Unregistration on %s done."),sal_op_get_proxy(op));
495 lc->vtable.display_status(lc,msg);
501 static void register_failure(SalOp *op, SalError error, SalReason reason, const char *details){
502 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
503 LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)sal_op_get_user_pointer(op);
506 ms_warning("Registration failed for unknown proxy config.");
510 details=_("no response timeout");
512 if (lc->vtable.display_status) {
513 char *msg=ortp_strdup_printf(_("Registration on %s failed: %s"),sal_op_get_proxy(op),details );
514 lc->vtable.display_status(lc,msg);
517 if (error== SalErrorFailure && reason == SalReasonForbidden) {
518 linphone_proxy_config_set_error(cfg, LinphoneErrorBadCredentials);
519 } else if (error == SalErrorNoResponse) {
520 linphone_proxy_config_set_error(cfg, LinphoneErrorNoResponse);
522 linphone_proxy_config_set_state(cfg,LinphoneRegistrationFailed,details);
525 static void vfu_request(SalOp *op){
527 LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer (op);
529 ms_warning("VFU request but no call !");
532 if (call->videostream)
533 video_stream_send_vfu(call->videostream);
537 static void dtmf_received(SalOp *op, char dtmf){
538 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
539 LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
540 if (lc->vtable.dtmf_received != NULL)
541 lc->vtable.dtmf_received(lc, call, dtmf);
544 static void refer_received(Sal *sal, SalOp *op, const char *referto){
545 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal);
546 LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
548 if (call->refer_to!=NULL){
549 ms_free(call->refer_to);
551 call->refer_to=ms_strdup(referto);
552 call->refer_pending=TRUE;
553 linphone_call_set_state(call,LinphoneCallRefered,"Refered");
554 if (lc->vtable.display_status){
555 char *msg=ms_strdup_printf(_("We are transferred to %s"),referto);
556 lc->vtable.display_status(lc,msg);
559 if (lc->current_call==NULL) linphone_core_start_pending_refered_calls (lc);
560 sal_refer_accept(op);
561 }else if (lc->vtable.refer_received){
562 lc->vtable.refer_received(lc,referto);
563 sal_refer_accept(op);
567 static void text_received(Sal *sal, const char *from, const char *msg){
568 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal);
569 linphone_core_text_received(lc,from,msg);
572 static void notify(SalOp *op, const char *from, const char *msg){
573 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
574 LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer (op);
575 ms_message("get a %s notify from %s",msg,from);
576 if(lc->vtable.notify_recv)
577 lc->vtable.notify_recv(lc,call,from,msg);
580 static void notify_presence(SalOp *op, SalSubscribeState ss, SalPresenceStatus status, const char *msg){
581 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
582 linphone_notify_recv(lc,op,ss,status);
585 static void subscribe_received(SalOp *op, const char *from){
586 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
587 linphone_subscription_new(lc,op,from);
590 static void subscribe_closed(SalOp *op, const char *from){
591 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
592 linphone_subscription_closed(lc,op);
595 static void internal_message(Sal *sal, const char *msg){
596 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal);
601 static void ping_reply(SalOp *op){
602 LinphoneCall *call=(LinphoneCall*) sal_op_get_user_pointer(op);
603 ms_message("ping reply !");
605 if (call->state==LinphoneCallOutgoingInit){
606 linphone_core_start_invite(call->core,call,NULL);
611 ms_warning("ping reply without call attached...");
615 SalCallbacks linphone_sal_callbacks={