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 ms_message("Starting local ring...");
104 lc->ringstream=ring_start(lc->sound_conf.local_ring,2000,lc->sound_conf.ring_sndcard);
106 linphone_call_set_state(call,LCStateRinging);
107 sal_call_notify_ringing(h);
108 linphone_core_init_media_streams(lc,lc->call);
109 if (lc->vtable.inv_recv) lc->vtable.inv_recv(lc,tmp);
114 static void call_ringing(SalOp *h){
115 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h));
116 LinphoneCall *call=lc->call;
117 SalMediaDescription *md;
118 if (call==NULL) return;
119 if (lc->vtable.display_status)
120 lc->vtable.display_status(lc,_("Remote ringing."));
121 md=sal_call_get_final_media_description(h);
123 if (lc->ringstream!=NULL) return; /*already ringing !*/
124 if (lc->sound_conf.play_sndcard!=NULL){
125 ms_message("Remote ringing...");
126 lc->ringstream=ring_start(lc->sound_conf.remote_ring,2000,lc->sound_conf.play_sndcard);
129 /*accept early media */
130 if (lc->audiostream && lc->audiostream->ticker!=NULL){
131 /*streams already started */
132 ms_message("Early media already started.");
135 sal_media_description_ref(md);
137 if (lc->vtable.show) lc->vtable.show(lc);
138 if (lc->vtable.display_status)
139 lc->vtable.display_status(lc,_("Early media."));
140 gstate_new_state(lc, GSTATE_CALL_OUT_CONNECTED, NULL);
141 if (lc->ringstream!=NULL){
142 ring_stop(lc->ringstream);
145 ms_message("Doing early media...");
146 linphone_core_start_media_streams(lc,call);
147 call->media_pending=TRUE;
149 call->state=LCStateRinging;
152 static void call_accepted(SalOp *op){
153 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
154 LinphoneCall *call=lc->call;
156 ms_warning("No call to accept.");
159 if (sal_op_get_user_pointer(op)!=lc->call){
160 ms_warning("call_accepted: ignoring.");
163 if (call->state==LCStateAVRunning){
164 return ; /*already accepted*/
166 if (lc->audiostream->ticker!=NULL){
167 /*case where we accepted early media */
168 linphone_core_stop_media_streams(lc,call);
169 linphone_core_init_media_streams(lc,call);
171 if (call->resultdesc)
172 sal_media_description_unref(call->resultdesc);
173 call->resultdesc=sal_call_get_final_media_description(op);
174 if (call->resultdesc){
175 sal_media_description_ref(call->resultdesc);
176 call->media_pending=FALSE;
178 if (call->resultdesc && !sal_media_description_empty(call->resultdesc)){
179 gstate_new_state(lc, GSTATE_CALL_OUT_CONNECTED, NULL);
180 linphone_connect_incoming(lc,call);
183 ms_error("Incompatible SDP offer received in 200Ok, need to abort the call");
184 linphone_core_terminate_call(lc,NULL);
188 static void call_ack(SalOp *op){
189 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
190 LinphoneCall *call=lc->call;
192 ms_warning("No call to be ACK'd");
195 if (sal_op_get_user_pointer(op)!=lc->call){
196 ms_warning("call_ack: ignoring.");
199 if (call->media_pending){
200 if (lc->audiostream->ticker!=NULL){
201 /*case where we accepted early media */
202 linphone_core_stop_media_streams(lc,call);
203 linphone_core_init_media_streams(lc,call);
205 if (call->resultdesc)
206 sal_media_description_unref(call->resultdesc);
207 call->resultdesc=sal_call_get_final_media_description(op);
208 if (call->resultdesc)
209 sal_media_description_ref(call->resultdesc);
210 if (call->resultdesc && !sal_media_description_empty(call->resultdesc)){
211 gstate_new_state(lc, GSTATE_CALL_IN_CONNECTED, NULL);
212 linphone_connect_incoming(lc,call);
215 ms_error("Incompatible SDP response received in ACK, need to abort the call");
216 linphone_core_terminate_call(lc,NULL);
218 call->media_pending=FALSE;
222 static void call_updated(SalOp *op){
223 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
224 LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
225 linphone_core_stop_media_streams(lc,call);
226 linphone_core_init_media_streams(lc,call);
227 if (call->resultdesc)
228 sal_media_description_unref(call->resultdesc);
229 call->resultdesc=sal_call_get_final_media_description(op);
230 if (call->resultdesc){
231 sal_media_description_ref(call->resultdesc);
232 if (sal_media_description_empty(call->resultdesc)){
233 linphone_connect_incoming(lc,call);
238 static void call_terminated(SalOp *op, const char *from){
239 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
240 if (sal_op_get_user_pointer(op)!=lc->call){
241 ms_warning("call_terminated: ignoring.");
244 ms_message("Current call terminated...");
245 if (lc->ringstream!=NULL) {
246 ring_stop(lc->ringstream);
249 linphone_core_stop_media_streams(lc,lc->call);
251 lc->vtable.display_status(lc,_("Call terminated."));
252 gstate_new_state(lc, GSTATE_CALL_END, NULL);
253 if (lc->vtable.bye_recv!=NULL){
254 LinphoneAddress *addr=linphone_address_new(from);
256 linphone_address_clean(addr);
257 tmp=linphone_address_as_string(addr);
258 lc->vtable.bye_recv(lc,tmp);
260 linphone_address_destroy(addr);
262 linphone_call_destroy(lc->call);
266 static void call_failure(SalOp *op, SalError error, SalReason sr, const char *details){
267 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
268 char *msg486=_("User is busy.");
269 char *msg480=_("User is temporarily unavailable.");
270 /*char *retrymsg=_("%s. Retry after %i minute(s).");*/
271 char *msg600=_("User does not want to be disturbed.");
272 char *msg603=_("Call declined.");
274 LinphoneCall *call=lc->call;
276 if (sal_op_get_user_pointer(op)!=lc->call){
277 ms_warning("call_failure: ignoring.");
280 if (lc->vtable.show) lc->vtable.show(lc);
282 if (error==SalErrorNoResponse){
283 if (lc->vtable.display_status)
284 lc->vtable.display_status(lc,_("No response."));
285 }else if (error==SalErrorProtocol){
286 if (lc->vtable.display_status)
287 lc->vtable.display_status(lc, details ? details : _("Protocol error."));
288 }else if (error==SalErrorFailure){
290 case SalReasonDeclined:
292 if (lc->vtable.display_status)
293 lc->vtable.display_status(lc,msg603);
297 if (lc->vtable.display_status)
298 lc->vtable.display_status(lc,msg486);
300 case SalReasonRedirect:
302 if (lc->vtable.display_status)
303 lc->vtable.display_status(lc,msg);
305 case SalReasonTemporarilyUnavailable:
307 if (lc->vtable.display_status)
308 lc->vtable.display_status(lc,msg480);
310 case SalReasonNotFound:
312 if (lc->vtable.display_status)
313 lc->vtable.display_status(lc,msg);
315 case SalReasonDoNotDisturb:
317 if (lc->vtable.display_status)
318 lc->vtable.display_status(lc,msg600);
321 msg=_("No common codecs");
322 if (lc->vtable.display_status)
323 lc->vtable.display_status(lc,msg);
326 if (lc->vtable.display_status)
327 lc->vtable.display_status(lc,_("Call failed."));
330 if (lc->ringstream!=NULL) {
331 ring_stop(lc->ringstream);
334 linphone_core_stop_media_streams(lc,call);
336 linphone_call_destroy(call);
337 if (sr!=SalReasonDeclined) gstate_new_state(lc, GSTATE_CALL_ERROR, msg);
338 else gstate_new_state(lc, GSTATE_CALL_END, NULL);
343 static void auth_requested(SalOp *h, const char *realm, const char *username){
344 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h));
345 LinphoneAuthInfo *ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,realm,username);
346 ms_message("auth_requested() for realm=%s, username=%s",realm,username);
347 if (ai && (ai->works || ai->usecount<3)){
349 sai.username=ai->username;
350 sai.userid=ai->userid;
352 sai.password=ai->passwd;
353 ms_message("auth_requested(): authenticating realm=%s, username=%s",realm,username);
354 sal_op_authenticate(h,&sai);
357 if (lc->vtable.auth_info_requested)
358 lc->vtable.auth_info_requested(lc,realm,username);
362 static void auth_success(SalOp *h, const char *realm, const char *username){
363 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h));
364 LinphoneAuthInfo *ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,realm,username);
366 ms_message("%s/%s authentication works.",realm,username);
371 static void register_success(SalOp *op, bool_t registered){
372 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
373 LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)sal_op_get_user_pointer(op);
375 cfg->registered=registered;
376 gstate_new_state(lc, GSTATE_REG_OK, NULL);
377 if (cfg->registered) msg=ms_strdup_printf(_("Registration on %s successful."),sal_op_get_proxy(op));
378 else msg=ms_strdup_printf(_("Unregistration on %s done."),sal_op_get_proxy(op));
379 if (lc->vtable.display_status)
380 lc->vtable.display_status(lc,msg);
384 static void register_failure(SalOp *op, SalError error, SalReason reason, const char *details){
385 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
386 char *msg=ortp_strdup_printf(_("Registration on %s failed: %s"),sal_op_get_proxy(op),(details!=NULL) ? details : _("no response timeout"));
387 if (lc->vtable.display_status) lc->vtable.display_status(lc,msg);
388 gstate_new_state(lc, GSTATE_REG_FAILED, msg);
392 static void vfu_request(SalOp *op){
394 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
396 video_stream_send_vfu(lc->videostream);
400 static void dtmf_received(SalOp *op, char dtmf){
401 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
402 if (lc->vtable.dtmf_received != NULL)
403 lc->vtable.dtmf_received(lc, dtmf);
406 static void refer_received(Sal *sal, SalOp *op, const char *referto){
407 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal);
408 if (lc->vtable.refer_received){
409 lc->vtable.refer_received(lc,referto);
410 if (op) sal_refer_accept(op);
414 static void text_received(Sal *sal, const char *from, const char *msg){
415 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal);
416 linphone_core_text_received(lc,from,msg);
419 static void notify(SalOp *op, const char *from, const char *msg){
420 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
422 ms_message("get a %s notify from %s",msg,from);
423 if(lc->vtable.notify_recv)
424 lc->vtable.notify_recv(lc,from,msg);
427 static void notify_presence(SalOp *op, SalSubscribeState ss, SalPresenceStatus status, const char *msg){
428 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
429 linphone_notify_recv(lc,op,ss,status);
432 static void subscribe_received(SalOp *op, const char *from){
433 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
434 linphone_subscription_new(lc,op,from);
437 static void subscribe_closed(SalOp *op, const char *from){
438 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
439 linphone_subscription_closed(lc,op);
442 static void internal_message(Sal *sal, const char *msg){
443 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal);
448 static void ping_reply(SalOp *op){
449 LinphoneCall *call=(LinphoneCall*) sal_op_get_user_pointer(op);
450 ms_message("ping reply !");
452 if (call->state==LCStatePreEstablishing){
453 linphone_core_start_invite(call->core,call,NULL);
458 SalCallbacks linphone_sal_callbacks={