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 linphone_core_add_call(lc,call);
105 from_parsed=linphone_address_new(sal_op_get_from(h));
106 linphone_address_clean(from_parsed);
107 tmp=linphone_address_as_string(from_parsed);
108 linphone_address_destroy(from_parsed);
110 gstate_new_state(lc, GSTATE_CALL_IN_INVITE, gctx, tmp);
111 barmesg=ortp_strdup_printf("%s %s%s",tmp,_("is contacting you"),
112 (sal_call_autoanswer_asked(h)) ?_(" and asked autoanswer."):_("."));
113 if (lc->vtable.show) lc->vtable.show(lc);
114 if (lc->vtable.display_status)
115 lc->vtable.display_status(lc,barmesg);
118 if (lc->sound_conf.ring_sndcard!=NULL && !linphone_core_in_call(lc)){
119 if(lc->ringstream==NULL){
120 MSSndCard *ringcard=lc->sound_conf.lsd_card ?lc->sound_conf.lsd_card : lc->sound_conf.ring_sndcard;
121 ms_message("Starting local ring...");
122 lc->ringstream=ring_start(lc->sound_conf.local_ring,2000,ringcard);
126 ms_message("the local ring is already started");
129 call->state=LinphoneCallRinging;
130 sal_call_notify_ringing(h);
131 linphone_core_init_media_streams(lc,call);
132 if (lc->vtable.inv_recv) lc->vtable.inv_recv(lc,call);
137 static void call_ringing(SalOp *h){
138 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h));
139 LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(h);
140 SalMediaDescription *md;
141 LinphoneGeneralStateContext gctx;
143 if (call==NULL) return;
146 if (lc->vtable.display_status)
147 lc->vtable.display_status(lc,_("Remote ringing."));
148 if (lc->vtable.ringing_recv)
149 lc->vtable.ringing_recv(lc,call);
150 md=sal_call_get_final_media_description(h);
152 if (lc->ringstream!=NULL) return; /*already ringing !*/
153 if (lc->sound_conf.play_sndcard!=NULL){
154 MSSndCard *ringcard=lc->sound_conf.lsd_card ? lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard;
155 ms_message("Remote ringing...");
156 lc->ringstream=ring_start(lc->sound_conf.remote_ring,2000,ringcard);
158 gstate_new_state(lc, GSTATE_CALL_OUT_RINGING, gctx, NULL);
161 /*accept early media */
162 if (lc->audiostream && lc->audiostream->ticker!=NULL){
163 /*streams already started */
164 ms_message("Early media already started.");
167 sal_media_description_ref(md);
169 if (lc->vtable.show) lc->vtable.show(lc);
170 if (lc->vtable.display_status)
171 lc->vtable.display_status(lc,_("Early media."));
172 gstate_new_state(lc, GSTATE_CALL_OUT_RINGING, gctx, NULL);
173 if (lc->ringstream!=NULL){
174 ring_stop(lc->ringstream);
177 ms_message("Doing early media...");
178 if(call == linphone_core_get_current_call(lc))
179 linphone_core_start_media_streams(lc,call);
180 call->media_pending=TRUE;
182 call->state=LinphoneCallRinging;
187 * - when the call is accepted
188 * - when a request is accepted (pause, resume)
190 static void call_accepted(SalOp *op){
191 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
192 LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
193 LinphoneGeneralStateContext gctx;
195 ms_warning("No call to accept.");
199 if (call->state==LinphoneCallAVRunning){
200 ms_message("GET ACK of resume\n");
201 if(lc->vtable.ack_resumed_recv)
202 lc->vtable.ack_resumed_recv(lc,call);
203 return ; //already accepted
205 if ((lc->audiostream!=NULL) && (lc->audiostream->ticker!=NULL)){
206 /*case where we accepted early media */
207 if(call == linphone_core_get_current_call(lc))
209 linphone_core_stop_media_streams(lc,call);
210 linphone_core_init_media_streams(lc,call);
213 if (call->resultdesc)
214 sal_media_description_unref(call->resultdesc);
215 call->resultdesc=sal_call_get_final_media_description(op);
216 if (call->resultdesc){
217 sal_media_description_ref(call->resultdesc);
218 call->media_pending=FALSE;
220 if (call->resultdesc && !sal_media_description_empty(call->resultdesc)){
221 //if we initiate a pause
222 if(call->state == LinphoneCallPaused)
224 ms_message("GET ACK of pause\n");
225 if(lc->vtable.ack_paused_recv)
226 lc->vtable.ack_paused_recv(lc,call);
227 }//if there is an accepted incoming call
230 linphone_core_set_as_current_call (lc,call);
231 gstate_new_state(lc, GSTATE_CALL_OUT_CONNECTED, gctx, NULL);
232 linphone_connect_incoming(lc,call);
236 ms_error("Incompatible SDP offer received in 200Ok, need to abort the call");
237 linphone_core_terminate_call(lc,NULL);
241 static void call_ack(SalOp *op){
242 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
243 LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
244 LinphoneGeneralStateContext gctx;
246 ms_warning("No call to be ACK'd");
250 if (call->media_pending){
251 if (lc->audiostream->ticker!=NULL){
252 /*case where we accepted early media */
253 if(call == linphone_core_get_current_call(lc))
255 linphone_core_stop_media_streams(lc,call);
256 linphone_core_init_media_streams(lc,call);
259 if (call->resultdesc)
260 sal_media_description_unref(call->resultdesc);
261 call->resultdesc=sal_call_get_final_media_description(op);
262 if (call->resultdesc)
263 sal_media_description_ref(call->resultdesc);
264 if (call->resultdesc && !sal_media_description_empty(call->resultdesc)){
265 gstate_new_state(lc, GSTATE_CALL_IN_CONNECTED, gctx, NULL);
266 linphone_connect_incoming(lc,call);
269 ms_error("Incompatible SDP response received in ACK, need to abort the call");
270 linphone_core_terminate_call(lc,NULL);
272 call->media_pending=FALSE;
276 static void call_updated(SalOp *op){
277 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
278 LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
279 if (call->resultdesc)
280 sal_media_description_unref(call->resultdesc);
281 call->resultdesc=sal_call_get_final_media_description(op);
282 if (call->resultdesc)
283 sal_media_description_ref(call->resultdesc);
285 if (call->resultdesc && !sal_media_description_empty(call->resultdesc))
287 if( (call->state == LinphoneCallPaused) && strcmp(call->resultdesc->addr,"0.0.0.0"))
289 if(lc->vtable.display_status)
290 lc->vtable.display_status(lc,"we have been resumed...");
291 call->state = LinphoneCallAVRunning;
292 lc->vtable.resumed_recv(lc,call);
293 //we have to keep sending when holded
294 //linphone_core_start_media_streams(lc,call);
296 else if( (call->state != LinphoneCallPaused) && !strcmp(call->resultdesc->addr,"0.0.0.0"))
298 if(lc->vtable.display_status)
299 lc->vtable.display_status(lc,"we have been paused...");
300 call->state = LinphoneCallPaused;
301 lc->vtable.paused_recv(lc,call);
302 //we have to keep sending when holded
304 if(call == linphone_core_get_current_call(lc))
306 linphone_core_stop_media_streams(lc,call);
307 linphone_core_init_media_streams(lc,call);
313 if(call == linphone_core_get_current_call(lc))
315 linphone_core_stop_media_streams(lc,call);
316 linphone_core_init_media_streams(lc,call);
318 linphone_connect_incoming(lc,call);
323 static void call_terminated(SalOp *op, const char *from){
324 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
325 LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
326 LinphoneGeneralStateContext gctx;
328 if (linphone_call_get_state(call)==LinphoneCallTerminated){
329 ms_warning("call_terminated: ignoring.");
332 ms_message("Current call terminated...");
333 //we stop the call only if we have this current call or if we are in call
334 if (lc->ringstream!=NULL && ( (ms_list_size(lc->calls) == 1) || linphone_core_in_call(lc) )) {
335 ring_stop(lc->ringstream);
338 if(call == linphone_core_get_current_call(lc))
339 linphone_core_stop_media_streams(lc,call);
340 if (lc->vtable.show!=NULL)
342 if (lc->vtable.display_status!=NULL)
343 lc->vtable.display_status(lc,_("Call terminated."));
344 call->state=LinphoneCallTerminated;
345 gstate_new_state(lc, GSTATE_CALL_END, gctx, NULL);
346 if (lc->vtable.bye_recv!=NULL){
347 LinphoneAddress *addr=linphone_address_new(from);
349 linphone_address_clean(addr);
350 tmp=linphone_address_as_string(addr);
351 if (lc->vtable.bye_recv!=NULL)
352 lc->vtable.bye_recv(lc,call);
354 linphone_address_destroy(addr);
356 linphone_call_set_terminated(call);
359 static void call_failure(SalOp *op, SalError error, SalReason sr, const char *details, int code){
360 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
361 char *msg486=_("User is busy.");
362 char *msg480=_("User is temporarily unavailable.");
363 /*char *retrymsg=_("%s. Retry after %i minute(s).");*/
364 char *msg600=_("User does not want to be disturbed.");
365 char *msg603=_("Call declined.");
366 char *msg=(char*)details;
367 LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
368 LinphoneGeneralStateContext gctx;
371 if (lc->vtable.show) lc->vtable.show(lc);
373 if (error==SalErrorNoResponse){
374 if (lc->vtable.display_status)
375 lc->vtable.display_status(lc,_("No response."));
376 }else if (error==SalErrorProtocol){
377 if (lc->vtable.display_status)
378 lc->vtable.display_status(lc, details ? details : _("Protocol error."));
379 }else if (error==SalErrorFailure){
381 case SalReasonDeclined:
383 if (lc->vtable.display_status)
384 lc->vtable.display_status(lc,msg603);
388 if (lc->vtable.display_status)
389 lc->vtable.display_status(lc,msg486);
391 case SalReasonRedirect:
393 if (lc->vtable.display_status)
394 lc->vtable.display_status(lc,msg);
396 case SalReasonTemporarilyUnavailable:
398 if (lc->vtable.display_status)
399 lc->vtable.display_status(lc,msg480);
401 case SalReasonNotFound:
403 if (lc->vtable.display_status)
404 lc->vtable.display_status(lc,msg);
406 case SalReasonDoNotDisturb:
408 if (lc->vtable.display_status)
409 lc->vtable.display_status(lc,msg600);
412 msg=_("No common codecs");
413 if (lc->vtable.display_status)
414 lc->vtable.display_status(lc,msg);
417 if (lc->vtable.display_status)
418 lc->vtable.display_status(lc,_("Call failed."));
421 if (lc->vtable.failure_recv)
422 lc->vtable.failure_recv(lc,call,code);
423 if (lc->ringstream!=NULL) {
424 ring_stop(lc->ringstream);
427 if(call == linphone_core_get_current_call(lc))
428 linphone_core_stop_media_streams(lc,call);
430 if (sr!=SalReasonDeclined) gstate_new_state(lc, GSTATE_CALL_ERROR, gctx, msg);
431 else gstate_new_state(lc, GSTATE_CALL_END, gctx, NULL);
432 linphone_call_set_terminated(call);
436 static void auth_requested(SalOp *h, const char *realm, const char *username){
437 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h));
438 LinphoneAuthInfo *ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,realm,username);
439 ms_message("auth_requested() for realm=%s, username=%s",realm,username);
440 if (ai && (ai->works || ai->usecount<3)){
442 sai.username=ai->username;
443 sai.userid=ai->userid;
445 sai.password=ai->passwd;
446 ms_message("auth_requested(): authenticating realm=%s, username=%s",realm,username);
447 sal_op_authenticate(h,&sai);
450 if (lc->vtable.auth_info_requested)
451 lc->vtable.auth_info_requested(lc,realm,username);
455 static void auth_success(SalOp *h, const char *realm, const char *username){
456 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h));
457 LinphoneAuthInfo *ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,realm,username);
459 ms_message("%s/%s authentication works.",realm,username);
464 static void register_success(SalOp *op, bool_t registered){
465 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
466 LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)sal_op_get_user_pointer(op);
468 LinphoneGeneralStateContext gctx;
470 cfg->registered=registered;
471 gstate_new_state(lc, GSTATE_REG_OK,gctx, NULL);
472 if (cfg->registered) msg=ms_strdup_printf(_("Registration on %s successful."),sal_op_get_proxy(op));
473 else msg=ms_strdup_printf(_("Unregistration on %s done."),sal_op_get_proxy(op));
474 if (lc->vtable.display_status)
475 lc->vtable.display_status(lc,msg);
479 static void register_failure(SalOp *op, SalError error, SalReason reason, const char *details){
480 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
481 LinphoneGeneralStateContext gctx;
482 char *msg=ortp_strdup_printf(_("Registration on %s failed: %s"),sal_op_get_proxy(op),(details!=NULL) ? details : _("no response timeout"));
483 if (lc->vtable.display_status) lc->vtable.display_status(lc,msg);
484 gctx.proxy=(LinphoneProxyConfig*)sal_op_get_user_pointer (op);
485 gstate_new_state(lc, GSTATE_REG_FAILED, gctx, msg);
489 static void vfu_request(SalOp *op){
491 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
493 video_stream_send_vfu(lc->videostream);
497 static void dtmf_received(SalOp *op, char dtmf){
498 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
499 if (lc->vtable.dtmf_received != NULL)
500 lc->vtable.dtmf_received(lc, dtmf);
503 static void refer_received(Sal *sal, SalOp *op, const char *referto){
504 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal);
505 LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
506 if (lc->vtable.refer_received){
507 lc->vtable.refer_received(lc,call,referto);
508 if (op) sal_refer_accept(op);
512 static void text_received(Sal *sal, const char *from, const char *msg){
513 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal);
514 linphone_core_text_received(lc,from,msg);
517 static void notify(SalOp *op, const char *from, const char *msg){
518 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
520 ms_message("get a %s notify from %s",msg,from);
521 if(lc->vtable.notify_recv)
522 lc->vtable.notify_recv(lc,from,msg);
525 static void notify_presence(SalOp *op, SalSubscribeState ss, SalPresenceStatus status, const char *msg){
526 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
527 linphone_notify_recv(lc,op,ss,status);
530 static void subscribe_received(SalOp *op, const char *from){
531 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
532 linphone_subscription_new(lc,op,from);
535 static void subscribe_closed(SalOp *op, const char *from){
536 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
537 linphone_subscription_closed(lc,op);
540 static void internal_message(Sal *sal, const char *msg){
541 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal);
546 static void ping_reply(SalOp *op){
547 LinphoneCall *call=(LinphoneCall*) sal_op_get_user_pointer(op);
548 ms_message("ping reply !");
550 if (call->state==LinphoneCallPreEstablishing){
551 linphone_core_start_invite(call->core,call,NULL);
556 ms_warning("ping reply without call attached...");
560 SalCallbacks linphone_sal_callbacks={