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 linphone_connect_incoming(LinphoneCore *lc, LinphoneCall *call){
31 if (lc->vtable.display_status)
32 lc->vtable.display_status(lc,_("Connected."));
33 if (lc->vtable.connected_recv)
34 lc->vtable.connected_recv(lc,call);
35 call->state=LinphoneCallAVRunning;
36 if (lc->ringstream!=NULL){
37 ring_stop(lc->ringstream);
40 if(!linphone_core_in_call(lc))
42 linphone_core_set_as_current_call(lc,call);
44 if(call == linphone_core_get_current_call(lc))
45 linphone_core_start_media_streams(lc,call);
48 static void call_received(SalOp *h){
49 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h));
54 LinphoneAddress *from_parsed;
55 LinphoneGeneralStateContext gctx;
57 /* first check if we can answer successfully to this invite */
58 if (lc->presence_mode!=LINPHONE_STATUS_ONLINE){
59 ms_message("Not present !! presence mode : %d\n",lc->presence_mode);
60 if (lc->presence_mode==LINPHONE_STATUS_BUSY)
61 sal_call_decline(h,SalReasonBusy,NULL);
62 else if (lc->presence_mode==LINPHONE_STATUS_AWAY
63 ||lc->presence_mode==LINPHONE_STATUS_BERIGHTBACK
64 ||lc->presence_mode==LINPHONE_STATUS_ONTHEPHONE
65 ||lc->presence_mode==LINPHONE_STATUS_OUTTOLUNCH
66 ||lc->presence_mode==LINPHONE_STATUS_OFFLINE)
67 sal_call_decline(h,SalReasonTemporarilyUnavailable,NULL);
68 else if (lc->presence_mode==LINPHONE_STATUS_NOT_DISTURB)
69 sal_call_decline(h,SalReasonTemporarilyUnavailable,NULL);
70 else if (lc->alt_contact!=NULL && lc->presence_mode==LINPHONE_STATUS_MOVED)
71 sal_call_decline(h,SalReasonRedirect,lc->alt_contact);
73 sal_call_decline(h,SalReasonBusy,NULL);
77 if (!linphone_core_can_we_add_call(lc)){/*busy*/
78 sal_call_decline(h,SalReasonBusy,NULL);
82 from=sal_op_get_from(h);
85 call=linphone_call_new_incoming(lc,linphone_address_new(from),linphone_address_new(to),h);
87 if(linphone_core_get_current_call(lc)!=NULL) //we are already in call just inform that an incoming call is going on
90 snprintf(temp,sizeof(temp)-1,"A new incoming call from %s during call",from);
91 lc->vtable.display_status(lc,temp);
93 sal_call_set_local_media_description(h,call->localdesc);
94 call->resultdesc=sal_call_get_final_media_description(h);
96 sal_media_description_ref(call->resultdesc);
97 if (call->resultdesc && sal_media_description_empty(call->resultdesc)){
98 sal_call_decline(h,SalReasonMedia,NULL);
99 linphone_call_unref(call);
102 /* the call is acceptable so we can now add it to our list */
103 if(linphone_core_add_call(lc,call)!= 0)
105 ms_warning("we cannot handle anymore call\n");
106 sal_call_decline(h,SalReasonMedia,NULL);
107 linphone_call_unref(call);
110 from_parsed=linphone_address_new(sal_op_get_from(h));
111 linphone_address_clean(from_parsed);
112 tmp=linphone_address_as_string(from_parsed);
113 linphone_address_destroy(from_parsed);
115 gstate_new_state(lc, GSTATE_CALL_IN_INVITE, gctx, tmp);
116 barmesg=ortp_strdup_printf("%s %s%s",tmp,_("is contacting you"),
117 (sal_call_autoanswer_asked(h)) ?_(" and asked autoanswer."):_("."));
118 if (lc->vtable.show) lc->vtable.show(lc);
119 if (lc->vtable.display_status)
120 lc->vtable.display_status(lc,barmesg);
123 if (lc->sound_conf.ring_sndcard!=NULL && !linphone_core_in_call(lc)){
124 if(lc->ringstream==NULL){
125 MSSndCard *ringcard=lc->sound_conf.lsd_card ?lc->sound_conf.lsd_card : lc->sound_conf.ring_sndcard;
126 ms_message("Starting local ring...");
127 lc->ringstream=ring_start(lc->sound_conf.local_ring,2000,ringcard);
131 ms_message("the local ring is already started");
134 call->state=LinphoneCallRinging;
135 sal_call_notify_ringing(h);
136 #if !(__IPHONE_OS_VERSION_MIN_REQUIRED >= 40000)
137 linphone_core_init_media_streams(lc,lc->call);
139 if (lc->vtable.inv_recv) lc->vtable.inv_recv(lc,call);
145 static void call_ringing(SalOp *h){
146 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h));
147 LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(h);
148 SalMediaDescription *md;
149 LinphoneGeneralStateContext gctx;
151 if (call==NULL) return;
154 if (lc->vtable.display_status)
155 lc->vtable.display_status(lc,_("Remote ringing."));
156 if (lc->vtable.ringing_recv)
157 lc->vtable.ringing_recv(lc,call);
158 md=sal_call_get_final_media_description(h);
160 if (lc->ringstream!=NULL) return; /*already ringing !*/
161 if (lc->sound_conf.play_sndcard!=NULL){
162 MSSndCard *ringcard=lc->sound_conf.lsd_card ? lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard;
163 ms_message("Remote ringing...");
164 lc->ringstream=ring_start(lc->sound_conf.remote_ring,2000,ringcard);
166 gstate_new_state(lc, GSTATE_CALL_OUT_RINGING, gctx, NULL);
169 /*accept early media */
170 if (lc->audiostream && lc->audiostream->ticker!=NULL){
171 /*streams already started */
172 ms_message("Early media already started.");
175 sal_media_description_ref(md);
177 if (lc->vtable.show) lc->vtable.show(lc);
178 if (lc->vtable.display_status)
179 lc->vtable.display_status(lc,_("Early media."));
180 gstate_new_state(lc, GSTATE_CALL_OUT_RINGING, gctx, NULL);
181 if (lc->ringstream!=NULL){
182 ring_stop(lc->ringstream);
185 ms_message("Doing early media...");
186 if(call == linphone_core_get_current_call(lc))
187 linphone_core_start_media_streams(lc,call);
188 call->media_pending=TRUE;
190 call->state=LinphoneCallRinging;
195 * - when the call is accepted
196 * - when a request is accepted (pause, resume)
198 static void call_accepted(SalOp *op){
199 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
200 LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
201 LinphoneGeneralStateContext gctx;
203 ms_warning("No call to accept.");
207 if (call->state==LinphoneCallAVRunning){
208 ms_message("GET ACK of resume\n");
209 if(lc->vtable.ack_resumed_recv)
210 lc->vtable.ack_resumed_recv(lc,call);
211 return ; //already accepted
213 if ((lc->audiostream!=NULL) && (lc->audiostream->ticker!=NULL)){
214 /*case where we accepted early media */
215 if(call == linphone_core_get_current_call(lc))
217 linphone_core_stop_media_streams(lc,call);
218 linphone_core_init_media_streams(lc,call);
221 if (call->resultdesc)
222 sal_media_description_unref(call->resultdesc);
223 call->resultdesc=sal_call_get_final_media_description(op);
224 if (call->resultdesc){
225 sal_media_description_ref(call->resultdesc);
226 call->media_pending=FALSE;
228 if (call->resultdesc && !sal_media_description_empty(call->resultdesc)){
229 //if we initiate a pause
230 if(call->state == LinphoneCallPaused)
232 ms_message("GET ACK of pause\n");
233 if(lc->vtable.ack_paused_recv)
234 lc->vtable.ack_paused_recv(lc,call);
235 }//if there is an accepted incoming call
239 * Do not set the call as current here,
240 * because we can go through this function not only when an incoming call is accepted
242 //linphone_core_set_as_current_call (lc,call);
243 gstate_new_state(lc, GSTATE_CALL_OUT_CONNECTED, gctx, NULL);
244 linphone_connect_incoming(lc,call);
248 ms_error("Incompatible SDP offer received in 200Ok, need to abort the call");
249 linphone_core_terminate_call(lc,NULL);
253 static void call_ack(SalOp *op){
254 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
255 LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
256 LinphoneGeneralStateContext gctx;
258 ms_warning("No call to be ACK'd");
262 if (call->media_pending){
263 if (lc->audiostream->ticker!=NULL){
264 /*case where we accepted early media */
265 if(call == linphone_core_get_current_call(lc))
267 linphone_core_stop_media_streams(lc,call);
268 linphone_core_init_media_streams(lc,call);
271 if (call->resultdesc)
272 sal_media_description_unref(call->resultdesc);
273 call->resultdesc=sal_call_get_final_media_description(op);
274 if (call->resultdesc)
275 sal_media_description_ref(call->resultdesc);
276 if (call->resultdesc && !sal_media_description_empty(call->resultdesc)){
277 gstate_new_state(lc, GSTATE_CALL_IN_CONNECTED, gctx, NULL);
278 linphone_connect_incoming(lc,call);
281 ms_error("Incompatible SDP response received in ACK, need to abort the call");
282 linphone_core_terminate_call(lc,NULL);
284 call->media_pending=FALSE;
288 static void call_updated(SalOp *op){
289 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
290 LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
291 if (call->resultdesc)
292 sal_media_description_unref(call->resultdesc);
293 call->resultdesc=sal_call_get_final_media_description(op);
294 if (call->resultdesc)
295 sal_media_description_ref(call->resultdesc);
297 if (call->resultdesc && !sal_media_description_empty(call->resultdesc))
299 if( (call->state == LinphoneCallPaused) && strcmp(call->resultdesc->addr,"0.0.0.0"))
301 if(lc->vtable.display_status)
302 lc->vtable.display_status(lc,"we have been resumed...");
303 call->state = LinphoneCallAVRunning;
304 lc->vtable.resumed_recv(lc,call);
305 //we have to keep sending when holded
306 //linphone_core_start_media_streams(lc,call);
308 else if( (call->state != LinphoneCallPaused) && !strcmp(call->resultdesc->addr,"0.0.0.0"))
310 if(lc->vtable.display_status)
311 lc->vtable.display_status(lc,"we have been paused...");
312 call->state = LinphoneCallPaused;
313 lc->vtable.paused_recv(lc,call);
314 //we have to keep sending when holded
316 if(call == linphone_core_get_current_call(lc))
318 linphone_core_stop_media_streams(lc,call);
319 linphone_core_init_media_streams(lc,call);
325 if(call == linphone_core_get_current_call(lc))
327 linphone_core_stop_media_streams(lc,call);
328 linphone_core_init_media_streams(lc,call);
330 linphone_connect_incoming(lc,call);
335 static void call_terminated(SalOp *op, const char *from){
336 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
337 LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
338 LinphoneGeneralStateContext gctx;
340 if (linphone_call_get_state(call)==LinphoneCallTerminated){
341 ms_warning("call_terminated: ignoring.");
344 ms_message("Current call terminated...");
345 //we stop the call only if we have this current call or if we are in call
346 if (lc->ringstream!=NULL && ( (ms_list_size(lc->calls) == 1) || linphone_core_in_call(lc) )) {
347 ring_stop(lc->ringstream);
350 if(call == linphone_core_get_current_call(lc))
351 linphone_core_stop_media_streams(lc,call);
352 if (lc->vtable.show!=NULL)
354 if (lc->vtable.display_status!=NULL)
355 lc->vtable.display_status(lc,_("Call terminated."));
356 call->state=LinphoneCallTerminated;
357 gstate_new_state(lc, GSTATE_CALL_END, gctx, NULL);
358 if (lc->vtable.bye_recv!=NULL){
359 LinphoneAddress *addr=linphone_address_new(from);
361 linphone_address_clean(addr);
362 tmp=linphone_address_as_string(addr);
363 if (lc->vtable.bye_recv!=NULL)
364 lc->vtable.bye_recv(lc,call);
366 linphone_address_destroy(addr);
368 linphone_call_set_terminated(call);
371 static void call_failure(SalOp *op, SalError error, SalReason sr, const char *details, int code){
372 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
373 char *msg486=_("User is busy.");
374 char *msg480=_("User is temporarily unavailable.");
375 /*char *retrymsg=_("%s. Retry after %i minute(s).");*/
376 char *msg600=_("User does not want to be disturbed.");
377 char *msg603=_("Call declined.");
378 const char *msg=details;
379 LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
380 LinphoneGeneralStateContext gctx;
383 if (lc->vtable.show) lc->vtable.show(lc);
385 if (error==SalErrorNoResponse){
386 msg=_("No response.");
387 if (lc->vtable.display_status)
388 lc->vtable.display_status(lc,msg);
389 }else if (error==SalErrorProtocol){
390 msg=details ? details : _("Protocol error.");
391 if (lc->vtable.display_status)
392 lc->vtable.display_status(lc, msg);
393 }else if (error==SalErrorFailure){
395 case SalReasonDeclined:
397 if (lc->vtable.display_status)
398 lc->vtable.display_status(lc,msg603);
402 if (lc->vtable.display_status)
403 lc->vtable.display_status(lc,msg486);
405 case SalReasonRedirect:
407 if (lc->vtable.display_status)
408 lc->vtable.display_status(lc,msg);
410 case SalReasonTemporarilyUnavailable:
412 if (lc->vtable.display_status)
413 lc->vtable.display_status(lc,msg480);
415 case SalReasonNotFound:
417 if (lc->vtable.display_status)
418 lc->vtable.display_status(lc,msg);
420 case SalReasonDoNotDisturb:
422 if (lc->vtable.display_status)
423 lc->vtable.display_status(lc,msg600);
426 msg=_("No common codecs");
427 if (lc->vtable.display_status)
428 lc->vtable.display_status(lc,msg);
431 if (lc->vtable.display_status)
432 lc->vtable.display_status(lc,_("Call failed."));
435 if (lc->vtable.failure_recv)
436 lc->vtable.failure_recv(lc,call,code);
437 if (lc->ringstream!=NULL) {
438 ring_stop(lc->ringstream);
441 if(call == linphone_core_get_current_call(lc))
442 linphone_core_stop_media_streams(lc,call);
444 if (sr!=SalReasonDeclined) gstate_new_state(lc, GSTATE_CALL_ERROR, gctx, msg);
445 else gstate_new_state(lc, GSTATE_CALL_END, gctx, NULL);
446 linphone_call_set_terminated(call);
450 static void auth_requested(SalOp *h, const char *realm, const char *username){
451 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h));
452 LinphoneAuthInfo *ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,realm,username);
453 ms_message("auth_requested() for realm=%s, username=%s",realm,username);
454 if (ai && (ai->works || ai->usecount<3)){
456 sai.username=ai->username;
457 sai.userid=ai->userid;
459 sai.password=ai->passwd;
460 ms_message("auth_requested(): authenticating realm=%s, username=%s",realm,username);
461 sal_op_authenticate(h,&sai);
464 if (lc->vtable.auth_info_requested)
465 lc->vtable.auth_info_requested(lc,realm,username);
469 static void auth_success(SalOp *h, const char *realm, const char *username){
470 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h));
471 LinphoneAuthInfo *ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,realm,username);
473 ms_message("%s/%s authentication works.",realm,username);
478 static void register_success(SalOp *op, bool_t registered){
479 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
480 LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)sal_op_get_user_pointer(op);
482 LinphoneGeneralStateContext gctx;
484 cfg->registered=registered;
485 gstate_new_state(lc, GSTATE_REG_OK,gctx, NULL);
486 if (cfg->registered) msg=ms_strdup_printf(_("Registration on %s successful."),sal_op_get_proxy(op));
487 else msg=ms_strdup_printf(_("Unregistration on %s done."),sal_op_get_proxy(op));
488 if (lc->vtable.display_status)
489 lc->vtable.display_status(lc,msg);
493 static void register_failure(SalOp *op, SalError error, SalReason reason, const char *details){
494 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
495 LinphoneGeneralStateContext gctx;
496 char *msg=ortp_strdup_printf(_("Registration on %s failed: %s"),sal_op_get_proxy(op),(details!=NULL) ? details : _("no response timeout"));
497 if (lc->vtable.display_status) lc->vtable.display_status(lc,msg);
498 gctx.proxy=(LinphoneProxyConfig*)sal_op_get_user_pointer (op);
499 gstate_new_state(lc, GSTATE_REG_FAILED, gctx, msg);
503 static void vfu_request(SalOp *op){
505 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
507 video_stream_send_vfu(lc->videostream);
511 static void dtmf_received(SalOp *op, char dtmf){
512 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
513 LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
514 if (lc->vtable.dtmf_received != NULL)
515 lc->vtable.dtmf_received(lc, call, dtmf);
518 static void refer_received(Sal *sal, SalOp *op, const char *referto){
519 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal);
520 LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
521 if (lc->vtable.refer_received){
522 lc->vtable.refer_received(lc,call,referto);
523 if (op) sal_refer_accept(op);
527 static void text_received(Sal *sal, const char *from, const char *msg){
528 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal);
529 linphone_core_text_received(lc,from,msg);
532 static void notify(SalOp *op, const char *from, const char *msg){
533 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
535 ms_message("get a %s notify from %s",msg,from);
536 if(lc->vtable.notify_recv)
537 lc->vtable.notify_recv(lc,from,msg);
540 static void notify_presence(SalOp *op, SalSubscribeState ss, SalPresenceStatus status, const char *msg){
541 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
542 linphone_notify_recv(lc,op,ss,status);
545 static void subscribe_received(SalOp *op, const char *from){
546 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
547 linphone_subscription_new(lc,op,from);
550 static void subscribe_closed(SalOp *op, const char *from){
551 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
552 linphone_subscription_closed(lc,op);
555 static void internal_message(Sal *sal, const char *msg){
556 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal);
561 static void ping_reply(SalOp *op){
562 LinphoneCall *call=(LinphoneCall*) sal_op_get_user_pointer(op);
563 ms_message("ping reply !");
565 if (call->state==LinphoneCallPreEstablishing){
566 linphone_core_start_invite(call->core,call,NULL);
571 ms_warning("ping reply without call attached...");
575 SalCallbacks linphone_sal_callbacks={