]> sjero.net Git - linphone/blob - coreapi/callbacks.c
work in progress
[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
26 static void linphone_connect_incoming(LinphoneCore *lc, LinphoneCall *call){
27         if (lc->vtable.show)
28                 lc->vtable.show(lc);
29         if (lc->vtable.display_status)
30                 lc->vtable.display_status(lc,_("Connected."));
31         call->state=LCStateAVRunning;
32         if (lc->ringstream!=NULL){
33                 ring_stop(lc->ringstream);
34                 lc->ringstream=NULL;
35         }
36         linphone_core_start_media_streams(lc,call);
37 }
38
39 static void call_received(SalOp *h){
40         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_root(h));
41         char *barmesg;
42         int err;
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(op);
66                 return;
67         }
68         if (lc->call!=NULL){/*busy*/
69                 sal_call_decline(h,SalReasonBusy,NULL);
70                 sal_op_release(op);
71                 return;
72         }
73         from=sal_op_get_from(op);
74         to=sal_op_get_to(op);
75         
76         call=linphone_call_new_incoming(lc,linphone_address_new(from),linphone_address_new(to),op);
77         lc->call=call;
78         sal_call_set_local_media_description(op,call->localdesc);
79         call->resultdesc=sal_call_get_final_media_description(op);
80         if (call->resultdesc && sal_media_description_empty(call->resultdesc){
81                 sal_call_decline(op,SalReasonMedia,NULL);
82                 linphone_call_destroy(call);
83                 lc->call=NULL;
84                 return;
85         }
86         
87         from_parsed=linphone_address_new(sal_op_get_from(op));
88         linphone_address_clean(from_parsed);
89         tmp=linphone_address_as_string(from_parsed);
90         linphone_address_destroy(from_parsed);
91         gstate_new_state(lc, GSTATE_CALL_IN_INVITE, tmp);
92         barmesg=ortp_strdup_printf("%s %s",tmp,_("is contacting you."));
93         if (lc->vtable.show) lc->vtable.show(lc);
94         if (lc->vtable.display_status) 
95             lc->vtable.display_status(lc,barmesg);
96
97         /* play the ring */
98         if (lc->sound_conf.ring_sndcard!=NULL){
99                 ms_message("Starting local ring...");
100                 lc->ringstream=ring_start(lc->sound_conf.local_ring,2000,lc->sound_conf.ring_sndcard);
101         }
102         linphone_call_set_state(call,LCStateRinging);
103         sal_call_notify_ringing(op);
104
105         if (lc->vtable.inv_recv) lc->vtable.inv_recv(lc,tmp);
106         ms_free(barmesg);
107         ms_free(tmp);
108 }
109
110 static void call_ringing(SalOp *h){
111         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_root(h));
112         LinphoneCall *call=lc->call;
113         SalMediaDescription *md;
114         if (call==NULL) return;
115         if (lc->vtable.display_status)
116                 lc->vtable.display_status(lc,_("Remote ringing."));
117         md=sal_call_get_final_media_description(h);
118         if (md==NULL){
119                 if (lc->ringstream!=NULL) return;       /*already ringing !*/
120                 if (lc->sound_conf.play_sndcard!=NULL){
121                         ms_message("Remote ringing...");
122                         lc->ringstream=ring_start(lc->sound_conf.remote_ring,2000,lc->sound_conf.play_sndcard);
123                 }
124         }else{
125                 /*accept early media */
126                 if (lc->audiostream->ticker!=NULL){
127                         /*streams already started */
128                         ms_message("Early media already started.");
129                         return;
130                 }
131                 sal_media_description_ref(md);
132                 call->resultdesc=md;
133                 if (lc->vtable.show) lc->vtable.show(lc);
134                 if (lc->vtable.display_status) 
135                         lc->vtable.display_status(lc,_("Early media."));
136                 gstate_new_state(lc, GSTATE_CALL_OUT_CONNECTED, NULL);
137                 if (lc->ringstream!=NULL){
138                         ring_stop(lc->ringstream);
139                         lc->ringstream=NULL;
140                 }
141                 ms_message("Doing early media...");
142                 linphone_core_start_media_streams(lc,call);
143         }
144         call->state=LCStateRinging;
145 }
146
147 static void call_accepted(SalOp *op){
148         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_root(h));
149         LinphoneCall *call=lc->call;
150         if (call==NULL){
151                 ms_warning("No call to accept.");
152                 return 0;
153         }
154         if (sal_op_get_user_pointer(op)!=lc->call){
155                 ms_warning("call_accepted: ignoring.");
156                 return;
157         }
158         if (call->state==LCStateAVRunning){
159                 return 0; /*already accepted*/
160         }
161         if (lc->audiostream->ticker!=NULL){
162                 /*case where we accepted early media */
163                 linphone_core_stop_media_streams(lc,call);
164                 linphone_core_init_media_streams(lc,call);
165         }
166         if (call->resultdesc)
167                 sal_media_description_unref(call->resultdesc);
168         call->resultdesc=sal_call_get_final_media_description(op);
169         if (call->resultdesc && !sal_media_description_empty(call->resultdesc)){
170                 gstate_new_state(lc, GSTATE_CALL_OUT_CONNECTED, NULL);
171                 linphone_connect_incoming(lc,call);
172         }else{
173                 /*send a bye*/
174                 ms_error("Incompatible SDP offer received in 200Ok, need to abort the call");
175                 linphone_core_terminate_call(lc,NULL);
176         }
177 }
178
179 static void call_ack(SalOp *h){
180         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_root(h));
181         LinphoneCall *call=lc->call;
182         if (call==NULL){
183                 ms_warning("No call to be ACK'd");
184                 return ;
185         }
186         if (sal_op_get_user_pointer(op)!=lc->call){
187                 ms_warning("call_ack: ignoring.");
188                 return;
189         }
190         if (lc->audiostream->ticker!=NULL){
191                 /*case where we accepted early media */
192                 linphone_core_stop_media_streams(lc,call);
193                 linphone_core_init_media_streams(lc,call);
194         }
195         if (call->resultdesc)
196                 sal_media_description_unref(call->resultdesc);
197         call->resultdesc=sal_call_get_final_media_description(op);
198         if (call->resultdesc && !sal_media_description_empty(call->resultdesc)){
199                 gstate_new_state(lc, GSTATE_CALL_IN_CONNECTED, NULL);
200                 linphone_connect_incoming(lc,call);
201         }else{
202                 /*send a bye*/
203                 ms_error("Incompatible SDP response received in ACK, need to abort the call");
204                 linphone_core_terminate_call(lc,NULL);
205         }
206 }
207
208 static void call_updated(SalOp *){
209         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_root(h));
210         linphone_core_stop_media_streams(lc,call);
211         linphone_core_init_media_streams(lc,call);
212         if (call->resultdesc)
213                 sal_media_description_unref(call->resultdesc);
214         call->resultdesc=sal_call_get_final_media_description(op);
215         if (call->resultdesc && !sal_media_description_empty(call->resultdesc)){
216                 linphone_connect_incoming(lc,call);
217         }
218 }
219
220 static void call_terminated(SalOp *h, const char *from){
221         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_root(h));
222         if (sal_op_get_user_pointer(op)!=lc->call){
223                 ms_warning("call_terminated: ignoring.");
224                 return;
225         }
226         ms_message("Current call terminated...");
227         if (lc->ringstream!=NULL) {
228                 ring_stop(lc->ringstream);
229                 lc->ringstream=NULL;
230         }
231         linphone_core_stop_media_streams(lc,lc->call);
232         lc->vtable.show(lc);
233         lc->vtable.display_status(lc,_("Call terminated."));
234         gstate_new_state(lc, GSTATE_CALL_END, NULL);
235         if (lc->vtable.bye_recv!=NULL){
236                 LinphoneAddress *addr=linphone_address_new(from);
237                 char *tmp;
238                 linphone_address_clean(addr);
239                 tmp=linphone_address_as_string(from);
240                 lc->vtable.bye_recv(lc,tmp);
241                 ms_free(tmp);
242                 linphone_address_destroy(addr);
243         }
244         linphone_call_destroy(lc->call);
245         lc->call=NULL;
246 }
247
248 static void call_failure(SalOp *op, SalError error, SalReason sr, const char *details){
249         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_root(h));
250         const char *reason="";
251         char *msg486=_("User is busy.");
252         char *msg480=_("User is temporarily unavailable.");
253         /*char *retrymsg=_("%s. Retry after %i minute(s).");*/
254         char *msg600=_("User does not want to be disturbed.");
255         char *msg603=_("Call declined.");
256         char* tmpmsg=msg486;
257         int code;
258         LinphoneCall *call=lc->call;
259         if (sal_op_get_user_pointer(op)!=lc->call){
260                 ms_warning("call_failure: ignoring.");
261                 return;
262         }
263         if (lc->vtable.show) lc->vtable.show(lc);
264
265         if (error==SalErrorNoResponse){
266                 if (lc->vtale.display_status)
267                         lc->vtable.display_status(lc,_("No response."));
268         }else if (error==SalErrorProtocol){
269                 if (lc->vtale.display_status)
270                         lc->vtable.display_status(lc, details ? details : _("Error."));
271         }else if (error==SalErrorFailure){
272                 switch(sr){
273                         case SalReasonDeclined:
274                                 if (lc->vtable.display_status)
275                                         lc->vtable.display_status(lc,msg603);
276                         break;
277                         case SalReasonBusy:
278                                 if (lc->vtable.display_status)
279                                         lc->vtable.display_status(lc,msg486);
280                         break;
281                         case SalReasonRedirect:
282                                 if (lc->vtable.display_status)
283                                         lc->vtable.display_status(lc,_("Redirected"));
284                         break;
285                         case SalReasonTemporarilyUnavailable:
286                                 if (lc->vtable.display_status)
287                                         lc->vtable.display_status(lc,msg480);
288                         break;
289                         case SalReasonNotFound:
290                                 if (lc->vtable.display_status)
291                                         lc->vtable.display_status(lc,msg404);
292                         break;
293                         case SalReasonDoNotDisturb:
294                                 if (lc->vtable.display_status)
295                                         lc->vtable.display_status(lc,msg600);
296                         break;
297                         case SalReasonMedia:
298                                 if (lc->vtable.display_status)
299                                         lc->vtable.display_status(lc,_("No common codecs"));
300                         break;
301                         default:
302                                 if (lc->vtable.display_status)
303                                         lc->vtable.display_status(lc,_("Call failed."));
304                 }
305         }
306         if (lc->ringstream!=NULL) {
307                 ring_stop(lc->ringstream);
308                 lc->ringstream=NULL;
309         }
310         linphone_core_stop_media_streams(lc);
311         if (call!=NULL) {
312                 linphone_call_destroy(call);
313                 gstate_new_state(lc, GSTATE_CALL_ERROR, NULL);
314                 lc->call=NULL;
315         }
316 }
317
318 static void auth_requested(SalOp *h, const char *realm, const char *username){
319         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_root(h));
320         LinphoneAuthInfo *ai=linphone_core_find_auth_info(lc);
321 }
322
323 static void auth_success(SalOp *h, const char *realm, const char *username){
324 }
325
326 static void register_success(SalOp *op, bool_t registered){
327 }
328
329 static void register_failure(SalOp *op, SalError error, SalReason reason, const char *details){
330 }
331
332 static void vfu_request(SalOp *op){
333 }
334
335 static void dtmf_received(SalOp *op, char dtmf){
336 }
337
338 static void refer_received(SalOp *op, SalOp *op, const char *referto){
339 }
340
341 static void text_received(Sal *sal, const char *from, const char *msg){
342 }
343
344 static void presence_changed(SalOp *op, SalPresenceStatus status, const char *msg){
345 }
346
347 static void subscribe_received(SalOp *op, const char *from){
348 }
349
350 static void internal_message(SalOp *op, const char *msg){
351 }
352
353
354
355 SalCallbacks linphone_sal_callbacks={
356         call_received,
357         call_ringing,
358         call_accepted,
359         call_ack,
360         call_updated,
361         call_terminated,
362         call_failure,
363         auth_requested,
364         auth_success,
365         register_success,
366         register_failure,
367         vfu_request,
368         dtmf_received,
369         refer_received,
370         text_received,
371         presence_changed,
372         subscribe_received,
373         internal_message
374 };
375
376