]> sjero.net Git - linphone/blob - coreapi/callbacks.c
3431614928e8662c622cea445540525bd9b10a40
[linphone] / coreapi / callbacks.c
1 /*
2 linphone
3 Copyright (C) 2010  Simon MORLAT (simon.morlat@free.fr)
4
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.
9
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.
14
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.
18 */
19
20
21 #include "sal.h"
22
23 #include "linphonecore.h"
24 #include "private.h"
25 #include "mediastreamer2/mediastream.h"
26
27 static void linphone_connect_incoming(LinphoneCore *lc, LinphoneCall *call){
28         if (lc->vtable.show)
29                 lc->vtable.show(lc);
30         if (lc->vtable.display_status)
31                 lc->vtable.display_status(lc,_("Connected."));
32         call->state=LCStateAVRunning;
33         if (lc->ringstream!=NULL){
34                 ring_stop(lc->ringstream);
35                 lc->ringstream=NULL;
36         }
37         linphone_core_start_media_streams(lc,call);
38 }
39
40 static void call_received(SalOp *h){
41         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h));
42         char *barmesg;
43         LinphoneCall *call;
44         const char *from,*to;
45         char *tmp;
46         LinphoneAddress *from_parsed;
47
48         /* first check if we can answer successfully to this invite */
49         if (lc->presence_mode!=LINPHONE_STATUS_ONLINE){
50                 ms_message("Not present !! presence mode : %d\n",lc->presence_mode);
51                 if (lc->presence_mode==LINPHONE_STATUS_BUSY)
52                         sal_call_decline(h,SalReasonBusy,NULL);
53                 else if (lc->presence_mode==LINPHONE_STATUS_AWAY
54                          ||lc->presence_mode==LINPHONE_STATUS_BERIGHTBACK
55                          ||lc->presence_mode==LINPHONE_STATUS_ONTHEPHONE
56                          ||lc->presence_mode==LINPHONE_STATUS_OUTTOLUNCH
57                          ||lc->presence_mode==LINPHONE_STATUS_OFFLINE)
58                         sal_call_decline(h,SalReasonTemporarilyUnavailable,NULL);
59                 else if (lc->presence_mode==LINPHONE_STATUS_NOT_DISTURB)
60                         sal_call_decline(h,SalReasonTemporarilyUnavailable,NULL);
61                 else if (lc->alt_contact!=NULL && lc->presence_mode==LINPHONE_STATUS_MOVED)
62                         sal_call_decline(h,SalReasonRedirect,lc->alt_contact);
63                 else
64                         sal_call_decline(h,SalReasonBusy,NULL);
65                 sal_op_release(h);
66                 return;
67         }
68         if (lc->call!=NULL){/*busy*/
69                 sal_call_decline(h,SalReasonBusy,NULL);
70                 sal_op_release(h);
71                 return;
72         }
73         from=sal_op_get_from(h);
74         to=sal_op_get_to(h);
75         
76         call=linphone_call_new_incoming(lc,linphone_address_new(from),linphone_address_new(to),h);
77         lc->call=call;
78         sal_call_set_local_media_description(h,call->localdesc);
79         call->resultdesc=sal_call_get_final_media_description(h);
80         if (call->resultdesc)
81                 sal_media_description_ref(call->resultdesc);
82         if (call->resultdesc && sal_media_description_empty(call->resultdesc)){
83                 sal_call_decline(h,SalReasonMedia,NULL);
84                 linphone_call_destroy(call);
85                 lc->call=NULL;
86                 return;
87         }
88         
89         from_parsed=linphone_address_new(sal_op_get_from(h));
90         linphone_address_clean(from_parsed);
91         tmp=linphone_address_as_string(from_parsed);
92         linphone_address_destroy(from_parsed);
93         gstate_new_state(lc, GSTATE_CALL_IN_INVITE, tmp);
94         barmesg=ortp_strdup_printf(_("%s is contacting you"),tmp);
95         if (lc->vtable.show) lc->vtable.show(lc);
96         if (lc->vtable.display_status) 
97             lc->vtable.display_status(lc,barmesg);
98
99         /* play the ring */
100         if (lc->sound_conf.ring_sndcard!=NULL){
101                 ms_message("Starting local ring...");
102                 lc->ringstream=ring_start(lc->sound_conf.local_ring,2000,lc->sound_conf.ring_sndcard);
103         }
104         linphone_call_set_state(call,LCStateRinging);
105         sal_call_notify_ringing(h);
106         linphone_core_init_media_streams(lc,lc->call);
107         if (lc->vtable.inv_recv) lc->vtable.inv_recv(lc,tmp);
108         ms_free(barmesg);
109         ms_free(tmp);
110 }
111
112 static void call_ringing(SalOp *h){
113         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h));
114         LinphoneCall *call=lc->call;
115         SalMediaDescription *md;
116         if (call==NULL) return;
117         if (lc->vtable.display_status)
118                 lc->vtable.display_status(lc,_("Remote ringing."));
119         md=sal_call_get_final_media_description(h);
120         if (md==NULL){
121                 if (lc->ringstream!=NULL) return;       /*already ringing !*/
122                 if (lc->sound_conf.play_sndcard!=NULL){
123                         ms_message("Remote ringing...");
124                         lc->ringstream=ring_start(lc->sound_conf.remote_ring,2000,lc->sound_conf.play_sndcard);
125                 }
126         }else{
127                 /*accept early media */
128                 if (lc->audiostream && lc->audiostream->ticker!=NULL){
129                         /*streams already started */
130                         ms_message("Early media already started.");
131                         return;
132                 }
133                 sal_media_description_ref(md);
134                 call->resultdesc=md;
135                 if (lc->vtable.show) lc->vtable.show(lc);
136                 if (lc->vtable.display_status) 
137                         lc->vtable.display_status(lc,_("Early media."));
138                 gstate_new_state(lc, GSTATE_CALL_OUT_CONNECTED, NULL);
139                 if (lc->ringstream!=NULL){
140                         ring_stop(lc->ringstream);
141                         lc->ringstream=NULL;
142                 }
143                 ms_message("Doing early media...");
144                 linphone_core_start_media_streams(lc,call);
145                 call->media_pending=TRUE;
146         }
147         call->state=LCStateRinging;
148 }
149
150 static void call_accepted(SalOp *op){
151         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
152         LinphoneCall *call=lc->call;
153         if (call==NULL){
154                 ms_warning("No call to accept.");
155                 return ;
156         }
157         if (sal_op_get_user_pointer(op)!=lc->call){
158                 ms_warning("call_accepted: ignoring.");
159                 return;
160         }
161         if (call->state==LCStateAVRunning){
162                 return ; /*already accepted*/
163         }
164         if (lc->audiostream->ticker!=NULL){
165                 /*case where we accepted early media */
166                 linphone_core_stop_media_streams(lc,call);
167                 linphone_core_init_media_streams(lc,call);
168         }
169         if (call->resultdesc)
170                 sal_media_description_unref(call->resultdesc);
171         call->resultdesc=sal_call_get_final_media_description(op);
172         if (call->resultdesc){
173                 sal_media_description_ref(call->resultdesc);
174                 call->media_pending=FALSE;
175         }
176         if (call->resultdesc && !sal_media_description_empty(call->resultdesc)){
177                 gstate_new_state(lc, GSTATE_CALL_OUT_CONNECTED, NULL);
178                 linphone_connect_incoming(lc,call);
179         }else{
180                 /*send a bye*/
181                 ms_error("Incompatible SDP offer received in 200Ok, need to abort the call");
182                 linphone_core_terminate_call(lc,NULL);
183         }
184 }
185
186 static void call_ack(SalOp *op){
187         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
188         LinphoneCall *call=lc->call;
189         if (call==NULL){
190                 ms_warning("No call to be ACK'd");
191                 return ;
192         }
193         if (sal_op_get_user_pointer(op)!=lc->call){
194                 ms_warning("call_ack: ignoring.");
195                 return;
196         }
197         if (call->media_pending){
198                 if (lc->audiostream->ticker!=NULL){
199                         /*case where we accepted early media */
200                         linphone_core_stop_media_streams(lc,call);
201                         linphone_core_init_media_streams(lc,call);
202                 }
203                 if (call->resultdesc)
204                         sal_media_description_unref(call->resultdesc);
205                 call->resultdesc=sal_call_get_final_media_description(op);
206                 if (call->resultdesc)
207                         sal_media_description_ref(call->resultdesc);
208                 if (call->resultdesc && !sal_media_description_empty(call->resultdesc)){
209                         gstate_new_state(lc, GSTATE_CALL_IN_CONNECTED, NULL);
210                         linphone_connect_incoming(lc,call);
211                 }else{
212                         /*send a bye*/
213                         ms_error("Incompatible SDP response received in ACK, need to abort the call");
214                         linphone_core_terminate_call(lc,NULL);
215                 }
216                 call->media_pending=FALSE;
217         }
218 }
219
220 static void call_updated(SalOp *op){
221         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
222         LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
223         linphone_core_stop_media_streams(lc,call);
224         linphone_core_init_media_streams(lc,call);
225         if (call->resultdesc)
226                 sal_media_description_unref(call->resultdesc);
227         call->resultdesc=sal_call_get_final_media_description(op);
228         if (call->resultdesc && !sal_media_description_empty(call->resultdesc)){
229                 linphone_connect_incoming(lc,call);
230         }
231 }
232
233 static void call_terminated(SalOp *op, const char *from){
234         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
235         if (sal_op_get_user_pointer(op)!=lc->call){
236                 ms_warning("call_terminated: ignoring.");
237                 return;
238         }
239         ms_message("Current call terminated...");
240         if (lc->ringstream!=NULL) {
241                 ring_stop(lc->ringstream);
242                 lc->ringstream=NULL;
243         }
244         linphone_core_stop_media_streams(lc,lc->call);
245         lc->vtable.show(lc);
246         lc->vtable.display_status(lc,_("Call terminated."));
247         gstate_new_state(lc, GSTATE_CALL_END, NULL);
248         if (lc->vtable.bye_recv!=NULL){
249                 LinphoneAddress *addr=linphone_address_new(from);
250                 char *tmp;
251                 linphone_address_clean(addr);
252                 tmp=linphone_address_as_string(addr);
253                 lc->vtable.bye_recv(lc,tmp);
254                 ms_free(tmp);
255                 linphone_address_destroy(addr);
256         }
257         linphone_call_destroy(lc->call);
258         lc->call=NULL;
259 }
260
261 static void call_failure(SalOp *op, SalError error, SalReason sr, const char *details){
262         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
263         char *msg486=_("User is busy.");
264         char *msg480=_("User is temporarily unavailable.");
265         /*char *retrymsg=_("%s. Retry after %i minute(s).");*/
266         char *msg600=_("User does not want to be disturbed.");
267         char *msg603=_("Call declined.");
268         LinphoneCall *call=lc->call;
269
270         if (sal_op_get_user_pointer(op)!=lc->call){
271                 ms_warning("call_failure: ignoring.");
272                 return;
273         }
274         if (lc->vtable.show) lc->vtable.show(lc);
275
276         if (error==SalErrorNoResponse){
277                 if (lc->vtable.display_status)
278                         lc->vtable.display_status(lc,_("No response."));
279         }else if (error==SalErrorProtocol){
280                 if (lc->vtable.display_status)
281                         lc->vtable.display_status(lc, details ? details : _("Error."));
282         }else if (error==SalErrorFailure){
283                 switch(sr){
284                         case SalReasonDeclined:
285                                 if (lc->vtable.display_status)
286                                         lc->vtable.display_status(lc,msg603);
287                         break;
288                         case SalReasonBusy:
289                                 if (lc->vtable.display_status)
290                                         lc->vtable.display_status(lc,msg486);
291                         break;
292                         case SalReasonRedirect:
293                                 if (lc->vtable.display_status)
294                                         lc->vtable.display_status(lc,_("Redirected"));
295                         break;
296                         case SalReasonTemporarilyUnavailable:
297                                 if (lc->vtable.display_status)
298                                         lc->vtable.display_status(lc,msg480);
299                         break;
300                         case SalReasonNotFound:
301                                 if (lc->vtable.display_status)
302                                         lc->vtable.display_status(lc,_("Not found"));
303                         break;
304                         case SalReasonDoNotDisturb:
305                                 if (lc->vtable.display_status)
306                                         lc->vtable.display_status(lc,msg600);
307                         break;
308                         case SalReasonMedia:
309                                 if (lc->vtable.display_status)
310                                         lc->vtable.display_status(lc,_("No common codecs"));
311                         break;
312                         default:
313                                 if (lc->vtable.display_status)
314                                         lc->vtable.display_status(lc,_("Call failed."));
315                 }
316         }
317         if (lc->ringstream!=NULL) {
318                 ring_stop(lc->ringstream);
319                 lc->ringstream=NULL;
320         }
321         linphone_core_stop_media_streams(lc,call);
322         if (call!=NULL) {
323                 linphone_call_destroy(call);
324                 gstate_new_state(lc, GSTATE_CALL_ERROR, NULL);
325                 lc->call=NULL;
326         }
327 }
328
329 static void auth_requested(SalOp *h, const char *realm, const char *username){
330         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h));
331         LinphoneAuthInfo *ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,realm,username);
332         ms_message("auth_requested() for realm=%s, username=%s",realm,username);
333         if (ai && (ai->works || ai->usecount<3)){
334                 SalAuthInfo sai;
335                 sai.username=ai->username;
336                 sai.userid=ai->userid;
337                 sai.realm=ai->realm;
338                 sai.password=ai->passwd;
339                 ms_message("auth_requested(): authenticating realm=%s, username=%s",realm,username);
340                 sal_op_authenticate(h,&sai);
341                 ai->usecount++;
342         }else{
343                 if (lc->vtable.auth_info_requested)
344                         lc->vtable.auth_info_requested(lc,realm,username);
345         }
346 }
347
348 static void auth_success(SalOp *h, const char *realm, const char *username){
349         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h));
350         LinphoneAuthInfo *ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,realm,username);
351         if (ai){
352                 ms_message("%s/%s authentication works.",realm,username);
353                 ai->works=TRUE;
354         }
355 }
356
357 static void register_success(SalOp *op, bool_t registered){
358         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
359         LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)sal_op_get_user_pointer(op);
360         char *msg;
361         gstate_new_state(lc, GSTATE_REG_OK, NULL);
362         cfg->registered=registered;
363         if (cfg->registered) msg=ms_strdup_printf(_("Registration on %s successful."),sal_op_get_proxy(op));
364         else msg=ms_strdup_printf(_("Unregistration on %s done."),sal_op_get_proxy(op));
365         if (lc->vtable.display_status) 
366                 lc->vtable.display_status(lc,msg);
367         ms_free(msg);
368 }
369
370 static void register_failure(SalOp *op, SalError error, SalReason reason, const char *details){
371         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
372         char *msg=ortp_strdup_printf(_("Registration on %s failed: %s"),sal_op_get_proxy(op),(details!=NULL) ? details : _("no response timeout"));
373         if (lc->vtable.display_status) lc->vtable.display_status(lc,msg);
374         gstate_new_state(lc, GSTATE_REG_FAILED, msg);
375         ms_free(msg);
376 }
377
378 static void vfu_request(SalOp *op){
379         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
380 #ifdef VIDEO_ENABLED
381         if (lc->videostream)
382                 video_stream_send_vfu(lc->videostream);
383 #endif
384 }
385
386 static void dtmf_received(SalOp *op, char dtmf){
387         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
388         if (lc->vtable.dtmf_received != NULL)
389                 lc->vtable.dtmf_received(lc, dtmf);
390 }
391
392 static void refer_received(Sal *sal, SalOp *op, const char *referto){
393         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal);
394         if (lc->vtable.refer_received)
395                 lc->vtable.refer_received(lc,referto);
396 }
397
398 static void text_received(Sal *sal, const char *from, const char *msg){
399         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal);
400         linphone_core_text_received(lc,from,msg);
401 }
402
403 static void notify(SalOp *op, SalSubscribeState ss, SalPresenceStatus status, const char *msg){
404         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
405         linphone_notify_recv(lc,op,ss,status);
406 }
407
408 static void subscribe_received(SalOp *op, const char *from){
409         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
410         linphone_subscription_new(lc,op,from);
411 }
412
413 static void subscribe_closed(SalOp *op, const char *from){
414         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
415         linphone_subscription_closed(lc,op);
416 }
417
418 static void internal_message(Sal *sal, const char *msg){
419         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal);
420         if (lc->vtable.show)
421                 lc->vtable.show(lc);
422 }
423
424 static void ping_reply(SalOp *op){
425         LinphoneCall *call=(LinphoneCall*) sal_op_get_user_pointer(op);
426         ms_message("ping reply !");
427         if (call){
428                 if (call->state==LCStatePreEstablishing){
429                         linphone_core_start_invite(call->core,call,NULL);
430                 }
431         }
432 }
433
434 SalCallbacks linphone_sal_callbacks={
435         call_received,
436         call_ringing,
437         call_accepted,
438         call_ack,
439         call_updated,
440         call_terminated,
441         call_failure,
442         auth_requested,
443         auth_success,
444         register_success,
445         register_failure,
446         vfu_request,
447         dtmf_received,
448         refer_received,
449         text_received,
450         notify,
451         subscribe_received,
452         subscribe_closed,
453         internal_message,
454         ping_reply
455 };
456
457