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"
26 static void linphone_connect_incoming(LinphoneCore *lc, LinphoneCall *call){
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);
36 linphone_core_start_media_streams(lc,call);
39 static void call_received(SalOp *h){
40 LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_root(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(op);
76 call=linphone_call_new_incoming(lc,linphone_address_new(from),linphone_address_new(to),op);
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);
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);
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);
102 linphone_call_set_state(call,LCStateRinging);
103 sal_call_notify_ringing(op);
105 if (lc->vtable.inv_recv) lc->vtable.inv_recv(lc,tmp);
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);
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);
125 /*accept early media */
126 if (lc->audiostream->ticker!=NULL){
127 /*streams already started */
128 ms_message("Early media already started.");
131 sal_media_description_ref(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);
141 ms_message("Doing early media...");
142 linphone_core_start_media_streams(lc,call);
144 call->state=LCStateRinging;
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;
151 ms_warning("No call to accept.");
154 if (sal_op_get_user_pointer(op)!=lc->call){
155 ms_warning("call_accepted: ignoring.");
158 if (call->state==LCStateAVRunning){
159 return 0; /*already accepted*/
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);
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);
174 ms_error("Incompatible SDP offer received in 200Ok, need to abort the call");
175 linphone_core_terminate_call(lc,NULL);
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;
183 ms_warning("No call to be ACK'd");
186 if (sal_op_get_user_pointer(op)!=lc->call){
187 ms_warning("call_ack: ignoring.");
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);
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);
203 ms_error("Incompatible SDP response received in ACK, need to abort the call");
204 linphone_core_terminate_call(lc,NULL);
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);
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.");
226 ms_message("Current call terminated...");
227 if (lc->ringstream!=NULL) {
228 ring_stop(lc->ringstream);
231 linphone_core_stop_media_streams(lc,lc->call);
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);
238 linphone_address_clean(addr);
239 tmp=linphone_address_as_string(from);
240 lc->vtable.bye_recv(lc,tmp);
242 linphone_address_destroy(addr);
244 linphone_call_destroy(lc->call);
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.");
258 LinphoneCall *call=lc->call;
259 if (sal_op_get_user_pointer(op)!=lc->call){
260 ms_warning("call_failure: ignoring.");
263 if (lc->vtable.show) lc->vtable.show(lc);
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){
273 case SalReasonDeclined:
274 if (lc->vtable.display_status)
275 lc->vtable.display_status(lc,msg603);
278 if (lc->vtable.display_status)
279 lc->vtable.display_status(lc,msg486);
281 case SalReasonRedirect:
282 if (lc->vtable.display_status)
283 lc->vtable.display_status(lc,_("Redirected"));
285 case SalReasonTemporarilyUnavailable:
286 if (lc->vtable.display_status)
287 lc->vtable.display_status(lc,msg480);
289 case SalReasonNotFound:
290 if (lc->vtable.display_status)
291 lc->vtable.display_status(lc,msg404);
293 case SalReasonDoNotDisturb:
294 if (lc->vtable.display_status)
295 lc->vtable.display_status(lc,msg600);
298 if (lc->vtable.display_status)
299 lc->vtable.display_status(lc,_("No common codecs"));
302 if (lc->vtable.display_status)
303 lc->vtable.display_status(lc,_("Call failed."));
306 if (lc->ringstream!=NULL) {
307 ring_stop(lc->ringstream);
310 linphone_core_stop_media_streams(lc);
312 linphone_call_destroy(call);
313 gstate_new_state(lc, GSTATE_CALL_ERROR, NULL);
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);
323 static void auth_success(SalOp *h, const char *realm, const char *username){
326 static void register_success(SalOp *op, bool_t registered){
329 static void register_failure(SalOp *op, SalError error, SalReason reason, const char *details){
332 static void vfu_request(SalOp *op){
335 static void dtmf_received(SalOp *op, char dtmf){
338 static void refer_received(SalOp *op, SalOp *op, const char *referto){
341 static void text_received(Sal *sal, const char *from, const char *msg){
344 static void presence_changed(SalOp *op, SalPresenceStatus status, const char *msg){
347 static void subscribe_received(SalOp *op, const char *from){
350 static void internal_message(SalOp *op, const char *msg){
355 SalCallbacks linphone_sal_callbacks={