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"
27 static void linphone_connect_incoming(LinphoneCore *lc, LinphoneCall *call){
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);
37 linphone_core_start_media_streams(lc,call);
40 static void call_received(SalOp *h){
41 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h));
46 LinphoneAddress *from_parsed;
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);
64 sal_call_decline(h,SalReasonBusy,NULL);
68 if (lc->call!=NULL){/*busy*/
69 sal_call_decline(h,SalReasonBusy,NULL);
73 from=sal_op_get_from(h);
76 call=linphone_call_new_incoming(lc,linphone_address_new(from),linphone_address_new(to),h);
78 sal_call_set_local_media_description(h,call->localdesc);
79 call->resultdesc=sal_call_get_final_media_description(h);
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);
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);
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);
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);
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);
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);
127 /*accept early media */
128 if (lc->audiostream->ticker!=NULL){
129 /*streams already started */
130 ms_message("Early media already started.");
133 sal_media_description_ref(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);
143 ms_message("Doing early media...");
144 linphone_core_start_media_streams(lc,call);
145 call->media_pending=TRUE;
147 call->state=LCStateRinging;
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;
154 ms_warning("No call to accept.");
157 if (sal_op_get_user_pointer(op)!=lc->call){
158 ms_warning("call_accepted: ignoring.");
161 if (call->state==LCStateAVRunning){
162 return ; /*already accepted*/
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);
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;
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);
181 ms_error("Incompatible SDP offer received in 200Ok, need to abort the call");
182 linphone_core_terminate_call(lc,NULL);
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;
190 ms_warning("No call to be ACK'd");
193 if (sal_op_get_user_pointer(op)!=lc->call){
194 ms_warning("call_ack: ignoring.");
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);
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);
213 ms_error("Incompatible SDP response received in ACK, need to abort the call");
214 linphone_core_terminate_call(lc,NULL);
216 call->media_pending=FALSE;
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);
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.");
239 ms_message("Current call terminated...");
240 if (lc->ringstream!=NULL) {
241 ring_stop(lc->ringstream);
244 linphone_core_stop_media_streams(lc,lc->call);
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);
251 linphone_address_clean(addr);
252 tmp=linphone_address_as_string(addr);
253 lc->vtable.bye_recv(lc,tmp);
255 linphone_address_destroy(addr);
257 linphone_call_destroy(lc->call);
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;
270 if (sal_op_get_user_pointer(op)!=lc->call){
271 ms_warning("call_failure: ignoring.");
274 if (lc->vtable.show) lc->vtable.show(lc);
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){
284 case SalReasonDeclined:
285 if (lc->vtable.display_status)
286 lc->vtable.display_status(lc,msg603);
289 if (lc->vtable.display_status)
290 lc->vtable.display_status(lc,msg486);
292 case SalReasonRedirect:
293 if (lc->vtable.display_status)
294 lc->vtable.display_status(lc,_("Redirected"));
296 case SalReasonTemporarilyUnavailable:
297 if (lc->vtable.display_status)
298 lc->vtable.display_status(lc,msg480);
300 case SalReasonNotFound:
301 if (lc->vtable.display_status)
302 lc->vtable.display_status(lc,_("Not found"));
304 case SalReasonDoNotDisturb:
305 if (lc->vtable.display_status)
306 lc->vtable.display_status(lc,msg600);
309 if (lc->vtable.display_status)
310 lc->vtable.display_status(lc,_("No common codecs"));
313 if (lc->vtable.display_status)
314 lc->vtable.display_status(lc,_("Call failed."));
317 if (lc->ringstream!=NULL) {
318 ring_stop(lc->ringstream);
321 linphone_core_stop_media_streams(lc,call);
323 linphone_call_destroy(call);
324 gstate_new_state(lc, GSTATE_CALL_ERROR, NULL);
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 if (ai && (ai->works || ai->usecount<3)){
334 sai.username=ai->username;
335 sai.userid=ai->userid;
337 sai.password=ai->passwd;
338 sal_op_authenticate(h,&sai);
341 if (lc->vtable.auth_info_requested)
342 lc->vtable.auth_info_requested(lc,realm,username);
346 static void auth_success(SalOp *h, const char *realm, const char *username){
347 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h));
348 LinphoneAuthInfo *ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,realm,username);
353 static void register_success(SalOp *op, bool_t registered){
354 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
355 LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)sal_op_get_user_pointer(op);
357 gstate_new_state(lc, GSTATE_REG_OK, NULL);
358 cfg->registered=registered;
359 if (cfg->registered) msg=ms_strdup_printf(_("Registration on %s successful."),sal_op_get_proxy(op));
360 else msg=ms_strdup_printf(_("Unregistration on %s done."),sal_op_get_proxy(op));
361 if (lc->vtable.display_status)
362 lc->vtable.display_status(lc,msg);
366 static void register_failure(SalOp *op, SalError error, SalReason reason, const char *details){
367 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
368 char *msg=ortp_strdup_printf(_("Registration on %s failed: %s"),sal_op_get_proxy(op),(details!=NULL) ? details : _("no response timeout"));
369 if (lc->vtable.display_status) lc->vtable.display_status(lc,msg);
370 gstate_new_state(lc, GSTATE_REG_FAILED, msg);
374 static void vfu_request(SalOp *op){
375 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
378 video_stream_send_vfu(lc->videostream);
382 static void dtmf_received(SalOp *op, char dtmf){
383 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
384 if (lc->vtable.dtmf_received != NULL)
385 lc->vtable.dtmf_received(lc, dtmf);
388 static void refer_received(Sal *sal, SalOp *op, const char *referto){
389 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal);
390 if (lc->vtable.refer_received)
391 lc->vtable.refer_received(lc,referto);
394 static void text_received(Sal *sal, const char *from, const char *msg){
395 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal);
396 linphone_core_text_received(lc,from,msg);
399 static void notify(SalOp *op, SalSubscribeState ss, SalPresenceStatus status, const char *msg){
400 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
401 linphone_notify_recv(lc,op,ss,status);
404 static void subscribe_received(SalOp *op, const char *from){
405 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
406 linphone_subscription_new(lc,op,from);
409 static void subscribe_closed(SalOp *op, const char *from){
410 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
411 linphone_subscription_closed(lc,op);
414 static void internal_message(Sal *sal, const char *msg){
415 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal);
420 SalCallbacks linphone_sal_callbacks={