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 call->state=LCStateAVRunning;
34 if (lc->ringstream!=NULL){
35 ring_stop(lc->ringstream);
38 linphone_core_start_media_streams(lc,call);
41 static void call_received(SalOp *h){
42 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h));
47 LinphoneAddress *from_parsed;
49 /* first check if we can answer successfully to this invite */
50 if (lc->presence_mode!=LINPHONE_STATUS_ONLINE){
51 ms_message("Not present !! presence mode : %d\n",lc->presence_mode);
52 if (lc->presence_mode==LINPHONE_STATUS_BUSY)
53 sal_call_decline(h,SalReasonBusy,NULL);
54 else if (lc->presence_mode==LINPHONE_STATUS_AWAY
55 ||lc->presence_mode==LINPHONE_STATUS_BERIGHTBACK
56 ||lc->presence_mode==LINPHONE_STATUS_ONTHEPHONE
57 ||lc->presence_mode==LINPHONE_STATUS_OUTTOLUNCH
58 ||lc->presence_mode==LINPHONE_STATUS_OFFLINE)
59 sal_call_decline(h,SalReasonTemporarilyUnavailable,NULL);
60 else if (lc->presence_mode==LINPHONE_STATUS_NOT_DISTURB)
61 sal_call_decline(h,SalReasonTemporarilyUnavailable,NULL);
62 else if (lc->alt_contact!=NULL && lc->presence_mode==LINPHONE_STATUS_MOVED)
63 sal_call_decline(h,SalReasonRedirect,lc->alt_contact);
65 sal_call_decline(h,SalReasonBusy,NULL);
69 if (lc->call!=NULL){/*busy*/
70 sal_call_decline(h,SalReasonBusy,NULL);
74 from=sal_op_get_from(h);
77 call=linphone_call_new_incoming(lc,linphone_address_new(from),linphone_address_new(to),h);
79 sal_call_set_local_media_description(h,call->localdesc);
80 call->resultdesc=sal_call_get_final_media_description(h);
82 sal_media_description_ref(call->resultdesc);
83 if (call->resultdesc && sal_media_description_empty(call->resultdesc)){
84 sal_call_decline(h,SalReasonMedia,NULL);
85 linphone_call_destroy(call);
90 from_parsed=linphone_address_new(sal_op_get_from(h));
91 linphone_address_clean(from_parsed);
92 tmp=linphone_address_as_string(from_parsed);
93 linphone_address_destroy(from_parsed);
94 gstate_new_state(lc, GSTATE_CALL_IN_INVITE, tmp);
95 barmesg=ortp_strdup_printf("%s %s%s",tmp,_("is contacting you"),
96 (sal_call_autoanswer_asked(h)) ?_(" and asked autoanswer."):_("."));
97 if (lc->vtable.show) lc->vtable.show(lc);
98 if (lc->vtable.display_status)
99 lc->vtable.display_status(lc,barmesg);
102 if (lc->sound_conf.ring_sndcard!=NULL){
103 MSSndCard *ringcard=lc->sound_conf.lsd_card ? lc->sound_conf.lsd_card : lc->sound_conf.ring_sndcard;
104 ms_message("Starting local ring...");
105 lc->ringstream=ring_start(lc->sound_conf.local_ring,2000,ringcard);
107 linphone_call_set_state(call,LCStateRinging);
108 sal_call_notify_ringing(h);
109 linphone_core_init_media_streams(lc,lc->call);
110 if (lc->vtable.inv_recv) lc->vtable.inv_recv(lc,tmp);
115 static void call_ringing(SalOp *h){
116 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h));
117 LinphoneCall *call=lc->call;
118 SalMediaDescription *md;
119 if (call==NULL) return;
120 if (lc->vtable.display_status)
121 lc->vtable.display_status(lc,_("Remote ringing."));
122 md=sal_call_get_final_media_description(h);
124 if (lc->ringstream!=NULL) return; /*already ringing !*/
125 if (lc->sound_conf.play_sndcard!=NULL){
126 MSSndCard *ringcard=lc->sound_conf.lsd_card ? lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard;
127 ms_message("Remote ringing...");
128 lc->ringstream=ring_start(lc->sound_conf.remote_ring,2000,ringcard);
131 /*accept early media */
132 if (lc->audiostream && lc->audiostream->ticker!=NULL){
133 /*streams already started */
134 ms_message("Early media already started.");
137 sal_media_description_ref(md);
139 if (lc->vtable.show) lc->vtable.show(lc);
140 if (lc->vtable.display_status)
141 lc->vtable.display_status(lc,_("Early media."));
142 gstate_new_state(lc, GSTATE_CALL_OUT_CONNECTED, NULL);
143 if (lc->ringstream!=NULL){
144 ring_stop(lc->ringstream);
147 ms_message("Doing early media...");
148 linphone_core_start_media_streams(lc,call);
149 call->media_pending=TRUE;
151 call->state=LCStateRinging;
154 static void call_accepted(SalOp *op){
155 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
156 LinphoneCall *call=lc->call;
158 ms_warning("No call to accept.");
161 if (sal_op_get_user_pointer(op)!=lc->call){
162 ms_warning("call_accepted: ignoring.");
165 if (call->state==LCStateAVRunning){
166 return ; /*already accepted*/
168 if (lc->audiostream->ticker!=NULL){
169 /*case where we accepted early media */
170 linphone_core_stop_media_streams(lc,call);
171 linphone_core_init_media_streams(lc,call);
173 if (call->resultdesc)
174 sal_media_description_unref(call->resultdesc);
175 call->resultdesc=sal_call_get_final_media_description(op);
176 if (call->resultdesc){
177 sal_media_description_ref(call->resultdesc);
178 call->media_pending=FALSE;
180 if (call->resultdesc && !sal_media_description_empty(call->resultdesc)){
181 gstate_new_state(lc, GSTATE_CALL_OUT_CONNECTED, NULL);
182 linphone_connect_incoming(lc,call);
185 ms_error("Incompatible SDP offer received in 200Ok, need to abort the call");
186 linphone_core_terminate_call(lc,NULL);
190 static void call_ack(SalOp *op){
191 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
192 LinphoneCall *call=lc->call;
194 ms_warning("No call to be ACK'd");
197 if (sal_op_get_user_pointer(op)!=lc->call){
198 ms_warning("call_ack: ignoring.");
201 if (call->media_pending){
202 if (lc->audiostream->ticker!=NULL){
203 /*case where we accepted early media */
204 linphone_core_stop_media_streams(lc,call);
205 linphone_core_init_media_streams(lc,call);
207 if (call->resultdesc)
208 sal_media_description_unref(call->resultdesc);
209 call->resultdesc=sal_call_get_final_media_description(op);
210 if (call->resultdesc)
211 sal_media_description_ref(call->resultdesc);
212 if (call->resultdesc && !sal_media_description_empty(call->resultdesc)){
213 gstate_new_state(lc, GSTATE_CALL_IN_CONNECTED, NULL);
214 linphone_connect_incoming(lc,call);
217 ms_error("Incompatible SDP response received in ACK, need to abort the call");
218 linphone_core_terminate_call(lc,NULL);
220 call->media_pending=FALSE;
224 static void call_updated(SalOp *op){
225 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
226 LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
227 linphone_core_stop_media_streams(lc,call);
228 linphone_core_init_media_streams(lc,call);
229 if (call->resultdesc)
230 sal_media_description_unref(call->resultdesc);
231 call->resultdesc=sal_call_get_final_media_description(op);
232 if (call->resultdesc){
233 sal_media_description_ref(call->resultdesc);
234 if (sal_media_description_empty(call->resultdesc)){
235 linphone_connect_incoming(lc,call);
240 static void call_terminated(SalOp *op, const char *from){
241 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
242 if (sal_op_get_user_pointer(op)!=lc->call){
243 ms_warning("call_terminated: ignoring.");
246 ms_message("Current call terminated...");
247 if (lc->ringstream!=NULL) {
248 ring_stop(lc->ringstream);
251 linphone_core_stop_media_streams(lc,lc->call);
253 lc->vtable.display_status(lc,_("Call terminated."));
254 gstate_new_state(lc, GSTATE_CALL_END, NULL);
255 if (lc->vtable.bye_recv!=NULL){
256 LinphoneAddress *addr=linphone_address_new(from);
258 linphone_address_clean(addr);
259 tmp=linphone_address_as_string(addr);
260 lc->vtable.bye_recv(lc,tmp);
262 linphone_address_destroy(addr);
264 linphone_call_destroy(lc->call);
268 static void call_failure(SalOp *op, SalError error, SalReason sr, const char *details){
269 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
270 char *msg486=_("User is busy.");
271 char *msg480=_("User is temporarily unavailable.");
272 /*char *retrymsg=_("%s. Retry after %i minute(s).");*/
273 char *msg600=_("User does not want to be disturbed.");
274 char *msg603=_("Call declined.");
276 LinphoneCall *call=lc->call;
278 if (sal_op_get_user_pointer(op)!=lc->call){
279 ms_warning("call_failure: ignoring.");
282 if (lc->vtable.show) lc->vtable.show(lc);
284 if (error==SalErrorNoResponse){
285 if (lc->vtable.display_status)
286 lc->vtable.display_status(lc,_("No response."));
287 }else if (error==SalErrorProtocol){
288 if (lc->vtable.display_status)
289 lc->vtable.display_status(lc, details ? details : _("Protocol error."));
290 }else if (error==SalErrorFailure){
292 case SalReasonDeclined:
294 if (lc->vtable.display_status)
295 lc->vtable.display_status(lc,msg603);
299 if (lc->vtable.display_status)
300 lc->vtable.display_status(lc,msg486);
302 case SalReasonRedirect:
304 if (lc->vtable.display_status)
305 lc->vtable.display_status(lc,msg);
307 case SalReasonTemporarilyUnavailable:
309 if (lc->vtable.display_status)
310 lc->vtable.display_status(lc,msg480);
312 case SalReasonNotFound:
314 if (lc->vtable.display_status)
315 lc->vtable.display_status(lc,msg);
317 case SalReasonDoNotDisturb:
319 if (lc->vtable.display_status)
320 lc->vtable.display_status(lc,msg600);
323 msg=_("No common codecs");
324 if (lc->vtable.display_status)
325 lc->vtable.display_status(lc,msg);
328 if (lc->vtable.display_status)
329 lc->vtable.display_status(lc,_("Call failed."));
332 if (lc->ringstream!=NULL) {
333 ring_stop(lc->ringstream);
336 linphone_core_stop_media_streams(lc,call);
338 linphone_call_destroy(call);
339 if (sr!=SalReasonDeclined) gstate_new_state(lc, GSTATE_CALL_ERROR, msg);
340 else gstate_new_state(lc, GSTATE_CALL_END, NULL);
345 static void auth_requested(SalOp *h, const char *realm, const char *username){
346 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h));
347 LinphoneAuthInfo *ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,realm,username);
348 ms_message("auth_requested() for realm=%s, username=%s",realm,username);
349 if (ai && (ai->works || ai->usecount<3)){
351 sai.username=ai->username;
352 sai.userid=ai->userid;
354 sai.password=ai->passwd;
355 ms_message("auth_requested(): authenticating realm=%s, username=%s",realm,username);
356 sal_op_authenticate(h,&sai);
359 if (lc->vtable.auth_info_requested)
360 lc->vtable.auth_info_requested(lc,realm,username);
364 static void auth_success(SalOp *h, const char *realm, const char *username){
365 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h));
366 LinphoneAuthInfo *ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,realm,username);
368 ms_message("%s/%s authentication works.",realm,username);
373 static void register_success(SalOp *op, bool_t registered){
374 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
375 LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)sal_op_get_user_pointer(op);
377 cfg->registered=registered;
378 gstate_new_state(lc, GSTATE_REG_OK, NULL);
379 if (cfg->registered) msg=ms_strdup_printf(_("Registration on %s successful."),sal_op_get_proxy(op));
380 else msg=ms_strdup_printf(_("Unregistration on %s done."),sal_op_get_proxy(op));
381 if (lc->vtable.display_status)
382 lc->vtable.display_status(lc,msg);
386 static void register_failure(SalOp *op, SalError error, SalReason reason, const char *details){
387 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
388 char *msg=ortp_strdup_printf(_("Registration on %s failed: %s"),sal_op_get_proxy(op),(details!=NULL) ? details : _("no response timeout"));
389 if (lc->vtable.display_status) lc->vtable.display_status(lc,msg);
390 gstate_new_state(lc, GSTATE_REG_FAILED, msg);
394 static void vfu_request(SalOp *op){
396 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
398 video_stream_send_vfu(lc->videostream);
402 static void dtmf_received(SalOp *op, char dtmf){
403 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
404 if (lc->vtable.dtmf_received != NULL)
405 lc->vtable.dtmf_received(lc, dtmf);
408 static void refer_received(Sal *sal, SalOp *op, const char *referto){
409 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal);
410 if (lc->vtable.refer_received){
411 lc->vtable.refer_received(lc,referto);
412 if (op) sal_refer_accept(op);
416 static void text_received(Sal *sal, const char *from, const char *msg){
417 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal);
418 linphone_core_text_received(lc,from,msg);
421 static void notify(SalOp *op, const char *from, const char *msg){
422 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
424 ms_message("get a %s notify from %s",msg,from);
425 if(lc->vtable.notify_recv)
426 lc->vtable.notify_recv(lc,from,msg);
429 static void notify_presence(SalOp *op, SalSubscribeState ss, SalPresenceStatus status, const char *msg){
430 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
431 linphone_notify_recv(lc,op,ss,status);
434 static void subscribe_received(SalOp *op, const char *from){
435 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
436 linphone_subscription_new(lc,op,from);
439 static void subscribe_closed(SalOp *op, const char *from){
440 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
441 linphone_subscription_closed(lc,op);
444 static void internal_message(Sal *sal, const char *msg){
445 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal);
450 static void ping_reply(SalOp *op){
451 LinphoneCall *call=(LinphoneCall*) sal_op_get_user_pointer(op);
452 ms_message("ping reply !");
454 if (call->state==LCStatePreEstablishing){
455 linphone_core_start_invite(call->core,call,NULL);
460 SalCallbacks linphone_sal_callbacks={