1
2 /*
3 linphone
4 Copyright (C) 2010 Belledonne Communications SARL
5 (simon.morlat@linphone.org)
6
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; either version 2
10 of the License, or (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21 #ifdef _WIN32
22 #include <time.h>
23 #endif
24 #include "linphone/core.h"
25 #include "linphone/sipsetup.h"
26 #include "linphone/lpconfig.h"
27 #include "private.h"
28 #include "conference_private.h"
29
30 #include <ortp/event.h>
31 #include <ortp/b64.h>
32 #include <math.h>
33
34 #include "mediastreamer2/mediastream.h"
35 #include "mediastreamer2/msvolume.h"
36 #include "mediastreamer2/msequalizer.h"
37 #include "mediastreamer2/msfileplayer.h"
38 #include "mediastreamer2/msjpegwriter.h"
39 #include "mediastreamer2/msogl.h"
40 #include "mediastreamer2/mseventqueue.h"
41 #include "mediastreamer2/mssndcard.h"
42 #include "mediastreamer2/msrtt4103.h"
43
44 #include <bctoolbox/defs.h>
45
46
47 static const char *EC_STATE_STORE = ".linphone.ecstate";
48 #define EC_STATE_MAX_LEN 1048576 // 1Mo
49
50 static void linphone_call_stats_uninit(LinphoneCallStats *stats);
51 static void linphone_call_get_local_ip(LinphoneCall *call, const LinphoneAddress *remote_addr);
52 static void _linphone_call_set_next_video_frame_decoded_trigger(LinphoneCall *call);
53 void linphone_call_handle_stream_events(LinphoneCall *call, int stream_index);
54
55
56 typedef belle_sip_object_t_vptr_t LinphoneCallCbs_vptr_t;
57 BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneCallCbs);
58 BELLE_SIP_INSTANCIATE_VPTR(LinphoneCallCbs, belle_sip_object_t,
59 NULL, // destroy
60 NULL, // clone
61 NULL, // Marshall
62 FALSE
63 );
64
_linphone_call_cbs_new(void)65 LinphoneCallCbs *_linphone_call_cbs_new(void) {
66 LinphoneCallCbs *obj = belle_sip_object_new(LinphoneCallCbs);
67 return obj;
68 }
69
linphone_call_cbs_ref(LinphoneCallCbs * cbs)70 LinphoneCallCbs *linphone_call_cbs_ref(LinphoneCallCbs *cbs) {
71 return (LinphoneCallCbs *)belle_sip_object_ref(cbs);
72 }
73
linphone_call_cbs_unref(LinphoneCallCbs * cbs)74 void linphone_call_cbs_unref(LinphoneCallCbs *cbs) {
75 belle_sip_object_unref(cbs);
76 }
77
linphone_call_cbs_get_user_data(const LinphoneCallCbs * cbs)78 void *linphone_call_cbs_get_user_data(const LinphoneCallCbs *cbs) {
79 return cbs->user_data;
80 }
81
linphone_call_cbs_set_user_data(LinphoneCallCbs * cbs,void * user_data)82 void linphone_call_cbs_set_user_data(LinphoneCallCbs *cbs, void *user_data) {
83 cbs->user_data = user_data;
84 }
85
linphone_call_cbs_get_dtmf_received(LinphoneCallCbs * cbs)86 LinphoneCallCbsDtmfReceivedCb linphone_call_cbs_get_dtmf_received(LinphoneCallCbs *cbs) {
87 return cbs->dtmf_received_cb;
88 }
89
linphone_call_cbs_set_dtmf_received(LinphoneCallCbs * cbs,LinphoneCallCbsDtmfReceivedCb cb)90 void linphone_call_cbs_set_dtmf_received(LinphoneCallCbs *cbs, LinphoneCallCbsDtmfReceivedCb cb) {
91 cbs->dtmf_received_cb = cb;
92 }
93
linphone_call_cbs_get_encryption_changed(LinphoneCallCbs * cbs)94 LinphoneCallCbsEncryptionChangedCb linphone_call_cbs_get_encryption_changed(LinphoneCallCbs *cbs) {
95 return cbs->encryption_changed_cb;
96 }
97
linphone_call_cbs_set_encryption_changed(LinphoneCallCbs * cbs,LinphoneCallCbsEncryptionChangedCb cb)98 void linphone_call_cbs_set_encryption_changed(LinphoneCallCbs *cbs, LinphoneCallCbsEncryptionChangedCb cb) {
99 cbs->encryption_changed_cb = cb;
100 }
101
linphone_call_cbs_get_info_message_received(LinphoneCallCbs * cbs)102 LinphoneCallCbsInfoMessageReceivedCb linphone_call_cbs_get_info_message_received(LinphoneCallCbs *cbs) {
103 return cbs->info_message_received_cb;
104 }
105
linphone_call_cbs_set_info_message_received(LinphoneCallCbs * cbs,LinphoneCallCbsInfoMessageReceivedCb cb)106 void linphone_call_cbs_set_info_message_received(LinphoneCallCbs *cbs, LinphoneCallCbsInfoMessageReceivedCb cb) {
107 cbs->info_message_received_cb = cb;
108 }
109
linphone_call_cbs_get_state_changed(LinphoneCallCbs * cbs)110 LinphoneCallCbsStateChangedCb linphone_call_cbs_get_state_changed(LinphoneCallCbs *cbs) {
111 return cbs->state_changed_cb;
112 }
113
linphone_call_cbs_set_state_changed(LinphoneCallCbs * cbs,LinphoneCallCbsStateChangedCb cb)114 void linphone_call_cbs_set_state_changed(LinphoneCallCbs *cbs, LinphoneCallCbsStateChangedCb cb) {
115 cbs->state_changed_cb = cb;
116 }
117
linphone_call_cbs_get_stats_updated(LinphoneCallCbs * cbs)118 LinphoneCallCbsStatsUpdatedCb linphone_call_cbs_get_stats_updated(LinphoneCallCbs *cbs) {
119 return cbs->stats_updated_cb;
120 }
121
linphone_call_cbs_set_stats_updated(LinphoneCallCbs * cbs,LinphoneCallCbsStatsUpdatedCb cb)122 void linphone_call_cbs_set_stats_updated(LinphoneCallCbs *cbs, LinphoneCallCbsStatsUpdatedCb cb) {
123 cbs->stats_updated_cb = cb;
124 }
125
linphone_call_cbs_get_transfer_state_changed(LinphoneCallCbs * cbs)126 LinphoneCallCbsTransferStateChangedCb linphone_call_cbs_get_transfer_state_changed(LinphoneCallCbs *cbs) {
127 return cbs->transfer_state_changed_cb;
128 }
129
linphone_call_cbs_set_transfer_state_changed(LinphoneCallCbs * cbs,LinphoneCallCbsTransferStateChangedCb cb)130 void linphone_call_cbs_set_transfer_state_changed(LinphoneCallCbs *cbs, LinphoneCallCbsTransferStateChangedCb cb) {
131 cbs->transfer_state_changed_cb = cb;
132 }
133
linphone_call_cbs_get_ack_processing(LinphoneCallCbs * cbs)134 LinphoneCallCbsAckProcessingCb linphone_call_cbs_get_ack_processing(LinphoneCallCbs *cbs){
135 return cbs->ack_processing;
136 }
137
linphone_call_cbs_set_ack_processing(LinphoneCallCbs * cbs,LinphoneCallCbsAckProcessingCb cb)138 void linphone_call_cbs_set_ack_processing(LinphoneCallCbs *cbs, LinphoneCallCbsAckProcessingCb cb){
139 cbs->ack_processing = cb;
140 }
141
142
linphone_call_state_is_early(LinphoneCallState state)143 bool_t linphone_call_state_is_early(LinphoneCallState state){
144 switch (state){
145 case LinphoneCallIdle:
146 case LinphoneCallOutgoingInit:
147 case LinphoneCallOutgoingEarlyMedia:
148 case LinphoneCallOutgoingRinging:
149 case LinphoneCallOutgoingProgress:
150 case LinphoneCallIncomingReceived:
151 case LinphoneCallIncomingEarlyMedia:
152 case LinphoneCallEarlyUpdatedByRemote:
153 case LinphoneCallEarlyUpdating:
154 return TRUE;
155 case LinphoneCallResuming:
156 case LinphoneCallEnd:
157 case LinphoneCallUpdating:
158 case LinphoneCallRefered:
159 case LinphoneCallPausing:
160 case LinphoneCallPausedByRemote:
161 case LinphoneCallPaused:
162 case LinphoneCallConnected:
163 case LinphoneCallError:
164 case LinphoneCallUpdatedByRemote:
165 case LinphoneCallReleased:
166 case LinphoneCallStreamsRunning:
167 break;
168 }
169 return FALSE;
170 }
171
get_nowebcam_device(MSFactory * f)172 MSWebCam *get_nowebcam_device(MSFactory* f){
173 #ifdef VIDEO_ENABLED
174 return ms_web_cam_manager_get_cam(ms_factory_get_web_cam_manager(f),"StaticImage: Static picture");
175 #else
176 return NULL;
177 #endif
178 }
179
generate_b64_crypto_key(size_t key_length,char * key_out,size_t key_out_size)180 static bool_t generate_b64_crypto_key(size_t key_length, char* key_out, size_t key_out_size) {
181 size_t b64_size;
182 uint8_t* tmp = (uint8_t*) ms_malloc0(key_length);
183 if (sal_get_random_bytes(tmp, key_length)==NULL) {
184 ms_error("Failed to generate random key");
185 ms_free(tmp);
186 return FALSE;
187 }
188
189 b64_size = b64_encode((const char*)tmp, key_length, NULL, 0);
190 if (b64_size == 0) {
191 ms_error("Failed to get b64 result size");
192 ms_free(tmp);
193 return FALSE;
194 }
195 if (b64_size>=key_out_size){
196 ms_error("Insufficient room for writing base64 SRTP key");
197 ms_free(tmp);
198 return FALSE;
199 }
200 b64_size=b64_encode((const char*)tmp, key_length, key_out, key_out_size);
201 if (b64_size == 0) {
202 ms_error("Failed to b64 encode key");
203 ms_free(tmp);
204 return FALSE;
205 }
206 key_out[b64_size] = '\0';
207 ms_free(tmp);
208 return TRUE;
209 }
210
linphone_call_encryption_mandatory(LinphoneCall * call)211 static bool_t linphone_call_encryption_mandatory(LinphoneCall *call){
212 if (call->params->media_encryption==LinphoneMediaEncryptionDTLS) {
213 ms_message("Forced encryption mandatory on call [%p] due to SRTP-DTLS",call);
214 return TRUE;
215 }
216 return call->params->encryption_mandatory;
217 }
218
linphone_call_get_core(const LinphoneCall * call)219 LinphoneCore *linphone_call_get_core(const LinphoneCall *call){
220 return call->core;
221 }
222
linphone_call_get_authentication_token(LinphoneCall * call)223 const char* linphone_call_get_authentication_token(LinphoneCall *call){
224 return call->auth_token;
225 }
226
linphone_call_get_authentication_token_verified(LinphoneCall * call)227 bool_t linphone_call_get_authentication_token_verified(LinphoneCall *call){
228 return call->auth_token_verified;
229 }
230
at_least_one_stream_started(const LinphoneCall * call)231 static bool_t at_least_one_stream_started(const LinphoneCall *call){
232 return (call->audiostream && media_stream_get_state((MediaStream *)call->audiostream) == MSStreamStarted )
233 || (call->videostream && media_stream_get_state((MediaStream *)call->videostream) == MSStreamStarted)
234 || (call->textstream && media_stream_get_state((MediaStream *)call->textstream) == MSStreamStarted);
235 }
236
linphone_call_all_streams_encrypted(const LinphoneCall * call)237 static bool_t linphone_call_all_streams_encrypted(const LinphoneCall *call) {
238 int number_of_encrypted_stream = 0;
239 int number_of_active_stream = 0;
240
241 if (call->audiostream && media_stream_get_state((MediaStream *)call->audiostream) == MSStreamStarted) {
242 number_of_active_stream++;
243 if(media_stream_secured((MediaStream *)call->audiostream))
244 number_of_encrypted_stream++;
245 }
246 if (call->videostream && media_stream_get_state((MediaStream *)call->videostream) == MSStreamStarted) {
247 number_of_active_stream++;
248 if (media_stream_secured((MediaStream *)call->videostream))
249 number_of_encrypted_stream++;
250 }
251 if (call->textstream && media_stream_get_state((MediaStream *)call->textstream) == MSStreamStarted) {
252 number_of_active_stream++;
253 if (media_stream_secured((MediaStream *)call->textstream))
254 number_of_encrypted_stream++;
255 }
256 return number_of_active_stream>0 && number_of_active_stream==number_of_encrypted_stream;
257 }
258
linphone_call_all_streams_avpf_enabled(const LinphoneCall * call)259 static bool_t linphone_call_all_streams_avpf_enabled(const LinphoneCall *call) {
260 int nb_active_streams = 0;
261 int nb_avpf_enabled_streams = 0;
262 if (call) {
263 if (call->audiostream && media_stream_get_state((MediaStream *)call->audiostream) == MSStreamStarted) {
264 nb_active_streams++;
265 if (media_stream_avpf_enabled((MediaStream *)call->audiostream))
266 nb_avpf_enabled_streams++;
267 }
268 if (call->videostream && media_stream_get_state((MediaStream *)call->videostream) == MSStreamStarted) {
269 nb_active_streams++;
270 if (media_stream_avpf_enabled((MediaStream *)call->videostream))
271 nb_avpf_enabled_streams++;
272 }
273 }
274 return ((nb_active_streams > 0) && (nb_active_streams == nb_avpf_enabled_streams));
275 }
276
linphone_call_get_avpf_rr_interval(const LinphoneCall * call)277 static uint16_t linphone_call_get_avpf_rr_interval(const LinphoneCall *call) {
278 uint16_t rr_interval = 0;
279 uint16_t stream_rr_interval;
280 if (call) {
281 if (call->audiostream && media_stream_get_state((MediaStream *)call->audiostream) == MSStreamStarted) {
282 stream_rr_interval = media_stream_get_avpf_rr_interval((MediaStream *)call->audiostream);
283 if (stream_rr_interval > rr_interval) rr_interval = stream_rr_interval;
284 }
285 if (call->videostream && media_stream_get_state((MediaStream *)call->videostream) == MSStreamStarted) {
286 stream_rr_interval = media_stream_get_avpf_rr_interval((MediaStream *)call->videostream);
287 if (stream_rr_interval > rr_interval) rr_interval = stream_rr_interval;
288 }
289 } else {
290 rr_interval = 5000;
291 }
292 return rr_interval;
293 }
294
propagate_encryption_changed(LinphoneCall * call)295 static void propagate_encryption_changed(LinphoneCall *call){
296 if (!linphone_call_all_streams_encrypted(call)) {
297 ms_message("Some streams are not encrypted");
298 call->current_params->media_encryption=LinphoneMediaEncryptionNone;
299 linphone_call_notify_encryption_changed(call, FALSE, call->auth_token);
300 } else {
301 if (call->auth_token) {/* ZRTP only is using auth_token */
302 call->current_params->media_encryption=LinphoneMediaEncryptionZRTP;
303 } else { /* otherwise it must be DTLS as SDES doesn't go through this function */
304 call->current_params->media_encryption=LinphoneMediaEncryptionDTLS;
305 }
306 ms_message("All streams are encrypted key exchanged using %s", call->current_params->media_encryption==LinphoneMediaEncryptionZRTP?"ZRTP":call->current_params->media_encryption==LinphoneMediaEncryptionDTLS?"DTLS":"Unknown mechanism");
307 linphone_call_notify_encryption_changed(call, TRUE, call->auth_token);
308 #ifdef VIDEO_ENABLED
309 if (linphone_call_encryption_mandatory(call) && call->videostream && media_stream_started((MediaStream *)call->videostream)) {
310 video_stream_send_vfu(call->videostream); /*nothing could have been sent yet so generating key frame*/
311 }
312 #endif
313 }
314 }
315
linphone_call_audiostream_encryption_changed(void * data,bool_t encrypted)316 static void linphone_call_audiostream_encryption_changed(void *data, bool_t encrypted) {
317 char status[255]={0};
318 LinphoneCall *call;
319
320 call = (LinphoneCall *)data;
321
322 if (encrypted) {
323 if (call->params->media_encryption==LinphoneMediaEncryptionZRTP) { /* if encryption is DTLS, no status to be displayed */
324 snprintf(status,sizeof(status)-1,_("Authentication token is %s"),call->auth_token);
325 linphone_core_notify_display_status(call->core, status);
326 }
327 }
328
329 propagate_encryption_changed(call);
330
331 #ifdef VIDEO_ENABLED
332 // Enable video encryption
333 if (call->params->media_encryption==LinphoneMediaEncryptionZRTP) {
334 const LinphoneCallParams *params=linphone_call_get_current_params(call);
335 if (params->has_video) {
336 ms_message("Trying to start ZRTP encryption on video stream");
337 video_stream_start_zrtp(call->videostream);
338 }
339 }
340 #endif
341 }
342
linphone_call_audiostream_auth_token_ready(void * data,const char * auth_token,bool_t verified)343 static void linphone_call_audiostream_auth_token_ready(void *data, const char* auth_token, bool_t verified) {
344 LinphoneCall *call=(LinphoneCall *)data;
345 if (call->auth_token != NULL)
346 ms_free(call->auth_token);
347
348 call->auth_token=ms_strdup(auth_token);
349 call->auth_token_verified=verified;
350
351 ms_message("Authentication token is %s (%s)", auth_token, verified?"verified":"unverified");
352 }
353
linphone_call_set_authentication_token_verified(LinphoneCall * call,bool_t verified)354 void linphone_call_set_authentication_token_verified(LinphoneCall *call, bool_t verified){
355 if (call->audiostream==NULL || !media_stream_started(&call->audiostream->ms)){
356 ms_error("linphone_call_set_authentication_token_verified(): No audio stream or not started");
357 return;
358 }
359 if (call->audiostream->ms.sessions.zrtp_context==NULL){
360 ms_error("linphone_call_set_authentication_token_verified(): No zrtp context.");
361 return;
362 }
363 if (!call->auth_token_verified && verified){
364 ms_zrtp_sas_verified(call->audiostream->ms.sessions.zrtp_context);
365 }else if (call->auth_token_verified && !verified){
366 ms_zrtp_sas_reset_verified(call->audiostream->ms.sessions.zrtp_context);
367 }
368 call->auth_token_verified=verified;
369 propagate_encryption_changed(call);
370 }
371
get_max_codec_sample_rate(const bctbx_list_t * codecs)372 static int get_max_codec_sample_rate(const bctbx_list_t *codecs){
373 int max_sample_rate=0;
374 const bctbx_list_t *it;
375 for(it=codecs;it!=NULL;it=it->next){
376 PayloadType *pt=(PayloadType*)it->data;
377 int sample_rate;
378
379 if( strcasecmp("G722",pt->mime_type) == 0 ){
380 /* G722 spec says 8000 but the codec actually requires 16000 */
381 sample_rate = 16000;
382 }else sample_rate=pt->clock_rate;
383 if (sample_rate>max_sample_rate) max_sample_rate=sample_rate;
384 }
385 return max_sample_rate;
386 }
387
find_payload_type_number(const bctbx_list_t * assigned,const PayloadType * pt)388 static int find_payload_type_number(const bctbx_list_t *assigned, const PayloadType *pt){
389 const bctbx_list_t *elem;
390 const PayloadType *candidate=NULL;
391 for(elem=assigned;elem!=NULL;elem=elem->next){
392 const PayloadType *it=(const PayloadType*)elem->data;
393 if ((strcasecmp(pt->mime_type, payload_type_get_mime(it)) == 0)
394 && (it->clock_rate==pt->clock_rate)
395 && (it->channels==pt->channels || pt->channels<=0)) {
396 candidate=it;
397 if ((it->recv_fmtp!=NULL && pt->recv_fmtp!=NULL && strcasecmp(it->recv_fmtp, pt->recv_fmtp)==0)
398 || (it->recv_fmtp==NULL && pt->recv_fmtp==NULL)){
399 break;/*exact match*/
400 }
401 }
402 }
403 return candidate ? payload_type_get_number(candidate) : -1;
404 }
405
is_payload_type_number_available(const bctbx_list_t * l,int number,const PayloadType * ignore)406 bool_t is_payload_type_number_available(const bctbx_list_t *l, int number, const PayloadType *ignore){
407 const bctbx_list_t *elem;
408 for (elem=l; elem!=NULL; elem=elem->next){
409 const PayloadType *pt=(PayloadType*)elem->data;
410 if (pt!=ignore && payload_type_get_number(pt)==number) return FALSE;
411 }
412 return TRUE;
413 }
414
linphone_core_assign_payload_type_numbers(LinphoneCore * lc,bctbx_list_t * codecs)415 static void linphone_core_assign_payload_type_numbers(LinphoneCore *lc, bctbx_list_t *codecs){
416 bctbx_list_t *elem;
417 int dyn_number=lc->codecs_conf.dyn_pt;
418 PayloadType *red = NULL, *t140 = NULL;
419
420 for (elem=codecs; elem!=NULL; elem=elem->next){
421 PayloadType *pt=(PayloadType*)elem->data;
422 int number=payload_type_get_number(pt);
423
424 /*check if number is duplicated: it could be the case if the remote forced us to use a mapping with a previous offer*/
425 if (number!=-1 && !(pt->flags & PAYLOAD_TYPE_FROZEN_NUMBER)){
426 if (!is_payload_type_number_available(codecs, number, pt)){
427 ms_message("Reassigning payload type %i %s/%i because already offered.", number, pt->mime_type, pt->clock_rate);
428 number=-1; /*need to be re-assigned*/
429 }
430 }
431
432 if (number==-1){
433 while(dyn_number<127){
434 if (is_payload_type_number_available(codecs, dyn_number, NULL)){
435 payload_type_set_number(pt, dyn_number);
436 dyn_number++;
437 break;
438 }
439 dyn_number++;
440 }
441 if (dyn_number==127){
442 ms_error("Too many payload types configured ! codec %s/%i is disabled.", pt->mime_type, pt->clock_rate);
443 payload_type_set_enable(pt, FALSE);
444 }
445 }
446
447 if (strcmp(pt->mime_type, payload_type_t140_red.mime_type) == 0) {
448 red = pt;
449 } else if (strcmp(pt->mime_type, payload_type_t140.mime_type) == 0) {
450 t140 = pt;
451 }
452 }
453
454 if (t140 && red) {
455 int t140_payload_type_number = payload_type_get_number(t140);
456 char *red_fmtp = ms_strdup_printf("%i/%i/%i", t140_payload_type_number, t140_payload_type_number, t140_payload_type_number);
457 payload_type_set_recv_fmtp(red, red_fmtp);
458 ms_free(red_fmtp);
459 }
460 }
461
has_telephone_event_at_rate(const bctbx_list_t * tev,int rate)462 static bool_t has_telephone_event_at_rate(const bctbx_list_t *tev, int rate){
463 const bctbx_list_t *it;
464 for(it=tev;it!=NULL;it=it->next){
465 const PayloadType *pt=(PayloadType*)it->data;
466 if (pt->clock_rate==rate) return TRUE;
467 }
468 return FALSE;
469 }
470
create_telephone_events(LinphoneCore * lc,const bctbx_list_t * codecs)471 static bctbx_list_t * create_telephone_events(LinphoneCore *lc, const bctbx_list_t *codecs){
472 const bctbx_list_t *it;
473 bctbx_list_t *ret=NULL;
474 for(it=codecs;it!=NULL;it=it->next){
475 const PayloadType *pt=(PayloadType*)it->data;
476 if (!has_telephone_event_at_rate(ret,pt->clock_rate)){
477 PayloadType *tev=payload_type_clone(&payload_type_telephone_event);
478 tev->clock_rate=pt->clock_rate;
479 /*let it choose the number dynamically as for normal codecs*/
480 payload_type_set_number(tev, -1);
481 if (ret==NULL){
482 /*But for first telephone-event, prefer the number that was configured in the core*/
483 if (is_payload_type_number_available(codecs, lc->codecs_conf.telephone_event_pt, NULL)){
484 payload_type_set_number(tev, lc->codecs_conf.telephone_event_pt);
485 }
486 }
487 ret=bctbx_list_append(ret,tev);
488 }
489 }
490 return ret;
491 }
492
create_special_payload_types(LinphoneCore * lc,const bctbx_list_t * codecs)493 static bctbx_list_t *create_special_payload_types(LinphoneCore *lc, const bctbx_list_t *codecs){
494 bctbx_list_t *ret=create_telephone_events(lc, codecs);
495 if (linphone_core_generic_comfort_noise_enabled(lc)){
496 PayloadType *cn=payload_type_clone(&payload_type_cn);
497 payload_type_set_number(cn, 13);
498 ret=bctbx_list_append(ret, cn);
499 }
500 return ret;
501 }
502
503 typedef struct _CodecConstraints{
504 int bandwidth_limit;
505 int max_codecs;
506 bctbx_list_t *previously_used;
507 }CodecConstraints;
508
make_codec_list(LinphoneCore * lc,CodecConstraints * hints,SalStreamType stype,const bctbx_list_t * codecs)509 static bctbx_list_t *make_codec_list(LinphoneCore *lc, CodecConstraints * hints, SalStreamType stype, const bctbx_list_t *codecs){
510 bctbx_list_t *l=NULL;
511 const bctbx_list_t *it;
512 int nb = 0;
513
514 for(it=codecs;it!=NULL;it=it->next){
515 PayloadType *pt=(PayloadType*)it->data;
516 int num;
517
518 if (!payload_type_enabled(pt)) {
519 continue;
520 }
521 if (hints->bandwidth_limit>0 && !linphone_core_is_payload_type_usable_for_bandwidth(lc,pt,hints->bandwidth_limit)){
522 ms_message("Codec %s/%i eliminated because of audio bandwidth constraint of %i kbit/s",
523 pt->mime_type,pt->clock_rate,hints->bandwidth_limit);
524 continue;
525 }
526 if (!_linphone_core_check_payload_type_usability(lc, pt)) {
527 continue;
528 }
529 pt=payload_type_clone(pt);
530
531 /*look for a previously assigned number for this codec*/
532 num=find_payload_type_number(hints->previously_used, pt);
533 if (num!=-1){
534 payload_type_set_number(pt,num);
535 payload_type_set_flag(pt, PAYLOAD_TYPE_FROZEN_NUMBER);
536 }
537
538 l=bctbx_list_append(l, pt);
539 nb++;
540 if ((hints->max_codecs > 0) && (nb >= hints->max_codecs)) break;
541 }
542 if (stype==SalAudio){
543 bctbx_list_t *specials=create_special_payload_types(lc,l);
544 l=bctbx_list_concat(l,specials);
545 }
546 linphone_core_assign_payload_type_numbers(lc, l);
547 return l;
548 }
549
update_media_description_from_stun(SalMediaDescription * md,const StunCandidate * ac,const StunCandidate * vc,const StunCandidate * tc)550 static void update_media_description_from_stun(SalMediaDescription *md, const StunCandidate *ac, const StunCandidate *vc, const StunCandidate *tc){
551 int i;
552 for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) {
553 if (!sal_stream_description_active(&md->streams[i])) continue;
554 if ((md->streams[i].type == SalAudio) && (ac->port != 0)) {
555 strcpy(md->streams[i].rtp_addr,ac->addr);
556 md->streams[i].rtp_port=ac->port;
557 if ((ac->addr[0]!='\0' && vc->addr[0]!='\0' && strcmp(ac->addr,vc->addr)==0) || sal_media_description_get_nb_active_streams(md)==1){
558 strcpy(md->addr,ac->addr);
559 }
560 } else if ((md->streams[i].type == SalVideo) && (vc->port != 0)) {
561 strcpy(md->streams[i].rtp_addr,vc->addr);
562 md->streams[i].rtp_port=vc->port;
563 } else if ((md->streams[i].type == SalText) && (tc->port != 0)) {
564 strcpy(md->streams[i].rtp_addr,tc->addr);
565 md->streams[i].rtp_port=tc->port;
566 }
567 }
568 }
569
setup_encryption_key(SalSrtpCryptoAlgo * crypto,MSCryptoSuite suite,unsigned int tag)570 static int setup_encryption_key(SalSrtpCryptoAlgo *crypto, MSCryptoSuite suite, unsigned int tag){
571 size_t keylen=0;
572 crypto->tag=tag;
573 crypto->algo=suite;
574 switch(suite){
575 case MS_AES_128_SHA1_80:
576 case MS_AES_128_SHA1_32:
577 case MS_AES_128_NO_AUTH:
578 case MS_NO_CIPHER_SHA1_80: /*not sure for this one*/
579 keylen=30;
580 break;
581 case MS_AES_256_SHA1_80:
582 case MS_AES_CM_256_SHA1_80:
583 case MS_AES_256_SHA1_32:
584 keylen=46;
585 break;
586 case MS_CRYPTO_SUITE_INVALID:
587 break;
588 }
589 if (keylen==0 || !generate_b64_crypto_key(keylen, crypto->master_key, SAL_SRTP_KEY_SIZE)){
590 ms_error("Could not generate SRTP key.");
591 crypto->algo = 0;
592 return -1;
593 }
594 return 0;
595 }
setup_dtls_keys(LinphoneCall * call,SalMediaDescription * md)596 static void setup_dtls_keys(LinphoneCall *call, SalMediaDescription *md){
597 int i;
598 for(i=0; i<SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) {
599 if (!sal_stream_description_active(&md->streams[i])) continue;
600 /* if media encryption is set to DTLS check presence of fingerprint in the call which shall have been set at stream init but it may have failed when retrieving certificate resulting in no fingerprint present and then DTLS not usable */
601 if (sal_stream_description_has_dtls(&md->streams[i]) == TRUE) {
602 strncpy(md->streams[i].dtls_fingerprint, call->dtls_certificate_fingerprint, sizeof(md->streams[i].dtls_fingerprint)); /* get the self fingerprint from call(it's computed at stream init) */
603 md->streams[i].dtls_role = SalDtlsRoleUnset; /* if we are offering, SDP will have actpass setup attribute when role is unset, if we are responding the result mediadescription will be set to SalDtlsRoleIsClient */
604 } else {
605 md->streams[i].dtls_fingerprint[0] = '\0';
606 md->streams[i].dtls_role = SalDtlsRoleInvalid;
607
608 }
609 }
610
611 }
setup_encryption_keys(LinphoneCall * call,SalMediaDescription * md)612 static void setup_encryption_keys(LinphoneCall *call, SalMediaDescription *md){
613 LinphoneCore *lc=call->core;
614 int i,j;
615 SalMediaDescription *old_md=call->localdesc;
616 bool_t keep_srtp_keys=lp_config_get_int(lc->config,"sip","keep_srtp_keys",1);
617
618 for(i=0; i<SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) {
619 if (!sal_stream_description_active(&md->streams[i])) continue;
620 if (sal_stream_description_has_srtp(&md->streams[i]) == TRUE) {
621 if (keep_srtp_keys && old_md && (sal_stream_description_active(&old_md->streams[i]) == TRUE) && (sal_stream_description_has_srtp(&old_md->streams[i]) == TRUE)) {
622 int j;
623 ms_message("Keeping same crypto keys.");
624 for(j=0;j<SAL_CRYPTO_ALGO_MAX;++j){
625 memcpy(&md->streams[i].crypto[j],&old_md->streams[i].crypto[j],sizeof(SalSrtpCryptoAlgo));
626 }
627 }else{
628 const MSCryptoSuite *suites=linphone_core_get_srtp_crypto_suites(lc);
629 for(j=0;suites!=NULL && suites[j]!=MS_CRYPTO_SUITE_INVALID && j<SAL_CRYPTO_ALGO_MAX;++j){
630 setup_encryption_key(&md->streams[i].crypto[j],suites[j],j+1);
631 }
632 }
633 }
634 }
635 }
636
637
setup_zrtp_hash(LinphoneCall * call,SalMediaDescription * md)638 static void setup_zrtp_hash(LinphoneCall *call, SalMediaDescription *md) {
639 int i;
640 if (linphone_core_media_encryption_supported(call->core, LinphoneMediaEncryptionZRTP)) { /* set the hello hash for all streams */
641 for(i=0; i<SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) {
642 if (!sal_stream_description_active(&md->streams[i])) continue;
643 if (call->sessions[i].zrtp_context!=NULL) {
644 ms_zrtp_getHelloHash(call->sessions[i].zrtp_context, md->streams[i].zrtphash, 128);
645 if (call->params->media_encryption==LinphoneMediaEncryptionZRTP) { /* turn on the flag to use it if ZRTP is set */
646 md->streams[i].haveZrtpHash = 1;
647 } else {
648 md->streams[i].haveZrtpHash = 0;
649 }
650 } else {
651 md->streams[i].haveZrtpHash = 0;
652 }
653 }
654 }
655 }
656
setup_rtcp_fb(LinphoneCall * call,SalMediaDescription * md)657 static void setup_rtcp_fb(LinphoneCall *call, SalMediaDescription *md) {
658 bctbx_list_t *pt_it;
659 PayloadType *pt;
660 PayloadTypeAvpfParams avpf_params;
661 LinphoneCore *lc = call->core;
662 int i;
663
664 for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) {
665 if (!sal_stream_description_active(&md->streams[i])) continue;
666 md->streams[i].rtcp_fb.generic_nack_enabled = lp_config_get_int(lc->config, "rtp", "rtcp_fb_generic_nack_enabled", 0);
667 md->streams[i].rtcp_fb.tmmbr_enabled = lp_config_get_int(lc->config, "rtp", "rtcp_fb_tmmbr_enabled", 1);
668 md->streams[i].implicit_rtcp_fb = call->params->implicit_rtcp_fb;
669
670 for (pt_it = md->streams[i].payloads; pt_it != NULL; pt_it = pt_it->next) {
671 pt = (PayloadType *)pt_it->data;
672
673 if (call->params->avpf_enabled == FALSE && call->params->implicit_rtcp_fb == FALSE) {
674 payload_type_unset_flag(pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED);
675 memset(&avpf_params, 0, sizeof(avpf_params));
676 }else {
677 payload_type_set_flag(pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED);
678 avpf_params = payload_type_get_avpf_params(pt);
679 avpf_params.trr_interval = call->params->avpf_rr_interval;
680 }
681 payload_type_set_avpf_params(pt, avpf_params);
682 }
683 }
684 }
685
setup_rtcp_xr(LinphoneCall * call,SalMediaDescription * md)686 static void setup_rtcp_xr(LinphoneCall *call, SalMediaDescription *md) {
687 LinphoneCore *lc = call->core;
688 int i;
689
690 md->rtcp_xr.enabled = lp_config_get_int(lc->config, "rtp", "rtcp_xr_enabled", 1);
691 if (md->rtcp_xr.enabled == TRUE) {
692 const char *rcvr_rtt_mode = lp_config_get_string(lc->config, "rtp", "rtcp_xr_rcvr_rtt_mode", "all");
693 if (strcasecmp(rcvr_rtt_mode, "all") == 0) md->rtcp_xr.rcvr_rtt_mode = OrtpRtcpXrRcvrRttAll;
694 else if (strcasecmp(rcvr_rtt_mode, "sender") == 0) md->rtcp_xr.rcvr_rtt_mode = OrtpRtcpXrRcvrRttSender;
695 else md->rtcp_xr.rcvr_rtt_mode = OrtpRtcpXrRcvrRttNone;
696 if (md->rtcp_xr.rcvr_rtt_mode != OrtpRtcpXrRcvrRttNone) {
697 md->rtcp_xr.rcvr_rtt_max_size = lp_config_get_int(lc->config, "rtp", "rtcp_xr_rcvr_rtt_max_size", 10000);
698 }
699 md->rtcp_xr.stat_summary_enabled = lp_config_get_int(lc->config, "rtp", "rtcp_xr_stat_summary_enabled", 1);
700 if (md->rtcp_xr.stat_summary_enabled == TRUE) {
701 md->rtcp_xr.stat_summary_flags = OrtpRtcpXrStatSummaryLoss | OrtpRtcpXrStatSummaryDup | OrtpRtcpXrStatSummaryJitt | OrtpRtcpXrStatSummaryTTL;
702 }
703 md->rtcp_xr.voip_metrics_enabled = lp_config_get_int(lc->config, "rtp", "rtcp_xr_voip_metrics_enabled", 1);
704 }
705 for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) {
706 if (!sal_stream_description_active(&md->streams[i])) continue;
707 memcpy(&md->streams[i].rtcp_xr, &md->rtcp_xr, sizeof(md->streams[i].rtcp_xr));
708 }
709 }
710
linphone_call_increment_local_media_description(LinphoneCall * call)711 void linphone_call_increment_local_media_description(LinphoneCall *call){
712 SalMediaDescription *md=call->localdesc;
713 md->session_ver++;
714 }
715
linphone_call_update_local_media_description_from_ice_or_upnp(LinphoneCall * call)716 void linphone_call_update_local_media_description_from_ice_or_upnp(LinphoneCall *call){
717 LinphoneCore *lc = call->core;
718 if (call->ice_session != NULL) {
719 /*set this to FALSE once flexisip are updated everywhere, let's say in December 2016.*/
720 bool_t use_nortpproxy = lp_config_get_int(lc->config, "sip", "ice_uses_nortpproxy", TRUE);
721 _update_local_media_description_from_ice(call->localdesc, call->ice_session, use_nortpproxy);
722 linphone_call_update_ice_state_in_call_stats(call);
723 }
724 #ifdef BUILD_UPNP
725 if(call->upnp_session != NULL) {
726 linphone_call_update_local_media_description_from_upnp(call->localdesc, call->upnp_session);
727 linphone_call_update_upnp_state_in_call_stats(call);
728 }
729 #endif //BUILD_UPNP
730 }
731
transfer_already_assigned_payload_types(SalMediaDescription * old,SalMediaDescription * md)732 static void transfer_already_assigned_payload_types(SalMediaDescription *old, SalMediaDescription *md){
733 int i;
734 for(i=0;i<SAL_MEDIA_DESCRIPTION_MAX_STREAMS;++i){
735 md->streams[i].already_assigned_payloads=old->streams[i].already_assigned_payloads;
736 old->streams[i].already_assigned_payloads=NULL;
737 }
738 }
739
linphone_call_get_bind_ip_for_stream(LinphoneCall * call,int stream_index)740 static const char *linphone_call_get_bind_ip_for_stream(LinphoneCall *call, int stream_index){
741 const char *bind_ip = lp_config_get_string(call->core->config,"rtp","bind_address",
742 call->af == AF_INET6 ? "::0" : "0.0.0.0");
743 PortConfig *pc = &call->media_ports[stream_index];
744 if (pc->multicast_ip[0]!='\0'){
745 if (call->dir==LinphoneCallOutgoing){
746 /*as multicast sender, we must decide a local interface to use to send multicast, and bind to it*/
747 linphone_core_get_local_ip_for(strchr(pc->multicast_ip,':') ? AF_INET6 : AF_INET,
748 NULL, pc->multicast_bind_ip);
749 bind_ip = pc->multicast_bind_ip;
750 }else{
751 /*otherwise we shall use an address family of the same family of the multicast address, because
752 * dual stack socket and multicast don't work well on Mac OS (linux is OK, as usual).*/
753 bind_ip = strchr(pc->multicast_ip,':') ? "::0" : "0.0.0.0";
754 }
755 }
756 return bind_ip;
757 }
758
linphone_call_get_public_ip_for_stream(LinphoneCall * call,int stream_index)759 static const char *linphone_call_get_public_ip_for_stream(LinphoneCall *call, int stream_index){
760 const char *public_ip=call->media_localip;
761
762 if (call->media_ports[stream_index].multicast_ip[0]!='\0')
763 public_ip=call->media_ports[stream_index].multicast_ip;
764 return public_ip;
765 }
766
linphone_call_update_biggest_desc(LinphoneCall * call,SalMediaDescription * md)767 void linphone_call_update_biggest_desc(LinphoneCall *call, SalMediaDescription *md){
768 if (call->biggestdesc==NULL || md->nb_streams>call->biggestdesc->nb_streams){
769 /*we have been offered and now are ready to proceed, or we added a new stream*/
770 /*store the media description to remember the mapping of calls*/
771 if (call->biggestdesc){
772 sal_media_description_unref(call->biggestdesc);
773 call->biggestdesc=NULL;
774 }
775 call->biggestdesc=sal_media_description_ref(md);
776 }
777 }
778
force_streams_dir_according_to_state(LinphoneCall * call,SalMediaDescription * md)779 static void force_streams_dir_according_to_state(LinphoneCall *call, SalMediaDescription *md){
780 int i;
781
782 for (i=0; i<SAL_MEDIA_DESCRIPTION_MAX_STREAMS; ++i){
783 SalStreamDescription *sd = &md->streams[i];
784
785 switch (call->state){
786 case LinphoneCallPausing:
787 case LinphoneCallPaused:
788 if (sd->dir != SalStreamInactive) {
789 sd->dir = SalStreamSendOnly;
790 if (sd->type == SalVideo){
791 if (lp_config_get_int(call->core->config, "sip", "inactive_video_on_pause", 0)) {
792 sd->dir = SalStreamInactive;
793 }
794 }
795 }
796 break;
797 default:
798 break;
799 }
800
801 /* Reflect the stream directions in the call params */
802 if (i == call->main_audio_stream_index) {
803 linphone_call_params_set_audio_direction(call->current_params, media_direction_from_sal_stream_dir(sd->dir));
804 } else if (i == call->main_video_stream_index) {
805 linphone_call_params_set_video_direction(call->current_params, media_direction_from_sal_stream_dir(sd->dir));
806 }
807 }
808 }
809
linphone_call_make_local_media_description(LinphoneCall * call)810 void linphone_call_make_local_media_description(LinphoneCall *call) {
811 bctbx_list_t *l;
812 SalMediaDescription *old_md=call->localdesc;
813 int i;
814 int max_index = 0;
815 SalMediaDescription *md=sal_media_description_new();
816 LinphoneAddress *addr;
817 const char *subject;
818 CodecConstraints codec_hints={0};
819 LinphoneCallParams *params = call->params;
820 LinphoneCore *lc = call->core;
821 bool_t rtcp_mux = lp_config_get_int(lc->config, "rtp", "rtcp_mux", 0);
822
823 /*multicast is only set in case of outgoing call*/
824 if (call->dir == LinphoneCallOutgoing && linphone_call_params_audio_multicast_enabled(params)) {
825 md->streams[call->main_audio_stream_index].ttl=linphone_core_get_audio_multicast_ttl(lc);
826 md->streams[call->main_audio_stream_index].multicast_role = SalMulticastSender;
827 }
828
829 if (call->dir == LinphoneCallOutgoing && linphone_call_params_video_multicast_enabled(params)) {
830 md->streams[call->main_video_stream_index].ttl=linphone_core_get_video_multicast_ttl(lc);
831 md->streams[call->main_video_stream_index].multicast_role = SalMulticastSender;
832 }
833
834 subject=linphone_call_params_get_session_name(params);
835
836 linphone_core_adapt_to_network(lc,call->ping_time,params);
837
838 if (call->dest_proxy) {
839 addr=linphone_address_clone(linphone_proxy_config_get_identity_address(call->dest_proxy));
840 } else {
841 addr=linphone_address_new(linphone_core_get_identity(lc));
842 }
843
844 md->session_id=(old_md ? old_md->session_id : (rand() & 0xfff));
845 md->session_ver=(old_md ? (old_md->session_ver+1) : (rand() & 0xfff));
846 md->nb_streams=(call->biggestdesc ? call->biggestdesc->nb_streams : 1);
847
848 /*re-check local ip address each time we make a new offer, because it may change in case of network reconnection*/
849 linphone_call_get_local_ip(call, call->dir == LinphoneCallOutgoing ? call->log->to : call->log->from);
850 strncpy(md->addr,call->media_localip,sizeof(md->addr));
851 if (linphone_address_get_username(addr)) /*might be null in case of identity without userinfo*/
852 strncpy(md->username,linphone_address_get_username(addr),sizeof(md->username));
853 if (subject) strncpy(md->name,subject,sizeof(md->name));
854
855 if (params->down_bw)
856 md->bandwidth=params->down_bw;
857 else md->bandwidth=linphone_core_get_download_bandwidth(lc);
858
859 if (params->custom_sdp_attributes)
860 md->custom_sdp_attributes = sal_custom_sdp_attribute_clone(params->custom_sdp_attributes);
861
862 /*set audio capabilities */
863
864 codec_hints.bandwidth_limit=params->audio_bw;
865 codec_hints.max_codecs=-1;
866 codec_hints.previously_used=old_md ? old_md->streams[call->main_audio_stream_index].already_assigned_payloads : NULL;
867 l=make_codec_list(lc, &codec_hints, SalAudio, lc->codecs_conf.audio_codecs);
868
869 if (params->has_audio && l != NULL) {
870 strncpy(md->streams[call->main_audio_stream_index].rtp_addr,linphone_call_get_public_ip_for_stream(call,call->main_audio_stream_index),sizeof(md->streams[call->main_audio_stream_index].rtp_addr));
871 strncpy(md->streams[call->main_audio_stream_index].rtcp_addr,linphone_call_get_public_ip_for_stream(call,call->main_audio_stream_index),sizeof(md->streams[call->main_audio_stream_index].rtcp_addr));
872 strncpy(md->streams[call->main_audio_stream_index].name,"Audio",sizeof(md->streams[call->main_audio_stream_index].name)-1);
873 md->streams[call->main_audio_stream_index].rtp_port=call->media_ports[call->main_audio_stream_index].rtp_port;
874 md->streams[call->main_audio_stream_index].rtcp_port=call->media_ports[call->main_audio_stream_index].rtcp_port;
875 md->streams[call->main_audio_stream_index].proto=get_proto_from_call_params(params);
876 md->streams[call->main_audio_stream_index].dir=get_audio_dir_from_call_params(params);
877 md->streams[call->main_audio_stream_index].type=SalAudio;
878 md->streams[call->main_audio_stream_index].rtcp_mux = rtcp_mux;
879 if (params->down_ptime)
880 md->streams[call->main_audio_stream_index].ptime=params->down_ptime;
881 else
882 md->streams[call->main_audio_stream_index].ptime=linphone_core_get_download_ptime(lc);
883 md->streams[call->main_audio_stream_index].max_rate=get_max_codec_sample_rate(l);
884 md->streams[call->main_audio_stream_index].payloads=l;
885 if (call->audiostream && call->audiostream->ms.sessions.rtp_session) {
886 char* me = linphone_address_as_string_uri_only(call->me);
887 md->streams[call->main_audio_stream_index].rtp_ssrc=rtp_session_get_send_ssrc(call->audiostream->ms.sessions.rtp_session);
888 strncpy(md->streams[call->main_audio_stream_index].rtcp_cname,me,sizeof(md->streams[call->main_audio_stream_index].rtcp_cname));
889 ms_free(me);
890 }
891 else
892 ms_warning("Cannot get audio local ssrc for call [%p]",call);
893 if (call->main_audio_stream_index > max_index)
894 max_index = call->main_audio_stream_index;
895 } else {
896 ms_message("Don't put audio stream on local offer for call [%p]",call);
897 md->streams[call->main_audio_stream_index].dir = SalStreamInactive;
898 if(l) l=bctbx_list_free_with_data(l, (void (*)(void *))payload_type_destroy);
899 }
900 if (params->custom_sdp_media_attributes[LinphoneStreamTypeAudio])
901 md->streams[call->main_audio_stream_index].custom_sdp_attributes = sal_custom_sdp_attribute_clone(params->custom_sdp_media_attributes[LinphoneStreamTypeAudio]);
902
903 md->streams[call->main_video_stream_index].proto=md->streams[call->main_audio_stream_index].proto;
904 md->streams[call->main_video_stream_index].dir=get_video_dir_from_call_params(params);
905 md->streams[call->main_video_stream_index].type=SalVideo;
906 md->streams[call->main_video_stream_index].rtcp_mux = rtcp_mux;
907 strncpy(md->streams[call->main_video_stream_index].name,"Video",sizeof(md->streams[call->main_video_stream_index].name)-1);
908
909 codec_hints.bandwidth_limit=0;
910 codec_hints.max_codecs=-1;
911 codec_hints.previously_used=old_md ? old_md->streams[call->main_video_stream_index].already_assigned_payloads : NULL;
912 l=make_codec_list(lc, &codec_hints, SalVideo, lc->codecs_conf.video_codecs);
913
914 if (params->has_video && l != NULL){
915 strncpy(md->streams[call->main_video_stream_index].rtp_addr,linphone_call_get_public_ip_for_stream(call,call->main_video_stream_index),sizeof(md->streams[call->main_video_stream_index].rtp_addr));
916 strncpy(md->streams[call->main_video_stream_index].rtcp_addr,linphone_call_get_public_ip_for_stream(call,call->main_video_stream_index),sizeof(md->streams[call->main_video_stream_index].rtcp_addr));
917 md->streams[call->main_video_stream_index].rtp_port=call->media_ports[call->main_video_stream_index].rtp_port;
918 md->streams[call->main_video_stream_index].rtcp_port=call->media_ports[call->main_video_stream_index].rtcp_port;
919 md->streams[call->main_video_stream_index].payloads=l;
920 if (call->videostream && call->videostream->ms.sessions.rtp_session) {
921 char* me = linphone_address_as_string_uri_only(call->me);
922 md->streams[call->main_video_stream_index].rtp_ssrc=rtp_session_get_send_ssrc(call->videostream->ms.sessions.rtp_session);
923 strncpy(md->streams[call->main_video_stream_index].rtcp_cname,me,sizeof(md->streams[call->main_video_stream_index].rtcp_cname));
924 ms_free(me);
925 }
926 else
927 ms_warning("Cannot get video local ssrc for call [%p]",call);
928 if (call->main_video_stream_index > max_index)
929 max_index = call->main_video_stream_index;
930 } else {
931 ms_message("Don't put video stream on local offer for call [%p]",call);
932 md->streams[call->main_video_stream_index].dir = SalStreamInactive;
933 if(l) l=bctbx_list_free_with_data(l, (void (*)(void *))payload_type_destroy);
934 }
935 if (params->custom_sdp_media_attributes[LinphoneStreamTypeVideo])
936 md->streams[call->main_video_stream_index].custom_sdp_attributes = sal_custom_sdp_attribute_clone(params->custom_sdp_media_attributes[LinphoneStreamTypeVideo]);
937
938 md->streams[call->main_text_stream_index].proto=md->streams[call->main_audio_stream_index].proto;
939 md->streams[call->main_text_stream_index].dir=SalStreamSendRecv;
940 md->streams[call->main_text_stream_index].type=SalText;
941 md->streams[call->main_text_stream_index].rtcp_mux = rtcp_mux;
942 strncpy(md->streams[call->main_text_stream_index].name,"Text",sizeof(md->streams[call->main_text_stream_index].name)-1);
943 if (params->realtimetext_enabled) {
944 strncpy(md->streams[call->main_text_stream_index].rtp_addr,linphone_call_get_public_ip_for_stream(call,call->main_text_stream_index),sizeof(md->streams[call->main_text_stream_index].rtp_addr));
945 strncpy(md->streams[call->main_text_stream_index].rtcp_addr,linphone_call_get_public_ip_for_stream(call,call->main_text_stream_index),sizeof(md->streams[call->main_text_stream_index].rtcp_addr));
946
947 md->streams[call->main_text_stream_index].rtp_port=call->media_ports[call->main_text_stream_index].rtp_port;
948 md->streams[call->main_text_stream_index].rtcp_port=call->media_ports[call->main_text_stream_index].rtcp_port;
949
950 codec_hints.bandwidth_limit=0;
951 codec_hints.max_codecs=-1;
952 codec_hints.previously_used=old_md ? old_md->streams[call->main_text_stream_index].already_assigned_payloads : NULL;
953 l=make_codec_list(lc, &codec_hints, SalText, lc->codecs_conf.text_codecs);
954 md->streams[call->main_text_stream_index].payloads=l;
955 if (call->textstream && call->textstream->ms.sessions.rtp_session) {
956 char* me = linphone_address_as_string_uri_only(call->me);
957 md->streams[call->main_text_stream_index].rtp_ssrc=rtp_session_get_send_ssrc(call->textstream->ms.sessions.rtp_session);
958 strncpy(md->streams[call->main_text_stream_index].rtcp_cname,me,sizeof(md->streams[call->main_text_stream_index].rtcp_cname));
959 ms_free(me);
960 }
961 else
962 ms_warning("Cannot get text local ssrc for call [%p]",call);
963 if (call->main_text_stream_index > max_index)
964 max_index = call->main_text_stream_index;
965 } else {
966 ms_message("Don't put text stream on local offer for call [%p]",call);
967 md->streams[call->main_text_stream_index].dir = SalStreamInactive;
968 }
969 if (params->custom_sdp_media_attributes[LinphoneStreamTypeText])
970 md->streams[call->main_text_stream_index].custom_sdp_attributes = sal_custom_sdp_attribute_clone(params->custom_sdp_media_attributes[LinphoneStreamTypeText]);
971
972 md->nb_streams = MAX(md->nb_streams,max_index+1);
973
974 /* Deactivate unused streams. */
975 for (i = md->nb_streams; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) {
976 if (md->streams[i].rtp_port == 0) {
977 md->streams[i].dir = SalStreamInactive;
978 if (call->biggestdesc && i < call->biggestdesc->nb_streams) {
979 md->streams[i].proto = call->biggestdesc->streams[i].proto;
980 md->streams[i].type = call->biggestdesc->streams[i].type;
981 }
982 }
983 }
984 setup_encryption_keys(call,md);
985 setup_dtls_keys(call,md);
986 setup_zrtp_hash(call, md);
987
988 setup_rtcp_fb(call, md);
989 setup_rtcp_xr(call, md);
990
991 update_media_description_from_stun(md, &call->ac, &call->vc, &call->tc);
992 call->localdesc=md;
993 linphone_call_update_local_media_description_from_ice_or_upnp(call);
994 linphone_address_unref(addr);
995 if (old_md){
996 transfer_already_assigned_payload_types(old_md,md);
997 call->localdesc_changed=sal_media_description_equals(md,old_md);
998 sal_media_description_unref(old_md);
999 if (call->params->internal_call_update){
1000 /*
1001 * An internal call update (ICE reINVITE) is not expected to modify the actual media stream parameters.
1002 * However, the localdesc may change between first INVITE and ICE reINVITE, for example if the remote party has declined a video stream.
1003 * We use the internal_call_update flag to prevent trigger an unnecessary media restart.
1004 */
1005 call->localdesc_changed = 0;
1006 }
1007 }
1008 force_streams_dir_according_to_state(call, md);
1009 }
1010
find_port_offset(LinphoneCore * lc,int stream_index,int base_port)1011 static int find_port_offset(LinphoneCore *lc, int stream_index, int base_port){
1012 int offset;
1013 bctbx_list_t *elem;
1014 int tried_port;
1015 int existing_port;
1016 bool_t already_used=FALSE;
1017
1018 for(offset=0;offset<100;offset+=2){
1019 tried_port=base_port+offset;
1020 already_used=FALSE;
1021 for(elem=lc->calls;elem!=NULL;elem=elem->next){
1022 LinphoneCall *call=(LinphoneCall*)elem->data;
1023 existing_port=call->media_ports[stream_index].rtp_port;
1024 if (existing_port==tried_port) {
1025 already_used=TRUE;
1026 break;
1027 }
1028 }
1029 if (!already_used) break;
1030 }
1031 if (offset==100){
1032 ms_error("Could not find any free port !");
1033 return -1;
1034 }
1035 return offset;
1036 }
1037
select_random_port(LinphoneCore * lc,int stream_index,int min_port,int max_port)1038 static int select_random_port(LinphoneCore *lc, int stream_index, int min_port, int max_port) {
1039 bctbx_list_t *elem;
1040 int nb_tries;
1041 int tried_port = 0;
1042 int existing_port = 0;
1043 bool_t already_used = FALSE;
1044
1045 tried_port = (ortp_random() % (max_port - min_port) + min_port) & ~0x1;
1046 if (tried_port < min_port) tried_port = min_port + 2;
1047 for (nb_tries = 0; nb_tries < 100; nb_tries++) {
1048 for (elem = lc->calls; elem != NULL; elem = elem->next) {
1049 LinphoneCall *call = (LinphoneCall *)elem->data;
1050 existing_port=call->media_ports[stream_index].rtp_port;
1051 if (existing_port == tried_port) {
1052 already_used = TRUE;
1053 break;
1054 }
1055 }
1056 if (!already_used) break;
1057 }
1058 if (nb_tries == 100) {
1059 ms_error("Could not find any free port!");
1060 return -1;
1061 }
1062 return tried_port;
1063 }
1064
port_config_set_random(LinphoneCall * call,int stream_index)1065 static void port_config_set_random(LinphoneCall *call, int stream_index){
1066 call->media_ports[stream_index].rtp_port=-1;
1067 call->media_ports[stream_index].rtcp_port=-1;
1068 }
1069
port_config_set(LinphoneCall * call,int stream_index,int min_port,int max_port)1070 static void port_config_set(LinphoneCall *call, int stream_index, int min_port, int max_port){
1071 int port_offset;
1072 if (min_port>0 && max_port>0){
1073 if (min_port == max_port) {
1074 /* Used fixed RTP audio port. */
1075 port_offset=find_port_offset(call->core, stream_index, min_port);
1076 if (port_offset==-1) {
1077 port_config_set_random(call, stream_index);
1078 return;
1079 }
1080 call->media_ports[stream_index].rtp_port=min_port+port_offset;
1081 } else {
1082 /* Select random RTP audio port in the specified range. */
1083 call->media_ports[stream_index].rtp_port = select_random_port(call->core, stream_index, min_port, max_port);
1084 }
1085 call->media_ports[stream_index].rtcp_port=call->media_ports[stream_index].rtp_port+1;
1086 }else port_config_set_random(call,stream_index);
1087 }
1088
linphone_call_init_common(LinphoneCall * call,LinphoneAddress * from,LinphoneAddress * to)1089 static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){
1090 int min_port, max_port;
1091 ms_message("New LinphoneCall [%p] initialized (LinphoneCore version: %s)",call,linphone_core_get_version());
1092 call->ei = linphone_error_info_new();
1093 call->core->send_call_stats_periodical_updates = lp_config_get_int(call->core->config, "misc", "send_call_stats_periodical_updates", 0);
1094 call->main_audio_stream_index = LINPHONE_CALL_STATS_AUDIO;
1095 call->main_video_stream_index = LINPHONE_CALL_STATS_VIDEO;
1096 call->main_text_stream_index = LINPHONE_CALL_STATS_TEXT;
1097 call->state=LinphoneCallIdle;
1098 call->transfer_state = LinphoneCallIdle;
1099 call->log=linphone_call_log_new(call->dir, from, to);
1100 call->camera_enabled=TRUE;
1101 call->current_params = linphone_call_params_new();
1102 call->current_params->media_encryption=LinphoneMediaEncryptionNone;
1103 call->dtls_certificate_fingerprint = NULL;
1104 if (call->dir == LinphoneCallIncoming)
1105 call->me=to;
1106 else
1107 call->me=from;
1108 linphone_address_ref(call->me);
1109
1110 linphone_core_get_audio_port_range(call->core, &min_port, &max_port);
1111 port_config_set(call,call->main_audio_stream_index,min_port,max_port);
1112
1113 linphone_core_get_video_port_range(call->core, &min_port, &max_port);
1114 port_config_set(call,call->main_video_stream_index,min_port,max_port);
1115
1116 linphone_core_get_text_port_range(call->core, &min_port, &max_port);
1117 port_config_set(call,call->main_text_stream_index,min_port,max_port);
1118
1119 linphone_call_init_stats(call->audio_stats, LINPHONE_CALL_STATS_AUDIO);
1120 linphone_call_init_stats(call->video_stats, LINPHONE_CALL_STATS_VIDEO);
1121 linphone_call_init_stats(call->text_stats, LINPHONE_CALL_STATS_TEXT);
1122
1123 if (call->dest_proxy == NULL) {
1124 /* Try to define the destination proxy if it has not already been done to have a correct contact field in the SIP messages */
1125 call->dest_proxy = linphone_core_lookup_known_proxy(call->core, call->log->to);
1126 }
1127
1128
1129 if (call->dest_proxy != NULL)
1130 call->nat_policy = linphone_proxy_config_get_nat_policy(call->dest_proxy);
1131 if (call->nat_policy == NULL)
1132 call->nat_policy = linphone_core_get_nat_policy(call->core);
1133
1134 linphone_nat_policy_ref(call->nat_policy);
1135
1136 }
1137
linphone_call_init_stats(LinphoneCallStats * stats,int type)1138 void linphone_call_init_stats(LinphoneCallStats *stats, int type) {
1139 stats->type = type;
1140 stats->received_rtcp = NULL;
1141 stats->sent_rtcp = NULL;
1142 stats->ice_state = LinphoneIceStateNotActivated;
1143 #ifdef BUILD_UPNP
1144 stats->upnp_state = LinphoneUpnpStateIdle;
1145 #else
1146 stats->upnp_state = LinphoneUpnpStateNotAvailable;
1147 #endif //BUILD_UPNP
1148 }
1149
discover_mtu(LinphoneCore * lc,const char * remote)1150 static void discover_mtu(LinphoneCore *lc, const char *remote){
1151 int mtu;
1152 if (lc->net_conf.mtu==0 ){
1153 /*attempt to discover mtu*/
1154 mtu=ms_discover_mtu(remote);
1155 if (mtu>0){
1156 ms_factory_set_mtu(lc->factory, mtu);
1157 ms_message("Discovered mtu is %i, RTP payload max size is %i",
1158 mtu, ms_factory_get_payload_max_size(lc->factory));
1159 }
1160 }
1161 }
1162
linphone_call_create_op(LinphoneCall * call)1163 void linphone_call_create_op(LinphoneCall *call){
1164 if (call->op) sal_op_release(call->op);
1165 call->op=sal_op_new(call->core->sal);
1166 sal_op_set_user_pointer(call->op,call);
1167 if (call->params->referer)
1168 sal_call_set_referer(call->op,call->params->referer->op);
1169 linphone_configure_op(call->core,call->op,call->log->to,call->params->custom_headers,FALSE);
1170 if (call->params->privacy != LinphonePrivacyDefault)
1171 sal_op_set_privacy(call->op,(SalPrivacyMask)call->params->privacy);
1172 /*else privacy might be set by proxy */
1173 }
1174
1175 /*
1176 * Choose IP version we are going to use for RTP streams IP address advertised in SDP.
1177 * The algorithm is as follows:
1178 * - if ipv6 is disabled at the core level, it is always AF_INET
1179 * - Otherwise, if the destination address for the call is an IPv6 address, use IPv6.
1180 * - Otherwise, if the call is done through a known proxy config, then use the information obtained during REGISTER
1181 * to know if IPv6 is supported by the server.
1182 **/
linphone_call_outgoing_select_ip_version(LinphoneCall * call,LinphoneAddress * to,LinphoneProxyConfig * cfg)1183 static void linphone_call_outgoing_select_ip_version(LinphoneCall *call, LinphoneAddress *to, LinphoneProxyConfig *cfg){
1184 if (linphone_core_ipv6_enabled(call->core)){
1185 if (sal_address_is_ipv6((SalAddress*)to)){
1186 call->af=AF_INET6;
1187 }else if (cfg && cfg->op){
1188 call->af=sal_op_get_address_family(cfg->op);
1189 }else{
1190 call->af=AF_UNSPEC;
1191 }
1192 if (call->af == AF_UNSPEC) {
1193 char ipv4[LINPHONE_IPADDR_SIZE];
1194 char ipv6[LINPHONE_IPADDR_SIZE];
1195 bool_t have_ipv6 = FALSE;
1196 bool_t have_ipv4 = FALSE;
1197 /*check connectivity for IPv4 and IPv6*/
1198 if (linphone_core_get_local_ip_for(AF_INET6, NULL, ipv6) == 0){
1199 have_ipv6 = TRUE;
1200 }
1201 if (linphone_core_get_local_ip_for(AF_INET, NULL, ipv4) == 0){
1202 have_ipv4 = TRUE;
1203 }
1204 if (have_ipv6){
1205 if (!have_ipv4) {
1206 call->af = AF_INET6;
1207 }else if (lp_config_get_int(call->core->config, "rtp", "prefer_ipv6", 1)){ /*this property tells whether ipv6 is prefered if two versions are available*/
1208 call->af = AF_INET6;
1209 }else{
1210 call->af = AF_INET;
1211 }
1212 }else call->af = AF_INET;
1213 /*fill the media_localip default value since we have it here*/
1214 strncpy(call->media_localip,call->af == AF_INET6 ? ipv6 : ipv4, LINPHONE_IPADDR_SIZE);
1215 }
1216 }else call->af=AF_INET;
1217 }
1218
1219 /**
1220 * Fill the local ip that routes to the internet according to the destination, or guess it by other special means (upnp).
1221 */
linphone_call_get_local_ip(LinphoneCall * call,const LinphoneAddress * remote_addr)1222 static void linphone_call_get_local_ip(LinphoneCall *call, const LinphoneAddress *remote_addr){
1223 const char *ip = NULL;
1224 int af = call->af;
1225 const char *dest = NULL;
1226
1227 if (linphone_core_get_firewall_policy(call->core)==LinphonePolicyUseNatAddress
1228 && (ip=linphone_core_get_nat_address_resolved(call->core))!=NULL){
1229 strncpy(call->media_localip,ip,LINPHONE_IPADDR_SIZE);
1230 return;
1231 }
1232 #ifdef BUILD_UPNP
1233 else if (call->core->upnp != NULL && linphone_core_get_firewall_policy(call->core)==LinphonePolicyUseUpnp &&
1234 linphone_upnp_context_get_state(call->core->upnp) == LinphoneUpnpStateOk) {
1235 ip = linphone_upnp_context_get_external_ipaddress(call->core->upnp);
1236 strncpy(call->media_localip,ip,LINPHONE_IPADDR_SIZE);
1237 goto found;
1238 }
1239 #endif //BUILD_UPNP
1240
1241 /*next, sometime, override from config*/
1242 if ((ip=lp_config_get_string(call->core->config,"rtp","bind_address",NULL)) != NULL)
1243 goto found;
1244
1245 /*if a known proxy was identified for this call, then we may have a chance to take the local ip address
1246 * from the socket that connect to this proxy */
1247 if (call->dest_proxy && call->dest_proxy->op){
1248 if ((ip = sal_op_get_local_address(call->dest_proxy->op, NULL)) != NULL){
1249 ms_message("Found media local-ip from signaling.");
1250 goto found;
1251 }
1252 }
1253
1254 /*in last resort, attempt to find the local ip that routes to destination if given as an IP address,
1255 or the default route (dest=NULL)*/
1256 if (call->dest_proxy == NULL) {
1257 struct addrinfo hints;
1258 struct addrinfo *res = NULL;
1259 int err;
1260 /*FIXME the following doesn't work for IPv6 address because of brakets*/
1261 const char *domain = linphone_address_get_domain(remote_addr);
1262 memset(&hints, 0, sizeof(hints));
1263 hints.ai_family = AF_UNSPEC;
1264 hints.ai_socktype = SOCK_DGRAM;
1265 hints.ai_flags = AI_NUMERICHOST;
1266 err = getaddrinfo(domain, NULL, &hints, &res);
1267 if (err == 0) {
1268 dest = domain;
1269 }
1270 if (res != NULL) freeaddrinfo(res);
1271 }
1272
1273 if (dest != NULL || call->media_localip[0] == '\0' || call->need_localip_refresh){
1274 call->need_localip_refresh = FALSE;
1275 linphone_core_get_local_ip(call->core, af, dest, call->media_localip);
1276 }
1277 return;
1278 found:
1279 strncpy(call->media_localip,ip,LINPHONE_IPADDR_SIZE);
1280 }
1281
1282 static void linphone_call_destroy(LinphoneCall *obj);
1283
1284 BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneCall);
1285
1286 BELLE_SIP_INSTANCIATE_VPTR(LinphoneCall, belle_sip_object_t,
1287 (belle_sip_object_destroy_t)linphone_call_destroy,
1288 NULL, // clone
1289 NULL, // marshal
1290 FALSE
1291 );
1292
linphone_call_fill_media_multicast_addr(LinphoneCall * call)1293 void linphone_call_fill_media_multicast_addr(LinphoneCall *call) {
1294 if (linphone_call_params_audio_multicast_enabled(call->params)){
1295 strncpy(call->media_ports[call->main_audio_stream_index].multicast_ip,
1296 linphone_core_get_audio_multicast_addr(call->core), sizeof(call->media_ports[call->main_audio_stream_index].multicast_ip));
1297 } else
1298 call->media_ports[call->main_audio_stream_index].multicast_ip[0]='\0';
1299
1300 if (linphone_call_params_video_multicast_enabled(call->params)){
1301 strncpy(call->media_ports[call->main_video_stream_index].multicast_ip,
1302 linphone_core_get_video_multicast_addr(call->core), sizeof(call->media_ports[call->main_video_stream_index].multicast_ip));
1303 } else
1304 call->media_ports[call->main_video_stream_index].multicast_ip[0]='\0';
1305 }
1306
linphone_call_check_ice_session(LinphoneCall * call,IceRole role,bool_t is_reinvite)1307 void linphone_call_check_ice_session(LinphoneCall *call, IceRole role, bool_t is_reinvite){
1308 if (call->ice_session) return; /*already created*/
1309
1310 if (!linphone_nat_policy_ice_enabled(call->nat_policy)){
1311 return;
1312 }
1313
1314 if (is_reinvite && lp_config_get_int(call->core->config, "net", "allow_late_ice", 0) == 0) return;
1315
1316 call->ice_session = ice_session_new();
1317 /*for backward compatibility purposes, shall be enabled by default in futur*/
1318 ice_session_enable_message_integrity_check(call->ice_session,lp_config_get_int(call->core->config,"net","ice_session_enable_message_integrity_check",1));
1319 if (lp_config_get_int(call->core->config, "net", "dont_default_to_stun_candidates", 0)){
1320 IceCandidateType types[ICT_CandidateTypeMax];
1321 types[0] = ICT_HostCandidate;
1322 types[1] = ICT_RelayedCandidate;
1323 types[2] = ICT_CandidateInvalid;
1324 ice_session_set_default_candidates_types(call->ice_session, types);
1325 }
1326 ice_session_set_role(call->ice_session, role);
1327 }
1328
linphone_call_new_outgoing(struct _LinphoneCore * lc,LinphoneAddress * from,LinphoneAddress * to,const LinphoneCallParams * params,LinphoneProxyConfig * cfg)1329 LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params, LinphoneProxyConfig *cfg){
1330 LinphoneCall *call = belle_sip_object_new(LinphoneCall);
1331 call->dir=LinphoneCallOutgoing;
1332 call->core=lc;
1333 call->dest_proxy=cfg;
1334 call->audio_stats = linphone_call_stats_ref(linphone_call_stats_new());
1335 call->video_stats = linphone_call_stats_ref(linphone_call_stats_new());
1336 call->text_stats = linphone_call_stats_ref(linphone_call_stats_new());
1337 linphone_call_outgoing_select_ip_version(call,to,cfg);
1338 linphone_call_get_local_ip(call, to);
1339 call->params = linphone_call_params_copy(params);
1340 linphone_call_init_common(call, from, to);
1341
1342 call->current_params->update_call_when_ice_completed = call->params->update_call_when_ice_completed; /*copy param*/
1343
1344 linphone_call_fill_media_multicast_addr(call);
1345
1346 linphone_call_check_ice_session(call, IR_Controlling, FALSE);
1347
1348 if (linphone_nat_policy_ice_enabled(call->nat_policy)) {
1349 call->ping_time=linphone_core_run_stun_tests(call->core,call);
1350 }
1351 #ifdef BUILD_UPNP
1352 if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseUpnp) {
1353 if(!lc->rtp_conf.disable_upnp) {
1354 call->upnp_session = linphone_upnp_session_new(call);
1355 }
1356 }
1357 #endif //BUILD_UPNP
1358
1359 discover_mtu(lc,linphone_address_get_domain (to));
1360 if (params->referer){
1361 call->referer=linphone_call_ref(params->referer);
1362 }
1363
1364 linphone_call_create_op(call);
1365 return call;
1366 }
1367
1368 /*Select IP version to use for advertising local addresses of RTP streams, for an incoming call.
1369 *If the call is received through a know proxy that is IPv6, use IPv6.
1370 *Otherwise check the remote contact address.
1371 *If later the resulting media description tells that we have to send IPv4, it won't be a problem because the RTP sockets
1372 * are dual stack.
1373 */
linphone_call_incoming_select_ip_version(LinphoneCall * call,LinphoneProxyConfig * cfg)1374 static void linphone_call_incoming_select_ip_version(LinphoneCall *call, LinphoneProxyConfig *cfg){
1375 if (linphone_core_ipv6_enabled(call->core)){
1376 if (cfg && cfg->op){
1377 call->af=sal_op_get_address_family(cfg->op);
1378 }else{
1379 call->af=sal_op_get_address_family(call->op);
1380 }
1381 }else call->af=AF_INET;
1382 }
1383
1384 /**
1385 * Fix call parameters on incoming call to eg. enable AVPF if the incoming call propose it and it is not enabled locally.
1386 */
linphone_call_set_compatible_incoming_call_parameters(LinphoneCall * call,SalMediaDescription * md)1387 void linphone_call_set_compatible_incoming_call_parameters(LinphoneCall *call, SalMediaDescription *md) {
1388 /* Handle AVPF, SRTP and DTLS. */
1389 call->params->avpf_enabled = sal_media_description_has_avpf(md);
1390 if (call->dest_proxy != NULL) {
1391 call->params->avpf_rr_interval = linphone_proxy_config_get_avpf_rr_interval(call->dest_proxy) * 1000;
1392 } else {
1393 call->params->avpf_rr_interval = linphone_core_get_avpf_rr_interval(call->core)*1000;
1394 }
1395
1396 if ((sal_media_description_has_zrtp(md) == TRUE) && (linphone_core_media_encryption_supported(call->core, LinphoneMediaEncryptionZRTP) == TRUE)) {
1397 call->params->media_encryption = LinphoneMediaEncryptionZRTP;
1398 }else if ((sal_media_description_has_dtls(md) == TRUE) && (media_stream_dtls_supported() == TRUE)) {
1399 call->params->media_encryption = LinphoneMediaEncryptionDTLS;
1400 }else if ((sal_media_description_has_srtp(md) == TRUE) && (ms_srtp_supported() == TRUE)) {
1401 call->params->media_encryption = LinphoneMediaEncryptionSRTP;
1402 }else if (call->params->media_encryption != LinphoneMediaEncryptionZRTP){
1403 call->params->media_encryption = LinphoneMediaEncryptionNone;
1404 }
1405
1406 /*in case of nat64, even ipv4 addresses are reachable from v6. Should be enhanced to manage stream by stream connectivity (I.E v6 or v4)*/
1407 /*if (!sal_media_description_has_ipv6(md)){
1408 ms_message("The remote SDP doesn't seem to offer any IPv6 connectivity, so disabling IPv6 for this call.");
1409 call->af = AF_INET;
1410 }*/
1411 linphone_call_fix_call_parameters(call, md);
1412 }
1413
linphone_call_compute_streams_indexes(LinphoneCall * call,const SalMediaDescription * md)1414 static void linphone_call_compute_streams_indexes(LinphoneCall *call, const SalMediaDescription *md) {
1415 int i, j;
1416 bool_t audio_found = FALSE, video_found = FALSE, text_found = FALSE;
1417
1418 for (i = 0; i < md->nb_streams; i++) {
1419 if (md->streams[i].type == SalAudio) {
1420 if (!audio_found) {
1421 call->main_audio_stream_index = i;
1422 audio_found = TRUE;
1423 ms_message("audio stream index found: %i, updating main audio stream index", i);
1424 } else {
1425 ms_message("audio stream index found: %i, but main audio stream already set to %i", i, call->main_audio_stream_index);
1426 }
1427
1428 // Check that the default value of a another stream doesn't match the new one
1429 if (i == call->main_video_stream_index) {
1430 for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; j++) {
1431 if (sal_stream_description_active(&md->streams[j])) continue;
1432 if (j != call->main_video_stream_index && j != call->main_text_stream_index) {
1433 ms_message("%i was used for video stream ; now using %i", i, j);
1434 call->main_video_stream_index = j;
1435 break;
1436 }
1437 }
1438 }
1439 if (i == call->main_text_stream_index) {
1440 for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; j++) {
1441 if (sal_stream_description_active(&md->streams[j])) continue;
1442 if (j != call->main_video_stream_index && j != call->main_text_stream_index) {
1443 ms_message("%i was used for text stream ; now using %i", i, j);
1444 call->main_text_stream_index = j;
1445 break;
1446 }
1447 }
1448 }
1449 } else if (md->streams[i].type == SalVideo) {
1450 if (!video_found) {
1451 call->main_video_stream_index = i;
1452 video_found = TRUE;
1453 ms_message("video stream index found: %i, updating main video stream index", i);
1454 } else {
1455 ms_message("video stream index found: %i, but main video stream already set to %i", i, call->main_video_stream_index);
1456 }
1457
1458 // Check that the default value of a another stream doesn't match the new one
1459 if (i == call->main_audio_stream_index) {
1460 for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; j++) {
1461 if (sal_stream_description_active(&md->streams[j])) continue;
1462 if (j != call->main_audio_stream_index && j != call->main_text_stream_index) {
1463 ms_message("%i was used for audio stream ; now using %i", i, j);
1464 call->main_audio_stream_index = j;
1465 break;
1466 }
1467 }
1468 }
1469 if (i == call->main_text_stream_index) {
1470 for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; j++) {
1471 if (sal_stream_description_active(&md->streams[j])) continue;
1472 if (j != call->main_audio_stream_index && j != call->main_text_stream_index) {
1473 ms_message("%i was used for text stream ; now using %i", i, j);
1474 call->main_text_stream_index = j;
1475 break;
1476 }
1477 }
1478 }
1479 } else if (md->streams[i].type == SalText) {
1480 if (!text_found) {
1481 call->main_text_stream_index = i;
1482 text_found = TRUE;
1483 ms_message("text stream index found: %i, updating main text stream index", i);
1484 } else {
1485 ms_message("text stream index found: %i, but main text stream already set to %i", i, call->main_text_stream_index);
1486 }
1487
1488 // Check that the default value of a another stream doesn't match the new one
1489 if (i == call->main_audio_stream_index) {
1490 for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; j++) {
1491 if (sal_stream_description_active(&md->streams[j])) continue;
1492 if (j != call->main_video_stream_index && j != call->main_audio_stream_index) {
1493 ms_message("%i was used for audio stream ; now using %i", i, j);
1494 call->main_audio_stream_index = j;
1495 break;
1496 }
1497 }
1498 }
1499 if (i == call->main_video_stream_index) {
1500 for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; j++) {
1501 if (sal_stream_description_active(&md->streams[j])) continue;
1502 if (j != call->main_video_stream_index && j != call->main_audio_stream_index) {
1503 ms_message("%i was used for video stream ; now using %i", i, j);
1504 call->main_video_stream_index = j;
1505 break;
1506 }
1507 }
1508 }
1509 }
1510 }
1511 }
1512
linphone_call_new_incoming(LinphoneCore * lc,LinphoneAddress * from,LinphoneAddress * to,SalOp * op)1513 LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op){
1514 LinphoneCall *call = belle_sip_object_new(LinphoneCall);
1515 SalMediaDescription *md;
1516 LinphoneNatPolicy *nat_policy = NULL;
1517 int i;
1518 call->dir=LinphoneCallIncoming;
1519 call->audio_stats = linphone_call_stats_ref(linphone_call_stats_new());
1520 call->video_stats = linphone_call_stats_ref(linphone_call_stats_new());
1521 call->text_stats = linphone_call_stats_ref(linphone_call_stats_new());
1522 sal_op_set_user_pointer(op,call);
1523 call->op=op;
1524 call->core=lc;
1525
1526 call->dest_proxy = linphone_core_lookup_known_proxy(call->core, to);
1527 linphone_call_incoming_select_ip_version(call, call->dest_proxy);
1528 /*note that the choice of IP version for streams is later refined by
1529 * linphone_call_set_compatible_incoming_call_parameters() when examining the remote offer, if any.
1530 * If the remote offer contains IPv4 addresses, we should propose IPv4 as well*/
1531
1532 sal_op_cnx_ip_to_0000_if_sendonly_enable(op,lp_config_get_default_int(lc->config,"sip","cnx_ip_to_0000_if_sendonly_enabled",0));
1533
1534 md = sal_call_get_remote_media_description(op);
1535
1536 if (lc->sip_conf.ping_with_options){
1537 #ifdef BUILD_UPNP
1538 if (lc->upnp != NULL && linphone_core_get_firewall_policy(lc)==LinphonePolicyUseUpnp &&
1539 linphone_upnp_context_get_state(lc->upnp) == LinphoneUpnpStateOk) {
1540 #else //BUILD_UPNP
1541 {
1542 #endif //BUILD_UPNP
1543 /*the following sends an option request back to the caller so that
1544 we get a chance to discover our nat'd address before answering.*/
1545 call->ping_op=sal_op_new(lc->sal);
1546
1547 linphone_configure_op(lc, call->ping_op, from, NULL, FALSE);
1548
1549 sal_op_set_route(call->ping_op,sal_op_get_network_origin(op));
1550 sal_op_set_user_pointer(call->ping_op,call);
1551
1552 sal_ping(call->ping_op,sal_op_get_from(call->ping_op), sal_op_get_to(call->ping_op));
1553 }
1554 }
1555
1556 linphone_address_clean(from);
1557 linphone_call_get_local_ip(call, from);
1558 call->params = linphone_call_params_new();
1559 linphone_call_init_common(call, from, to);
1560 call->log->call_id=ms_strdup(sal_op_get_call_id(op)); /*must be known at that time*/
1561 linphone_core_init_default_params(lc, call->params);
1562
1563 /*
1564 * Initialize call parameters according to incoming call parameters. This is to avoid to ask later (during reINVITEs) for features that the remote
1565 * end apparently does not support. This features are: privacy, video
1566 */
1567 /*set privacy*/
1568 call->current_params->privacy=(LinphonePrivacyMask)sal_op_get_privacy(call->op);
1569 /*config params*/
1570 call->current_params->update_call_when_ice_completed = call->params->update_call_when_ice_completed; /*copy config params*/
1571
1572 /*set video support */
1573 call->params->has_video = linphone_core_video_enabled(lc) && lc->video_policy.automatically_accept;
1574 if (md) {
1575 // It is licit to receive an INVITE without SDP
1576 // In this case WE chose the media parameters according to policy.
1577 linphone_call_set_compatible_incoming_call_parameters(call, md);
1578 /* set multicast role & address if any*/
1579 if (!sal_call_is_offerer(op)){
1580 for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) {
1581 if (md->streams[i].dir == SalStreamInactive) {
1582 continue;
1583 }
1584
1585 if (md->streams[i].rtp_addr[0]!='\0' && ms_is_multicast(md->streams[i].rtp_addr)){
1586 md->streams[i].multicast_role = SalMulticastReceiver;
1587 strncpy(call->media_ports[i].multicast_ip,md->streams[i].rtp_addr,sizeof(call->media_ports[i].multicast_ip));
1588 }
1589 }
1590 }
1591 }
1592
1593 nat_policy=call->nat_policy;
1594 if ((nat_policy != NULL) && linphone_nat_policy_ice_enabled(nat_policy)) {
1595 /* Create the ice session now if ICE is required */
1596 if (md){
1597 linphone_call_check_ice_session(call, IR_Controlled, FALSE);
1598 }else{
1599 nat_policy = NULL;
1600 ms_warning("ICE not supported for incoming INVITE without SDP.");
1601 }
1602 }
1603
1604 /*reserve the sockets immediately*/
1605 linphone_call_init_media_streams(call);
1606 if (nat_policy != NULL) {
1607 if (linphone_nat_policy_ice_enabled(nat_policy)) {
1608 call->defer_notify_incoming = linphone_call_prepare_ice(call,TRUE) == 1;
1609 } else if (linphone_nat_policy_stun_enabled(nat_policy)) {
1610 call->ping_time=linphone_core_run_stun_tests(call->core,call);
1611 } else if (linphone_nat_policy_upnp_enabled(nat_policy)) {
1612 #ifdef BUILD_UPNP
1613 if(!lc->rtp_conf.disable_upnp) {
1614 call->upnp_session = linphone_upnp_session_new(call);
1615 if (call->upnp_session != NULL) {
1616 if (linphone_call_update_upnp_from_remote_media_description(call, sal_call_get_remote_media_description(op))<0) {
1617 /* uPnP port mappings failed, proceed with the call anyway. */
1618 linphone_call_delete_upnp_session(call);
1619 }
1620 }
1621 }
1622 #endif //BUILD_UPNP
1623 }
1624 }
1625
1626 discover_mtu(lc,linphone_address_get_domain(from));
1627 return call;
1628 }
1629
1630 /*
1631 * Frees the media resources of the call.
1632 * This has to be done at the earliest, unlike signaling resources that sometimes need to be kept a bit more longer.
1633 * It is called by linphone_call_set_terminated() (for termination of calls signaled to the application), or directly by the destructor of LinphoneCall
1634 * (_linphone_call_destroy) if the call was never notified to the application.
1635 */
1636 static void linphone_call_free_media_resources(LinphoneCall *call){
1637 int i;
1638
1639 linphone_call_stop_media_streams(call);
1640 linphone_call_delete_upnp_session(call);
1641 linphone_call_delete_ice_session(call);
1642 for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; ++i){
1643 ms_media_stream_sessions_uninit(&call->sessions[i]);
1644 }
1645 linphone_call_stats_uninit(call->audio_stats);
1646 linphone_call_stats_uninit(call->video_stats);
1647 linphone_call_stats_uninit(call->text_stats);
1648 }
1649
1650 /*
1651 * Called internally when reaching the Released state, to perform cleanups to break circular references.
1652 **/
1653 static void linphone_call_set_released(LinphoneCall *call){
1654 if (call->op!=NULL) {
1655 /*transfer the last error so that it can be obtained even in Released state*/
1656 if (!call->non_op_error){
1657 linphone_error_info_from_sal_op(call->ei, call->op);
1658 }
1659 /* so that we cannot have anymore upcalls for SAL
1660 concerning this call*/
1661 sal_op_release(call->op);
1662 call->op=NULL;
1663 }
1664 /*it is necessary to reset pointers to other call to prevent circular references that would result in memory never freed.*/
1665 if (call->referer){
1666 linphone_call_unref(call->referer);
1667 call->referer=NULL;
1668 }
1669 if (call->transfer_target){
1670 linphone_call_unref(call->transfer_target);
1671 call->transfer_target=NULL;
1672 }
1673 if (call->chat_room){
1674 linphone_chat_room_unref(call->chat_room);
1675 call->chat_room = NULL;
1676 }
1677 linphone_call_unref(call);
1678 }
1679
1680 /* this function is called internally to get rid of a call that was notified to the application, because it reached the end or error state.
1681 It performs the following tasks:
1682 - remove the call from the internal list of calls
1683 - update the call logs accordingly
1684 */
1685 static void linphone_call_set_terminated(LinphoneCall *call){
1686 LinphoneCore *lc=call->core;
1687
1688 linphone_call_free_media_resources(call);
1689 linphone_call_log_completed(call);
1690
1691 if (call == lc->current_call){
1692 ms_message("Resetting the current call");
1693 lc->current_call=NULL;
1694 }
1695
1696 if (linphone_core_del_call(lc,call) != 0){
1697 ms_error("Could not remove the call from the list !!!");
1698 }
1699 if(lc->conf_ctx) linphone_conference_on_call_terminating(lc->conf_ctx, call);
1700 if (call->ringing_beep){
1701 linphone_core_stop_dtmf(lc);
1702 call->ringing_beep=FALSE;
1703 }
1704 if (call->chat_room){
1705 call->chat_room->call = NULL;
1706 }
1707 }
1708
1709 /*function to be called at each incoming reINVITE, in order to adjust various local parameters to what is being offered by remote:
1710 * - the video enablement parameter according to what is offered and our local policy.
1711 * Fixing the call->params to proper values avoid request video by accident during internal call updates, pauses and resumes
1712 * - the stream indexes.
1713 */
1714 void linphone_call_fix_call_parameters(LinphoneCall *call, SalMediaDescription *rmd){
1715 const LinphoneCallParams* rcp;
1716
1717 if (rmd) {
1718 linphone_call_compute_streams_indexes(call, rmd);
1719 linphone_call_update_biggest_desc(call, rmd);
1720 /* Why disabling implicit_rtcp_fb ? It is a local policy choice actually. It doesn't disturb to propose it again and again
1721 * even if the other end apparently doesn't support it.
1722 * The following line of code is causing trouble, while for example making an audio call, then adding video.
1723 * Due to the 200Ok response of the audio-only offer where no rtcp-fb attribute is present, implicit_rtcp_fb is set to
1724 * FALSE, which is then preventing it to be eventually used when video is later added to the call.
1725 * I did the choice of commenting it out.
1726 */
1727 /*call->params->implicit_rtcp_fb &= sal_media_description_has_implicit_avpf(rmd);*/
1728 }
1729 rcp = linphone_call_get_remote_params(call);
1730 if (rcp){
1731 if (call->params->has_audio && !rcp->has_audio){
1732 ms_message("Call [%p]: disabling audio in our call params because the remote doesn't want it.", call);
1733 call->params->has_audio = FALSE;
1734 }
1735 if (call->params->has_video && !rcp->has_video){
1736 ms_message("Call [%p]: disabling video in our call params because the remote doesn't want it.", call);
1737 call->params->has_video = FALSE;
1738 }
1739
1740 if (rcp->has_video && call->core->video_policy.automatically_accept && linphone_core_video_enabled(call->core) && !call->params->has_video){
1741 ms_message("Call [%p]: re-enabling video in our call params because the remote wants it and the policy allows to automatically accept.", call);
1742 linphone_call_params_enable_video(call->params, TRUE);
1743 }
1744
1745 if (rcp->realtimetext_enabled && !call->params->realtimetext_enabled) {
1746 call->params->realtimetext_enabled = TRUE;
1747 }
1748 }
1749 }
1750
1751 const char *linphone_call_state_to_string(LinphoneCallState cs){
1752 switch (cs){
1753 case LinphoneCallIdle:
1754 return "LinphoneCallIdle";
1755 case LinphoneCallIncomingReceived:
1756 return "LinphoneCallIncomingReceived";
1757 case LinphoneCallOutgoingInit:
1758 return "LinphoneCallOutgoingInit";
1759 case LinphoneCallOutgoingProgress:
1760 return "LinphoneCallOutgoingProgress";
1761 case LinphoneCallOutgoingRinging:
1762 return "LinphoneCallOutgoingRinging";
1763 case LinphoneCallOutgoingEarlyMedia:
1764 return "LinphoneCallOutgoingEarlyMedia";
1765 case LinphoneCallConnected:
1766 return "LinphoneCallConnected";
1767 case LinphoneCallStreamsRunning:
1768 return "LinphoneCallStreamsRunning";
1769 case LinphoneCallPausing:
1770 return "LinphoneCallPausing";
1771 case LinphoneCallPaused:
1772 return "LinphoneCallPaused";
1773 case LinphoneCallResuming:
1774 return "LinphoneCallResuming";
1775 case LinphoneCallRefered:
1776 return "LinphoneCallRefered";
1777 case LinphoneCallError:
1778 return "LinphoneCallError";
1779 case LinphoneCallEnd:
1780 return "LinphoneCallEnd";
1781 case LinphoneCallPausedByRemote:
1782 return "LinphoneCallPausedByRemote";
1783 case LinphoneCallUpdatedByRemote:
1784 return "LinphoneCallUpdatedByRemote";
1785 case LinphoneCallIncomingEarlyMedia:
1786 return "LinphoneCallIncomingEarlyMedia";
1787 case LinphoneCallUpdating:
1788 return "LinphoneCallUpdating";
1789 case LinphoneCallReleased:
1790 return "LinphoneCallReleased";
1791 case LinphoneCallEarlyUpdatedByRemote:
1792 return "LinphoneCallEarlyUpdatedByRemote";
1793 case LinphoneCallEarlyUpdating:
1794 return "LinphoneCallEarlyUpdating";
1795 }
1796 return "undefined state";
1797 }
1798
1799 void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message){
1800 LinphoneCore *lc=call->core;
1801
1802 if (call->state!=cstate){
1803 call->prevstate=call->state;
1804
1805 /*Make sanity checks with call state changes. Any bad transition can result in unpredictable results
1806 *or irrecoverable errors in the application*/
1807 if (call->state==LinphoneCallEnd || call->state==LinphoneCallError){
1808 if (cstate!=LinphoneCallReleased){
1809 ms_fatal("Abnormal call resurection from %s to %s, aborting." ,linphone_call_state_to_string(call->state)
1810 ,linphone_call_state_to_string(cstate));
1811 return;
1812 }
1813 }else if (cstate == LinphoneCallReleased && (call->prevstate != LinphoneCallError && call->prevstate != LinphoneCallEnd)){
1814 ms_fatal("Attempt to move call [%p] to Released state while it was not previously in Error or End state. Aborting.", call);
1815 return;
1816 }
1817 ms_message("Call %p: moving from state %s to %s",call
1818 ,linphone_call_state_to_string(call->state)
1819 ,linphone_call_state_to_string(cstate));
1820
1821 if (cstate!=LinphoneCallRefered){
1822 /*LinphoneCallRefered is rather an event, not a state.
1823 Indeed it does not change the state of the call (still paused or running)*/
1824 call->state=cstate;
1825 }
1826
1827 switch (cstate) {
1828 case LinphoneCallOutgoingInit:
1829 case LinphoneCallIncomingReceived:
1830 #ifdef __ANDROID__
1831 ms_message("Call [%p] acquires both wifi and multicast lock",call);
1832 linphone_core_wifi_lock_acquire(call->core);
1833 linphone_core_multicast_lock_acquire(call->core); /*does no affect battery more than regular rtp traffic*/
1834 #endif
1835 break;
1836 case LinphoneCallEnd:
1837 case LinphoneCallError:
1838 switch(linphone_error_info_get_reason(linphone_call_get_error_info(call))) {
1839 case LinphoneReasonDeclined:
1840 call->log->status=LinphoneCallDeclined;
1841 break;
1842 case LinphoneReasonNotAnswered:
1843 if (call->log->dir == LinphoneCallIncoming){
1844 call->log->status=LinphoneCallMissed;
1845 }
1846 break;
1847 default:
1848 break;
1849 }
1850 linphone_call_set_terminated(call);
1851 break;
1852 case LinphoneCallConnected:
1853 call->log->status=LinphoneCallSuccess;
1854 call->log->connected_date_time = ms_time(NULL);
1855 break;
1856 case LinphoneCallReleased:
1857 #ifdef __ANDROID__
1858 ms_message("Call [%p] releases wifi/multicast lock",call);
1859 linphone_core_wifi_lock_release(call->core);
1860 linphone_core_multicast_lock_release(call->core);
1861 #endif
1862 break;
1863 case LinphoneCallStreamsRunning:
1864 if (call->prevstate == LinphoneCallUpdating || call->prevstate == LinphoneCallUpdatedByRemote) {
1865 LinphoneReason reason = linphone_call_get_reason(call);
1866 char *msg;
1867 if (reason != LinphoneReasonNone) {
1868 msg = ms_strdup_printf(_("Call parameters could not be modified: %s."), linphone_reason_to_string(reason));
1869 } else {
1870 msg = ms_strdup(_("Call parameters were successfully modified."));
1871 }
1872 linphone_core_notify_display_status(lc, msg);
1873 ms_free(msg);
1874 }
1875 break;
1876 default:
1877 break;
1878 }
1879
1880 if(cstate!=LinphoneCallStreamsRunning) {
1881 if (call->dtmfs_timer!=NULL){
1882 /*cancelling DTMF sequence, if any*/
1883 linphone_call_cancel_dtmfs(call);
1884 }
1885 }
1886 if (!message) {
1887 ms_error("%s(): You must fill a reason when changing call state (from %s o %s)."
1888 , __FUNCTION__
1889 , linphone_call_state_to_string(call->prevstate)
1890 , linphone_call_state_to_string(call->state));
1891 }
1892 linphone_call_notify_state_changed(call, cstate, message ? message : "");
1893 linphone_reporting_call_state_updated(call);
1894 if (cstate==LinphoneCallReleased) {/*shall be performed after app notification*/
1895 linphone_call_set_released(call);
1896 }
1897 }
1898 }
1899
1900 static void linphone_call_destroy(LinphoneCall *obj){
1901 ms_message("Call [%p] freed.",obj);
1902 bctbx_list_free_with_data(obj->callbacks, (bctbx_list_free_func)linphone_call_cbs_unref);
1903 if (obj->audiostream || obj->videostream){
1904 linphone_call_free_media_resources(obj);
1905 }
1906 if (obj->audio_stats) {
1907 linphone_call_stats_unref(obj->audio_stats);
1908 obj->audio_stats = NULL;
1909 }
1910 if (obj->video_stats) {
1911 linphone_call_stats_unref(obj->video_stats);
1912 obj->video_stats = NULL;
1913 }
1914 if (obj->text_stats) {
1915 linphone_call_stats_unref(obj->text_stats);
1916 obj->text_stats = NULL;
1917 }
1918 if (obj->op!=NULL) {
1919 sal_op_release(obj->op);
1920 obj->op=NULL;
1921 }
1922 if (obj->biggestdesc!=NULL){
1923 sal_media_description_unref(obj->biggestdesc);
1924 obj->biggestdesc=NULL;
1925 }
1926 if (obj->resultdesc!=NULL) {
1927 sal_media_description_unref(obj->resultdesc);
1928 obj->resultdesc=NULL;
1929 }
1930 if (obj->localdesc!=NULL) {
1931 sal_media_description_unref(obj->localdesc);
1932 obj->localdesc=NULL;
1933 }
1934 if (obj->ping_op) {
1935 sal_op_release(obj->ping_op);
1936 obj->ping_op=NULL;
1937 }
1938 if (obj->refer_to){
1939 ms_free(obj->refer_to);
1940 obj->refer_to=NULL;
1941 }
1942 if (obj->referer){
1943 linphone_call_unref(obj->referer);
1944 obj->referer=NULL;
1945 }
1946 if (obj->transfer_target){
1947 linphone_call_unref(obj->transfer_target);
1948 obj->transfer_target=NULL;
1949 }
1950 if (obj->log) {
1951 linphone_call_log_unref(obj->log);
1952 obj->log=NULL;
1953 }
1954 if (obj->auth_token) {
1955 ms_free(obj->auth_token);
1956 obj->auth_token=NULL;
1957 }
1958 if (obj->dtls_certificate_fingerprint) {
1959 ms_free(obj->dtls_certificate_fingerprint);
1960 obj->dtls_certificate_fingerprint=NULL;
1961 }
1962 if (obj->dtmfs_timer) {
1963 linphone_call_cancel_dtmfs(obj);
1964 }
1965 if (obj->params){
1966 linphone_call_params_unref(obj->params);
1967 obj->params=NULL;
1968 }
1969 if (obj->current_params){
1970 linphone_call_params_unref(obj->current_params);
1971 obj->current_params=NULL;
1972 }
1973 if (obj->remote_params != NULL) {
1974 linphone_call_params_unref(obj->remote_params);
1975 obj->remote_params=NULL;
1976 }
1977 if (obj->me) {
1978 linphone_address_unref(obj->me);
1979 obj->me = NULL;
1980 }
1981 if (obj->onhold_file) ms_free(obj->onhold_file);
1982
1983 if (obj->ei) linphone_error_info_unref(obj->ei);
1984 if (obj->nat_policy)
1985 linphone_nat_policy_unref(obj->nat_policy);
1986 }
1987
1988 LinphoneCall * linphone_call_ref(LinphoneCall *obj){
1989 belle_sip_object_ref(obj);
1990 return obj;
1991 }
1992
1993 void linphone_call_unref(LinphoneCall *obj){
1994 belle_sip_object_unref(obj);
1995 }
1996
1997 static unsigned int linphone_call_get_n_active_streams(const LinphoneCall *call) {
1998 SalMediaDescription *md=NULL;
1999 if (call->op)
2000 md = sal_call_get_remote_media_description(call->op);
2001 if (!md)
2002 return 0;
2003 return sal_media_description_nb_active_streams_of_type(md, SalAudio) + sal_media_description_nb_active_streams_of_type(md, SalVideo) + sal_media_description_nb_active_streams_of_type(md, SalText);
2004 }
2005
2006 const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call){
2007 SalMediaDescription *md=call->resultdesc;
2008 int all_streams_encrypted = 0;
2009 #ifdef VIDEO_ENABLED
2010 VideoStream *vstream;
2011 #endif
2012 MS_VIDEO_SIZE_ASSIGN(call->current_params->sent_vsize, UNKNOWN);
2013 MS_VIDEO_SIZE_ASSIGN(call->current_params->recv_vsize, UNKNOWN);
2014 #ifdef VIDEO_ENABLED
2015 if (call->current_params->sent_vdef != NULL) linphone_video_definition_unref(call->current_params->sent_vdef);
2016 call->current_params->sent_vdef = NULL;
2017 if (call->current_params->recv_vdef != NULL) linphone_video_definition_unref(call->current_params->recv_vdef);
2018 call->current_params->recv_vdef = NULL;
2019 vstream = call->videostream;
2020 if (vstream != NULL) {
2021 call->current_params->sent_vsize = video_stream_get_sent_video_size(vstream);
2022 call->current_params->recv_vsize = video_stream_get_received_video_size(vstream);
2023 call->current_params->sent_vdef = linphone_video_definition_ref(linphone_factory_find_supported_video_definition(
2024 linphone_factory_get(), call->current_params->sent_vsize.width, call->current_params->sent_vsize.height));
2025 call->current_params->recv_vdef = linphone_video_definition_ref(linphone_factory_find_supported_video_definition(
2026 linphone_factory_get(), call->current_params->recv_vsize.width, call->current_params->recv_vsize.height));
2027 call->current_params->sent_fps = video_stream_get_sent_framerate(vstream);
2028 call->current_params->received_fps = video_stream_get_received_framerate(vstream);
2029 }
2030 #endif
2031
2032 /* REVISITED
2033 * Previous code was buggy.
2034 * Relying on the mediastream's state (added by jehan: only) to know the current encryption is unreliable.
2035 * For (added by jehan: both DTLS and) ZRTP it is though necessary.
2036 * But for all others the current_params->media_encryption state should reflect (added by jehan: both) what is agreed by the offer/answer
2037 * mechanism (added by jehan: and encryption status from media which is much stronger than only result of offer/answer )
2038 * Typically there can be inactive streams for which the media layer has no idea of whether they are encrypted or not.
2039 */
2040
2041 switch (call->params->media_encryption) {
2042 case LinphoneMediaEncryptionZRTP:
2043 if (at_least_one_stream_started(call)){
2044 if ((all_streams_encrypted = linphone_call_all_streams_encrypted(call)) && linphone_call_get_authentication_token(call)) {
2045 call->current_params->media_encryption=LinphoneMediaEncryptionZRTP;
2046 } else {
2047 /*to avoid to many traces*/
2048 ms_debug("Encryption was requested to be %s, but isn't effective (all_streams_encrypted=%i, auth_token=%s)",
2049 linphone_media_encryption_to_string(call->params->media_encryption), all_streams_encrypted, call->auth_token == NULL ? "" : call->auth_token);
2050 call->current_params->media_encryption=LinphoneMediaEncryptionNone;
2051 }
2052 }//else don't update the state if all streams are shutdown.
2053 break;
2054 case LinphoneMediaEncryptionDTLS:
2055 case LinphoneMediaEncryptionSRTP:
2056 if (at_least_one_stream_started(call)){
2057 if (linphone_call_get_n_active_streams(call)==0 || (all_streams_encrypted = linphone_call_all_streams_encrypted(call))) {
2058 call->current_params->media_encryption = call->params->media_encryption;
2059 } else {
2060 /*to avoid to many traces*/
2061 ms_debug("Encryption was requested to be %s, but isn't effective (all_streams_encrypted=%i)",
2062 linphone_media_encryption_to_string(call->params->media_encryption), all_streams_encrypted);
2063 call->current_params->media_encryption=LinphoneMediaEncryptionNone;
2064 }
2065 }//else don't update the state if all streams are shutdown.
2066 break;
2067 case LinphoneMediaEncryptionNone:
2068 /* check if we actually switched to ZRTP */
2069 if (at_least_one_stream_started(call) && (all_streams_encrypted = linphone_call_all_streams_encrypted(call)) && linphone_call_get_authentication_token(call)) {
2070 call->current_params->media_encryption=LinphoneMediaEncryptionZRTP;
2071 } else {
2072 call->current_params->media_encryption=LinphoneMediaEncryptionNone;
2073 }
2074 break;
2075 }
2076 call->current_params->avpf_enabled = linphone_call_all_streams_avpf_enabled(call) && sal_media_description_has_avpf(md);
2077 if (call->current_params->avpf_enabled == TRUE) {
2078 call->current_params->avpf_rr_interval = linphone_call_get_avpf_rr_interval(call);
2079 } else {
2080 call->current_params->avpf_rr_interval = 0;
2081 }
2082 if (md){
2083 const char *rtp_addr;
2084
2085 SalStreamDescription *sd=sal_media_description_find_best_stream(md,SalAudio);
2086
2087 call->current_params->audio_dir=sd ? media_direction_from_sal_stream_dir(sd->dir) : LinphoneMediaDirectionInactive;
2088 if (call->current_params->audio_dir != LinphoneMediaDirectionInactive) {
2089 rtp_addr = sd->rtp_addr[0]!='\0' ? sd->rtp_addr : call->resultdesc->addr;
2090 call->current_params->audio_multicast_enabled = ms_is_multicast(rtp_addr);
2091 } else
2092 call->current_params->audio_multicast_enabled = FALSE;
2093
2094 sd=sal_media_description_find_best_stream(md,SalVideo);
2095 call->current_params->implicit_rtcp_fb = sd ? sal_stream_description_has_implicit_avpf(sd): FALSE;
2096 call->current_params->video_dir=sd ? media_direction_from_sal_stream_dir(sd->dir) : LinphoneMediaDirectionInactive;
2097 if (call->current_params->video_dir != LinphoneMediaDirectionInactive) {
2098 rtp_addr = sd->rtp_addr[0]!='\0' ? sd->rtp_addr : call->resultdesc->addr;
2099 call->current_params->video_multicast_enabled = ms_is_multicast(rtp_addr);
2100 } else
2101 call->current_params->video_multicast_enabled = FALSE;
2102
2103 }
2104
2105 return call->current_params;
2106 }
2107
2108 const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call){
2109 if (call->op){
2110 LinphoneCallParams *cp;
2111 SalMediaDescription *md;
2112 const SalCustomHeader *ch;
2113
2114 md=sal_call_get_remote_media_description(call->op);
2115 if (md) {
2116 SalStreamDescription *sd;
2117 unsigned int i;
2118 unsigned int nb_audio_streams = sal_media_description_nb_active_streams_of_type(md, SalAudio);
2119 unsigned int nb_video_streams = sal_media_description_nb_active_streams_of_type(md, SalVideo);
2120 unsigned int nb_text_streams = sal_media_description_nb_active_streams_of_type(md, SalText);
2121 if (call->remote_params != NULL) linphone_call_params_unref(call->remote_params);
2122 cp = call->remote_params = linphone_call_params_new();
2123
2124 for (i = 0; i < nb_video_streams; i++) {
2125 sd = sal_media_description_get_active_stream_of_type(md, SalVideo, i);
2126 if (sal_stream_description_active(sd) == TRUE) cp->has_video = TRUE;
2127 if (sal_stream_description_has_srtp(sd) == TRUE) cp->media_encryption = LinphoneMediaEncryptionSRTP;
2128 }
2129 for (i = 0; i < nb_audio_streams; i++) {
2130 sd = sal_media_description_get_active_stream_of_type(md, SalAudio, i);
2131 if (sal_stream_description_has_srtp(sd) == TRUE) cp->media_encryption = LinphoneMediaEncryptionSRTP;
2132 }
2133 for (i = 0; i < nb_text_streams; i++) {
2134 sd = sal_media_description_get_active_stream_of_type(md, SalText, i);
2135 if (sal_stream_description_has_srtp(sd) == TRUE) cp->media_encryption = LinphoneMediaEncryptionSRTP;
2136 cp->realtimetext_enabled = TRUE;
2137 }
2138 if (!cp->has_video){
2139 if (md->bandwidth>0 && md->bandwidth<=linphone_core_get_edge_bw(call->core)){
2140 cp->low_bandwidth=TRUE;
2141 }
2142 }
2143 if (md->name[0]!='\0') linphone_call_params_set_session_name(cp,md->name);
2144
2145 linphone_call_params_set_custom_sdp_attributes(call->remote_params, md->custom_sdp_attributes);
2146 linphone_call_params_set_custom_sdp_media_attributes(call->remote_params, LinphoneStreamTypeAudio, md->streams[call->main_audio_stream_index].custom_sdp_attributes);
2147 linphone_call_params_set_custom_sdp_media_attributes(call->remote_params, LinphoneStreamTypeVideo, md->streams[call->main_video_stream_index].custom_sdp_attributes);
2148 linphone_call_params_set_custom_sdp_media_attributes(call->remote_params, LinphoneStreamTypeText, md->streams[call->main_text_stream_index].custom_sdp_attributes);
2149 }
2150 ch = sal_op_get_recv_custom_header(call->op);
2151 if (ch){
2152 /*instanciate a remote_params only if a SIP message was received before (custom headers indicates this).*/
2153 if (call->remote_params == NULL) call->remote_params = linphone_call_params_new();
2154 linphone_call_params_set_custom_headers(call->remote_params, ch);
2155 }
2156 return call->remote_params;
2157 }
2158 return NULL;
2159 }
2160
2161 const LinphoneAddress * linphone_call_get_remote_address(const LinphoneCall *call){
2162 return call->dir==LinphoneCallIncoming ? call->log->from : call->log->to;
2163 }
2164
2165 const LinphoneAddress * linphone_call_get_to_address(const LinphoneCall *call){
2166 return (const LinphoneAddress *)sal_op_get_to_address(call->op);
2167 }
2168
2169 char *linphone_call_get_remote_address_as_string(const LinphoneCall *call){
2170 return linphone_address_as_string(linphone_call_get_remote_address(call));
2171 }
2172
2173 const LinphoneAddress * linphone_call_get_diversion_address(const LinphoneCall *call){
2174 return call->op?(const LinphoneAddress *)sal_op_get_diversion_address(call->op):NULL;
2175 }
2176
2177 LinphoneCallState linphone_call_get_state(const LinphoneCall *call){
2178 return call->state;
2179 }
2180
2181 LinphoneReason linphone_call_get_reason(const LinphoneCall *call){
2182 return linphone_error_info_get_reason(linphone_call_get_error_info(call));
2183 }
2184
2185 const LinphoneErrorInfo *linphone_call_get_error_info(const LinphoneCall *call){
2186 if (!call->non_op_error){
2187 linphone_error_info_from_sal_op(call->ei, call->op);
2188 }
2189 return call->ei;
2190 }
2191
2192 void *linphone_call_get_user_data(const LinphoneCall *call)
2193 {
2194 return call->user_data;
2195 }
2196
2197 void linphone_call_set_user_data(LinphoneCall *call, void *user_pointer)
2198 {
2199 call->user_data = user_pointer;
2200 }
2201
2202 LinphoneCallLog *linphone_call_get_call_log(const LinphoneCall *call){
2203 return call->log;
2204 }
2205
2206 const char *linphone_call_get_refer_to(const LinphoneCall *call){
2207 return call->refer_to;
2208 }
2209
2210 LinphoneCall *linphone_call_get_transferer_call(const LinphoneCall *call){
2211 return call->referer;
2212 }
2213
2214 LinphoneCall *linphone_call_get_transfer_target_call(const LinphoneCall *call){
2215 return call->transfer_target;
2216 }
2217
2218 LinphoneCallDir linphone_call_get_dir(const LinphoneCall *call){
2219 return call->log->dir;
2220 }
2221
2222 const char *linphone_call_get_remote_user_agent(LinphoneCall *call){
2223 if (call->op){
2224 return sal_op_get_remote_ua (call->op);
2225 }
2226 return NULL;
2227 }
2228
2229 const char *linphone_call_get_remote_contact(LinphoneCall *call){
2230 if( call->op ){
2231 /*sal_op_get_remote_contact preserves header params*/
2232 return sal_op_get_remote_contact(call->op);
2233 }
2234 return NULL;
2235 }
2236
2237 bool_t linphone_call_has_transfer_pending(const LinphoneCall *call){
2238 return call->refer_pending;
2239 }
2240
2241 static int _linphone_call_compute_duration (const LinphoneCall *call) {
2242 if (call->log->connected_date_time == 0) return 0;
2243 else return (int)(ms_time(NULL) - call->log->connected_date_time);
2244 }
2245
2246 int linphone_call_get_duration(const LinphoneCall *call) {
2247 switch (call->state) {
2248 case LinphoneCallEnd:
2249 case LinphoneCallError:
2250 case LinphoneCallReleased:
2251 return call->log->duration;
2252 default:
2253 return _linphone_call_compute_duration(call);
2254 }
2255 }
2256
2257 LinphoneCall *linphone_call_get_replaced_call(LinphoneCall *call){
2258 SalOp *op=sal_call_get_replaces(call->op);
2259 if (op){
2260 return (LinphoneCall*)sal_op_get_user_pointer(op);
2261 }
2262 return NULL;
2263 }
2264
2265 void linphone_call_enable_camera (LinphoneCall *call, bool_t enable){
2266 #ifdef VIDEO_ENABLED
2267 call->camera_enabled=enable;
2268 switch(call->state) {
2269 case LinphoneCallStreamsRunning:
2270 case LinphoneCallOutgoingEarlyMedia:
2271 case LinphoneCallIncomingEarlyMedia:
2272 case LinphoneCallConnected:
2273 if(call->videostream!=NULL
2274 && video_stream_started(call->videostream)
2275 && video_stream_get_camera(call->videostream) != linphone_call_get_video_device(call)) {
2276 const char *cur_cam, *new_cam;
2277 cur_cam = video_stream_get_camera(call->videostream) ? ms_web_cam_get_name(video_stream_get_camera(call->videostream)) : "NULL";
2278 new_cam = linphone_call_get_video_device(call) ? ms_web_cam_get_name(linphone_call_get_video_device(call)) : "NULL";
2279 ms_message("Switching video cam from [%s] to [%s] on call [%p]" , cur_cam, new_cam, call);
2280 video_stream_change_camera(call->videostream, linphone_call_get_video_device(call));
2281 }
2282 break;
2283
2284 default: break;
2285 }
2286 #endif
2287 }
2288
2289 void linphone_call_send_vfu_request(LinphoneCall *call) {
2290 #ifdef VIDEO_ENABLED
2291 const LinphoneCallParams *current_params = linphone_call_get_current_params(call);
2292 if ((current_params->avpf_enabled || current_params->implicit_rtcp_fb )&& call->videostream && media_stream_get_state((const MediaStream *)call->videostream) == MSStreamStarted) { // || sal_media_description_has_implicit_avpf((const SalMediaDescription *)call->resultdesc)
2293 ms_message("Request Full Intra Request on call [%p]", call);
2294 video_stream_send_fir(call->videostream);
2295 } else if (call->core->sip_conf.vfu_with_info) {
2296 ms_message("Request SIP INFO FIR on call [%p]", call);
2297 if (LinphoneCallStreamsRunning == linphone_call_get_state(call))
2298 sal_call_send_vfu_request(call->op);
2299 } else {
2300 ms_message("vfu request using sip disabled from config [sip,vfu_with_info]");
2301 }
2302 #endif
2303 }
2304
2305 LinphoneStatus linphone_call_take_video_snapshot(LinphoneCall *call, const char *file) {
2306 #ifdef VIDEO_ENABLED
2307 if (call->videostream!=NULL && call->videostream->jpegwriter!=NULL){
2308 return ms_filter_call_method(call->videostream->jpegwriter,MS_JPEG_WRITER_TAKE_SNAPSHOT,(void*)file);
2309 }
2310 ms_warning("Cannot take snapshot: no currently running video stream on this call.");
2311 #endif
2312 return -1;
2313 }
2314
2315 LinphoneStatus linphone_call_take_preview_snapshot(LinphoneCall *call, const char *file) {
2316 #ifdef VIDEO_ENABLED
2317 if (call->videostream!=NULL && call->videostream->local_jpegwriter!=NULL){
2318 return ms_filter_call_method(call->videostream->local_jpegwriter,MS_JPEG_WRITER_TAKE_SNAPSHOT,(void*)file);
2319 }
2320 ms_warning("Cannot take local snapshot: no currently running video stream on this call.");
2321 return -1;
2322 #endif
2323 return -1;
2324 }
2325
2326 bool_t linphone_call_camera_enabled (const LinphoneCall *call){
2327 return call->camera_enabled;
2328 }
2329
2330 /**
2331 * @ingroup call_control
2332 * @return string value of LinphonePrivacy enum
2333 **/
2334 const char* linphone_privacy_to_string(LinphonePrivacy privacy) {
2335 switch(privacy) {
2336 case LinphonePrivacyDefault: return "LinphonePrivacyDefault";
2337 case LinphonePrivacyUser: return "LinphonePrivacyUser";
2338 case LinphonePrivacyHeader: return "LinphonePrivacyHeader";
2339 case LinphonePrivacySession: return "LinphonePrivacySession";
2340 case LinphonePrivacyId: return "LinphonePrivacyId";
2341 case LinphonePrivacyNone: return "LinphonePrivacyNone";
2342 case LinphonePrivacyCritical: return "LinphonePrivacyCritical";
2343 default: return "Unknown privacy mode";
2344 }
2345 }
2346
2347
2348 #ifdef TEST_EXT_RENDERER
2349 static void rendercb(void *data, const MSPicture *local, const MSPicture *remote){
2350 ms_message("rendercb, local buffer=%p, remote buffer=%p",
2351 local ? local->planes[0] : NULL, remote? remote->planes[0] : NULL);
2352 }
2353 #endif
2354
2355 #ifdef VIDEO_ENABLED
2356 static void video_stream_event_cb(void *user_pointer, const MSFilter *f, const unsigned int event_id, const void *args){
2357 LinphoneCall* call = (LinphoneCall*) user_pointer;
2358 switch (event_id) {
2359 case MS_VIDEO_DECODER_DECODING_ERRORS:
2360 ms_warning("MS_VIDEO_DECODER_DECODING_ERRORS");
2361 if (call->videostream && (video_stream_is_decoding_error_to_be_reported(call->videostream, 5000) == TRUE)) {
2362 video_stream_decoding_error_reported(call->videostream);
2363 linphone_call_send_vfu_request(call);
2364 }
2365 break;
2366 case MS_VIDEO_DECODER_RECOVERED_FROM_ERRORS:
2367 ms_message("MS_VIDEO_DECODER_RECOVERED_FROM_ERRORS");
2368 if (call->videostream) {
2369 video_stream_decoding_error_recovered(call->videostream);
2370 }
2371 break;
2372 case MS_VIDEO_DECODER_FIRST_IMAGE_DECODED:
2373 ms_message("First video frame decoded successfully");
2374 if (call->nextVideoFrameDecoded._func != NULL){
2375 call->nextVideoFrameDecoded._func(call, call->nextVideoFrameDecoded._user_data);
2376 call->nextVideoFrameDecoded._func = NULL;
2377 call->nextVideoFrameDecoded._user_data = NULL;
2378 }
2379 break;
2380 case MS_VIDEO_DECODER_SEND_PLI:
2381 case MS_VIDEO_DECODER_SEND_SLI:
2382 case MS_VIDEO_DECODER_SEND_RPSI:
2383 /* Handled internally by mediastreamer2. */
2384 break;
2385 default:
2386 ms_warning("Unhandled event %i", event_id);
2387 break;
2388 }
2389 }
2390 #endif
2391
2392 static void _linphone_call_set_next_video_frame_decoded_trigger(LinphoneCall *call){
2393 #ifdef VIDEO_ENABLED
2394 if (call->nextVideoFrameDecoded._func && call->videostream && call->videostream->ms.decoder)
2395 ms_filter_call_method_noarg(call->videostream->ms.decoder, MS_VIDEO_DECODER_RESET_FIRST_IMAGE_NOTIFICATION);
2396 #endif
2397 }
2398
2399 void linphone_call_set_next_video_frame_decoded_callback(LinphoneCall *call, LinphoneCallCbFunc cb, void* user_data) {
2400 call->nextVideoFrameDecoded._func = cb;
2401 call->nextVideoFrameDecoded._user_data = user_data;
2402 _linphone_call_set_next_video_frame_decoded_trigger(call);
2403 }
2404
2405 static void port_config_set_random_choosed(LinphoneCall *call, int stream_index, RtpSession *session){
2406 call->media_ports[stream_index].rtp_port=rtp_session_get_local_port(session);
2407 call->media_ports[stream_index].rtcp_port=rtp_session_get_local_rtcp_port(session);
2408 }
2409
2410 static void _linphone_call_prepare_ice_for_stream(LinphoneCall *call, int stream_index, bool_t create_checklist){
2411 MediaStream *ms = stream_index == call->main_audio_stream_index ? (MediaStream*)call->audiostream : stream_index == call->main_video_stream_index ? (MediaStream*)call->videostream : (MediaStream*)call->textstream;
2412 if (linphone_nat_policy_ice_enabled(call->nat_policy) && (call->ice_session != NULL)){
2413 IceCheckList *cl;
2414 rtp_session_set_pktinfo(ms->sessions.rtp_session, TRUE);
2415 cl=ice_session_check_list(call->ice_session, stream_index);
2416 if (cl == NULL && create_checklist) {
2417 cl=ice_check_list_new();
2418 ice_session_add_check_list(call->ice_session, cl, stream_index);
2419 ms_message("Created new ICE check list for stream [%i]",stream_index);
2420 }
2421 if (cl) {
2422 media_stream_set_ice_check_list(ms, cl);
2423 }
2424 }
2425 }
2426
2427 int linphone_call_prepare_ice(LinphoneCall *call, bool_t incoming_offer){
2428 SalMediaDescription *remote = NULL;
2429 int err;
2430 bool_t has_video=FALSE;
2431
2432 if (linphone_nat_policy_ice_enabled(call->nat_policy) && (call->ice_session != NULL)){
2433 if (incoming_offer){
2434 remote=sal_call_get_remote_media_description(call->op);
2435 has_video=linphone_core_video_enabled(call->core) && linphone_core_media_description_contains_video_stream(remote);
2436 }else has_video=call->params->has_video;
2437
2438 _linphone_call_prepare_ice_for_stream(call,call->main_audio_stream_index,TRUE);
2439 if (has_video) _linphone_call_prepare_ice_for_stream(call,call->main_video_stream_index,TRUE);
2440 if (call->params->realtimetext_enabled) _linphone_call_prepare_ice_for_stream(call,call->main_text_stream_index,TRUE);
2441 /*start ICE gathering*/
2442 if (incoming_offer)
2443 linphone_call_update_ice_from_remote_media_description(call, remote, TRUE); /*this may delete the ice session*/
2444 if (call->ice_session && !ice_session_candidates_gathered(call->ice_session)){
2445 if (call->audiostream->ms.state==MSStreamInitialized)
2446 audio_stream_prepare_sound(call->audiostream, NULL, NULL);
2447 #ifdef VIDEO_ENABLED
2448 if (has_video && call->videostream && call->videostream->ms.state==MSStreamInitialized) {
2449 video_stream_prepare_video(call->videostream);
2450 }
2451 #endif
2452 if (call->params->realtimetext_enabled && call->textstream->ms.state==MSStreamInitialized) {
2453 text_stream_prepare_text(call->textstream);
2454 }
2455 err = linphone_core_gather_ice_candidates(call->core,call);
2456 if (err == 0) {
2457 /* Ice candidates gathering wasn't started, but we can proceed with the call anyway. */
2458 linphone_call_stop_media_streams_for_ice_gathering(call);
2459 }else if (err == -1) {
2460 linphone_call_stop_media_streams_for_ice_gathering(call);
2461 linphone_call_delete_ice_session(call);
2462 }
2463 return err;/* 1= gathering in progress, wait; 0=proceed*/
2464 }
2465 }
2466 return 0;
2467 }
2468
2469 /*eventually join to a multicast group if told to do so*/
2470 static void linphone_call_join_multicast_group(LinphoneCall *call, int stream_index, MediaStream *ms){
2471 if (call->media_ports[stream_index].multicast_ip[stream_index]!='\0'){
2472 media_stream_join_multicast_group(ms, call->media_ports[stream_index].multicast_ip);
2473 } else
2474 ms_error("Cannot join multicast group if multicast ip is not set for call [%p]",call);
2475 }
2476
2477 static SalMulticastRole linphone_call_get_multicast_role(const LinphoneCall *call,SalStreamType type) {
2478 SalMulticastRole multicast_role=SalMulticastInactive;
2479 SalMediaDescription *remotedesc, *localdesc;
2480 SalStreamDescription *stream_desc = NULL;
2481 if (!call->op) goto end;
2482 remotedesc = sal_call_get_remote_media_description(call->op);
2483 localdesc = call->localdesc;
2484 if (!localdesc && !remotedesc && call->dir == LinphoneCallOutgoing) {
2485 /*well using call dir*/
2486 if ((type == SalAudio && linphone_call_params_audio_multicast_enabled(call->params))
2487 || (type == SalVideo && linphone_call_params_video_multicast_enabled(call->params)))
2488 multicast_role=SalMulticastSender;
2489 } else if (localdesc && (!remotedesc || sal_call_is_offerer(call->op))) {
2490 stream_desc = sal_media_description_find_best_stream(localdesc, type);
2491 } else if (!sal_call_is_offerer(call->op) && remotedesc)
2492 stream_desc = sal_media_description_find_best_stream(remotedesc, type);
2493
2494 if (stream_desc)
2495 multicast_role = stream_desc->multicast_role;
2496
2497 end:
2498 ms_message("Call [%p], stream type [%s], multicast role is [%s]",call, sal_stream_type_to_string(type),
2499 sal_multicast_role_to_string(multicast_role));
2500 return multicast_role;
2501 }
2502
2503 static void setup_dtls_params(LinphoneCall *call, MediaStream* stream) {
2504 LinphoneCore *lc=call->core;
2505 if (call->params->media_encryption==LinphoneMediaEncryptionDTLS) {
2506 MSDtlsSrtpParams params;
2507 char *certificate, *key;
2508 memset(¶ms,0,sizeof(MSDtlsSrtpParams));
2509 /* TODO : search for a certificate with CNAME=sip uri(retrieved from variable me) or default : linphone-dtls-default-identity */
2510 /* This will parse the directory to find a matching fingerprint or generate it if not found */
2511 /* returned string must be freed */
2512 sal_certificates_chain_parse_directory(&certificate, &key, &call->dtls_certificate_fingerprint, lc->user_certificates_path, "linphone-dtls-default-identity", SAL_CERTIFICATE_RAW_FORMAT_PEM, TRUE, TRUE);
2513
2514 if (key!= NULL && certificate!=NULL) {
2515 params.pem_certificate = (char *)certificate;
2516 params.pem_pkey = (char *)key;
2517 params.role = MSDtlsSrtpRoleUnset; /* default is unset, then check if we have a result SalMediaDescription */
2518 media_stream_enable_dtls(stream,¶ms);
2519 ms_free(certificate);
2520 ms_free(key);
2521 } else {
2522 ms_error("Unable to retrieve or generate DTLS certificate and key - DTLS disabled");
2523 /* TODO : check if encryption forced, if yes, stop call */
2524 }
2525 }
2526 }
2527
2528 static void setZrtpCryptoTypesParameters(MSZrtpParams *params, LinphoneCore *lc)
2529 {
2530 int i;
2531 const MSCryptoSuite *srtp_suites;
2532 MsZrtpCryptoTypesCount ciphersCount, authTagsCount;
2533
2534 if (params == NULL) return;
2535 if (lc == NULL) return;
2536
2537 srtp_suites = linphone_core_get_srtp_crypto_suites(lc);
2538 if (srtp_suites!=NULL) {
2539 for(i=0; srtp_suites[i]!=MS_CRYPTO_SUITE_INVALID && i<SAL_CRYPTO_ALGO_MAX && i<MS_MAX_ZRTP_CRYPTO_TYPES; ++i){
2540 switch (srtp_suites[i]) {
2541 case MS_AES_128_SHA1_32:
2542 params->ciphers[params->ciphersCount++] = MS_ZRTP_CIPHER_AES1;
2543 params->authTags[params->authTagsCount++] = MS_ZRTP_AUTHTAG_HS32;
2544 break;
2545 case MS_AES_128_NO_AUTH:
2546 params->ciphers[params->ciphersCount++] = MS_ZRTP_CIPHER_AES1;
2547 break;
2548 case MS_NO_CIPHER_SHA1_80:
2549 params->authTags[params->authTagsCount++] = MS_ZRTP_AUTHTAG_HS80;
2550 break;
2551 case MS_AES_128_SHA1_80:
2552 params->ciphers[params->ciphersCount++] = MS_ZRTP_CIPHER_AES1;
2553 params->authTags[params->authTagsCount++] = MS_ZRTP_AUTHTAG_HS80;
2554 break;
2555 case MS_AES_CM_256_SHA1_80:
2556 ms_warning("Deprecated crypto suite MS_AES_CM_256_SHA1_80, use MS_AES_256_SHA1_80 instead");
2557 BCTBX_NO_BREAK;
2558 case MS_AES_256_SHA1_80:
2559 params->ciphers[params->ciphersCount++] = MS_ZRTP_CIPHER_AES3;
2560 params->authTags[params->authTagsCount++] = MS_ZRTP_AUTHTAG_HS80;
2561 break;
2562 case MS_AES_256_SHA1_32:
2563 params->ciphers[params->ciphersCount++] = MS_ZRTP_CIPHER_AES3;
2564 params->authTags[params->authTagsCount++] = MS_ZRTP_AUTHTAG_HS32;
2565 break;
2566 case MS_CRYPTO_SUITE_INVALID:
2567 break;
2568 }
2569 }
2570 }
2571
2572 /* linphone_core_get_srtp_crypto_suites is used to determine sensible defaults; here each can be overridden */
2573 ciphersCount = linphone_core_get_zrtp_cipher_suites(lc, params->ciphers); /* if not present in config file, params->ciphers is not modified */
2574 if (ciphersCount!=0) { /* use zrtp_cipher_suites config only when present, keep config from srtp_crypto_suite otherwise */
2575 params->ciphersCount = ciphersCount;
2576 }
2577 params->hashesCount = linphone_core_get_zrtp_hash_suites(lc, params->hashes);
2578 authTagsCount = linphone_core_get_zrtp_auth_suites(lc, params->authTags); /* if not present in config file, params->authTags is not modified */
2579 if (authTagsCount!=0) {
2580 params->authTagsCount = authTagsCount; /* use zrtp_auth_suites config only when present, keep config from srtp_crypto_suite otherwise */
2581 }
2582 params->sasTypesCount = linphone_core_get_zrtp_sas_suites(lc, params->sasTypes);
2583 params->keyAgreementsCount = linphone_core_get_zrtp_key_agreement_suites(lc, params->keyAgreements);
2584 }
2585
2586 static OrtpJitterBufferAlgorithm name_to_jb_algo(const char *value){
2587 if (value){
2588 if (strcasecmp(value, "basic") == 0) return OrtpJitterBufferBasic;
2589 else if (strcasecmp(value, "rls") == 0) return OrtpJitterBufferRecursiveLeastSquare;
2590 }
2591 ms_error("Invalid jitter buffer algorithm: %s", value);
2592 return OrtpJitterBufferRecursiveLeastSquare;
2593 }
2594
2595 static void apply_jitter_buffer_params(LinphoneCore *lc, RtpSession *session, LinphoneStreamType type){
2596 JBParameters params;
2597
2598 rtp_session_get_jitter_buffer_params(session, ¶ms);
2599 params.min_size = lp_config_get_int(lc->config, "rtp", "jitter_buffer_min_size", 40);
2600 params.max_size = lp_config_get_int(lc->config, "rtp", "jitter_buffer_max_size", 250);
2601 params.max_packets = params.max_size * 200 / 1000; /*allow 200 packet per seconds, quite large*/
2602 params.buffer_algorithm = name_to_jb_algo(lp_config_get_string(lc->config, "rtp", "jitter_buffer_algorithm", "rls"));
2603 params.refresh_ms = lp_config_get_int(lc->config, "rtp", "jitter_buffer_refresh_period", 5000);
2604 params.ramp_refresh_ms = lp_config_get_int(lc->config, "rtp", "jitter_buffer_ramp_refresh_period", 5000);
2605 params.ramp_step_ms = lp_config_get_int(lc->config, "rtp", "jitter_buffer_ramp_step", 20);
2606 params.ramp_threshold = lp_config_get_int(lc->config, "rtp", "jitter_buffer_ramp_threshold", 70);
2607
2608 switch (type){
2609 case LinphoneStreamTypeAudio:
2610 case LinphoneStreamTypeText: /*let's use the same params for text as for audio.*/
2611 params.nom_size = linphone_core_get_audio_jittcomp(lc);
2612 params.adaptive = linphone_core_audio_adaptive_jittcomp_enabled(lc);
2613 break;
2614 case LinphoneStreamTypeVideo:
2615 params.nom_size = linphone_core_get_video_jittcomp(lc);
2616 params.adaptive = linphone_core_video_adaptive_jittcomp_enabled(lc);
2617 break;
2618 case LinphoneStreamTypeUnknown:
2619 ms_fatal("apply_jitter_buffer_params: should not happen");
2620 break;
2621 }
2622 params.enabled = params.nom_size > 0;
2623 if (params.enabled){
2624 if (params.min_size > params.nom_size){
2625 params.min_size = params.nom_size;
2626 }
2627 if (params.max_size < params.nom_size){
2628 params.max_size = params.nom_size;
2629 }
2630 }
2631 rtp_session_set_jitter_buffer_params(session, ¶ms);
2632 }
2633
2634 void linphone_call_init_audio_stream(LinphoneCall *call){
2635 LinphoneCore *lc=call->core;
2636 AudioStream *audiostream;
2637 const char *location;
2638 int dscp;
2639 const char *rtcp_tool=linphone_core_get_user_agent(call->core);
2640 char* cname;
2641
2642 if (call->audiostream != NULL) return;
2643 if (call->sessions[call->main_audio_stream_index].rtp_session==NULL){
2644 SalMulticastRole multicast_role = linphone_call_get_multicast_role(call,SalAudio);
2645 SalMediaDescription *remotedesc=NULL;
2646 SalStreamDescription *stream_desc = NULL;
2647 if (call->op) remotedesc = sal_call_get_remote_media_description(call->op);
2648 if (remotedesc)
2649 stream_desc = sal_media_description_find_best_stream(remotedesc, SalAudio);
2650
2651 call->audiostream=audiostream=audio_stream_new2(lc->factory, linphone_call_get_bind_ip_for_stream(call,call->main_audio_stream_index),
2652 multicast_role == SalMulticastReceiver ? stream_desc->rtp_port : call->media_ports[call->main_audio_stream_index].rtp_port,
2653 multicast_role == SalMulticastReceiver ? 0 /*disabled for now*/ : call->media_ports[call->main_audio_stream_index].rtcp_port);
2654 if (multicast_role == SalMulticastReceiver)
2655 linphone_call_join_multicast_group(call, call->main_audio_stream_index, &audiostream->ms);
2656 rtp_session_enable_network_simulation(call->audiostream->ms.sessions.rtp_session, &lc->net_conf.netsim_params);
2657 apply_jitter_buffer_params(lc, call->audiostream->ms.sessions.rtp_session, LinphoneStreamTypeAudio);
2658 cname = linphone_address_as_string_uri_only(call->me);
2659 audio_stream_set_rtcp_information(call->audiostream, cname, rtcp_tool);
2660 ms_free(cname);
2661 rtp_session_set_symmetric_rtp(audiostream->ms.sessions.rtp_session,linphone_core_symmetric_rtp_enabled(lc));
2662 setup_dtls_params(call, &audiostream->ms);
2663
2664 /* init zrtp even if we didn't explicitely set it, just in case peer offers it */
2665 if (linphone_core_media_encryption_supported(lc, LinphoneMediaEncryptionZRTP)) {
2666 char *peerUri = linphone_address_as_string_uri_only((call->dir==LinphoneCallIncoming) ? call->log->from : call->log->to);
2667 char *selfUri = linphone_address_as_string_uri_only((call->dir==LinphoneCallIncoming) ? call->log->to : call->log->from);
2668 MSZrtpParams params;
2669 memset(¶ms,0,sizeof(MSZrtpParams));
2670 /*call->current_params.media_encryption will be set later when zrtp is activated*/
2671 params.zidCacheDB = linphone_core_get_zrtp_cache_db(lc);
2672 params.peerUri=peerUri;
2673 params.selfUri=selfUri;
2674 params.limeKeyTimeSpan = bctbx_time_string_to_sec(lp_config_get_string(lc->config, "sip", "lime_key_validity", "0")); /* get key lifespan from config file, default is 0:forever valid */
2675 setZrtpCryptoTypesParameters(¶ms,call->core);
2676 audio_stream_enable_zrtp(call->audiostream,¶ms);
2677 if (peerUri != NULL) ms_free(peerUri);
2678 if (selfUri != NULL) ms_free(selfUri);
2679 }
2680
2681 media_stream_reclaim_sessions(&audiostream->ms, &call->sessions[call->main_audio_stream_index]);
2682 }else{
2683 call->audiostream=audio_stream_new_with_sessions(lc->factory, &call->sessions[call->main_audio_stream_index]);
2684
2685 }
2686 audiostream=call->audiostream;
2687 if (call->media_ports[call->main_audio_stream_index].rtp_port==-1){
2688 port_config_set_random_choosed(call,call->main_audio_stream_index,audiostream->ms.sessions.rtp_session);
2689 }
2690 dscp=linphone_core_get_audio_dscp(lc);
2691 if (dscp!=-1)
2692 audio_stream_set_dscp(audiostream,dscp);
2693 if (linphone_core_echo_limiter_enabled(lc)){
2694 const char *type=lp_config_get_string(lc->config,"sound","el_type","mic");
2695 if (strcasecmp(type,"mic")==0)
2696 audio_stream_enable_echo_limiter(audiostream,ELControlMic);
2697 else if (strcasecmp(type,"full")==0)
2698 audio_stream_enable_echo_limiter(audiostream,ELControlFull);
2699 }
2700
2701 /* equalizer location in the graph: 'mic' = in input graph, otherwise in output graph.
2702 Any other value than mic will default to output graph for compatibility */
2703 location = lp_config_get_string(lc->config,"sound","eq_location","hp");
2704 audiostream->eq_loc = (strcasecmp(location,"mic") == 0) ? MSEqualizerMic : MSEqualizerHP;
2705 ms_message("Equalizer location: %s", location);
2706
2707 audio_stream_enable_gain_control(audiostream,TRUE);
2708 if (linphone_core_echo_cancellation_enabled(lc)){
2709 int len,delay,framesize;
2710 len=lp_config_get_int(lc->config,"sound","ec_tail_len",0);
2711 delay=lp_config_get_int(lc->config,"sound","ec_delay",0);
2712 framesize=lp_config_get_int(lc->config,"sound","ec_framesize",0);
2713 audio_stream_set_echo_canceller_params(audiostream,len,delay,framesize);
2714 if (audiostream->ec) {
2715 char *statestr=ms_malloc0(EC_STATE_MAX_LEN);
2716 if (lp_config_relative_file_exists(lc->config, EC_STATE_STORE)
2717 && lp_config_read_relative_file(lc->config, EC_STATE_STORE, statestr, EC_STATE_MAX_LEN) == 0) {
2718 ms_filter_call_method(audiostream->ec, MS_ECHO_CANCELLER_SET_STATE_STRING, statestr);
2719 }
2720 ms_free(statestr);
2721 }
2722 }
2723 audio_stream_enable_automatic_gain_control(audiostream,linphone_core_agc_enabled(lc));
2724 {
2725 int enabled=lp_config_get_int(lc->config,"sound","noisegate",0);
2726 audio_stream_enable_noise_gate(audiostream,enabled);
2727 }
2728
2729 audio_stream_set_features(audiostream,linphone_core_get_audio_features(lc));
2730
2731 if (lc->rtptf){
2732 RtpTransport *meta_rtp;
2733 RtpTransport *meta_rtcp;
2734
2735 rtp_session_get_transports(audiostream->ms.sessions.rtp_session,&meta_rtp,&meta_rtcp);
2736 if (meta_rtp_transport_get_endpoint(meta_rtp) == NULL) {
2737 ms_message("LinphoneCall[%p]: using custom audio RTP transport endpoint.", call);
2738 meta_rtp_transport_set_endpoint(meta_rtp,lc->rtptf->audio_rtp_func(lc->rtptf->audio_rtp_func_data, call->media_ports[call->main_audio_stream_index].rtp_port));
2739 }
2740 if (meta_rtp_transport_get_endpoint(meta_rtcp) == NULL) {
2741 meta_rtp_transport_set_endpoint(meta_rtcp,lc->rtptf->audio_rtcp_func(lc->rtptf->audio_rtcp_func_data, call->media_ports[call->main_audio_stream_index].rtcp_port));
2742 }
2743 }
2744
2745 call->audiostream_app_evq = ortp_ev_queue_new();
2746 rtp_session_register_event_queue(audiostream->ms.sessions.rtp_session,call->audiostream_app_evq);
2747
2748 _linphone_call_prepare_ice_for_stream(call,call->main_audio_stream_index,FALSE);
2749 }
2750
2751 void linphone_call_init_video_stream(LinphoneCall *call){
2752 #ifdef VIDEO_ENABLED
2753 LinphoneCore *lc=call->core;
2754 char* cname;
2755 const char *rtcp_tool = linphone_core_get_user_agent(call->core);
2756
2757 if (call->videostream == NULL){
2758 int video_recv_buf_size=lp_config_get_int(lc->config,"video","recv_buf_size",0);
2759 int dscp=linphone_core_get_video_dscp(lc);
2760 const char *display_filter=linphone_core_get_video_display_filter(lc);
2761
2762 if (call->sessions[call->main_video_stream_index].rtp_session==NULL){
2763 SalMulticastRole multicast_role = linphone_call_get_multicast_role(call,SalVideo);
2764 SalMediaDescription *remotedesc=NULL;
2765 SalStreamDescription *stream_desc = NULL;
2766 if (call->op) remotedesc = sal_call_get_remote_media_description(call->op);
2767 if (remotedesc)
2768 stream_desc = sal_media_description_find_best_stream(remotedesc, SalVideo);
2769
2770 call->videostream=video_stream_new2(lc->factory, linphone_call_get_bind_ip_for_stream(call,call->main_video_stream_index),
2771 multicast_role == SalMulticastReceiver ? stream_desc->rtp_port : call->media_ports[call->main_video_stream_index].rtp_port,
2772 multicast_role == SalMulticastReceiver ? 0 /*disabled for now*/ : call->media_ports[call->main_video_stream_index].rtcp_port);
2773 if (multicast_role == SalMulticastReceiver)
2774 linphone_call_join_multicast_group(call, call->main_video_stream_index, &call->videostream->ms);
2775 rtp_session_enable_network_simulation(call->videostream->ms.sessions.rtp_session, &lc->net_conf.netsim_params);
2776 apply_jitter_buffer_params(lc, call->videostream->ms.sessions.rtp_session, LinphoneStreamTypeVideo);
2777 cname = linphone_address_as_string_uri_only(call->me);
2778 video_stream_set_rtcp_information(call->videostream, cname, rtcp_tool);
2779 ms_free(cname);
2780 rtp_session_set_symmetric_rtp(call->videostream->ms.sessions.rtp_session,linphone_core_symmetric_rtp_enabled(lc));
2781 setup_dtls_params(call, &call->videostream->ms);
2782 /* init zrtp even if we didn't explicitely set it, just in case peer offers it */
2783 if (linphone_core_media_encryption_supported(lc, LinphoneMediaEncryptionZRTP)) {
2784 video_stream_enable_zrtp(call->videostream, call->audiostream);
2785 }
2786
2787 media_stream_reclaim_sessions(&call->videostream->ms, &call->sessions[call->main_video_stream_index]);
2788 }else{
2789 call->videostream=video_stream_new_with_sessions(lc->factory, &call->sessions[call->main_video_stream_index]);
2790 }
2791
2792 if (call->media_ports[call->main_video_stream_index].rtp_port==-1){
2793 port_config_set_random_choosed(call,call->main_video_stream_index,call->videostream->ms.sessions.rtp_session);
2794 }
2795 if (dscp!=-1)
2796 video_stream_set_dscp(call->videostream,dscp);
2797 video_stream_enable_display_filter_auto_rotate(call->videostream, lp_config_get_int(lc->config,"video","display_filter_auto_rotate",0));
2798 if (video_recv_buf_size>0) rtp_session_set_recv_buf_size(call->videostream->ms.sessions.rtp_session,video_recv_buf_size);
2799
2800 if (display_filter != NULL)
2801 video_stream_set_display_filter_name(call->videostream,display_filter);
2802 video_stream_set_event_callback(call->videostream,video_stream_event_cb, call);
2803
2804 if (lc->rtptf){
2805 RtpTransport *meta_rtp;
2806 RtpTransport *meta_rtcp;
2807
2808 rtp_session_get_transports(call->videostream->ms.sessions.rtp_session,&meta_rtp,&meta_rtcp);
2809 if (meta_rtp_transport_get_endpoint(meta_rtp) == NULL) {
2810 ms_message("LinphoneCall[%p]: using custom video RTP transport endpoint.", call);
2811 meta_rtp_transport_set_endpoint(meta_rtp,lc->rtptf->video_rtp_func(lc->rtptf->video_rtp_func_data, call->media_ports[call->main_video_stream_index].rtp_port));
2812 }
2813 if (meta_rtp_transport_get_endpoint(meta_rtcp) == NULL) {
2814 meta_rtp_transport_set_endpoint(meta_rtcp,lc->rtptf->video_rtcp_func(lc->rtptf->video_rtcp_func_data, call->media_ports[call->main_video_stream_index].rtcp_port));
2815 }
2816 }
2817 call->videostream_app_evq = ortp_ev_queue_new();
2818 rtp_session_register_event_queue(call->videostream->ms.sessions.rtp_session,call->videostream_app_evq);
2819 _linphone_call_prepare_ice_for_stream(call,call->main_video_stream_index,FALSE);
2820 #ifdef TEST_EXT_RENDERER
2821 video_stream_set_render_callback(call->videostream,rendercb,NULL);
2822 #endif
2823 }
2824 #else
2825 call->videostream=NULL;
2826 #endif
2827 }
2828
2829 void linphone_call_init_text_stream(LinphoneCall *call){
2830 TextStream *textstream;
2831 LinphoneCore *lc=call->core;
2832 char* cname;
2833
2834 if (call->textstream != NULL) return;
2835 if (call->sessions[call->main_text_stream_index].rtp_session == NULL) {
2836 SalMulticastRole multicast_role = linphone_call_get_multicast_role(call, SalText);
2837 SalMediaDescription *remotedesc = NULL;
2838 SalStreamDescription *stream_desc = NULL;
2839 if (call->op) remotedesc = sal_call_get_remote_media_description(call->op);
2840 if (remotedesc) stream_desc = sal_media_description_find_best_stream(remotedesc, SalText);
2841
2842 call->textstream = textstream = text_stream_new2(lc->factory, linphone_call_get_bind_ip_for_stream(call,call->main_text_stream_index),
2843 multicast_role == SalMulticastReceiver ? stream_desc->rtp_port : call->media_ports[call->main_text_stream_index].rtp_port,
2844 multicast_role == SalMulticastReceiver ? 0 /*disabled for now*/ : call->media_ports[call->main_text_stream_index].rtcp_port);
2845 if (multicast_role == SalMulticastReceiver)
2846 linphone_call_join_multicast_group(call, call->main_text_stream_index, &textstream->ms);
2847 rtp_session_enable_network_simulation(call->textstream->ms.sessions.rtp_session, &lc->net_conf.netsim_params);
2848 apply_jitter_buffer_params(lc, call->textstream->ms.sessions.rtp_session, LinphoneStreamTypeText);
2849 cname = linphone_address_as_string_uri_only(call->me);
2850 ms_free(cname);
2851 rtp_session_set_symmetric_rtp(textstream->ms.sessions.rtp_session,linphone_core_symmetric_rtp_enabled(lc));
2852 setup_dtls_params(call, &textstream->ms);
2853 media_stream_reclaim_sessions(&textstream->ms, &call->sessions[call->main_text_stream_index]);
2854 } else {
2855 call->textstream = text_stream_new_with_sessions(lc->factory, &call->sessions[call->main_text_stream_index]);
2856 }
2857 textstream = call->textstream;
2858 if (call->media_ports[call->main_text_stream_index].rtp_port == -1) {
2859 port_config_set_random_choosed(call, call->main_text_stream_index, textstream->ms.sessions.rtp_session);
2860 }
2861
2862 if (lc->rtptf){
2863 RtpTransport *meta_rtp;
2864 RtpTransport *meta_rtcp;
2865
2866 rtp_session_get_transports(textstream->ms.sessions.rtp_session, &meta_rtp, &meta_rtcp);
2867 if (meta_rtp_transport_get_endpoint(meta_rtp) == NULL) {
2868 meta_rtp_transport_set_endpoint(meta_rtp,lc->rtptf->audio_rtp_func(lc->rtptf->audio_rtp_func_data, call->media_ports[call->main_text_stream_index].rtp_port));
2869 }
2870 if (meta_rtp_transport_get_endpoint(meta_rtcp) == NULL) {
2871 meta_rtp_transport_set_endpoint(meta_rtcp,lc->rtptf->audio_rtcp_func(lc->rtptf->audio_rtcp_func_data, call->media_ports[call->main_text_stream_index].rtcp_port));
2872 }
2873 }
2874
2875 call->textstream_app_evq = ortp_ev_queue_new();
2876 rtp_session_register_event_queue(textstream->ms.sessions.rtp_session, call->textstream_app_evq);
2877
2878 _linphone_call_prepare_ice_for_stream(call, call->main_text_stream_index, FALSE);
2879 }
2880
2881 void linphone_call_init_media_streams(LinphoneCall *call){
2882 linphone_call_init_audio_stream(call);
2883 linphone_call_init_video_stream(call);
2884 linphone_call_init_text_stream(call);
2885 }
2886
2887
2888 static int dtmf_tab[16]={'0','1','2','3','4','5','6','7','8','9','*','#','A','B','C','D'};
2889
2890 static void linphone_core_dtmf_received(LinphoneCall *call, int dtmf){
2891 if (dtmf<0 || dtmf>15){
2892 ms_warning("Bad dtmf value %i",dtmf);
2893 return;
2894 }
2895 linphone_call_notify_dtmf_received(call, dtmf_tab[dtmf]);
2896 }
2897
2898 static void parametrize_equalizer(LinphoneCore *lc, AudioStream *st){
2899 const char *eq_active = lp_config_get_string(lc->config, "sound", "eq_active", NULL);
2900 const char *eq_gains = lp_config_get_string(lc->config, "sound", "eq_gains", NULL);
2901
2902 if(eq_active) ms_warning("'eq_active' linphonerc parameter has not effect anymore. Please use 'mic_eq_active' or 'spk_eq_active' instead");
2903 if(eq_gains) ms_warning("'eq_gains' linphonerc parameter has not effect anymore. Please use 'mic_eq_gains' or 'spk_eq_gains' instead");
2904 if (st->mic_equalizer){
2905 MSFilter *f=st->mic_equalizer;
2906 int enabled=lp_config_get_int(lc->config,"sound","mic_eq_active",0);
2907 const char *gains=lp_config_get_string(lc->config,"sound","mic_eq_gains",NULL);
2908 ms_filter_call_method(f,MS_EQUALIZER_SET_ACTIVE,&enabled);
2909 if (enabled && gains){
2910 bctbx_list_t *gains_list = ms_parse_equalizer_string(gains);
2911 bctbx_list_t *it;
2912 for(it=gains_list; it; it=it->next) {
2913 MSEqualizerGain *g = (MSEqualizerGain *)it->data;
2914 ms_message("Read microphone equalizer gains: %f(~%f) --> %f",g->frequency,g->width,g->gain);
2915 ms_filter_call_method(f,MS_EQUALIZER_SET_GAIN, g);
2916 }
2917 if(gains_list) bctbx_list_free_with_data(gains_list, ms_free);
2918 }
2919 }
2920 if (st->spk_equalizer){
2921 MSFilter *f=st->spk_equalizer;
2922 int enabled=lp_config_get_int(lc->config,"sound","spk_eq_active",0);
2923 const char *gains=lp_config_get_string(lc->config,"sound","spk_eq_gains",NULL);
2924 ms_filter_call_method(f,MS_EQUALIZER_SET_ACTIVE,&enabled);
2925 if (enabled && gains){
2926 bctbx_list_t *gains_list = ms_parse_equalizer_string(gains);
2927 bctbx_list_t *it;
2928 for(it=gains_list; it; it=it->next) {
2929 MSEqualizerGain *g = (MSEqualizerGain *)it->data;
2930 ms_message("Read speaker equalizer gains: %f(~%f) --> %f",g->frequency,g->width,g->gain);
2931 ms_filter_call_method(f,MS_EQUALIZER_SET_GAIN, g);
2932 }
2933 if(gains_list) bctbx_list_free_with_data(gains_list, ms_free);
2934 }
2935 }
2936 }
2937
2938 void set_mic_gain_db(AudioStream *st, float gain){
2939 audio_stream_set_mic_gain_db(st, gain);
2940 }
2941
2942 void set_playback_gain_db(AudioStream *st, float gain){
2943 if (st->volrecv){
2944 ms_filter_call_method(st->volrecv,MS_VOLUME_SET_DB_GAIN,&gain);
2945 }else ms_warning("Could not apply playback gain: gain control wasn't activated.");
2946 }
2947
2948 /*This function is not static because used internally in linphone-daemon project*/
2949 void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t muted){
2950 float mic_gain=lc->sound_conf.soft_mic_lev;
2951 float thres = 0;
2952 float recv_gain;
2953 float ng_thres=lp_config_get_float(lc->config,"sound","ng_thres",0.05f);
2954 float ng_floorgain=lp_config_get_float(lc->config,"sound","ng_floorgain",0);
2955 int dc_removal=lp_config_get_int(lc->config,"sound","dc_removal",0);
2956 float speed;
2957 float force;
2958 int sustain;
2959 float transmit_thres;
2960 MSFilter *f=NULL;
2961 float floorgain;
2962 int spk_agc;
2963
2964 if (!muted)
2965 set_mic_gain_db(st,mic_gain);
2966 else
2967 audio_stream_set_mic_gain(st,0);
2968
2969 recv_gain = lc->sound_conf.soft_play_lev;
2970 if (recv_gain != 0) {
2971 set_playback_gain_db(st,recv_gain);
2972 }
2973
2974 if (st->volsend){
2975 ms_filter_call_method(st->volsend,MS_VOLUME_REMOVE_DC,&dc_removal);
2976 speed=lp_config_get_float(lc->config,"sound","el_speed",-1);
2977 thres=lp_config_get_float(lc->config,"sound","el_thres",-1);
2978 force=lp_config_get_float(lc->config,"sound","el_force",-1);
2979 sustain=lp_config_get_int(lc->config,"sound","el_sustain",-1);
2980 transmit_thres=lp_config_get_float(lc->config,"sound","el_transmit_thres",-1);
2981 f=st->volsend;
2982 if (speed==-1) speed=0.03f;
2983 if (force==-1) force=25;
2984 ms_filter_call_method(f,MS_VOLUME_SET_EA_SPEED,&speed);
2985 ms_filter_call_method(f,MS_VOLUME_SET_EA_FORCE,&force);
2986 if (thres!=-1)
2987 ms_filter_call_method(f,MS_VOLUME_SET_EA_THRESHOLD,&thres);
2988 if (sustain!=-1)
2989 ms_filter_call_method(f,MS_VOLUME_SET_EA_SUSTAIN,&sustain);
2990 if (transmit_thres!=-1)
2991 ms_filter_call_method(f,MS_VOLUME_SET_EA_TRANSMIT_THRESHOLD,&transmit_thres);
2992
2993 ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_thres);
2994 ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&ng_floorgain);
2995 }
2996 if (st->volrecv){
2997 /* parameters for a limited noise-gate effect, using echo limiter threshold */
2998 floorgain = (float)(1/pow(10,mic_gain/10));
2999 spk_agc=lp_config_get_int(lc->config,"sound","speaker_agc_enabled",0);
3000 ms_filter_call_method(st->volrecv, MS_VOLUME_ENABLE_AGC, &spk_agc);
3001 ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_thres);
3002 ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&floorgain);
3003 }
3004 parametrize_equalizer(lc,st);
3005 }
3006
3007 static void post_configure_audio_streams(LinphoneCall *call, bool_t muted){
3008 AudioStream *st=call->audiostream;
3009 LinphoneCore *lc=call->core;
3010 _post_configure_audio_stream(st,lc,muted);
3011 if (linphone_core_dtmf_received_has_listener(lc)){
3012 audio_stream_play_received_dtmfs(call->audiostream,FALSE);
3013 }
3014 if (call->record_active)
3015 linphone_call_start_recording(call);
3016 }
3017
3018 static int get_ideal_audio_bw(LinphoneCall *call, const SalMediaDescription *md, const SalStreamDescription *desc){
3019 int remote_bw=0;
3020 int upload_bw;
3021 int total_upload_bw=linphone_core_get_upload_bandwidth(call->core);
3022 const LinphoneCallParams *params=call->params;
3023 bool_t will_use_video=linphone_core_media_description_contains_video_stream(md);
3024 bool_t forced=FALSE;
3025
3026 if (desc->bandwidth>0) remote_bw=desc->bandwidth;
3027 else if (md->bandwidth>0) {
3028 /*case where b=AS is given globally, not per stream*/
3029 remote_bw=md->bandwidth;
3030 }
3031 if (params->up_bw>0){
3032 forced=TRUE;
3033 upload_bw=params->up_bw;
3034 }else upload_bw=total_upload_bw;
3035 upload_bw=get_min_bandwidth(upload_bw,remote_bw);
3036 if (!will_use_video || forced) return upload_bw;
3037
3038 if (bandwidth_is_greater(upload_bw,512)){
3039 upload_bw=100;
3040 }else if (bandwidth_is_greater(upload_bw,256)){
3041 upload_bw=64;
3042 }else if (bandwidth_is_greater(upload_bw,128)){
3043 upload_bw=40;
3044 }else if (bandwidth_is_greater(upload_bw,0)){
3045 upload_bw=24;
3046 }
3047 return upload_bw;
3048 }
3049
3050 static int get_video_bw(LinphoneCall *call, const SalMediaDescription *md, const SalStreamDescription *desc){
3051 int remote_bw=0;
3052 int bw;
3053 if (desc->bandwidth>0) remote_bw=desc->bandwidth;
3054 else if (md->bandwidth>0) {
3055 /*case where b=AS is given globally, not per stream*/
3056 remote_bw=get_remaining_bandwidth_for_video(md->bandwidth,call->audio_bw);
3057 } else {
3058 remote_bw = lp_config_get_int(call->core->config, "net", "default_max_bandwidth", 1500);
3059 }
3060 bw=get_min_bandwidth(get_remaining_bandwidth_for_video(linphone_core_get_upload_bandwidth(call->core),call->audio_bw),remote_bw);
3061 return bw;
3062 }
3063
3064 static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *md, const SalStreamDescription *desc, int *used_pt){
3065 int bw=0;
3066 const bctbx_list_t *elem;
3067 RtpProfile *prof=rtp_profile_new("Call profile");
3068 bool_t first=TRUE;
3069 LinphoneCore *lc=call->core;
3070 int up_ptime=0;
3071 const LinphoneCallParams *params=call->params;
3072
3073 *used_pt=-1;
3074
3075 if (desc->type==SalAudio)
3076 bw=get_ideal_audio_bw(call,md,desc);
3077 else if (desc->type==SalVideo)
3078 bw=get_video_bw(call,md,desc);
3079 //else if (desc->type== SalText)
3080
3081
3082 for(elem=desc->payloads;elem!=NULL;elem=elem->next){
3083 PayloadType *pt=(PayloadType*)elem->data;
3084 int number;
3085 /* make a copy of the payload type, so that we left the ones from the SalStreamDescription unchanged.
3086 If the SalStreamDescription is freed, this will have no impact on the running streams*/
3087 pt=payload_type_clone(pt);
3088
3089 if ((pt->flags & PAYLOAD_TYPE_FLAG_CAN_SEND) && first) {
3090 /*first codec in list is the selected one*/
3091 if (desc->type==SalAudio){
3092 /*this will update call->audio_bw*/
3093 linphone_core_update_allocated_audio_bandwidth_in_call(call,pt,bw);
3094 bw=call->audio_bw;
3095 if (params->up_ptime)
3096 up_ptime=params->up_ptime;
3097 else up_ptime=linphone_core_get_upload_ptime(lc);
3098 }
3099 first=FALSE;
3100 }
3101 if (*used_pt == -1){
3102 /*don't select telephone-event as a payload type*/
3103 if (strcasecmp(pt->mime_type, "telephone-event") != 0){
3104 *used_pt = payload_type_get_number(pt);
3105 }
3106 }
3107
3108 if (pt->flags & PAYLOAD_TYPE_BITRATE_OVERRIDE){
3109 ms_message("Payload type [%s/%i] has explicit bitrate [%i] kbit/s", pt->mime_type, pt->clock_rate, pt->normal_bitrate/1000);
3110 pt->normal_bitrate=get_min_bandwidth(pt->normal_bitrate,bw*1000);
3111 } else pt->normal_bitrate=bw*1000;
3112 if (desc->ptime>0){
3113 up_ptime=desc->ptime;
3114 }
3115 if (up_ptime>0){
3116 char tmp[40];
3117 snprintf(tmp,sizeof(tmp),"ptime=%i",up_ptime);
3118 payload_type_append_send_fmtp(pt,tmp);
3119 }
3120 number=payload_type_get_number(pt);
3121 if (rtp_profile_get_payload(prof,number)!=NULL){
3122 ms_warning("A payload type with number %i already exists in profile !",number);
3123 }else
3124 rtp_profile_set_payload(prof,number,pt);
3125 }
3126 return prof;
3127 }
3128
3129 static void setup_ring_player(LinphoneCore *lc, LinphoneCall *call){
3130 int pause_time=3000;
3131 audio_stream_play(call->audiostream,lc->sound_conf.ringback_tone);
3132 ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time);
3133 }
3134
3135 static bool_t linphone_call_sound_resources_available(LinphoneCall *call){
3136 LinphoneCore *lc=call->core;
3137 LinphoneCall *current=linphone_core_get_current_call(lc);
3138 return !linphone_core_is_in_conference(lc) &&
3139 (current==NULL || current==call);
3140 }
3141
3142 static int find_crypto_index_from_tag(const SalSrtpCryptoAlgo crypto[],unsigned char tag) {
3143 int i;
3144 for(i=0; i<SAL_CRYPTO_ALGO_MAX; i++) {
3145 if (crypto[i].tag == tag) {
3146 return i;
3147 }
3148 }
3149 return -1;
3150 }
3151
3152 static void configure_rtp_session_for_rtcp_fb(LinphoneCall *call, const SalStreamDescription *stream) {
3153 RtpSession *session = NULL;
3154
3155 if (stream->type == SalAudio) {
3156 session = call->audiostream->ms.sessions.rtp_session;
3157 } else if (stream->type == SalVideo) {
3158 session = call->videostream->ms.sessions.rtp_session;
3159 } else {
3160 // Do nothing for streams that are not audio or video
3161 return;
3162 }
3163 if (stream->rtcp_fb.generic_nack_enabled)
3164 rtp_session_enable_avpf_feature(session, ORTP_AVPF_FEATURE_GENERIC_NACK, TRUE);
3165 else
3166 rtp_session_enable_avpf_feature(session, ORTP_AVPF_FEATURE_GENERIC_NACK, FALSE);
3167 if (stream->rtcp_fb.tmmbr_enabled)
3168 rtp_session_enable_avpf_feature(session, ORTP_AVPF_FEATURE_TMMBR, TRUE);
3169 else
3170 rtp_session_enable_avpf_feature(session, ORTP_AVPF_FEATURE_TMMBR, FALSE);
3171 }
3172
3173 static void configure_rtp_session_for_rtcp_xr(LinphoneCore *lc, LinphoneCall *call, SalStreamType type) {
3174 RtpSession *session = NULL;
3175 const OrtpRtcpXrConfiguration *localconfig;
3176 const OrtpRtcpXrConfiguration *remoteconfig;
3177 OrtpRtcpXrConfiguration currentconfig;
3178 const SalStreamDescription *localstream;
3179 const SalStreamDescription *remotestream;
3180 SalMediaDescription *remotedesc = sal_call_get_remote_media_description(call->op);
3181
3182 if (!remotedesc) return;
3183
3184 localstream = sal_media_description_find_best_stream(call->localdesc, type);
3185 if (!localstream) return;
3186 localconfig = &localstream->rtcp_xr;
3187 remotestream = sal_media_description_find_best_stream(remotedesc, type);
3188 if (!remotestream) return;
3189 remoteconfig = &remotestream->rtcp_xr;
3190
3191 if (localstream->dir == SalStreamInactive) return;
3192 else if (localstream->dir == SalStreamRecvOnly) {
3193 /* Use local config for unilateral parameters and remote config for collaborative parameters. */
3194 memcpy(¤tconfig, localconfig, sizeof(currentconfig));
3195 currentconfig.rcvr_rtt_mode = remoteconfig->rcvr_rtt_mode;
3196 currentconfig.rcvr_rtt_max_size = remoteconfig->rcvr_rtt_max_size;
3197 } else {
3198 memcpy(¤tconfig, remoteconfig, sizeof(currentconfig));
3199 }
3200 if (type == SalAudio) {
3201 session = call->audiostream->ms.sessions.rtp_session;
3202 } else if (type == SalVideo) {
3203 session = call->videostream->ms.sessions.rtp_session;
3204 } else if (type == SalText) {
3205 session = call->textstream->ms.sessions.rtp_session;
3206 }
3207 rtp_session_configure_rtcp_xr(session, ¤tconfig);
3208 }
3209
3210 static void start_dtls( MSMediaStreamSessions *sessions, const SalStreamDescription *sd,const SalStreamDescription *remote) {
3211 if (sal_stream_description_has_dtls(sd) == TRUE) {
3212 /*DTLS*/
3213 SalDtlsRole salRole = sd->dtls_role;
3214 if (salRole!=SalDtlsRoleInvalid) { /* if DTLS is available at both end points */
3215 /* give the peer certificate fingerprint to dtls context */
3216 ms_dtls_srtp_set_peer_fingerprint(sessions->dtls_context, remote->dtls_fingerprint);
3217 ms_dtls_srtp_set_role(sessions->dtls_context, (salRole == SalDtlsRoleIsClient)?MSDtlsSrtpRoleIsClient:MSDtlsSrtpRoleIsServer); /* set the role to client */
3218 ms_dtls_srtp_start(sessions->dtls_context); /* then start the engine, it will send the DTLS client Hello */
3219 } else {
3220 ms_warning("unable to start DTLS engine on stream session [%p], Dtls role in resulting media description is invalid",sessions);
3221 }
3222 }
3223 }
3224
3225 static void start_dtls_on_all_streams(LinphoneCall *call) {
3226 SalMediaDescription *remote_desc = sal_call_get_remote_media_description(call->op);
3227 SalMediaDescription *result_desc = sal_call_get_final_media_description(call->op);
3228 if( remote_desc == NULL || result_desc == NULL ){
3229 /* this can happen in some tricky cases (early-media without SDP in the 200). In that case, simply skip DTLS code */
3230 return;
3231 }
3232
3233 if (call->audiostream && (media_stream_get_state((const MediaStream *)call->audiostream) == MSStreamStarted))/*dtls must start at the end of ice*/
3234 start_dtls(&call->audiostream->ms.sessions
3235 ,sal_media_description_find_best_stream(result_desc,SalAudio)
3236 ,sal_media_description_find_best_stream(remote_desc,SalAudio));
3237 #if VIDEO_ENABLED
3238 if (call->videostream && (media_stream_get_state((const MediaStream *)call->videostream) == MSStreamStarted))/*dtls must start at the end of ice*/
3239 start_dtls(&call->videostream->ms.sessions
3240 ,sal_media_description_find_best_stream(result_desc,SalVideo)
3241 ,sal_media_description_find_best_stream(remote_desc,SalVideo));
3242 #endif
3243 if (call->textstream && (media_stream_get_state((const MediaStream *)call->textstream) == MSStreamStarted))/*dtls must start at the end of ice*/
3244 start_dtls(&call->textstream->ms.sessions
3245 ,sal_media_description_find_best_stream(result_desc,SalText)
3246 ,sal_media_description_find_best_stream(remote_desc,SalText));
3247 return;
3248 }
3249
3250 static void set_dtls_fingerprint( MSMediaStreamSessions *sessions, const SalStreamDescription *sd,const SalStreamDescription *remote) {
3251 if (sal_stream_description_has_dtls(sd) == TRUE) {
3252 /*DTLS*/
3253 SalDtlsRole salRole = sd->dtls_role;
3254 if (salRole!=SalDtlsRoleInvalid) { /* if DTLS is available at both end points */
3255 /* give the peer certificate fingerprint to dtls context */
3256 ms_dtls_srtp_set_peer_fingerprint(sessions->dtls_context, remote->dtls_fingerprint);
3257 } else {
3258 ms_warning("unable to start DTLS engine on stream session [%p], Dtls role in resulting media description is invalid",sessions);
3259 }
3260 }
3261 }
3262
3263 static void set_dtls_fingerprint_on_all_streams(LinphoneCall *call) {
3264 SalMediaDescription *remote_desc = sal_call_get_remote_media_description(call->op);
3265 SalMediaDescription *result_desc = sal_call_get_final_media_description(call->op);
3266
3267 if( remote_desc == NULL || result_desc == NULL ){
3268 /* this can happen in some tricky cases (early-media without SDP in the 200). In that case, simply skip DTLS code */
3269 return;
3270 }
3271
3272 if (call->audiostream && (media_stream_get_state((const MediaStream *)call->audiostream) == MSStreamStarted))/*dtls must start at the end of ice*/
3273 set_dtls_fingerprint(&call->audiostream->ms.sessions
3274 ,sal_media_description_find_best_stream(result_desc,SalAudio)
3275 ,sal_media_description_find_best_stream(remote_desc,SalAudio));
3276 #if VIDEO_ENABLED
3277 if (call->videostream && (media_stream_get_state((const MediaStream *)call->videostream) == MSStreamStarted))/*dtls must start at the end of ice*/
3278 set_dtls_fingerprint(&call->videostream->ms.sessions
3279 ,sal_media_description_find_best_stream(result_desc,SalVideo)
3280 ,sal_media_description_find_best_stream(remote_desc,SalVideo));
3281 #endif
3282 if (call->textstream && (media_stream_get_state((const MediaStream *)call->textstream) == MSStreamStarted))/*dtls must start at the end of ice*/
3283 set_dtls_fingerprint(&call->textstream->ms.sessions
3284 ,sal_media_description_find_best_stream(result_desc,SalText)
3285 ,sal_media_description_find_best_stream(remote_desc,SalText));
3286 return;
3287 }
3288
3289 static RtpSession * create_audio_rtp_io_session(LinphoneCall *call) {
3290 PayloadType *pt;
3291 LinphoneCore *lc = call->core;
3292 const char *local_ip = lp_config_get_string(lc->config, "sound", "rtp_local_addr", "127.0.0.1");
3293 const char *remote_ip = lp_config_get_string(lc->config, "sound", "rtp_remote_addr", "127.0.0.1");
3294 int local_port = lp_config_get_int(lc->config, "sound", "rtp_local_port", 17076);
3295 int remote_port = lp_config_get_int(lc->config, "sound", "rtp_remote_port", 17078);
3296 int ptnum = lp_config_get_int(lc->config, "sound", "rtp_ptnum", 0);
3297 const char *rtpmap = lp_config_get_string(lc->config, "sound", "rtp_map", "pcmu/8000/1");
3298 int symmetric = lp_config_get_int(lc->config, "sound", "rtp_symmetric", 0);
3299 int jittcomp = lp_config_get_int(lc->config, "sound", "rtp_jittcomp", 0); /* 0 means no jitter buffer*/
3300 RtpSession *rtp_session = NULL;
3301 pt = rtp_profile_get_payload_from_rtpmap(call->audio_profile, rtpmap);
3302 if (pt != NULL) {
3303 call->rtp_io_audio_profile = rtp_profile_new("RTP IO audio profile");
3304 rtp_profile_set_payload(call->rtp_io_audio_profile, ptnum, payload_type_clone(pt));
3305 rtp_session = ms_create_duplex_rtp_session(local_ip, local_port, -1, ms_factory_get_mtu(lc->factory));
3306 rtp_session_set_profile(rtp_session, call->rtp_io_audio_profile);
3307 rtp_session_set_remote_addr_and_port(rtp_session, remote_ip, remote_port, -1);
3308 rtp_session_enable_rtcp(rtp_session, FALSE);
3309 rtp_session_set_payload_type(rtp_session, ptnum);
3310 rtp_session_set_jitter_compensation(rtp_session, jittcomp);
3311 rtp_session_enable_jitter_buffer(rtp_session, jittcomp>0);
3312 rtp_session_set_symmetric_rtp(rtp_session, (bool_t)symmetric);
3313 }
3314 return rtp_session;
3315 }
3316
3317 static void linphone_call_set_on_hold_file(LinphoneCall *call, const char *file){
3318 if (call->onhold_file){
3319 ms_free(call->onhold_file);
3320 call->onhold_file = NULL;
3321 }
3322 if (file){
3323 call->onhold_file = ms_strdup(file);
3324 }
3325 }
3326
3327 static void configure_adaptive_rate_control(LinphoneCall *call, MediaStream *ms, PayloadType *pt, bool_t video_will_be_used){
3328 LinphoneCore *lc = call->core;
3329 bool_t enabled = linphone_core_adaptive_rate_control_enabled(lc);
3330
3331 if (enabled){
3332 const char *algo = linphone_core_get_adaptive_rate_algorithm(lc);
3333 bool_t is_advanced = TRUE;
3334 if (strcasecmp(algo, "basic") == 0) is_advanced = FALSE;
3335 else if (strcasecmp(algo, "advanced") == 0) is_advanced = TRUE;
3336
3337 if (is_advanced){
3338 /*we can't use media_stream_avpf_enabled() here because the active PayloadType is not set yet in the MediaStream.*/
3339 if (!pt || !(pt->flags & PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED)){
3340 ms_warning("LinphoneCall[%p] - advanced adaptive rate control requested but avpf is not activated in this stream. Reverting to basic rate control instead.", call);
3341 is_advanced = FALSE;
3342 }else{
3343 ms_message("LinphoneCall[%p] - setting up advanced rate control.", call);
3344 }
3345 }
3346
3347 if (is_advanced){
3348 ms_bandwidth_controller_add_stream(lc->bw_controller, ms);
3349 media_stream_enable_adaptive_bitrate_control(ms, FALSE);
3350 }else{
3351 media_stream_set_adaptive_bitrate_algorithm(ms, MSQosAnalyzerAlgorithmSimple);
3352 if (ms->type == MSAudio && video_will_be_used){
3353 enabled = FALSE; /*if this is an audio stream but video is going to be used, there is
3354 no need to perform basic rate control on the audio stream, just the video stream.*/
3355 }
3356 media_stream_enable_adaptive_bitrate_control(ms, enabled);
3357 }
3358 }else{
3359 media_stream_enable_adaptive_bitrate_control(ms, FALSE);
3360 }
3361 }
3362
3363 static void linphone_call_start_audio_stream(LinphoneCall *call, LinphoneCallState next_state, bool_t video_will_be_used){
3364 LinphoneCore *lc=call->core;
3365 int used_pt=-1;
3366 const SalStreamDescription *stream;
3367 MSSndCard *playcard;
3368 MSSndCard *captcard;
3369 bool_t use_ec;
3370 bool_t mute;
3371 const char *playfile;
3372 const char *recfile;
3373 const char *file_to_play = NULL;
3374 const SalStreamDescription *local_st_desc;
3375 int crypto_idx;
3376 MSMediaStreamIO io = MS_MEDIA_STREAM_IO_INITIALIZER;
3377 bool_t use_rtp_io = lp_config_get_int(lc->config, "sound", "rtp_io", FALSE);
3378 bool_t use_rtp_io_enable_local_output = lp_config_get_int(lc->config, "sound", "rtp_io_enable_local_output", FALSE);
3379
3380 stream = sal_media_description_find_best_stream(call->resultdesc, SalAudio);
3381 if (stream && stream->dir!=SalStreamInactive && stream->rtp_port!=0){
3382 /* get remote stream description to check for zrtp-hash presence */
3383 SalMediaDescription *remote_desc = sal_call_get_remote_media_description(call->op);
3384 const SalStreamDescription *remote_stream = sal_media_description_find_best_stream(remote_desc, SalAudio);
3385
3386 const char *rtp_addr=stream->rtp_addr[0]!='\0' ? stream->rtp_addr : call->resultdesc->addr;
3387 bool_t is_multicast=ms_is_multicast(rtp_addr);
3388 playcard=lc->sound_conf.lsd_card ?
3389 lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard;
3390 captcard=lc->sound_conf.capt_sndcard;
3391 playfile=lc->play_file;
3392 recfile=lc->rec_file;
3393 call->audio_profile=make_profile(call,call->resultdesc,stream,&used_pt);
3394
3395 if (used_pt!=-1){
3396 bool_t ok = TRUE;
3397 call->current_params->audio_codec = rtp_profile_get_payload(call->audio_profile, used_pt);
3398 call->current_params->has_audio = TRUE;
3399 if (playcard==NULL) {
3400 ms_warning("No card defined for playback !");
3401 }
3402 if (captcard==NULL) {
3403 ms_warning("No card defined for capture !");
3404 }
3405 /*Don't use file or soundcard capture when placed in recv-only mode*/
3406 if (stream->rtp_port==0
3407 || stream->dir==SalStreamRecvOnly
3408 || (stream->multicast_role == SalMulticastReceiver && is_multicast)){
3409 captcard=NULL;
3410 playfile=NULL;
3411 }
3412 if (next_state == LinphoneCallPaused){
3413 /*in paused state, we never use soundcard*/
3414 playcard=NULL;
3415 captcard=NULL;
3416 recfile=NULL;
3417 /*And we will eventually play "playfile" if set by the user*/
3418 }
3419 if (call->playing_ringbacktone){
3420 captcard=NULL;
3421 playfile=NULL;/* it is setup later*/
3422 if (lp_config_get_int(lc->config,"sound","send_ringback_without_playback", 0) == 1){
3423 playcard = NULL;
3424 recfile = NULL;
3425 }
3426 }
3427 /*if playfile are supplied don't use soundcards*/
3428 if (lc->use_files || (use_rtp_io && !use_rtp_io_enable_local_output)) {
3429 captcard=NULL;
3430 playcard=NULL;
3431 }
3432 if (call->params->in_conference){
3433 /* first create the graph without soundcard resources*/
3434 captcard=playcard=NULL;
3435 }
3436 if (!linphone_call_sound_resources_available(call)){
3437 ms_message("Sound resources are used by another call, not using soundcard.");
3438 captcard=playcard=NULL;
3439 }
3440 use_ec=captcard==NULL ? FALSE : linphone_core_echo_cancellation_enabled(lc);
3441 audio_stream_enable_echo_canceller(call->audiostream, use_ec);
3442 if (playcard && stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(playcard, stream->max_rate);
3443 if (captcard && stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(captcard, stream->max_rate);
3444
3445 rtp_session_enable_rtcp_mux(call->audiostream->ms.sessions.rtp_session, stream->rtcp_mux);
3446 if (!call->params->in_conference && call->params->record_file){
3447 audio_stream_mixed_record_open(call->audiostream,call->params->record_file);
3448 call->current_params->record_file=ms_strdup(call->params->record_file);
3449 }
3450 /* valid local tags are > 0 */
3451 if (sal_stream_description_has_srtp(stream) == TRUE) {
3452 local_st_desc=sal_media_description_find_stream(call->localdesc,stream->proto,SalAudio);
3453 crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, stream->crypto_local_tag);
3454
3455 if (crypto_idx >= 0) {
3456 ms_media_stream_sessions_set_srtp_recv_key_b64(&call->audiostream->ms.sessions, stream->crypto[0].algo,stream->crypto[0].master_key);
3457 ms_media_stream_sessions_set_srtp_send_key_b64(&call->audiostream->ms.sessions, stream->crypto[0].algo,local_st_desc->crypto[crypto_idx].master_key);
3458 } else {
3459 ms_warning("Failed to find local crypto algo with tag: %d", stream->crypto_local_tag);
3460 }
3461 }
3462 configure_rtp_session_for_rtcp_fb(call, stream);
3463 configure_rtp_session_for_rtcp_xr(lc, call, SalAudio);
3464 configure_adaptive_rate_control(call, (MediaStream*)call->audiostream, call->current_params->audio_codec, video_will_be_used);
3465 if (is_multicast)
3466 rtp_session_set_multicast_ttl(call->audiostream->ms.sessions.rtp_session,stream->ttl);
3467
3468 if (use_rtp_io) {
3469 if(use_rtp_io_enable_local_output){
3470 io.input.type = MSResourceRtp;
3471 io.input.session = create_audio_rtp_io_session(call);
3472
3473 if (playcard){
3474 io.output.type = MSResourceSoundcard;
3475 io.output.soundcard = playcard;
3476 }else{
3477 io.output.type = MSResourceFile;
3478 io.output.file = recfile;
3479 }
3480 }
3481 else {
3482 io.input.type = io.output.type = MSResourceRtp;
3483 io.input.session = io.output.session = create_audio_rtp_io_session(call);
3484 }
3485
3486 if (io.input.session == NULL) {
3487 ok = FALSE;
3488 }
3489 }else {
3490 if (playcard){
3491 io.output.type = MSResourceSoundcard;
3492 io.output.soundcard = playcard;
3493 }else{
3494 io.output.type = MSResourceFile;
3495 io.output.file = recfile;
3496 }
3497 if (captcard){
3498 io.input.type = MSResourceSoundcard;
3499 io.input.soundcard = captcard;
3500 }else{
3501 io.input.type = MSResourceFile;
3502 file_to_play = playfile;
3503 io.input.file = NULL; /*we prefer to use the remote_play api, that allows to play multimedia files */
3504 }
3505
3506 }
3507 if (ok == TRUE) {
3508 int err = audio_stream_start_from_io(call->audiostream,
3509 call->audio_profile,
3510 rtp_addr,
3511 stream->rtp_port,
3512 stream->rtcp_addr[0]!='\0' ? stream->rtcp_addr : call->resultdesc->addr,
3513 (linphone_core_rtcp_enabled(lc) && !is_multicast) ? (stream->rtcp_port ? stream->rtcp_port : stream->rtp_port+1) : 0,
3514 used_pt,
3515 &io);
3516 if (err == 0){
3517 post_configure_audio_streams(call, (call->all_muted || call->audio_muted) && !call->playing_ringbacktone);
3518 }
3519 }
3520
3521 ms_media_stream_sessions_set_encryption_mandatory(&call->audiostream->ms.sessions, linphone_call_encryption_mandatory(call));
3522
3523 if (next_state == LinphoneCallPaused && captcard == NULL && playfile != NULL){
3524 int pause_time=500;
3525 ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time);
3526 }
3527 if (call->playing_ringbacktone){
3528 setup_ring_player(lc,call);
3529 }
3530
3531 if (call->params->in_conference && lc->conf_ctx){
3532 /*transform the graph to connect it to the conference filter */
3533 mute = stream->dir==SalStreamRecvOnly;
3534 linphone_conference_on_call_stream_starting(lc->conf_ctx, call, mute);
3535 }
3536 call->current_params->in_conference=call->params->in_conference;
3537 call->current_params->low_bandwidth=call->params->low_bandwidth;
3538
3539 /* start ZRTP engine if needed : set here or remote have a zrtp-hash attribute */
3540 if (linphone_core_media_encryption_supported(lc, LinphoneMediaEncryptionZRTP) &&
3541 (call->params->media_encryption == LinphoneMediaEncryptionZRTP || remote_stream->haveZrtpHash==1) ){
3542 audio_stream_start_zrtp(call->audiostream);
3543 if (remote_stream->haveZrtpHash == 1) {
3544 int retval;
3545 if ((retval = ms_zrtp_setPeerHelloHash(call->audiostream->ms.sessions.zrtp_context, (uint8_t *)remote_stream->zrtphash, strlen((const char *)(remote_stream->zrtphash)))) != 0) {
3546 ms_error("Zrtp hash mismatch 0x%x", retval);
3547 }
3548 }
3549 }
3550 }else ms_warning("No audio stream accepted ?");
3551 }
3552 linphone_call_set_on_hold_file(call, file_to_play);
3553 }
3554
3555 #ifdef VIDEO_ENABLED
3556 static RtpSession * create_video_rtp_io_session(LinphoneCall *call) {
3557 PayloadType *pt;
3558 LinphoneCore *lc = call->core;
3559 const char *local_ip = lp_config_get_string(lc->config, "video", "rtp_local_addr", "127.0.0.1");
3560 const char *remote_ip = lp_config_get_string(lc->config, "video", "rtp_remote_addr", "127.0.0.1");
3561 int local_port = lp_config_get_int(lc->config, "video", "rtp_local_port", 19076);
3562 int remote_port = lp_config_get_int(lc->config, "video", "rtp_remote_port", 19078);
3563 int ptnum = lp_config_get_int(lc->config, "video", "rtp_ptnum", 0);
3564 const char *rtpmap = lp_config_get_string(lc->config, "video", "rtp_map", "vp8/90000/1");
3565 int symmetric = lp_config_get_int(lc->config, "video", "rtp_symmetric", 0);
3566 int jittcomp = lp_config_get_int(lc->config, "video", "rtp_jittcomp", 0); /* 0 means no jitter buffer*/
3567 RtpSession *rtp_session = NULL;
3568 pt = rtp_profile_get_payload_from_rtpmap(call->video_profile, rtpmap);
3569 if (pt != NULL) {
3570 call->rtp_io_video_profile = rtp_profile_new("RTP IO video profile");
3571 rtp_profile_set_payload(call->rtp_io_video_profile, ptnum, payload_type_clone(pt));
3572 rtp_session = ms_create_duplex_rtp_session(local_ip, local_port, -1, ms_factory_get_mtu(lc->factory));
3573 rtp_session_set_profile(rtp_session, call->rtp_io_video_profile);
3574 rtp_session_set_remote_addr_and_port(rtp_session, remote_ip, remote_port, -1);
3575 rtp_session_enable_rtcp(rtp_session, FALSE);
3576 rtp_session_set_payload_type(rtp_session, ptnum);
3577 rtp_session_set_symmetric_rtp(rtp_session, (bool_t)symmetric);
3578 rtp_session_set_jitter_compensation(rtp_session, jittcomp);
3579 rtp_session_enable_jitter_buffer(rtp_session, jittcomp>0);
3580 }
3581 return rtp_session;
3582 }
3583 #endif
3584
3585 static void linphone_call_start_video_stream(LinphoneCall *call, LinphoneCallState next_state){
3586 #ifdef VIDEO_ENABLED
3587 LinphoneCore *lc=call->core;
3588 int used_pt=-1;
3589 const SalStreamDescription *vstream;
3590 MSFilter* source = NULL;
3591 bool_t reused_preview = FALSE;
3592 bool_t use_rtp_io = lp_config_get_int(lc->config, "video", "rtp_io", FALSE);
3593 MSMediaStreamIO io = MS_MEDIA_STREAM_IO_INITIALIZER;
3594
3595 /* shutdown preview */
3596 if (lc->previewstream!=NULL) {
3597 if( lc->video_conf.reuse_preview_source == FALSE) video_preview_stop(lc->previewstream);
3598 else source = video_preview_stop_reuse_source(lc->previewstream);
3599 lc->previewstream=NULL;
3600 }
3601
3602 vstream = sal_media_description_find_best_stream(call->resultdesc, SalVideo);
3603 if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->rtp_port!=0) {
3604 const char *rtp_addr=vstream->rtp_addr[0]!='\0' ? vstream->rtp_addr : call->resultdesc->addr;
3605 const char *rtcp_addr=vstream->rtcp_addr[0]!='\0' ? vstream->rtcp_addr : call->resultdesc->addr;
3606 const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc,vstream->proto,SalVideo);
3607 bool_t is_multicast=ms_is_multicast(rtp_addr);
3608 call->video_profile=make_profile(call,call->resultdesc,vstream,&used_pt);
3609
3610 if (used_pt!=-1){
3611 MediaStreamDir dir= MediaStreamSendRecv;
3612 bool_t is_inactive=FALSE;
3613 MSWebCam *cam;
3614
3615 call->current_params->video_codec = rtp_profile_get_payload(call->video_profile, used_pt);
3616 call->current_params->has_video=TRUE;
3617
3618 rtp_session_enable_rtcp_mux(call->videostream->ms.sessions.rtp_session, vstream->rtcp_mux);
3619 if (lc->video_conf.preview_vsize.width!=0)
3620 video_stream_set_preview_size(call->videostream,lc->video_conf.preview_vsize);
3621 video_stream_set_fps(call->videostream,linphone_core_get_preferred_framerate(lc));
3622 if (lp_config_get_int(lc->config, "video", "nowebcam_uses_normal_fps", 0))
3623 call->videostream->staticimage_webcam_fps_optimization = FALSE;
3624 video_stream_set_sent_video_size(call->videostream,linphone_core_get_preferred_video_size(lc));
3625 video_stream_enable_self_view(call->videostream,lc->video_conf.selfview);
3626 if (call->video_window_id != NULL)
3627 video_stream_set_native_window_id(call->videostream, call->video_window_id);
3628 else if (lc->video_window_id != NULL)
3629 video_stream_set_native_window_id(call->videostream, lc->video_window_id);
3630 if (lc->preview_window_id != NULL)
3631 video_stream_set_native_preview_window_id(call->videostream, lc->preview_window_id);
3632 video_stream_use_preview_video_window (call->videostream,lc->use_preview_window);
3633
3634 if (is_multicast){
3635 if (vstream->multicast_role == SalMulticastReceiver)
3636 dir=MediaStreamRecvOnly;
3637 else
3638 dir=MediaStreamSendOnly;
3639 } else if (vstream->dir==SalStreamSendOnly && lc->video_conf.capture ){
3640 dir=MediaStreamSendOnly;
3641 }else if (vstream->dir==SalStreamRecvOnly && lc->video_conf.display ){
3642 dir=MediaStreamRecvOnly;
3643 }else if (vstream->dir==SalStreamSendRecv){
3644 if (lc->video_conf.display && lc->video_conf.capture)
3645 dir=MediaStreamSendRecv;
3646 else if (lc->video_conf.display)
3647 dir=MediaStreamRecvOnly;
3648 else
3649 dir=MediaStreamSendOnly;
3650 }else{
3651 ms_warning("video stream is inactive.");
3652 /*either inactive or incompatible with local capabilities*/
3653 is_inactive=TRUE;
3654 }
3655 cam = linphone_call_get_video_device(call);
3656 if (!is_inactive){
3657 /* get remote stream description to check for zrtp-hash presence */
3658 SalMediaDescription *remote_desc = sal_call_get_remote_media_description(call->op);
3659 const SalStreamDescription *remote_stream = sal_media_description_find_best_stream(remote_desc, SalVideo);
3660
3661 if (sal_stream_description_has_srtp(vstream) == TRUE) {
3662 int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, vstream->crypto_local_tag);
3663 if (crypto_idx >= 0) {
3664 ms_media_stream_sessions_set_srtp_recv_key_b64(&call->videostream->ms.sessions, vstream->crypto[0].algo,vstream->crypto[0].master_key);
3665 ms_media_stream_sessions_set_srtp_send_key_b64(&call->videostream->ms.sessions, vstream->crypto[0].algo,local_st_desc->crypto[crypto_idx].master_key);
3666 }
3667 }
3668 configure_rtp_session_for_rtcp_fb(call, vstream);
3669 configure_rtp_session_for_rtcp_xr(lc, call, SalVideo);
3670 configure_adaptive_rate_control(call, (MediaStream*)call->videostream, call->current_params->video_codec, TRUE);
3671
3672 call->log->video_enabled = TRUE;
3673 video_stream_set_direction (call->videostream, dir);
3674 ms_message("%s lc rotation:%d\n", __FUNCTION__, lc->device_rotation);
3675 video_stream_set_device_rotation(call->videostream, lc->device_rotation);
3676 video_stream_set_freeze_on_error(call->videostream, lp_config_get_int(lc->config, "video", "freeze_on_error", 1));
3677 if (is_multicast)
3678 rtp_session_set_multicast_ttl(call->videostream->ms.sessions.rtp_session,vstream->ttl);
3679
3680 video_stream_use_video_preset(call->videostream, lp_config_get_string(lc->config, "video", "preset", NULL));
3681 if (lc->video_conf.reuse_preview_source && source) {
3682 ms_message("video_stream_start_with_source kept: %p", source);
3683 video_stream_start_with_source(call->videostream,
3684 call->video_profile, rtp_addr, vstream->rtp_port,
3685 rtcp_addr,
3686 linphone_core_rtcp_enabled(lc) ? (vstream->rtcp_port ? vstream->rtcp_port : vstream->rtp_port+1) : 0,
3687 used_pt, -1, cam, source);
3688 reused_preview = TRUE;
3689 } else {
3690 bool_t ok = TRUE;
3691 if (use_rtp_io) {
3692 io.input.type = io.output.type = MSResourceRtp;
3693 io.input.session = io.output.session = create_video_rtp_io_session(call);
3694 if (io.input.session == NULL) {
3695 ok = FALSE;
3696 ms_warning("Cannot create video RTP IO session");
3697 }
3698 } else {
3699 io.input.type = MSResourceCamera;
3700 io.input.camera = cam;
3701 io.output.type = MSResourceDefault;
3702 }
3703 if (ok) {
3704 video_stream_start_from_io(call->videostream,
3705 call->video_profile, rtp_addr, vstream->rtp_port,
3706 rtcp_addr,
3707 (linphone_core_rtcp_enabled(lc) && !is_multicast) ? (vstream->rtcp_port ? vstream->rtcp_port : vstream->rtp_port+1) : 0,
3708 used_pt, &io);
3709 }
3710 }
3711 ms_media_stream_sessions_set_encryption_mandatory(&call->videostream->ms.sessions,
3712 linphone_call_encryption_mandatory(call));
3713 _linphone_call_set_next_video_frame_decoded_trigger(call);
3714
3715 /* start ZRTP engine if needed : set here or remote have a zrtp-hash attribute */
3716 if (call->params->media_encryption==LinphoneMediaEncryptionZRTP || remote_stream->haveZrtpHash==1) {
3717 /*audio stream is already encrypted and video stream is active*/
3718 if (media_stream_secured((MediaStream *)call->audiostream) && media_stream_get_state((MediaStream *)call->videostream) == MSStreamStarted) {
3719 video_stream_start_zrtp(call->videostream);
3720 if (remote_stream->haveZrtpHash == 1) {
3721 int retval;
3722 if ((retval = ms_zrtp_setPeerHelloHash(call->videostream->ms.sessions.zrtp_context, (uint8_t *)remote_stream->zrtphash, strlen((const char *)(remote_stream->zrtphash)))) != 0) {
3723 ms_error("video stream ZRTP hash mismatch 0x%x", retval);
3724 }
3725 }
3726 }
3727 }
3728 }
3729 }else ms_warning("No video stream accepted.");
3730 }else{
3731 ms_message("No valid video stream defined.");
3732 }
3733 if( reused_preview == FALSE && source != NULL ){
3734 /* destroy not-reused source filter */
3735 ms_warning("Video preview (%p) not reused: destroying it.", source);
3736 ms_filter_destroy(source);
3737 }
3738
3739 #endif
3740 }
3741
3742 static void real_time_text_character_received(void *userdata, struct _MSFilter *f, unsigned int id, void *arg) {
3743 if (id == MS_RTT_4103_RECEIVED_CHAR) {
3744 LinphoneCall *call = (LinphoneCall *)userdata;
3745 RealtimeTextReceivedCharacter *data = (RealtimeTextReceivedCharacter *)arg;
3746 LinphoneChatRoom * chat_room = linphone_call_get_chat_room(call);
3747 linphone_core_real_time_text_received(call->core, chat_room, data->character, call);
3748 }
3749 }
3750
3751 static void linphone_call_start_text_stream(LinphoneCall *call) {
3752 LinphoneCore *lc = call->core;
3753 int used_pt = -1;
3754 const SalStreamDescription *tstream;
3755
3756 tstream = sal_media_description_find_best_stream(call->resultdesc, SalText);
3757 if (tstream != NULL && tstream->dir != SalStreamInactive && tstream->rtp_port != 0) {
3758 const char *rtp_addr = tstream->rtp_addr[0] != '\0' ? tstream->rtp_addr : call->resultdesc->addr;
3759 const char *rtcp_addr = tstream->rtcp_addr[0] != '\0' ? tstream->rtcp_addr : call->resultdesc->addr;
3760 const SalStreamDescription *local_st_desc = sal_media_description_find_stream(call->localdesc, tstream->proto, SalText);
3761 bool_t is_multicast = ms_is_multicast(rtp_addr);
3762 call->text_profile = make_profile(call, call->resultdesc, tstream, &used_pt);
3763
3764 if (used_pt != -1) {
3765 call->current_params->text_codec = rtp_profile_get_payload(call->text_profile, used_pt);
3766 call->current_params->realtimetext_enabled = TRUE;
3767
3768 if (sal_stream_description_has_srtp(tstream) == TRUE) {
3769 int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, tstream->crypto_local_tag);
3770 if (crypto_idx >= 0) {
3771 ms_media_stream_sessions_set_srtp_recv_key_b64(&call->textstream->ms.sessions, tstream->crypto[0].algo, tstream->crypto[0].master_key);
3772 ms_media_stream_sessions_set_srtp_send_key_b64(&call->textstream->ms.sessions, tstream->crypto[0].algo, local_st_desc->crypto[crypto_idx].master_key);
3773 }
3774 }
3775
3776 configure_rtp_session_for_rtcp_fb(call, tstream);
3777 configure_rtp_session_for_rtcp_xr(lc, call, SalText);
3778 rtp_session_enable_rtcp_mux(call->textstream->ms.sessions.rtp_session, tstream->rtcp_mux);
3779
3780 if (is_multicast) rtp_session_set_multicast_ttl(call->textstream->ms.sessions.rtp_session,tstream->ttl);
3781
3782 text_stream_start(call->textstream, call->text_profile, rtp_addr, tstream->rtp_port, rtcp_addr, (linphone_core_rtcp_enabled(lc) && !is_multicast) ? (tstream->rtcp_port ? tstream->rtcp_port : tstream->rtp_port + 1) : 0, used_pt);
3783 ms_filter_add_notify_callback(call->textstream->rttsink, real_time_text_character_received, call, FALSE);
3784
3785 ms_media_stream_sessions_set_encryption_mandatory(&call->textstream->ms.sessions,
3786 linphone_call_encryption_mandatory(call));
3787 } else ms_warning("No text stream accepted.");
3788 } else {
3789 ms_message("No valid text stream defined.");
3790 }
3791 }
3792
3793 void linphone_call_set_symmetric_rtp(LinphoneCall *call, bool_t val){
3794 int i;
3795 for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; ++i){
3796 MSMediaStreamSessions *mss = &call->sessions[i];
3797 if (mss->rtp_session){
3798 rtp_session_set_symmetric_rtp(mss->rtp_session, val);
3799 }
3800 }
3801 }
3802
3803 void linphone_call_start_media_streams(LinphoneCall *call, LinphoneCallState next_state){
3804 LinphoneCore *lc=call->core;
3805 bool_t video_will_be_used = FALSE;
3806 #ifdef VIDEO_ENABLED
3807 const SalStreamDescription *vstream=sal_media_description_find_best_stream(call->resultdesc,SalVideo);
3808 #endif
3809
3810 switch (next_state){
3811 case LinphoneCallIncomingEarlyMedia:
3812 if (linphone_core_get_remote_ringback_tone(lc)){
3813 call->playing_ringbacktone = TRUE;
3814 }
3815 BCTBX_NO_BREAK;
3816 case LinphoneCallOutgoingEarlyMedia:
3817 if (!call->params->real_early_media){
3818 call->all_muted = TRUE;
3819 }
3820 break;
3821 default:
3822 call->playing_ringbacktone = FALSE;
3823 call->all_muted = FALSE;
3824 break;
3825 }
3826
3827 call->current_params->audio_codec = NULL;
3828 call->current_params->video_codec = NULL;
3829 call->current_params->text_codec = NULL;
3830
3831 if ((call->audiostream == NULL) && (call->videostream == NULL)) {
3832 ms_fatal("start_media_stream() called without prior init !");
3833 return;
3834 }
3835
3836 if (call->ice_session != NULL){
3837 /*if there is an ICE session when we are about to start streams, then ICE will conduct the media path checking and authentication properly.
3838 * Symmetric RTP must be turned off*/
3839 linphone_call_set_symmetric_rtp(call, FALSE);
3840 }
3841
3842 call->nb_media_starts++;
3843 #if defined(VIDEO_ENABLED)
3844 if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->payloads!=NULL){
3845 /*when video is used, do not make adaptive rate control on audio, it is stupid.*/
3846 video_will_be_used = TRUE;
3847 }
3848 #endif
3849 ms_message("linphone_call_start_media_streams() call=[%p] local upload_bandwidth=[%i] kbit/s; local download_bandwidth=[%i] kbit/s",
3850 call, linphone_core_get_upload_bandwidth(lc),linphone_core_get_download_bandwidth(lc));
3851
3852 call->current_params->has_audio = FALSE;
3853 if (call->audiostream!=NULL) {
3854 linphone_call_start_audio_stream(call, next_state, video_will_be_used);
3855 } else {
3856 ms_warning("linphone_call_start_media_streams(): no audio stream!");
3857 }
3858 call->current_params->has_video=FALSE;
3859 if (call->videostream!=NULL) {
3860 if (call->audiostream) audio_stream_link_video(call->audiostream,call->videostream);
3861 linphone_call_start_video_stream(call, next_state);
3862 }
3863 /*the onhold file is to be played once both audio and video are ready.*/
3864 if (call->onhold_file && !call->params->in_conference && call->audiostream){
3865 MSFilter *player = audio_stream_open_remote_play(call->audiostream, call->onhold_file);
3866 if (player){
3867 int pause_time=500;
3868 ms_filter_call_method(player, MS_PLAYER_SET_LOOP, &pause_time);
3869 ms_filter_call_method_noarg(player, MS_PLAYER_START);
3870 }
3871 }
3872
3873 call->up_bw=linphone_core_get_upload_bandwidth(lc);
3874
3875 if (call->params->realtimetext_enabled) {
3876 linphone_call_start_text_stream(call);
3877 }
3878
3879 set_dtls_fingerprint_on_all_streams(call);
3880
3881 if ((call->ice_session != NULL) && (ice_session_state(call->ice_session) != IS_Completed)) {
3882 if (call->params->media_encryption==LinphoneMediaEncryptionDTLS) {
3883 call->current_params->update_call_when_ice_completed = FALSE;
3884 ms_message("Disabling update call when ice completed on call [%p]",call);
3885 }
3886 ice_session_start_connectivity_checks(call->ice_session);
3887 } else {
3888 /*should not start dtls until ice is completed*/
3889 start_dtls_on_all_streams(call);
3890 }
3891
3892 }
3893
3894 void linphone_call_stop_media_streams_for_ice_gathering(LinphoneCall *call){
3895 if(call->audiostream && call->audiostream->ms.state==MSStreamPreparing) audio_stream_unprepare_sound(call->audiostream);
3896 #ifdef VIDEO_ENABLED
3897 if (call->videostream && call->videostream->ms.state==MSStreamPreparing) {
3898 video_stream_unprepare_video(call->videostream);
3899 }
3900 #endif
3901 if (call->textstream && call->textstream->ms.state == MSStreamPreparing) {
3902 text_stream_unprepare_text(call->textstream);
3903 }
3904 }
3905
3906 static bool_t update_stream_crypto_params(LinphoneCall *call, const SalStreamDescription *local_st_desc, SalStreamDescription *old_stream, SalStreamDescription *new_stream, MediaStream *ms){
3907 int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, new_stream->crypto_local_tag);
3908 if (crypto_idx >= 0) {
3909 if (call->localdesc_changed & SAL_MEDIA_DESCRIPTION_CRYPTO_KEYS_CHANGED)
3910 ms_media_stream_sessions_set_srtp_send_key_b64(&ms->sessions, new_stream->crypto[0].algo,local_st_desc->crypto[crypto_idx].master_key);
3911 if (strcmp(old_stream->crypto[0].master_key,new_stream->crypto[0].master_key)!=0){
3912 ms_media_stream_sessions_set_srtp_recv_key_b64(&ms->sessions, new_stream->crypto[0].algo,new_stream->crypto[0].master_key);
3913 }
3914 return TRUE;
3915 } else {
3916 ms_warning("Failed to find local crypto algo with tag: %d", new_stream->crypto_local_tag);
3917 }
3918 return FALSE;
3919 }
3920
3921 void linphone_call_update_crypto_parameters(LinphoneCall *call, SalMediaDescription *old_md, SalMediaDescription *new_md) {
3922 SalStreamDescription *old_stream;
3923 SalStreamDescription *new_stream;
3924 const SalStreamDescription *local_st_desc;
3925
3926 local_st_desc = sal_media_description_find_secure_stream_of_type(call->localdesc, SalAudio);
3927 old_stream = sal_media_description_find_secure_stream_of_type(old_md, SalAudio);
3928 new_stream = sal_media_description_find_secure_stream_of_type(new_md, SalAudio);
3929 if (call->audiostream && local_st_desc && old_stream && new_stream &&
3930 update_stream_crypto_params(call,local_st_desc,old_stream,new_stream,&call->audiostream->ms)){
3931 }
3932
3933 local_st_desc = sal_media_description_find_secure_stream_of_type(call->localdesc, SalText);
3934 old_stream = sal_media_description_find_secure_stream_of_type(old_md, SalText);
3935 new_stream = sal_media_description_find_secure_stream_of_type(new_md, SalText);
3936 if (call->textstream && local_st_desc && old_stream && new_stream &&
3937 update_stream_crypto_params(call,local_st_desc,old_stream,new_stream,&call->textstream->ms)){
3938 }
3939
3940 start_dtls_on_all_streams(call);
3941
3942 #ifdef VIDEO_ENABLED
3943 local_st_desc = sal_media_description_find_secure_stream_of_type(call->localdesc, SalVideo);
3944 old_stream = sal_media_description_find_secure_stream_of_type(old_md, SalVideo);
3945 new_stream = sal_media_description_find_secure_stream_of_type(new_md, SalVideo);
3946 if (call->videostream && local_st_desc && old_stream && new_stream &&
3947 update_stream_crypto_params(call,local_st_desc,old_stream,new_stream,&call->videostream->ms)){
3948 }
3949 #endif
3950 }
3951
3952 void linphone_call_update_remote_session_id_and_ver(LinphoneCall *call) {
3953 SalMediaDescription *remote_desc = sal_call_get_remote_media_description(call->op);
3954 if (remote_desc) {
3955 call->remote_session_id = remote_desc->session_id;
3956 call->remote_session_ver = remote_desc->session_ver;
3957 }
3958 }
3959
3960 void linphone_call_delete_ice_session(LinphoneCall *call){
3961 if (call->ice_session != NULL) {
3962 ice_session_destroy(call->ice_session);
3963 call->ice_session = NULL;
3964 if (call->audiostream != NULL) call->audiostream->ms.ice_check_list = NULL;
3965 if (call->videostream != NULL) call->videostream->ms.ice_check_list = NULL;
3966 if (call->textstream != NULL) call->textstream->ms.ice_check_list = NULL;
3967 call->audio_stats->ice_state = LinphoneIceStateNotActivated;
3968 call->video_stats->ice_state = LinphoneIceStateNotActivated;
3969 call->text_stats->ice_state = LinphoneIceStateNotActivated;
3970 }
3971 }
3972
3973 void linphone_call_delete_upnp_session(LinphoneCall *call){
3974 #ifdef BUILD_UPNP
3975 if(call->upnp_session!=NULL) {
3976 linphone_upnp_session_destroy(call->upnp_session);
3977 call->upnp_session=NULL;
3978 }
3979 #endif //BUILD_UPNP
3980 }
3981
3982 static void linphone_call_log_fill_stats(LinphoneCallLog *log, MediaStream *st){
3983 float quality=media_stream_get_average_quality_rating(st);
3984 if (quality>=0){
3985 if (log->quality!=-1){
3986 log->quality*=quality/5.0f;
3987 }else log->quality=quality;
3988 }
3989 }
3990
3991 static void update_rtp_stats(LinphoneCall *call, int stream_index) {
3992 if (call->sessions[stream_index].rtp_session) {
3993 const rtp_stats_t *stats = rtp_session_get_stats(call->sessions[stream_index].rtp_session);
3994 LinphoneCallStats *call_stats = NULL;
3995 if (stream_index == call->main_audio_stream_index) {
3996 call_stats = call->audio_stats;
3997 } else if (stream_index == call->main_video_stream_index) {
3998 call_stats = call->video_stats;
3999 } else {
4000 call_stats = call->text_stats;
4001 }
4002 if (call_stats) memcpy(&(call_stats->rtp_stats), stats, sizeof(*stats));
4003 }
4004 }
4005
4006 static void linphone_call_stop_audio_stream(LinphoneCall *call) {
4007 LinphoneCore *lc = call->core;
4008 if (call->audiostream!=NULL) {
4009 linphone_reporting_update_media_info(call, LINPHONE_CALL_STATS_AUDIO);
4010 media_stream_reclaim_sessions(&call->audiostream->ms,&call->sessions[call->main_audio_stream_index]);
4011
4012 if (call->audiostream->ec){
4013 char *state_str=NULL;
4014 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_GET_STATE_STRING,&state_str);
4015 if (state_str){
4016 ms_message("Writing echo canceler state, %i bytes",(int)strlen(state_str));
4017 lp_config_write_relative_file(call->core->config, EC_STATE_STORE, state_str);
4018 }
4019 }
4020 audio_stream_get_local_rtp_stats(call->audiostream,&call->log->local_stats);
4021 linphone_call_log_fill_stats (call->log,(MediaStream*)call->audiostream);
4022 if (call->endpoint){
4023 linphone_conference_on_call_stream_stopping(lc->conf_ctx, call);
4024 }
4025 ms_bandwidth_controller_remove_stream(lc->bw_controller, (MediaStream*)call->audiostream);
4026 audio_stream_stop(call->audiostream);
4027 update_rtp_stats(call, call->main_audio_stream_index);
4028 call->audiostream=NULL;
4029 linphone_call_handle_stream_events(call, call->main_audio_stream_index);
4030 rtp_session_unregister_event_queue(call->sessions[call->main_audio_stream_index].rtp_session, call->audiostream_app_evq);
4031 ortp_ev_queue_flush(call->audiostream_app_evq);
4032 ortp_ev_queue_destroy(call->audiostream_app_evq);
4033 call->audiostream_app_evq=NULL;
4034
4035 call->current_params->audio_codec = NULL;
4036 }
4037 }
4038
4039 static void linphone_call_stop_video_stream(LinphoneCall *call) {
4040 #ifdef VIDEO_ENABLED
4041 if (call->videostream!=NULL){
4042 linphone_reporting_update_media_info(call, LINPHONE_CALL_STATS_VIDEO);
4043 media_stream_reclaim_sessions(&call->videostream->ms,&call->sessions[call->main_video_stream_index]);
4044 linphone_call_log_fill_stats(call->log,(MediaStream*)call->videostream);
4045 ms_bandwidth_controller_remove_stream(call->core->bw_controller, (MediaStream*)call->videostream);
4046 video_stream_stop(call->videostream);
4047 update_rtp_stats(call, call->main_video_stream_index);
4048 call->videostream=NULL;
4049 linphone_call_handle_stream_events(call, call->main_video_stream_index);
4050 rtp_session_unregister_event_queue(call->sessions[call->main_video_stream_index].rtp_session, call->videostream_app_evq);
4051 ortp_ev_queue_flush(call->videostream_app_evq);
4052 ortp_ev_queue_destroy(call->videostream_app_evq);
4053 call->videostream_app_evq=NULL;
4054 call->current_params->video_codec = NULL;
4055 }
4056 #endif
4057 }
4058
4059 static void unset_rtp_profile(LinphoneCall *call, int i){
4060 if (call->sessions[i].rtp_session)
4061 rtp_session_set_profile(call->sessions[i].rtp_session,&av_profile);
4062 }
4063
4064 static void linphone_call_stop_text_stream(LinphoneCall *call) {
4065 if (call->textstream != NULL) {
4066 linphone_reporting_update_media_info(call, LINPHONE_CALL_STATS_TEXT);
4067 media_stream_reclaim_sessions(&call->textstream->ms, &call->sessions[call->main_text_stream_index]);
4068 linphone_call_log_fill_stats(call->log, (MediaStream*)call->textstream);
4069 text_stream_stop(call->textstream);
4070 update_rtp_stats(call, call->main_text_stream_index);
4071 call->textstream = NULL;
4072 linphone_call_handle_stream_events(call, call->main_text_stream_index);
4073 rtp_session_unregister_event_queue(call->sessions[call->main_text_stream_index].rtp_session, call->textstream_app_evq);
4074 ortp_ev_queue_flush(call->textstream_app_evq);
4075 ortp_ev_queue_destroy(call->textstream_app_evq);
4076 call->textstream_app_evq = NULL;
4077 call->current_params->text_codec = NULL;
4078 }
4079 }
4080
4081 void linphone_call_stop_media_streams(LinphoneCall *call){
4082 if (call->audiostream || call->videostream || call->textstream) {
4083 if (call->audiostream && call->videostream)
4084 audio_stream_unlink_video(call->audiostream, call->videostream);
4085 linphone_call_stop_audio_stream(call);
4086 linphone_call_stop_video_stream(call);
4087 linphone_call_stop_text_stream(call);
4088
4089 if (call->core->msevq != NULL) {
4090 ms_event_queue_skip(call->core->msevq);
4091 }
4092 }
4093
4094 if (call->audio_profile){
4095 rtp_profile_destroy(call->audio_profile);
4096 call->audio_profile=NULL;
4097 unset_rtp_profile(call,call->main_audio_stream_index);
4098 }
4099 if (call->video_profile){
4100 rtp_profile_destroy(call->video_profile);
4101 call->video_profile=NULL;
4102 unset_rtp_profile(call,call->main_video_stream_index);
4103 }
4104 if (call->text_profile){
4105 rtp_profile_destroy(call->text_profile);
4106 call->text_profile=NULL;
4107 unset_rtp_profile(call,call->main_text_stream_index);
4108 }
4109 if (call->rtp_io_audio_profile) {
4110 rtp_profile_destroy(call->rtp_io_audio_profile);
4111 call->rtp_io_audio_profile = NULL;
4112 }
4113 if (call->rtp_io_video_profile) {
4114 rtp_profile_destroy(call->rtp_io_video_profile);
4115 call->rtp_io_video_profile = NULL;
4116 }
4117
4118 linphone_core_soundcard_hint_check(call->core);
4119 }
4120
4121 void linphone_call_enable_echo_cancellation(LinphoneCall *call, bool_t enable) {
4122 if (call!=NULL && call->audiostream!=NULL && call->audiostream->ec){
4123 bool_t bypass_mode = !enable;
4124 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_SET_BYPASS_MODE,&bypass_mode);
4125 }
4126 }
4127
4128 bool_t linphone_call_echo_cancellation_enabled(LinphoneCall *call) {
4129 if (call!=NULL && call->audiostream!=NULL && call->audiostream->ec){
4130 bool_t val;
4131 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_GET_BYPASS_MODE,&val);
4132 return !val;
4133 } else {
4134 return linphone_core_echo_cancellation_enabled(call->core);
4135 }
4136 }
4137
4138 void linphone_call_enable_echo_limiter(LinphoneCall *call, bool_t val){
4139 if (call!=NULL && call->audiostream!=NULL ) {
4140 if (val) {
4141 const char *type=lp_config_get_string(call->core->config,"sound","el_type","mic");
4142 if (strcasecmp(type,"mic")==0)
4143 audio_stream_enable_echo_limiter(call->audiostream,ELControlMic);
4144 else if (strcasecmp(type,"full")==0)
4145 audio_stream_enable_echo_limiter(call->audiostream,ELControlFull);
4146 } else {
4147 audio_stream_enable_echo_limiter(call->audiostream,ELInactive);
4148 }
4149 }
4150 }
4151
4152 bool_t linphone_call_echo_limiter_enabled(const LinphoneCall *call){
4153 if (call!=NULL && call->audiostream!=NULL ){
4154 return call->audiostream->el_type !=ELInactive ;
4155 } else {
4156 return linphone_core_echo_limiter_enabled(call->core);
4157 }
4158 }
4159
4160 float linphone_call_get_play_volume(LinphoneCall *call){
4161 AudioStream *st=call->audiostream;
4162 if (st && st->volrecv){
4163 float vol=0;
4164 ms_filter_call_method(st->volrecv,MS_VOLUME_GET,&vol);
4165 return vol;
4166
4167 }
4168 return LINPHONE_VOLUME_DB_LOWEST;
4169 }
4170
4171 float linphone_call_get_record_volume(LinphoneCall *call){
4172 AudioStream *st=call->audiostream;
4173 if (st && st->volsend && !call->audio_muted && call->state==LinphoneCallStreamsRunning){
4174 float vol=0;
4175 ms_filter_call_method(st->volsend,MS_VOLUME_GET,&vol);
4176 return vol;
4177
4178 }
4179 return LINPHONE_VOLUME_DB_LOWEST;
4180 }
4181
4182 float linphone_call_get_speaker_volume_gain(const LinphoneCall *call) {
4183 if(call->audiostream) return audio_stream_get_sound_card_output_gain(call->audiostream);
4184 else {
4185 ms_error("Could not get playback volume: no audio stream");
4186 return -1.0f;
4187 }
4188 }
4189
4190 void linphone_call_set_speaker_volume_gain(LinphoneCall *call, float volume) {
4191 if(call->audiostream) audio_stream_set_sound_card_output_gain(call->audiostream, volume);
4192 else ms_error("Could not set playback volume: no audio stream");
4193 }
4194
4195 float linphone_call_get_microphone_volume_gain(const LinphoneCall *call) {
4196 if(call->audiostream) return audio_stream_get_sound_card_input_gain(call->audiostream);
4197 else {
4198 ms_error("Could not get record volume: no audio stream");
4199 return -1.0f;
4200 }
4201 }
4202
4203 void linphone_call_set_microphone_volume_gain(LinphoneCall *call, float volume) {
4204 if(call->audiostream) audio_stream_set_sound_card_input_gain(call->audiostream, volume);
4205 else ms_error("Could not set record volume: no audio stream");
4206 }
4207
4208 static float agregate_ratings(float audio_rating, float video_rating){
4209 float result;
4210 if (audio_rating<0 && video_rating<0) result=-1;
4211 else if (audio_rating<0) result=video_rating*5.0f;
4212 else if (video_rating<0) result=audio_rating*5.0f;
4213 else result=audio_rating*video_rating*5.0f;
4214 return result;
4215 }
4216
4217 float linphone_call_get_current_quality(LinphoneCall *call){
4218 float audio_rating=-1.f;
4219 float video_rating=-1.f;
4220
4221 if (call->audiostream){
4222 audio_rating=media_stream_get_quality_rating((MediaStream*)call->audiostream)/5.0f;
4223 }
4224 if (call->videostream){
4225 video_rating=media_stream_get_quality_rating((MediaStream*)call->videostream)/5.0f;
4226 }
4227 return agregate_ratings(audio_rating, video_rating);
4228 }
4229
4230 float linphone_call_get_average_quality(LinphoneCall *call){
4231 float audio_rating=-1.f;
4232 float video_rating=-1.f;
4233
4234 if (call->audiostream){
4235 audio_rating = media_stream_get_average_quality_rating((MediaStream*)call->audiostream)/5.0f;
4236 }
4237 if (call->videostream){
4238 video_rating = media_stream_get_average_quality_rating((MediaStream*)call->videostream)/5.0f;
4239 }
4240 return agregate_ratings(audio_rating, video_rating);
4241 }
4242
4243 static void update_local_stats(LinphoneCallStats *stats, MediaStream *stream) {
4244 PayloadType *pt;
4245 RtpSession *session = stream->sessions.rtp_session;
4246 const MSQualityIndicator *qi = media_stream_get_quality_indicator(stream);
4247 if (qi) {
4248 stats->local_late_rate=ms_quality_indicator_get_local_late_rate(qi);
4249 stats->local_loss_rate=ms_quality_indicator_get_local_loss_rate(qi);
4250 }
4251 media_stream_get_local_rtp_stats(stream, &stats->rtp_stats);
4252 pt = rtp_profile_get_payload(rtp_session_get_profile(session), rtp_session_get_send_payload_type(session));
4253 stats->clockrate = pt ? pt->clock_rate : 8000;
4254 }
4255
4256 static MediaStream *linphone_call_get_stream(LinphoneCall *call, LinphoneStreamType type){
4257 switch(type){
4258 case LinphoneStreamTypeAudio:
4259 return &call->audiostream->ms;
4260 case LinphoneStreamTypeVideo:
4261 return &call->videostream->ms;
4262 case LinphoneStreamTypeText:
4263 return &call->textstream->ms;
4264 case LinphoneStreamTypeUnknown:
4265 break;
4266 }
4267 return NULL;
4268 }
4269
4270 static void _linphone_call_stats_clone(LinphoneCallStats *dst, const LinphoneCallStats *src) {
4271 /*
4272 * Save the belle_sip_object_t part, copy the entire structure and restore the belle_sip_object_t part
4273 */
4274 belle_sip_object_t tmp = dst->base;
4275 memcpy(dst, src, sizeof(LinphoneCallStats));
4276 dst->base = tmp;
4277
4278 dst->received_rtcp = NULL;
4279 dst->sent_rtcp = NULL;
4280 }
4281
4282 LinphoneCallStats *linphone_call_get_stats(LinphoneCall *call, LinphoneStreamType type){
4283 if ((int)type >=0 && type<=LinphoneStreamTypeText){
4284 LinphoneCallStats *stats = NULL;
4285 LinphoneCallStats *stats_copy = linphone_call_stats_new();
4286 if (type == LinphoneStreamTypeAudio) {
4287 stats = call->audio_stats;
4288 } else if (type == LinphoneStreamTypeVideo) {
4289 stats = call->video_stats;
4290 } else if (type == LinphoneStreamTypeText) {
4291 stats = call->text_stats;
4292 }
4293 MediaStream *ms = linphone_call_get_stream(call, type);
4294 if (ms && stats) update_local_stats(stats, ms);
4295 _linphone_call_stats_clone(stats_copy, stats);
4296 return stats_copy;
4297 }
4298 ms_error("Invalid stream type %i", (int)type);
4299 return NULL;
4300 }
4301
4302 LinphoneCallStats *linphone_call_get_audio_stats(LinphoneCall *call) {
4303 return linphone_call_get_stats(call, LinphoneStreamTypeAudio);
4304 }
4305
4306 LinphoneCallStats *linphone_call_get_video_stats(LinphoneCall *call) {
4307 return linphone_call_get_stats(call, LinphoneStreamTypeVideo);
4308 }
4309
4310 LinphoneCallStats *linphone_call_get_text_stats(LinphoneCall *call) {
4311 return linphone_call_get_stats(call, LinphoneStreamTypeText);
4312 }
4313
4314 static bool_t ice_in_progress(LinphoneCallStats *stats){
4315 return stats->ice_state==LinphoneIceStateInProgress;
4316 }
4317
4318 bool_t linphone_call_media_in_progress(LinphoneCall *call){
4319 bool_t ret=FALSE;
4320 if (ice_in_progress(call->audio_stats) || ice_in_progress(call->video_stats) || ice_in_progress(call->text_stats))
4321 ret=TRUE;
4322 /*TODO: could check zrtp state, upnp state*/
4323 return ret;
4324 }
4325
4326 BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneCallStats);
4327
4328 BELLE_SIP_INSTANCIATE_VPTR(LinphoneCallStats, belle_sip_object_t,
4329 NULL, // destroy
4330 _linphone_call_stats_clone, // clone
4331 NULL, // marshal
4332 TRUE
4333 );
4334
4335 LinphoneCallStats *linphone_call_stats_new() {
4336 LinphoneCallStats *stats = belle_sip_object_new(LinphoneCallStats);
4337 return stats;
4338 }
4339
4340 LinphoneCallStats* linphone_call_stats_ref(LinphoneCallStats* stats) {
4341 return (LinphoneCallStats*) belle_sip_object_ref(stats);
4342 }
4343
4344 void linphone_call_stats_unref(LinphoneCallStats* stats) {
4345 belle_sip_object_unref(stats);
4346 }
4347
4348 void *linphone_call_stats_get_user_data(const LinphoneCallStats *stats) {
4349 return stats->user_data;
4350 }
4351
4352 void linphone_call_stats_set_user_data(LinphoneCallStats *stats, void *data) {
4353 stats->user_data = data;
4354 }
4355
4356 LinphoneStreamType linphone_call_stats_get_type(const LinphoneCallStats *stats) {
4357 return stats->type;
4358 }
4359
4360 float linphone_call_stats_get_sender_loss_rate(const LinphoneCallStats *stats) {
4361 const report_block_t *srb = NULL;
4362
4363 if (!stats || !stats->sent_rtcp)
4364 return 0.0;
4365 /* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */
4366 if (stats->sent_rtcp->b_cont != NULL)
4367 msgpullup(stats->sent_rtcp, -1);
4368
4369 do{
4370 if (rtcp_is_SR(stats->sent_rtcp))
4371 srb = rtcp_SR_get_report_block(stats->sent_rtcp, 0);
4372 else if (rtcp_is_RR(stats->sent_rtcp))
4373 srb = rtcp_RR_get_report_block(stats->sent_rtcp, 0);
4374 if (srb) break;
4375 }while (rtcp_next_packet(stats->sent_rtcp));
4376 rtcp_rewind(stats->sent_rtcp);
4377 if (!srb)
4378 return 0.0;
4379 return 100.0f * report_block_get_fraction_lost(srb) / 256.0f;
4380 }
4381
4382 float linphone_call_stats_get_receiver_loss_rate(const LinphoneCallStats *stats) {
4383 const report_block_t *rrb = NULL;
4384
4385 if (!stats || !stats->received_rtcp)
4386 return 0.0;
4387 /* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */
4388 if (stats->received_rtcp->b_cont != NULL)
4389 msgpullup(stats->received_rtcp, -1);
4390
4391 do{
4392 if (rtcp_is_RR(stats->received_rtcp))
4393 rrb = rtcp_RR_get_report_block(stats->received_rtcp, 0);
4394 else if (rtcp_is_SR(stats->received_rtcp))
4395 rrb = rtcp_SR_get_report_block(stats->received_rtcp, 0);
4396 if (rrb) break;
4397 }while (rtcp_next_packet(stats->received_rtcp));
4398 rtcp_rewind(stats->received_rtcp);
4399 if (!rrb)
4400 return 0.0;
4401 return 100.0f * report_block_get_fraction_lost(rrb) / 256.0f;
4402 }
4403
4404 float linphone_call_stats_get_local_loss_rate(const LinphoneCallStats *stats) {
4405 return stats->local_loss_rate;
4406 }
4407
4408 float linphone_call_stats_get_local_late_rate(const LinphoneCallStats *stats) {
4409 return stats->local_late_rate;
4410 }
4411
4412 float linphone_call_stats_get_sender_interarrival_jitter(const LinphoneCallStats *stats) {
4413 const report_block_t *srb = NULL;
4414
4415 if (!stats || !stats->sent_rtcp)
4416 return 0.0;
4417 /* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */
4418 if (stats->sent_rtcp->b_cont != NULL)
4419 msgpullup(stats->sent_rtcp, -1);
4420 if (rtcp_is_SR(stats->sent_rtcp))
4421 srb = rtcp_SR_get_report_block(stats->sent_rtcp, 0);
4422 else if (rtcp_is_RR(stats->sent_rtcp))
4423 srb = rtcp_RR_get_report_block(stats->sent_rtcp, 0);
4424 if (!srb)
4425 return 0.0;
4426 if (stats->clockrate == 0)
4427 return 0.0;
4428 return (float)report_block_get_interarrival_jitter(srb) / (float)stats->clockrate;
4429 }
4430
4431 float linphone_call_stats_get_receiver_interarrival_jitter(const LinphoneCallStats *stats) {
4432 const report_block_t *rrb = NULL;
4433
4434 if (!stats || !stats->received_rtcp)
4435 return 0.0;
4436 /* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */
4437 if (stats->received_rtcp->b_cont != NULL)
4438 msgpullup(stats->received_rtcp, -1);
4439 if (rtcp_is_SR(stats->received_rtcp))
4440 rrb = rtcp_SR_get_report_block(stats->received_rtcp, 0);
4441 else if (rtcp_is_RR(stats->received_rtcp))
4442 rrb = rtcp_RR_get_report_block(stats->received_rtcp, 0);
4443 if (!rrb)
4444 return 0.0;
4445 if (stats->clockrate == 0)
4446 return 0.0;
4447 return (float)report_block_get_interarrival_jitter(rrb) / (float)stats->clockrate;
4448 }
4449
4450 const rtp_stats_t *linphone_call_stats_get_rtp_stats(const LinphoneCallStats *stats) {
4451 return &stats->rtp_stats;
4452 }
4453
4454 uint64_t linphone_call_stats_get_late_packets_cumulative_number(const LinphoneCallStats *stats) {
4455 return linphone_call_stats_get_rtp_stats(stats)->outoftime;
4456 }
4457
4458 float linphone_call_stats_get_download_bandwidth(const LinphoneCallStats *stats) {
4459 return stats->download_bandwidth;
4460 }
4461
4462 float linphone_call_stats_get_upload_bandwidth(const LinphoneCallStats *stats) {
4463 return stats->upload_bandwidth;
4464 }
4465
4466 LinphoneIceState linphone_call_stats_get_ice_state(const LinphoneCallStats *stats) {
4467 return stats->ice_state;
4468 }
4469
4470 LinphoneUpnpState linphone_call_stats_get_upnp_state(const LinphoneCallStats *stats) {
4471 return stats->upnp_state;
4472 }
4473
4474 LinphoneAddressFamily linphone_call_stats_get_ip_family_of_remote(const LinphoneCallStats *stats) {
4475 return (LinphoneAddressFamily)stats->rtp_remote_family;
4476 }
4477
4478 float linphone_call_stats_get_jitter_buffer_size_ms(const LinphoneCallStats *stats) {
4479 return stats->jitter_stats.jitter_buffer_size_ms;
4480 }
4481
4482 float linphone_call_stats_get_round_trip_delay(const LinphoneCallStats *stats) {
4483 return stats->round_trip_delay;
4484 }
4485
4486 void linphone_call_start_recording(LinphoneCall *call){
4487 if (!call->params->record_file){
4488 ms_error("linphone_call_start_recording(): no output file specified. Use linphone_call_params_set_record_file().");
4489 return;
4490 }
4491 if (call->audiostream && !call->params->in_conference){
4492 audio_stream_mixed_record_start(call->audiostream);
4493 }
4494 call->record_active=TRUE;
4495 }
4496
4497 void linphone_call_stop_recording(LinphoneCall *call){
4498 if (call->audiostream && !call->params->in_conference){
4499 audio_stream_mixed_record_stop(call->audiostream);
4500 }
4501 call->record_active=FALSE;
4502 }
4503
4504 static void report_bandwidth_for_stream(LinphoneCall *call, MediaStream *ms, LinphoneStreamType type){
4505 bool_t active = ms ? (media_stream_get_state(ms) == MSStreamStarted) : FALSE;
4506 LinphoneCallStats *stats = NULL;
4507 if (type == LinphoneStreamTypeAudio) {
4508 stats = call->audio_stats;
4509 } else if (type == LinphoneStreamTypeVideo) {
4510 stats = call->video_stats;
4511 } else if (type == LinphoneStreamTypeText) {
4512 stats = call->text_stats;
4513 } else {
4514 return;
4515 }
4516
4517 stats->download_bandwidth=(active) ? (float)(media_stream_get_down_bw(ms)*1e-3) : 0.f;
4518 stats->upload_bandwidth=(active) ? (float)(media_stream_get_up_bw(ms)*1e-3) : 0.f;
4519 stats->rtcp_download_bandwidth=(active) ? (float)(media_stream_get_rtcp_down_bw(ms)*1e-3) : 0.f;
4520 stats->rtcp_upload_bandwidth=(active) ? (float)(media_stream_get_rtcp_up_bw(ms)*1e-3) : 0.f;
4521 stats->rtp_remote_family=(active)
4522 ? (ortp_stream_is_ipv6(&ms->sessions.rtp_session->rtp.gs) ? LinphoneAddressFamilyInet6 : LinphoneAddressFamilyInet) : LinphoneAddressFamilyUnspec;
4523
4524 if (call->core->send_call_stats_periodical_updates){
4525 if (active) update_local_stats(stats, ms);
4526 stats->updated |= LINPHONE_CALL_STATS_PERIODICAL_UPDATE;
4527 linphone_call_notify_stats_updated(call, stats);
4528 stats->updated=0;
4529 }
4530 }
4531
4532 static void report_bandwidth(LinphoneCall *call, MediaStream *as, MediaStream *vs, MediaStream *ts){
4533 report_bandwidth_for_stream(call, as, LinphoneStreamTypeAudio);
4534 report_bandwidth_for_stream(call, vs, LinphoneStreamTypeVideo);
4535 report_bandwidth_for_stream(call, ts, LinphoneStreamTypeText);
4536
4537 ms_message( "Bandwidth usage for call [%p]:\n"
4538 "\tRTP audio=[d=%5.1f,u=%5.1f], video=[d=%5.1f,u=%5.1f], text=[d=%5.1f,u=%5.1f] kbits/sec\n"
4539 "\tRTCP audio=[d=%5.1f,u=%5.1f], video=[d=%5.1f,u=%5.1f], text=[d=%5.1f,u=%5.1f] kbits/sec",
4540 call,
4541 call->audio_stats->download_bandwidth,
4542 call->audio_stats->upload_bandwidth,
4543 call->video_stats->download_bandwidth,
4544 call->video_stats->upload_bandwidth,
4545 call->text_stats->download_bandwidth,
4546 call->text_stats->upload_bandwidth,
4547 call->audio_stats->rtcp_download_bandwidth,
4548 call->audio_stats->rtcp_upload_bandwidth,
4549 call->video_stats->rtcp_download_bandwidth,
4550 call->video_stats->rtcp_upload_bandwidth,
4551 call->text_stats->rtcp_download_bandwidth,
4552 call->text_stats->rtcp_upload_bandwidth
4553 );
4554 }
4555
4556 static void linphone_call_lost(LinphoneCall *call){
4557 LinphoneCore *lc = call->core;
4558 char *temp = NULL;
4559 char *from = NULL;
4560
4561 from = linphone_call_get_remote_address_as_string(call);
4562 temp = ms_strdup_printf("Media connectivity with %s is lost, call is going to be closed.", from ? from : "?");
4563 if (from) ms_free(from);
4564 ms_message("LinphoneCall [%p]: %s", call, temp);
4565 linphone_core_notify_display_warning(lc, temp);
4566 call->non_op_error = TRUE;
4567 linphone_error_info_set(call->ei,NULL, LinphoneReasonIOError, 503, "Media lost", NULL);
4568 linphone_call_terminate(call);
4569 linphone_core_play_named_tone(lc, LinphoneToneCallLost);
4570 ms_free(temp);
4571 }
4572
4573 static void linphone_call_on_ice_gathering_finished(LinphoneCall *call){
4574 int ping_time;
4575 const SalMediaDescription *rmd = sal_call_get_remote_media_description(call->op);
4576 if (rmd){
4577 linphone_call_clear_unused_ice_candidates(call, rmd);
4578 }
4579 ice_session_compute_candidates_foundations(call->ice_session);
4580 ice_session_eliminate_redundant_candidates(call->ice_session);
4581 ice_session_choose_default_candidates(call->ice_session);
4582 ping_time = ice_session_average_gathering_round_trip_time(call->ice_session);
4583 if (ping_time >=0) {
4584 call->ping_time=ping_time;
4585 }
4586 }
4587
4588 static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){
4589 OrtpEventType evt=ortp_event_get_type(ev);
4590 OrtpEventData *evd=ortp_event_get_data(ev);
4591
4592 if (evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) {
4593 switch (ice_session_state(call->ice_session)) {
4594 case IS_Completed:
4595 case IS_Failed:
4596 /* At least one ICE session has succeeded, so perform a call update. */
4597 if (ice_session_has_completed_check_list(call->ice_session) == TRUE) {
4598 const LinphoneCallParams *current_param = linphone_call_get_current_params(call);
4599 if (ice_session_role(call->ice_session) == IR_Controlling && current_param->update_call_when_ice_completed ) {
4600 LinphoneCallParams *params = linphone_core_create_call_params(call->core, call);
4601 params->internal_call_update = TRUE;
4602 linphone_call_update(call, params);
4603 linphone_call_params_unref(params);
4604 }
4605 start_dtls_on_all_streams(call);
4606 }
4607 break;
4608 default:
4609 break;
4610 }
4611 linphone_call_update_ice_state_in_call_stats(call);
4612 } else if (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) {
4613 if (evd->info.ice_processing_successful==FALSE) {
4614 ms_warning("No STUN answer from [%s], continuing without STUN",linphone_core_get_stun_server(call->core));
4615 }
4616 linphone_call_on_ice_gathering_finished(call);
4617 switch (call->state) {
4618 case LinphoneCallUpdating:
4619 linphone_call_start_update(call);
4620 break;
4621 case LinphoneCallUpdatedByRemote:
4622 linphone_call_start_accept_update(call, call->prevstate,linphone_call_state_to_string(call->prevstate));
4623 break;
4624 case LinphoneCallOutgoingInit:
4625 linphone_call_stop_media_streams_for_ice_gathering(call);
4626 linphone_call_proceed_with_invite_if_ready(call, NULL);
4627 break;
4628 case LinphoneCallIdle:
4629 linphone_call_stop_media_streams_for_ice_gathering(call);
4630 linphone_call_update_local_media_description_from_ice_or_upnp(call);
4631 sal_call_set_local_media_description(call->op,call->localdesc);
4632 linphone_core_notify_incoming_call(call->core, call);
4633 break;
4634 default:
4635 break;
4636 }
4637 } else if (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) {
4638 if (call->state==LinphoneCallUpdatedByRemote){
4639 linphone_call_start_accept_update(call, call->prevstate, linphone_call_state_to_string(call->prevstate));
4640 linphone_call_update_ice_state_in_call_stats(call);
4641 }
4642 } else if (evt == ORTP_EVENT_ICE_RESTART_NEEDED) {
4643 ice_session_restart(call->ice_session, IR_Controlling);
4644 linphone_call_update(call, call->current_params);
4645 }
4646 }
4647
4648 /*do not change the prototype of this function, it is also used internally in linphone-daemon.*/
4649 void linphone_call_stats_fill(LinphoneCallStats *stats, MediaStream *ms, OrtpEvent *ev){
4650 OrtpEventType evt=ortp_event_get_type(ev);
4651 OrtpEventData *evd=ortp_event_get_data(ev);
4652
4653 if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) {
4654 stats->round_trip_delay = rtp_session_get_round_trip_propagation(ms->sessions.rtp_session);
4655 if(stats->received_rtcp != NULL)
4656 freemsg(stats->received_rtcp);
4657 stats->received_rtcp = evd->packet;
4658 stats->rtcp_received_via_mux = evd->info.socket_type == OrtpRTPSocket;
4659 evd->packet = NULL;
4660 stats->updated = LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE;
4661 update_local_stats(stats,ms);
4662 } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) {
4663 memcpy(&stats->jitter_stats, rtp_session_get_jitter_stats(ms->sessions.rtp_session), sizeof(jitter_stats_t));
4664 if (stats->sent_rtcp != NULL)
4665 freemsg(stats->sent_rtcp);
4666 stats->sent_rtcp = evd->packet;
4667 evd->packet = NULL;
4668 stats->updated = LINPHONE_CALL_STATS_SENT_RTCP_UPDATE;
4669 update_local_stats(stats,ms);
4670 }
4671 }
4672
4673 void linphone_call_stats_uninit(LinphoneCallStats *stats){
4674 if (stats->received_rtcp) {
4675 freemsg(stats->received_rtcp);
4676 stats->received_rtcp=NULL;
4677 }
4678 if (stats->sent_rtcp){
4679 freemsg(stats->sent_rtcp);
4680 stats->sent_rtcp=NULL;
4681 }
4682 }
4683
4684 void linphone_call_notify_stats_updated_with_stream_index(LinphoneCall *call, int stream_index){
4685 LinphoneCallStats *stats = NULL;
4686 if (stream_index == call->main_audio_stream_index) {
4687 stats = call->audio_stats;
4688 } else if (stream_index == call->main_video_stream_index) {
4689 stats = call->video_stats;
4690 } else {
4691 stats = call->text_stats;
4692 }
4693 if (stats->updated){
4694 switch(stats->updated) {
4695 case LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE:
4696 case LINPHONE_CALL_STATS_SENT_RTCP_UPDATE:
4697 linphone_reporting_on_rtcp_update(call, stream_index == call->main_audio_stream_index ? SalAudio : stream_index == call->main_video_stream_index ? SalVideo : SalText);
4698 break;
4699 default:
4700 break;
4701 }
4702 linphone_call_notify_stats_updated(call, stats);
4703 stats->updated = 0;
4704 }
4705 }
4706
4707 static MediaStream * linphone_call_get_media_stream(LinphoneCall *call, int stream_index){
4708 if (stream_index == call->main_audio_stream_index)
4709 return (MediaStream*)call->audiostream;
4710 if (stream_index == call->main_video_stream_index)
4711 return (MediaStream*)call->videostream;
4712 if (stream_index == call->main_text_stream_index)
4713 return (MediaStream*)call->textstream;
4714 ms_error("linphone_call_get_media_stream(): no stream index %i", stream_index);
4715 return NULL;
4716 }
4717
4718 static OrtpEvQueue *linphone_call_get_event_queue(LinphoneCall *call, int stream_index){
4719 if (stream_index == call->main_audio_stream_index)
4720 return call->audiostream_app_evq;
4721 if (stream_index == call->main_video_stream_index)
4722 return call->videostream_app_evq;
4723 if (stream_index == call->main_text_stream_index)
4724 return call->textstream_app_evq;
4725 ms_error("linphone_call_get_event_queue(): no stream index %i", stream_index);
4726 return NULL;
4727 }
4728
4729 void linphone_call_handle_stream_events(LinphoneCall *call, int stream_index){
4730 MediaStream *ms = stream_index == call->main_audio_stream_index ? (MediaStream *)call->audiostream : (stream_index == call->main_video_stream_index ? (MediaStream *)call->videostream : (MediaStream *)call->textstream);
4731 OrtpEvQueue *evq;
4732 OrtpEvent *ev;
4733
4734 if (ms){
4735 /* Ensure there is no dangling ICE check list. */
4736 if (call->ice_session == NULL) {
4737 media_stream_set_ice_check_list(ms, NULL);
4738 }
4739
4740 switch(ms->type){
4741 case MSAudio:
4742 audio_stream_iterate((AudioStream*)ms);
4743 break;
4744 case MSVideo:
4745 #ifdef VIDEO_ENABLED
4746 video_stream_iterate((VideoStream*)ms);
4747 #endif
4748 break;
4749 case MSText:
4750 text_stream_iterate((TextStream*)ms);
4751 break;
4752 default:
4753 ms_error("linphone_call_handle_stream_events(): unsupported stream type.");
4754 return;
4755 break;
4756 }
4757 }
4758 /*yes the event queue has to be taken at each iteration, because ice events may perform operations re-creating the streams*/
4759 while((evq = linphone_call_get_event_queue(call, stream_index)) != NULL && NULL != (ev=ortp_ev_queue_get(evq))){
4760 OrtpEventType evt=ortp_event_get_type(ev);
4761 OrtpEventData *evd=ortp_event_get_data(ev);
4762 int stats_index;
4763 LinphoneCallStats *stats = NULL;
4764
4765 if (stream_index == call->main_audio_stream_index) {
4766 stats_index = LINPHONE_CALL_STATS_AUDIO;
4767 stats = call->audio_stats;
4768 } else if (stream_index == call->main_video_stream_index) {
4769 stats_index = LINPHONE_CALL_STATS_VIDEO;
4770 stats = call->video_stats;
4771 } else {
4772 stats_index = LINPHONE_CALL_STATS_TEXT;
4773 stats = call->text_stats;
4774 }
4775
4776 /*and yes the MediaStream must be taken at each iteration, because it may have changed due to the handling of events
4777 * in this loop*/
4778 ms = linphone_call_get_media_stream(call, stream_index);
4779
4780 if (ms) linphone_call_stats_fill(stats,ms,ev);
4781 linphone_call_notify_stats_updated_with_stream_index(call,stats_index);
4782
4783 if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){
4784 if (stream_index == call->main_audio_stream_index)
4785 linphone_call_audiostream_encryption_changed(call, evd->info.zrtp_stream_encrypted);
4786 else if (stream_index == call->main_video_stream_index) {
4787 propagate_encryption_changed(call);
4788 }
4789 } else if (evt == ORTP_EVENT_ZRTP_SAS_READY) {
4790 if (stream_index == call->main_audio_stream_index)
4791 linphone_call_audiostream_auth_token_ready(call, evd->info.zrtp_info.sas, evd->info.zrtp_info.verified);
4792 } else if (evt == ORTP_EVENT_DTLS_ENCRYPTION_CHANGED) {
4793 if (stream_index == call->main_audio_stream_index)
4794 linphone_call_audiostream_encryption_changed(call, evd->info.dtls_stream_encrypted);
4795 else if (stream_index == call->main_video_stream_index)
4796 propagate_encryption_changed(call);
4797 }else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)
4798 || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) {
4799 if (ms) handle_ice_events(call, ev);
4800 } else if (evt==ORTP_EVENT_TELEPHONE_EVENT){
4801 linphone_core_dtmf_received(call,evd->info.telephone_event);
4802 } else if (evt == ORTP_EVENT_NEW_VIDEO_BANDWIDTH_ESTIMATION_AVAILABLE) {
4803 ms_message("Video bandwidth estimation is %i kbit/s", (int)evd->info.video_bandwidth_available / 1000);
4804 //TODO
4805 }
4806 ortp_event_destroy(ev);
4807 }
4808 }
4809
4810 void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapsed){
4811 int disconnect_timeout = linphone_core_get_nortp_timeout(call->core);
4812 bool_t disconnected=FALSE;
4813
4814 switch (call->state) {
4815 case LinphoneCallStreamsRunning:
4816 case LinphoneCallOutgoingEarlyMedia:
4817 case LinphoneCallIncomingEarlyMedia:
4818 case LinphoneCallPausedByRemote:
4819 case LinphoneCallPaused:
4820 if (one_second_elapsed){
4821 float audio_load=0, video_load=0, text_load=0;
4822 if (call->audiostream != NULL) {
4823 if (call->audiostream->ms.sessions.ticker)
4824 audio_load = ms_ticker_get_average_load(call->audiostream->ms.sessions.ticker);
4825 }
4826 if (call->videostream != NULL) {
4827 if (call->videostream->ms.sessions.ticker)
4828 video_load = ms_ticker_get_average_load(call->videostream->ms.sessions.ticker);
4829 }
4830 if (call->textstream != NULL) {
4831 if (call->textstream->ms.sessions.ticker)
4832 text_load = ms_ticker_get_average_load(call->textstream->ms.sessions.ticker);
4833 }
4834 report_bandwidth(call, (MediaStream*)call->audiostream, (MediaStream*)call->videostream, (MediaStream*)call->textstream);
4835 ms_message("Thread processing load: audio=%f\tvideo=%f\ttext=%f", audio_load, video_load, text_load);
4836 }
4837 break;
4838 default:
4839 /*no stats for other states*/
4840 break;
4841 }
4842
4843 #ifdef BUILD_UPNP
4844 linphone_upnp_call_process(call);
4845 #endif //BUILD_UPNP
4846
4847 linphone_call_handle_stream_events(call, call->main_audio_stream_index);
4848 linphone_call_handle_stream_events(call, call->main_video_stream_index);
4849 linphone_call_handle_stream_events(call, call->main_text_stream_index);
4850 if ((call->state == LinphoneCallStreamsRunning ||
4851 call->state == LinphoneCallPausedByRemote) && one_second_elapsed && call->audiostream!=NULL
4852 && call->audiostream->ms.state==MSStreamStarted && disconnect_timeout>0 ) {
4853 disconnected=!audio_stream_alive(call->audiostream,disconnect_timeout);
4854 }
4855 if (disconnected) linphone_call_lost(call);
4856 }
4857
4858 void linphone_call_log_completed(LinphoneCall *call){
4859 LinphoneCore *lc=call->core;
4860
4861 call->log->duration= _linphone_call_compute_duration(call); /*store duration since connected*/
4862 call->log->error_info = linphone_error_info_ref((LinphoneErrorInfo*)linphone_call_get_error_info(call));
4863
4864 if (call->log->status==LinphoneCallMissed){
4865 char *info;
4866 lc->missed_calls++;
4867 info=ortp_strdup_printf(ngettext("You have missed %i call.",
4868 "You have missed %i calls.", lc->missed_calls),
4869 lc->missed_calls);
4870 linphone_core_notify_display_status(lc,info);
4871 ms_free(info);
4872 }
4873 linphone_core_report_call_log(lc, call->log);
4874 }
4875
4876 LinphoneCallState linphone_call_get_transfer_state(LinphoneCall *call) {
4877 return call->transfer_state;
4878 }
4879
4880 void linphone_call_set_transfer_state(LinphoneCall* call, LinphoneCallState state) {
4881 if (state != call->transfer_state) {
4882 ms_message("Transfer state for call [%p] changed from [%s] to [%s]",call
4883 ,linphone_call_state_to_string(call->transfer_state)
4884 ,linphone_call_state_to_string(state));
4885 call->transfer_state = state;
4886 linphone_call_notify_transfer_state_changed(call, state);
4887 }
4888 }
4889
4890 bool_t linphone_call_is_in_conference(const LinphoneCall *call) {
4891 return call->params->in_conference;
4892 }
4893
4894 LinphoneConference *linphone_call_get_conference(const LinphoneCall *call) {
4895 return call->conf_ref;
4896 }
4897
4898 void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, float* cy) {
4899 VideoStream* vstream = call->videostream;
4900 if (vstream && vstream->output) {
4901 float zoom[3];
4902 float halfsize;
4903
4904 if (zoom_factor < 1)
4905 zoom_factor = 1;
4906 halfsize = 0.5f * 1.0f / zoom_factor;
4907
4908 if ((*cx - halfsize) < 0)
4909 *cx = 0 + halfsize;
4910 if ((*cx + halfsize) > 1)
4911 *cx = 1 - halfsize;
4912 if ((*cy - halfsize) < 0)
4913 *cy = 0 + halfsize;
4914 if ((*cy + halfsize) > 1)
4915 *cy = 1 - halfsize;
4916
4917 zoom[0] = zoom_factor;
4918 zoom[1] = *cx;
4919 zoom[2] = *cy;
4920 ms_filter_call_method(vstream->output, MS_VIDEO_DISPLAY_ZOOM, &zoom);
4921 }else ms_warning("Could not apply zoom: video output wasn't activated.");
4922 }
4923
4924 static LinphoneAddress *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , LinphoneProxyConfig *dest_proxy){
4925 LinphoneAddress *ctt=NULL;
4926 LinphoneAddress *ret=NULL;
4927 //const char *localip=call->localip;
4928
4929 /* first use user's supplied ip address if asked*/
4930 if (linphone_core_get_firewall_policy(lc)==LinphonePolicyUseNatAddress){
4931 ctt=linphone_core_get_primary_contact_parsed(lc);
4932 linphone_address_set_domain(ctt,linphone_core_get_nat_address_resolved(lc));
4933 ret=ctt;
4934 } else if (call->op && sal_op_get_contact_address(call->op)!=NULL){
4935 /* if already choosed, don't change it */
4936 return NULL;
4937 } else if (call->ping_op && sal_op_get_contact_address(call->ping_op)) {
4938 /* if the ping OPTIONS request succeeded use the contact guessed from the
4939 received, rport*/
4940 ms_message("Contact has been fixed using OPTIONS"/* to %s",guessed*/);
4941 ret=linphone_address_clone(sal_op_get_contact_address(call->ping_op));;
4942 } else if (dest_proxy && dest_proxy->op && sal_op_get_contact_address(dest_proxy->op)){
4943 /*if using a proxy, use the contact address as guessed with the REGISTERs*/
4944 ms_message("Contact has been fixed using proxy" /*to %s",fixed_contact*/);
4945 ret=linphone_address_clone(sal_op_get_contact_address(dest_proxy->op));
4946 } else {
4947 ctt=linphone_core_get_primary_contact_parsed(lc);
4948 if (ctt!=NULL){
4949 /*otherwise use supplied localip*/
4950 linphone_address_set_domain(ctt,NULL/*localip*/);
4951 linphone_address_set_port(ctt,-1/*linphone_core_get_sip_port(lc)*/);
4952 ms_message("Contact has not been fixed stack will do"/* to %s",ret*/);
4953 ret=ctt;
4954 }
4955 }
4956 return ret;
4957 }
4958
4959 void linphone_call_set_contact_op(LinphoneCall* call) {
4960 LinphoneAddress *contact;
4961 contact=get_fixed_contact(call->core,call,call->dest_proxy);
4962 if (contact){
4963 SalTransport tport=sal_address_get_transport((SalAddress*)contact);
4964 sal_address_clean((SalAddress*)contact); /* clean out contact_params that come from proxy config*/
4965 sal_address_set_transport((SalAddress*)contact,tport);
4966 sal_op_set_contact_address(call->op, contact);
4967 linphone_address_unref(contact);
4968 }
4969 }
4970
4971 LinphonePlayer *linphone_call_get_player(LinphoneCall *call){
4972 if (call->player==NULL)
4973 call->player=linphone_call_build_player(call);
4974 return call->player;
4975 }
4976
4977
4978 void linphone_call_set_params(LinphoneCall *call, const LinphoneCallParams *params){
4979 if ( call->state == LinphoneCallOutgoingInit || call->state == LinphoneCallIncomingReceived){
4980 _linphone_call_set_new_params(call, params);
4981 }
4982 else {
4983 ms_error("linphone_call_set_params() invalid state %s to call this function", linphone_call_state_to_string(call->state));
4984 }
4985 }
4986
4987
4988 void _linphone_call_set_new_params(LinphoneCall *call, const LinphoneCallParams *params){
4989 LinphoneCallParams *cp=NULL;
4990 if (params) cp=linphone_call_params_copy(params);
4991 if (call->params) linphone_call_params_unref(call->params);
4992 call->params=cp;
4993 }
4994
4995 const LinphoneCallParams * linphone_call_get_params(LinphoneCall *call){
4996 return call->params;
4997 }
4998
4999
5000 static int send_dtmf_handler(void *data, unsigned int revents){
5001 LinphoneCall *call = (LinphoneCall*)data;
5002 /*By default we send DTMF RFC2833 if we do not have enabled SIP_INFO but we can also send RFC2833 and SIP_INFO*/
5003 if (linphone_core_get_use_rfc2833_for_dtmf(call->core)!=0 || linphone_core_get_use_info_for_dtmf(call->core)==0)
5004 {
5005 /* In Band DTMF */
5006 if (call->audiostream!=NULL){
5007 audio_stream_send_dtmf(call->audiostream,*call->dtmf_sequence);
5008 }
5009 else
5010 {
5011 ms_error("Cannot send RFC2833 DTMF when we are not in communication.");
5012 return FALSE;
5013 }
5014 }
5015 if (linphone_core_get_use_info_for_dtmf(call->core)!=0){
5016 /* Out of Band DTMF (use INFO method) */
5017 sal_call_send_dtmf(call->op,*call->dtmf_sequence);
5018 }
5019
5020 /*this check is needed because linphone_call_send_dtmf does not set the timer since its a single character*/
5021 if (call->dtmfs_timer!=NULL) {
5022 memmove(call->dtmf_sequence, call->dtmf_sequence+1, strlen(call->dtmf_sequence));
5023 }
5024 /* continue only if the dtmf sequence is not empty*/
5025 if (call->dtmf_sequence!=NULL&&*call->dtmf_sequence!='\0') {
5026 return TRUE;
5027 } else {
5028 linphone_call_cancel_dtmfs(call);
5029 return FALSE;
5030 }
5031 }
5032
5033 LinphoneStatus linphone_call_send_dtmf(LinphoneCall *call, char dtmf) {
5034 if (call==NULL){
5035 ms_warning("linphone_call_send_dtmf(): invalid call, canceling DTMF.");
5036 return -1;
5037 }
5038 call->dtmf_sequence = &dtmf;
5039 send_dtmf_handler(call,0);
5040 call->dtmf_sequence = NULL;
5041 return 0;
5042 }
5043
5044 LinphoneStatus linphone_call_send_dtmfs(LinphoneCall *call,const char *dtmfs) {
5045 if (call==NULL){
5046 ms_warning("linphone_call_send_dtmfs(): invalid call, canceling DTMF sequence.");
5047 return -1;
5048 }
5049 if (call->dtmfs_timer!=NULL){
5050 ms_warning("linphone_call_send_dtmfs(): a DTMF sequence is already in place, canceling DTMF sequence.");
5051 return -2;
5052 }
5053 if (dtmfs != NULL) {
5054 int delay_ms = lp_config_get_int(call->core->config,"net","dtmf_delay_ms",200);
5055 call->dtmf_sequence = ms_strdup(dtmfs);
5056 call->dtmfs_timer = sal_create_timer(call->core->sal, send_dtmf_handler, call, delay_ms, "DTMF sequence timer");
5057 }
5058 return 0;
5059 }
5060
5061 void linphone_call_cancel_dtmfs(LinphoneCall *call) {
5062 /*nothing to do*/
5063 if (!call || !call->dtmfs_timer) return;
5064
5065 sal_cancel_timer(call->core->sal, call->dtmfs_timer);
5066 belle_sip_object_unref(call->dtmfs_timer);
5067 call->dtmfs_timer = NULL;
5068 if (call->dtmf_sequence != NULL) {
5069 ms_free(call->dtmf_sequence);
5070 call->dtmf_sequence = NULL;
5071 }
5072 }
5073
5074 void * linphone_call_get_native_video_window_id(const LinphoneCall *call) {
5075 if (call->video_window_id) {
5076 /* The video id was previously set by the app. */
5077 return call->video_window_id;
5078 }
5079 #ifdef VIDEO_ENABLED
5080 else if (call->videostream) {
5081 /* It was not set but we want to get the one automatically created by mediastreamer2 (desktop versions only). */
5082 return video_stream_get_native_window_id(call->videostream);
5083 }
5084 #endif
5085 return 0;
5086 }
5087
5088 void linphone_call_set_native_video_window_id(LinphoneCall *call, void *id) {
5089 call->video_window_id = id;
5090 #ifdef VIDEO_ENABLED
5091 if (call->videostream) {
5092 video_stream_set_native_window_id(call->videostream, id);
5093 }
5094 #endif
5095 }
5096
5097 MSWebCam *linphone_call_get_video_device(const LinphoneCall *call) {
5098 LinphoneCallState state = linphone_call_get_state(call);
5099 bool_t paused = (state == LinphoneCallPausing) || (state == LinphoneCallPaused);
5100 if (paused || call->all_muted || (call->camera_enabled == FALSE))
5101 return get_nowebcam_device(call->core->factory);
5102 else
5103 return call->core->video_conf.device;
5104 }
5105
5106 void linphone_call_set_audio_route(LinphoneCall *call, LinphoneAudioRoute route) {
5107 if (call != NULL && call->audiostream != NULL){
5108 audio_stream_set_audio_route(call->audiostream, (MSAudioRoute) route);
5109 }
5110 }
5111
5112 LinphoneChatRoom * linphone_call_get_chat_room(LinphoneCall *call) {
5113 if (!call->chat_room){
5114 if (call->state != LinphoneCallReleased && call->state != LinphoneCallEnd){
5115 call->chat_room = _linphone_core_create_chat_room_from_call(call);
5116 }
5117 }
5118 return call->chat_room;
5119 }
5120
5121 int linphone_call_get_stream_count(LinphoneCall *call) {
5122 // Revisit when multiple media streams will be implemented
5123 #ifdef VIDEO_ENABLED
5124 if (linphone_call_params_realtime_text_enabled(linphone_call_get_current_params(call))) {
5125 return 3;
5126 }
5127 return 2;
5128 #else
5129 if (linphone_call_params_realtime_text_enabled(linphone_call_get_current_params(call))) {
5130 return 2;
5131 }
5132 return 1;
5133 #endif
5134 }
5135
5136 MSFormatType linphone_call_get_stream_type(LinphoneCall *call, int stream_index) {
5137 // Revisit when multiple media streams will be implemented
5138 if (stream_index == call->main_video_stream_index) {
5139 return MSVideo;
5140 } else if (stream_index == call->main_text_stream_index) {
5141 return MSText;
5142 } else if (stream_index == call->main_audio_stream_index){
5143 return MSAudio;
5144 }
5145 return MSUnknownMedia;
5146 }
5147
5148 RtpTransport* linphone_call_get_meta_rtp_transport(LinphoneCall *call, int stream_index) {
5149 RtpTransport *meta_rtp;
5150 RtpTransport *meta_rtcp;
5151
5152 if (!call || stream_index < 0 || stream_index >= linphone_call_get_stream_count(call)) {
5153 return NULL;
5154 }
5155
5156 rtp_session_get_transports(call->sessions[stream_index].rtp_session, &meta_rtp, &meta_rtcp);
5157 return meta_rtp;
5158 }
5159
5160 RtpTransport* linphone_call_get_meta_rtcp_transport(LinphoneCall *call, int stream_index) {
5161 RtpTransport *meta_rtp;
5162 RtpTransport *meta_rtcp;
5163
5164 if (!call || stream_index < 0 || stream_index >= linphone_call_get_stream_count(call)) {
5165 return NULL;
5166 }
5167
5168 rtp_session_get_transports(call->sessions[stream_index].rtp_session, &meta_rtp, &meta_rtcp);
5169 return meta_rtcp;
5170 }
5171
5172 LinphoneStatus linphone_call_pause(LinphoneCall *call) {
5173 int err = _linphone_call_pause(call);
5174 if (err == 0) call->paused_by_app = TRUE;
5175 return err;
5176 }
5177
5178 /* Internal version that does not play tone indication*/
5179 int _linphone_call_pause(LinphoneCall *call) {
5180 LinphoneCore *lc;
5181 const char *subject = NULL;
5182
5183 if ((call->state != LinphoneCallStreamsRunning) && (call->state != LinphoneCallPausedByRemote)) {
5184 ms_warning("Cannot pause this call, it is not active.");
5185 return -1;
5186 }
5187 if (sal_media_description_has_dir(call->resultdesc, SalStreamSendRecv)) {
5188 subject = "Call on hold";
5189 } else if (sal_media_description_has_dir(call->resultdesc, SalStreamRecvOnly)) {
5190 subject = "Call on hold for me too";
5191 } else {
5192 ms_error("No reason to pause this call, it is already paused or inactive.");
5193 return -1;
5194 }
5195
5196 lc = linphone_call_get_core(call);
5197 call->broken = FALSE;
5198 linphone_call_set_state(call, LinphoneCallPausing, "Pausing call");
5199 linphone_call_make_local_media_description(call);
5200 #ifdef BUILD_UPNP
5201 if (call->upnp_session != NULL) {
5202 linphone_call_update_local_media_description_from_upnp(call->localdesc, call->upnp_session);
5203 }
5204 #endif // BUILD_UPNP
5205 sal_call_set_local_media_description(call->op, call->localdesc);
5206 if (sal_call_update(call->op, subject, FALSE) != 0) {
5207 linphone_core_notify_display_warning(lc, _("Could not pause the call"));
5208 }
5209 lc->current_call = NULL;
5210 linphone_core_notify_display_status(lc, _("Pausing the current call..."));
5211 if (call->audiostream || call->videostream || call->textstream)
5212 linphone_call_stop_media_streams(call);
5213 call->paused_by_app = FALSE;
5214 return 0;
5215 }
5216
5217 LinphoneStatus linphone_call_resume(LinphoneCall *call) {
5218 LinphoneCore *lc;
5219 const char *subject = "Call resuming";
5220 char *remote_address;
5221 char *display_status;
5222
5223 if (call->state != LinphoneCallPaused) {
5224 ms_warning("we cannot resume a call that has not been established and paused before");
5225 return -1;
5226 }
5227 lc = linphone_call_get_core(call);
5228 if (call->params->in_conference == FALSE) {
5229 if (linphone_core_sound_resources_locked(lc)) {
5230 ms_warning("Cannot resume call %p because another call is locking the sound resources.", call);
5231 return -1;
5232 }
5233 linphone_core_preempt_sound_resources(lc);
5234 ms_message("Resuming call %p", call);
5235 }
5236
5237 call->was_automatically_paused = FALSE;
5238 call->broken = FALSE;
5239
5240 /* Stop playing music immediately. If remote side is a conference it
5241 prevents the participants to hear it while the 200OK comes back. */
5242 if (call->audiostream) audio_stream_play(call->audiostream, NULL);
5243
5244 linphone_call_make_local_media_description(call);
5245 #ifdef BUILD_UPNP
5246 if (call->upnp_session != NULL) {
5247 linphone_call_update_local_media_description_from_upnp(call->localdesc, call->upnp_session);
5248 }
5249 #endif // BUILD_UPNP
5250 if (!lc->sip_conf.sdp_200_ack) {
5251 sal_call_set_local_media_description(call->op, call->localdesc);
5252 } else {
5253 sal_call_set_local_media_description(call->op, NULL);
5254 }
5255 sal_media_description_set_dir(call->localdesc, SalStreamSendRecv);
5256 if (call->params->in_conference && !call->current_params->in_conference) subject = "Conference";
5257 if (sal_call_update(call->op, subject, FALSE) != 0) {
5258 return -1;
5259 }
5260 linphone_call_set_state(call, LinphoneCallResuming,"Resuming");
5261 if (call->params->in_conference == FALSE)
5262 lc->current_call = call;
5263 remote_address = linphone_call_get_remote_address_as_string(call);
5264 display_status = ms_strdup_printf("Resuming the call with with %s", remote_address);
5265 ms_free(remote_address);
5266 linphone_core_notify_display_status(lc, display_status);
5267 ms_free(display_status);
5268
5269 if (lc->sip_conf.sdp_200_ack) {
5270 /* We are NOT offering, set local media description after sending the call so that we are ready to
5271 process the remote offer when it will arrive. */
5272 sal_call_set_local_media_description(call->op, call->localdesc);
5273 }
5274 return 0;
5275 }
5276
5277 static void terminate_call(LinphoneCall *call) {
5278 LinphoneCore *lc = linphone_call_get_core(call);
5279 const bctbx_list_t *calls = linphone_core_get_calls(lc);
5280 bool_t stop_ringing = TRUE;
5281
5282 if ((call->state == LinphoneCallIncomingReceived) && (linphone_error_info_get_reason(call->ei) != LinphoneReasonNotAnswered)){
5283 linphone_error_info_set_reason(call->ei, LinphoneReasonDeclined);
5284 call->non_op_error = TRUE;
5285 }
5286
5287 /* Stop ringing */
5288 bool_t ring_during_early_media = linphone_core_get_ring_during_incoming_early_media(lc);
5289 while(calls) {
5290 if (((LinphoneCall *)calls->data)->state == LinphoneCallIncomingReceived || (ring_during_early_media && ((LinphoneCall *)calls->data)->state == LinphoneCallIncomingEarlyMedia)) {
5291 stop_ringing = FALSE;
5292 break;
5293 }
5294 calls = calls->next;
5295 }
5296 if(stop_ringing) {
5297 linphone_core_stop_ringing(lc);
5298 }
5299 linphone_call_stop_media_streams(call);
5300
5301 #ifdef BUILD_UPNP
5302 linphone_call_delete_upnp_session(call);
5303 #endif // BUILD_UPNP
5304
5305 linphone_core_notify_display_status(lc, _("Call ended") );
5306 linphone_call_set_state(call, LinphoneCallEnd, "Call terminated");
5307 }
5308
5309 LinphoneStatus linphone_call_terminate(LinphoneCall *call) {
5310 return linphone_call_terminate_with_error_info(call, NULL);
5311 }
5312
5313
5314 LinphoneStatus linphone_call_terminate_with_error_info(LinphoneCall *call , const LinphoneErrorInfo *ei){
5315 SalErrorInfo sei={0};
5316 LinphoneErrorInfo* p_ei = (LinphoneErrorInfo*) ei;
5317
5318 ms_message("Terminate call [%p] which is currently in state %s", call, linphone_call_state_to_string(call->state));
5319 switch (call->state) {
5320 case LinphoneCallReleased:
5321 case LinphoneCallEnd:
5322 case LinphoneCallError:
5323 ms_warning("No need to terminate a call [%p] in state [%s]", call, linphone_call_state_to_string(call->state));
5324 return -1;
5325 case LinphoneCallIncomingReceived:
5326 case LinphoneCallIncomingEarlyMedia:
5327 return linphone_call_decline_with_error_info(call, p_ei);
5328 case LinphoneCallOutgoingInit:
5329 /* In state OutgoingInit, op has to be destroyed */
5330 sal_op_release(call->op);
5331 call->op = NULL;
5332 break;
5333 default:
5334
5335 if (ei == NULL){
5336 sal_call_terminate(call->op);
5337 }
5338 else{
5339 linphone_error_info_to_sal(ei, &sei);
5340 sal_call_terminate_with_error(call->op, &sei);
5341 sal_error_info_reset(&sei);
5342 }
5343 break;
5344 }
5345
5346 terminate_call(call);
5347 return 0;
5348
5349 }
5350
5351 LinphoneStatus linphone_call_redirect(LinphoneCall *call, const char *redirect_uri) {
5352 char *real_url = NULL;
5353 LinphoneCore *lc;
5354 LinphoneAddress *real_parsed_url;
5355 SalErrorInfo sei = {0};
5356
5357 if (call->state != LinphoneCallIncomingReceived) {
5358 ms_error("Bad state for call redirection.");
5359 return -1;
5360 }
5361
5362 lc = linphone_call_get_core(call);
5363 real_parsed_url = linphone_core_interpret_url(lc, redirect_uri);
5364 if (!real_parsed_url) {
5365 /* Bad url */
5366 ms_error("Bad redirect URI: %s", redirect_uri ? redirect_uri : "NULL");
5367 return -1;
5368 }
5369
5370 real_url = linphone_address_as_string(real_parsed_url);
5371 sal_error_info_set(&sei,SalReasonRedirect, "SIP", 0, NULL, NULL);
5372 sal_call_decline_with_error_info(call->op, &sei, real_url);
5373 ms_free(real_url);
5374 linphone_error_info_set(call->ei, NULL, LinphoneReasonMovedPermanently, 302, "Call redirected", NULL);
5375 call->non_op_error = TRUE;
5376 terminate_call(call);
5377 linphone_address_unref(real_parsed_url);
5378 sal_error_info_reset(&sei);
5379 return 0;
5380 }
5381
5382 LinphoneStatus linphone_call_decline(LinphoneCall * call, LinphoneReason reason) {
5383 LinphoneStatus status;
5384 LinphoneErrorInfo *ei = linphone_error_info_new();
5385 linphone_error_info_set(ei, "SIP", reason,linphone_reason_to_error_code(reason), NULL, NULL);
5386 status = linphone_call_decline_with_error_info(call, ei);
5387 linphone_error_info_unref(ei);
5388 return status;
5389 }
5390
5391
5392 LinphoneStatus linphone_call_decline_with_error_info(LinphoneCall * call, const LinphoneErrorInfo *ei) {
5393 SalErrorInfo sei = {0};
5394 SalErrorInfo sub_sei = {0};
5395
5396 sei.sub_sei = &sub_sei;
5397
5398 if ((call->state != LinphoneCallIncomingReceived) && (call->state != LinphoneCallIncomingEarlyMedia)) {
5399 ms_error("Cannot decline a call that is in state %s", linphone_call_state_to_string(call->state));
5400 return -1;
5401 }
5402 if (ei) {
5403 linphone_error_info_to_sal(ei, &sei);
5404 sal_call_decline_with_error_info(call->op, &sei , NULL);
5405 }else{
5406 sal_call_decline(call->op, SalReasonDeclined, NULL);
5407 }
5408 sal_error_info_reset(&sei);
5409 sal_error_info_reset(&sub_sei);
5410 terminate_call(call);
5411 return 0;
5412 }
5413
5414 LinphoneStatus linphone_call_accept(LinphoneCall *call) {
5415 return linphone_call_accept_with_params(call, NULL);
5416 }
5417
5418 LinphoneStatus linphone_call_accept_with_params(LinphoneCall *call, const LinphoneCallParams *params) {
5419 LinphoneCore *lc;
5420 SalOp *replaced;
5421 SalMediaDescription *new_md;
5422 bool_t was_ringing = FALSE;
5423 bctbx_list_t *iterator, *copy;
5424
5425 switch (call->state) {
5426 case LinphoneCallIncomingReceived:
5427 case LinphoneCallIncomingEarlyMedia:
5428 break;
5429 default:
5430 ms_error("linphone_core_accept_call_with_params() call [%p] is in state [%s], operation not permitted.",
5431 call, linphone_call_state_to_string(call->state));
5432 return -1;
5433 }
5434
5435 lc = linphone_call_get_core(call);
5436 for (iterator = copy = bctbx_list_copy(linphone_core_get_calls(lc)); iterator != NULL; iterator = bctbx_list_next(iterator)) {
5437 LinphoneCall *a_call = (LinphoneCall *)bctbx_list_get_data(iterator);
5438 if (a_call == call) continue;
5439 switch (a_call->state) {
5440 case LinphoneCallOutgoingInit:
5441 case LinphoneCallOutgoingProgress:
5442 case LinphoneCallOutgoingRinging:
5443 case LinphoneCallOutgoingEarlyMedia:
5444 ms_message("Already existing call [%p] in state [%s], canceling it before accepting new call [%p]",
5445 a_call, linphone_call_state_to_string(a_call->state), call);
5446 linphone_call_terminate(a_call);
5447 break;
5448 default:
5449 break; /* Nothing to do */
5450 }
5451 }
5452 bctbx_list_free(copy);
5453
5454 /* Check if this call is supposed to replace an already running one */
5455 replaced = sal_call_get_replaces(call->op);
5456 if (replaced) {
5457 LinphoneCall *rc = (LinphoneCall *)sal_op_get_user_pointer(replaced);
5458 if (rc) {
5459 ms_message("Call %p replaces call %p. This last one is going to be terminated automatically.", call, rc);
5460 linphone_call_terminate(rc);
5461 }
5462 }
5463
5464 if (lc->current_call != call) {
5465 linphone_core_preempt_sound_resources(lc);
5466 }
5467
5468 /* Stop ringing */
5469 if (linphone_ringtoneplayer_is_started(lc->ringtoneplayer)) {
5470 ms_message("Stop ringing");
5471 linphone_core_stop_ringing(lc);
5472 was_ringing = TRUE;
5473 }
5474 if (call->ringing_beep) {
5475 linphone_core_stop_dtmf(lc);
5476 call->ringing_beep = FALSE;
5477 }
5478
5479 /* Try to be best-effort in giving real local or routable contact address */
5480 linphone_call_set_contact_op(call);
5481 if (params) {
5482 _linphone_call_set_new_params(call, params);
5483 linphone_call_prepare_ice(call, TRUE);
5484 linphone_call_make_local_media_description(call);
5485 sal_call_set_local_media_description(call->op, call->localdesc);
5486 sal_op_set_sent_custom_header(call->op, params->custom_headers);
5487 }
5488
5489 /* Give a chance a set card prefered sampling frequency */
5490 if (call->localdesc->streams[0].max_rate > 0) {
5491 ms_message("Configuring prefered card sampling rate to [%i]", call->localdesc->streams[0].max_rate);
5492 if (lc->sound_conf.play_sndcard)
5493 ms_snd_card_set_preferred_sample_rate(lc->sound_conf.play_sndcard, call->localdesc->streams[0].max_rate);
5494 if (lc->sound_conf.capt_sndcard)
5495 ms_snd_card_set_preferred_sample_rate(lc->sound_conf.capt_sndcard, call->localdesc->streams[0].max_rate);
5496 }
5497
5498 if (!was_ringing && (call->audiostream->ms.state == MSStreamInitialized) && !lc->use_files) {
5499 audio_stream_prepare_sound(call->audiostream, lc->sound_conf.play_sndcard, lc->sound_conf.capt_sndcard);
5500 }
5501
5502 linphone_call_update_remote_session_id_and_ver(call);
5503
5504 sal_call_accept(call->op);
5505 linphone_core_notify_display_status(lc, _("Connected."));
5506 lc->current_call = call;
5507 linphone_call_set_state(call, LinphoneCallConnected, "Connected");
5508 new_md = sal_call_get_final_media_description(call->op);
5509 linphone_call_stop_ice_for_inactive_streams(call, new_md);
5510 if (new_md) {
5511 linphone_call_update_streams(call, new_md, LinphoneCallStreamsRunning);
5512 linphone_call_set_state(call, LinphoneCallStreamsRunning, "Connected (streams running)");
5513 } else {
5514 call->expect_media_in_ack = TRUE;
5515 }
5516
5517 ms_message("Call answered");
5518 return 0;
5519 }
5520
5521 LinphoneStatus linphone_call_accept_early_media(LinphoneCall* call) {
5522 return linphone_call_accept_early_media_with_params(call, NULL);
5523 }
5524
5525 LinphoneStatus linphone_call_accept_early_media_with_params(LinphoneCall *call, const LinphoneCallParams *params) {
5526 SalMediaDescription* md;
5527
5528 if (call->state != LinphoneCallIncomingReceived) {
5529 ms_error("Bad state %s for linphone_core_accept_early_media_with_params()", linphone_call_state_to_string(call->state));
5530 return -1;
5531 }
5532
5533 /* Try to be best-effort in giving real local or routable contact address for 100Rel case */
5534 linphone_call_set_contact_op(call);
5535
5536 /* If parameters are passed, update the media description */
5537 if (params) {
5538 _linphone_call_set_new_params(call, params);
5539 linphone_call_make_local_media_description(call);
5540 sal_call_set_local_media_description(call->op, call->localdesc);
5541 sal_op_set_sent_custom_header(call->op, params->custom_headers);
5542 }
5543
5544 sal_call_notify_ringing(call->op, TRUE);
5545
5546 linphone_call_set_state(call, LinphoneCallIncomingEarlyMedia, "Incoming call early media");
5547 md = sal_call_get_final_media_description(call->op);
5548 if (md) linphone_call_update_streams(call, md, call->state);
5549 return 0;
5550 }
5551
5552 LinphoneStatus linphone_call_update(LinphoneCall *call, const LinphoneCallParams *params) {
5553 int err = 0;
5554 LinphoneCallState nextstate;
5555 LinphoneCallState initial_state = call->state;
5556 const LinphoneCallParams *current_params;
5557
5558 #if defined(VIDEO_ENABLED) && defined(BUILD_UPNP)
5559 bool_t has_video = FALSE;
5560 #endif
5561
5562 switch (initial_state) {
5563 case LinphoneCallIncomingReceived:
5564 case LinphoneCallIncomingEarlyMedia:
5565 case LinphoneCallOutgoingRinging:
5566 case LinphoneCallOutgoingEarlyMedia:
5567 nextstate = LinphoneCallEarlyUpdating;
5568 break;
5569 case LinphoneCallStreamsRunning:
5570 case LinphoneCallPausedByRemote:
5571 case LinphoneCallUpdatedByRemote:
5572 nextstate = LinphoneCallUpdating;
5573 break;
5574 case LinphoneCallPaused:
5575 nextstate = LinphoneCallPausing;
5576 break;
5577 case LinphoneCallOutgoingProgress:
5578 case LinphoneCallPausing:
5579 case LinphoneCallResuming:
5580 case LinphoneCallUpdating:
5581 nextstate = initial_state;
5582 break;
5583 default:
5584 ms_error("linphone_call_update() is not allowed in [%s] state", linphone_call_state_to_string(call->state));
5585 return -1;
5586 }
5587
5588 current_params = linphone_call_get_current_params(call);
5589 if ((current_params != NULL) && (current_params == params)) {
5590 ms_warning("linphone_call_update() is given the current params of the call, this probably not what you intend to do!");
5591 }
5592
5593 linphone_call_check_ice_session(call, IR_Controlling, TRUE);
5594
5595 if (params != NULL) {
5596 call->broken = FALSE;
5597 linphone_call_set_state(call, nextstate, "Updating call");
5598 #if defined(VIDEO_ENABLED) && defined(BUILD_UPNP)
5599 has_video = call->params->has_video;
5600
5601 /* Video removal */
5602 if ((call->videostream != NULL) && !params->has_video) {
5603 if (call->upnp_session != NULL) {
5604 if (linphone_call_update_upnp(call) < 0) {
5605 /* uPnP port mappings failed, proceed with the call anyway. */
5606 linphone_call_delete_upnp_session(call);
5607 }
5608 }
5609 }
5610 #endif /* defined(VIDEO_ENABLED) && defined(BUILD_UPNP) */
5611 _linphone_call_set_new_params(call, params);
5612 err = linphone_call_prepare_ice(call, FALSE);
5613 if (err == 1) {
5614 ms_message("Defer call update to gather ICE candidates");
5615 return 0;
5616 }
5617
5618 #if defined(VIDEO_ENABLED) && defined(BUILD_UPNP)
5619 /* Video adding */
5620 if (!has_video && call->params->has_video) {
5621 if(call->upnp_session != NULL) {
5622 ms_message("Defer call update to add uPnP port mappings");
5623 video_stream_prepare_video(call->videostream);
5624 if (linphone_call_update_upnp(call) < 0) {
5625 /* uPnP port mappings failed, proceed with the call anyway. */
5626 linphone_call_delete_upnp_session(call);
5627 } else {
5628 return err;
5629 }
5630 }
5631 }
5632 #endif /* defined(VIDEO_ENABLED) && defined(BUILD_UPNP) */
5633 if ((err = linphone_call_start_update(call)) && (call->state != initial_state)) {
5634 /* Restore initial state */
5635 linphone_call_set_state(call, initial_state, "Restore initial state");
5636 }
5637 } else {
5638 #ifdef VIDEO_ENABLED
5639 LinphoneCore *lc = linphone_call_get_core(call);
5640 if ((call->videostream != NULL) && (call->state == LinphoneCallStreamsRunning)) {
5641 video_stream_set_sent_video_size(call->videostream, linphone_core_get_preferred_video_size(lc));
5642 video_stream_set_fps(call->videostream, linphone_core_get_preferred_framerate(lc));
5643 if (call->camera_enabled && (call->videostream->cam != lc->video_conf.device)) {
5644 video_stream_change_camera(call->videostream, lc->video_conf.device);
5645 } else {
5646 video_stream_update_video_params(call->videostream);
5647 }
5648 }
5649 #endif
5650 }
5651
5652 return err;
5653 }
5654
5655 int linphone_call_start_update(LinphoneCall *call) {
5656 const char *subject;
5657 int err;
5658 bool_t no_user_consent = call->params->no_user_consent;
5659 LinphoneCore *lc = linphone_call_get_core(call);
5660
5661 linphone_call_fill_media_multicast_addr(call);
5662
5663 if (!no_user_consent) linphone_call_make_local_media_description(call);
5664 #ifdef BUILD_UPNP
5665 if (call->upnp_session != NULL) {
5666 linphone_call_update_local_media_description_from_upnp(call->localdesc, call->upnp_session);
5667 }
5668 #endif // BUILD_UPNP
5669 if (call->params->in_conference) {
5670 subject = "Conference";
5671 } else if (call->params->internal_call_update) {
5672 subject = "ICE processing concluded";
5673 } else if (no_user_consent) {
5674 subject = "Refreshing";
5675 } else {
5676 subject = "Media change";
5677 }
5678 linphone_core_notify_display_status(lc, _("Modifying call parameters..."));
5679 if (!lc->sip_conf.sdp_200_ack) {
5680 sal_call_set_local_media_description(call->op, call->localdesc);
5681 } else {
5682 sal_call_set_local_media_description(call->op, NULL);
5683 }
5684 if (call->dest_proxy && call->dest_proxy->op) {
5685 /* Give a chance to update the contact address if connectivity has changed */
5686 sal_op_set_contact_address(call->op, sal_op_get_contact_address(call->dest_proxy->op));
5687 } else {
5688 sal_op_set_contact_address(call->op, NULL);
5689 }
5690 err = sal_call_update(call->op, subject, no_user_consent);
5691 if (lc->sip_conf.sdp_200_ack) {
5692 /* We are NOT offering, set local media description after sending the call so that we are ready to
5693 process the remote offer when it will arrive. */
5694 sal_call_set_local_media_description(call->op, call->localdesc);
5695 }
5696 return err;
5697 }
5698
5699 LinphoneStatus linphone_call_defer_update(LinphoneCall *call) {
5700 if (call->state != LinphoneCallUpdatedByRemote) {
5701 ms_error("linphone_call_defer_update() not done in state LinphoneCallUpdatedByRemote");
5702 return -1;
5703 }
5704
5705 if (call->expect_media_in_ack) {
5706 ms_error("linphone_call_defer_update() is not possible during a late offer incoming reINVITE (INVITE without SDP)");
5707 return -1;
5708 }
5709
5710 call->defer_update=TRUE;
5711 return 0;
5712 }
5713
5714 int linphone_call_start_accept_update(LinphoneCall *call, LinphoneCallState next_state, const char *state_info) {
5715 SalMediaDescription *md;
5716
5717 if ((call->ice_session != NULL) && (ice_session_nb_losing_pairs(call->ice_session) > 0)) {
5718 /* Defer the sending of the answer until there are no losing pairs left */
5719 return 0;
5720 }
5721
5722 linphone_call_make_local_media_description(call);
5723 linphone_call_update_remote_session_id_and_ver(call);
5724 sal_call_set_local_media_description(call->op, call->localdesc);
5725 sal_call_accept(call->op);
5726 md = sal_call_get_final_media_description(call->op);
5727 linphone_call_stop_ice_for_inactive_streams(call, md);
5728 if (md && !sal_media_description_empty(md)) {
5729 linphone_call_update_streams(call, md, next_state);
5730 }
5731 linphone_call_set_state(call, next_state, state_info);
5732 return 0;
5733 }
5734
5735 int _linphone_call_accept_update(LinphoneCall *call, const LinphoneCallParams *params, LinphoneCallState next_state, const char *state_info) {
5736 SalMediaDescription *remote_desc;
5737 bool_t keep_sdp_version;
5738 LinphoneCore *lc = linphone_call_get_core(call);
5739 #if defined(VIDEO_ENABLED) && defined(BUILD_UPNP)
5740 bool_t old_has_video = call->params->has_video;
5741 #endif
5742
5743 remote_desc = sal_call_get_remote_media_description(call->op);
5744 keep_sdp_version = lp_config_get_int(lc->config, "sip", "keep_sdp_version", 0);
5745 if (keep_sdp_version && (remote_desc->session_id == call->remote_session_id) && (remote_desc->session_ver == call->remote_session_ver)) {
5746 /* Remote has sent an INVITE with the same SDP as before, so send a 200 OK with the same SDP as before. */
5747 ms_warning("SDP version has not changed, send same SDP as before.");
5748 sal_call_accept(call->op);
5749 linphone_call_set_state(call, next_state, state_info);
5750 return 0;
5751 }
5752 if (params == NULL) {
5753 if (!sal_call_is_offerer(call->op)) {
5754 /* Reset call param for multicast because this param is only relevant when offering */
5755 linphone_call_params_enable_audio_multicast(call->params, FALSE);
5756 linphone_call_params_enable_video_multicast(call->params, FALSE);
5757 }
5758 } else {
5759 _linphone_call_set_new_params(call, params);
5760 }
5761
5762 if (call->params->has_video && !linphone_core_video_enabled(lc)) {
5763 ms_warning("Requested video but video support is globally disabled. Refusing video.");
5764 call->params->has_video = FALSE;
5765 }
5766 if (call->current_params->in_conference) {
5767 ms_warning("Video isn't supported in conference");
5768 call->params->has_video = FALSE;
5769 }
5770 /* Update multicast params according to call params */
5771 linphone_call_fill_media_multicast_addr(call);
5772
5773 linphone_call_check_ice_session(call, IR_Controlled, TRUE);
5774 linphone_call_init_media_streams(call); /* So that video stream is initialized if necessary */
5775 if (linphone_call_prepare_ice(call, TRUE) == 1) {
5776 return 0; /* Deferred until completion of ICE gathering */
5777 }
5778
5779 #ifdef BUILD_UPNP
5780 if (call->upnp_session != NULL) {
5781 linphone_call_update_upnp_from_remote_media_description(call, sal_call_get_remote_media_description(call->op));
5782 #ifdef VIDEO_ENABLED
5783 if ((call->params->has_video) && (call->params->has_video != old_has_video)) {
5784 video_stream_prepare_video(call->videostream);
5785 if (linphone_call_update_upnp(call) < 0) {
5786 /* uPnP update failed, proceed with the call anyway. */
5787 linphone_call_delete_upnp_session(call);
5788 } else return 0;
5789 }
5790 #endif // VIDEO_ENABLED
5791 }
5792 #endif // BUILD_UPNP
5793
5794 linphone_call_start_accept_update(call, next_state, state_info);
5795 return 0;
5796 }
5797
5798 LinphoneStatus linphone_call_accept_update(LinphoneCall *call, const LinphoneCallParams *params) {
5799 if (call->state != LinphoneCallUpdatedByRemote) {
5800 ms_error("linphone_call_accept_update(): invalid state %s to call this function.", linphone_call_state_to_string(call->state));
5801 return -1;
5802 }
5803 if (call->expect_media_in_ack) {
5804 ms_error("linphone_call_accept_update() is not possible during a late offer incoming reINVITE (INVITE without SDP)");
5805 return -1;
5806 }
5807 return _linphone_call_accept_update(call, params, call->prevstate, linphone_call_state_to_string(call->prevstate));
5808 }
5809
5810 LinphoneStatus linphone_call_transfer(LinphoneCall *call, const char *refer_to) {
5811 char *real_url = NULL;
5812 LinphoneCore *lc = linphone_call_get_core(call);
5813 LinphoneAddress *real_parsed_url = linphone_core_interpret_url(lc, refer_to);
5814
5815 if (!real_parsed_url) {
5816 /* bad url */
5817 return -1;
5818 }
5819 //lc->call = NULL; // Do not do that you will lose the call afterward...
5820 real_url = linphone_address_as_string(real_parsed_url);
5821 sal_call_refer(call->op, real_url);
5822 ms_free(real_url);
5823 linphone_address_unref(real_parsed_url);
5824 linphone_call_set_transfer_state(call, LinphoneCallOutgoingInit);
5825 return 0;
5826 }
5827
5828 LinphoneStatus linphone_call_transfer_to_another(LinphoneCall *call, LinphoneCall *dest) {
5829 int result = sal_call_refer_with_replaces (call->op, dest->op);
5830 linphone_call_set_transfer_state(call, LinphoneCallOutgoingInit);
5831 return result;
5832 }
5833
5834 int linphone_call_abort(LinphoneCall *call, const char *error) {
5835 LinphoneCore *lc = linphone_call_get_core(call);
5836
5837 sal_call_terminate(call->op);
5838
5839 /* Stop ringing */
5840 linphone_core_stop_ringing(lc);
5841 linphone_call_stop_media_streams(call);
5842
5843 #ifdef BUILD_UPNP
5844 linphone_call_delete_upnp_session(call);
5845 #endif // BUILD_UPNP
5846
5847 linphone_core_notify_display_status(lc, _("Call aborted"));
5848 linphone_call_set_state(call, LinphoneCallError, error);
5849 return 0;
5850 }
5851
5852 int linphone_call_proceed_with_invite_if_ready(LinphoneCall *call, LinphoneProxyConfig *dest_proxy) {
5853 bool_t ice_ready = FALSE;
5854 bool_t upnp_ready = FALSE;
5855 bool_t ping_ready = FALSE;
5856
5857 if (call->ice_session != NULL) {
5858 if (ice_session_candidates_gathered(call->ice_session)) ice_ready = TRUE;
5859 } else {
5860 ice_ready = TRUE;
5861 }
5862 #ifdef BUILD_UPNP
5863 if (call->upnp_session != NULL) {
5864 if (linphone_upnp_session_get_state(call->upnp_session) == LinphoneUpnpStateOk) upnp_ready = TRUE;
5865 } else {
5866 upnp_ready = TRUE;
5867 }
5868 #else
5869 upnp_ready=TRUE;
5870 #endif // BUILD_UPNP
5871 if (call->ping_op != NULL) {
5872 if (call->ping_replied == TRUE) ping_ready = TRUE;
5873 } else {
5874 ping_ready = TRUE;
5875 }
5876
5877 if ((ice_ready == TRUE) && (upnp_ready == TRUE) && (ping_ready == TRUE)) {
5878 return linphone_call_start_invite(call, NULL);
5879 }
5880 return 0;
5881 }
5882
5883 int linphone_call_start_invite(LinphoneCall *call, const LinphoneAddress *destination /* = NULL if to be taken from the call log */) {
5884 int err;
5885 char *real_url, *barmsg;
5886 char *from;
5887 LinphoneCore *lc = linphone_call_get_core(call);
5888
5889 /* Try to be best-effort in giving real local or routable contact address */
5890 linphone_call_set_contact_op(call);
5891
5892 linphone_core_stop_dtmf_stream(lc);
5893 linphone_call_make_local_media_description(call);
5894
5895 if (lc->ringstream == NULL) {
5896 if (lc->sound_conf.play_sndcard && lc->sound_conf.capt_sndcard) {
5897 /* Give a chance a set card prefered sampling frequency */
5898 if (call->localdesc->streams[0].max_rate > 0) {
5899 ms_snd_card_set_preferred_sample_rate(lc->sound_conf.play_sndcard, call->localdesc->streams[0].max_rate);
5900 }
5901 if (!lc->use_files) {
5902 audio_stream_prepare_sound(call->audiostream, lc->sound_conf.play_sndcard, lc->sound_conf.capt_sndcard);
5903 }
5904 }
5905 }
5906 real_url = linphone_address_as_string(destination ? destination : call->log->to);
5907 from = linphone_address_as_string(call->log->from);
5908
5909 if (!lc->sip_conf.sdp_200_ack) {
5910 /* We are offering, set local media description before sending the call */
5911 sal_call_set_local_media_description(call->op, call->localdesc);
5912 }
5913
5914 barmsg = ms_strdup_printf("%s %s", _("Contacting"), real_url);
5915 linphone_core_notify_display_status(lc, barmsg);
5916 ms_free(barmsg);
5917
5918 linphone_call_ref(call); /* Take a ref because sal_call() may destroy the call if no SIP transport is available */
5919 err = sal_call(call->op, from, real_url);
5920
5921 if (err < 0) {
5922 if ((call->state != LinphoneCallError) && (call->state != LinphoneCallReleased)) {
5923 /* sal_call() may invoke call_failure() and call_released() SAL callbacks synchronously,
5924 in which case there is no need to perform a state change here. */
5925 linphone_core_notify_display_status(lc, _("Could not call"));
5926 linphone_call_stop_media_streams(call);
5927 linphone_call_set_state(call, LinphoneCallError, "Call failed");
5928 }
5929 goto end;
5930 }
5931 if (lc->sip_conf.sdp_200_ack) {
5932 /* We are NOT offering, set local media description after sending the call so that we are ready to
5933 process the remote offer when it will arrive. */
5934 sal_call_set_local_media_description(call->op, call->localdesc);
5935 }
5936 call->log->call_id = ms_strdup(sal_op_get_call_id(call->op)); /* Must be known at that time */
5937 linphone_call_set_state(call, LinphoneCallOutgoingProgress, "Outgoing call in progress");
5938
5939 end:
5940 linphone_call_unref(call); /* Revert the ref taken before calling sal_call() */
5941 ms_free(real_url);
5942 ms_free(from);
5943 return err;
5944 }
5945
5946 int linphone_call_restart_invite(LinphoneCall *call) {
5947 linphone_call_create_op(call);
5948 linphone_call_stop_media_streams(call);
5949 ms_media_stream_sessions_uninit(&call->sessions[call->main_audio_stream_index]);
5950 ms_media_stream_sessions_uninit(&call->sessions[call->main_video_stream_index]);
5951 ms_media_stream_sessions_uninit(&call->sessions[call->main_text_stream_index]);
5952 linphone_call_init_media_streams(call);
5953 return linphone_call_start_invite(call, NULL);
5954 }
5955
5956 void linphone_call_set_broken(LinphoneCall *call){
5957 switch(call->state){
5958 /*for all the early states, we prefer to drop the call*/
5959 case LinphoneCallOutgoingInit:
5960 case LinphoneCallOutgoingProgress:
5961 case LinphoneCallOutgoingRinging:
5962 case LinphoneCallOutgoingEarlyMedia:
5963 case LinphoneCallIncomingReceived:
5964 case LinphoneCallIncomingEarlyMedia:
5965 /*during the early states, the SAL layer reports the failure from the dialog or transaction layer,
5966 * hence, there is nothing special to do*/
5967 //break;
5968 case LinphoneCallStreamsRunning:
5969 case LinphoneCallUpdating:
5970 case LinphoneCallPausing:
5971 case LinphoneCallResuming:
5972 case LinphoneCallPaused:
5973 case LinphoneCallPausedByRemote:
5974 case LinphoneCallUpdatedByRemote:
5975 /*during these states, the dialog is established. A failure of a transaction is not expected to close it.
5976 * Instead we have to repair the dialog by sending a reINVITE*/
5977 call->broken = TRUE;
5978 call->need_localip_refresh = TRUE;
5979 break;
5980 default:
5981 ms_error("linphone_call_set_broken() unimplemented case.");
5982 break;
5983 }
5984 }
5985
5986 static void linphone_call_repair_by_invite_with_replaces(LinphoneCall *call) {
5987 const char *call_id = sal_op_get_call_id(call->op);
5988 const char *from_tag = sal_call_get_local_tag(call->op);
5989 const char *to_tag = sal_call_get_remote_tag(call->op);
5990 sal_op_kill_dialog(call->op);
5991 linphone_call_create_op(call);
5992 sal_call_set_replaces(call->op, call_id, from_tag, to_tag);
5993 linphone_call_start_invite(call, NULL);
5994 }
5995
5996 void linphone_call_reinvite_to_recover_from_connection_loss(LinphoneCall *call) {
5997 LinphoneCallParams *params;
5998 ms_message("LinphoneCall[%p] is going to be updated (reINVITE) in order to recover from lost connectivity", call);
5999 if (call->ice_session){
6000 ice_session_reset(call->ice_session, IR_Controlling);
6001 }
6002 params = linphone_core_create_call_params(call->core, call);
6003 linphone_call_update(call, params);
6004 linphone_call_params_unref(params);
6005 }
6006
6007 void linphone_call_repair_if_broken(LinphoneCall *call){
6008 SalErrorInfo sei = {0};
6009 if (!call->broken) return;
6010 if (!call->core->media_network_reachable) return;
6011
6012 /*Make sure that the proxy from which we received this call, or to which we routed this call is registered first*/
6013 if (call->dest_proxy){
6014 /*in all other cases, ie no proxy config, or a proxy config for which no registration was requested, we can start the
6015 * call repair immediately.*/
6016 if (linphone_proxy_config_register_enabled(call->dest_proxy)
6017 && linphone_proxy_config_get_state(call->dest_proxy) != LinphoneRegistrationOk) return;
6018 }
6019
6020 switch (call->state){
6021 case LinphoneCallUpdating:
6022 case LinphoneCallPausing:
6023 if (sal_call_dialog_request_pending(call->op)) {
6024 /* Need to cancel first re-INVITE as described in section 5.5 of RFC 6141 */
6025 sal_call_cancel_invite(call->op);
6026 call->reinvite_on_cancel_response_requested = TRUE;
6027 }
6028 break;
6029 case LinphoneCallStreamsRunning:
6030 case LinphoneCallPaused:
6031 case LinphoneCallPausedByRemote:
6032 if (!sal_call_dialog_request_pending(call->op)) {
6033 linphone_call_reinvite_to_recover_from_connection_loss(call);
6034 }
6035 break;
6036 case LinphoneCallUpdatedByRemote:
6037 if (sal_call_dialog_request_pending(call->op)) {
6038 sal_error_info_set(&sei, SalReasonServiceUnavailable,"SIP", 0, NULL, NULL);
6039 sal_call_decline_with_error_info(call->op, &sei,NULL);
6040 }
6041 linphone_call_reinvite_to_recover_from_connection_loss(call);
6042 break;
6043 case LinphoneCallOutgoingInit:
6044 case LinphoneCallOutgoingProgress:
6045 sal_call_cancel_invite(call->op);
6046 call->reinvite_on_cancel_response_requested = TRUE;
6047 break;
6048 case LinphoneCallOutgoingEarlyMedia:
6049 case LinphoneCallOutgoingRinging:
6050 linphone_call_repair_by_invite_with_replaces(call);
6051 break;
6052 case LinphoneCallIncomingEarlyMedia:
6053 case LinphoneCallIncomingReceived:
6054 /* Keep the call broken until a forked INVITE is received from the server. */
6055 break;
6056 default:
6057 ms_warning("linphone_call_repair_if_broken(): don't know what to do in state [%s]", linphone_call_state_to_string(call->state));
6058 call->broken = FALSE;
6059 break;
6060 }
6061 sal_error_info_reset(&sei);
6062 }
6063
6064 void linphone_call_refresh_sockets(LinphoneCall *call){
6065 int i;
6066 for (i=0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; ++i){
6067 MSMediaStreamSessions *mss = &call->sessions[i];
6068 if (mss->rtp_session){
6069 rtp_session_refresh_sockets(mss->rtp_session);
6070 }
6071 }
6072 }
6073
6074 void linphone_call_replace_op(LinphoneCall *call, SalOp *op) {
6075 SalOp *oldop = call->op;
6076 LinphoneCallState oldstate = linphone_call_get_state(call);
6077 call->op = op;
6078 sal_op_set_user_pointer(call->op, call);
6079 sal_call_set_local_media_description(call->op, call->localdesc);
6080 switch (linphone_call_get_state(call)) {
6081 case LinphoneCallIncomingEarlyMedia:
6082 case LinphoneCallIncomingReceived:
6083 sal_call_notify_ringing(call->op, (linphone_call_get_state(call) == LinphoneCallIncomingEarlyMedia) ? TRUE : FALSE);
6084 break;
6085 case LinphoneCallConnected:
6086 case LinphoneCallStreamsRunning:
6087 sal_call_accept(call->op);
6088 break;
6089 default:
6090 ms_warning("linphone_call_replace_op(): don't know what to do in state [%s]", linphone_call_state_to_string(call->state));
6091 break;
6092 }
6093 switch (oldstate) {
6094 case LinphoneCallIncomingEarlyMedia:
6095 case LinphoneCallIncomingReceived:
6096 sal_op_set_user_pointer(oldop, NULL); /* To make the call does not get terminated by terminating this op. */
6097 /* Do not terminate a forked INVITE */
6098 if (sal_call_get_replaces(op)) {
6099 sal_call_terminate(oldop);
6100 } else {
6101 sal_op_kill_dialog(oldop);
6102 }
6103 break;
6104 case LinphoneCallConnected:
6105 case LinphoneCallStreamsRunning:
6106 sal_call_terminate(oldop);
6107 sal_op_kill_dialog(oldop);
6108 break;
6109 default:
6110 break;
6111 }
6112 sal_op_release(oldop);
6113 }
6114
6115 void linphone_call_ogl_render(const LinphoneCall *call) {
6116 #ifdef VIDEO_ENABLED
6117
6118 VideoStream *stream = call->videostream;
6119 if (stream && stream->output && ms_filter_get_id(stream->output) == MS_OGL_ID)
6120 ms_filter_call_method(stream->output, MS_OGL_RENDER, NULL);
6121
6122 #endif
6123 }
6124
6125 void linphone_call_add_callbacks(LinphoneCall *call, LinphoneCallCbs *cbs) {
6126 call->callbacks = bctbx_list_append(call->callbacks, linphone_call_cbs_ref(cbs));
6127 }
6128
6129 void linphone_call_remove_callbacks(LinphoneCall *call, LinphoneCallCbs *cbs) {
6130 call->callbacks = bctbx_list_remove(call->callbacks, cbs);
6131 linphone_call_cbs_unref(cbs);
6132 }
6133
6134 LinphoneCallCbs *linphone_call_get_current_callbacks(const LinphoneCall *call) {
6135 return call->current_cbs;
6136 }
6137
6138 #define NOTIFY_IF_EXIST(function_name, ...) \
6139 bctbx_list_t* iterator; \
6140 for (iterator = call->callbacks; iterator != NULL; iterator = bctbx_list_next(iterator)) { \
6141 call->current_cbs = (LinphoneCallCbs *)bctbx_list_get_data(iterator); \
6142 if (call->current_cbs->function_name != NULL) { \
6143 call->current_cbs->function_name(__VA_ARGS__); \
6144 } \
6145 }
6146
6147 void linphone_call_notify_state_changed(LinphoneCall *call, LinphoneCallState cstate, const char *message) {
6148 NOTIFY_IF_EXIST(state_changed_cb, call, cstate, message)
6149 linphone_core_notify_call_state_changed(linphone_call_get_core(call), call, cstate, message);
6150 }
6151
6152 void linphone_call_notify_dtmf_received(LinphoneCall *call, int dtmf) {
6153 NOTIFY_IF_EXIST(dtmf_received_cb, call, dtmf)
6154 linphone_core_notify_dtmf_received(linphone_call_get_core(call), call, dtmf);
6155 }
6156
6157 void linphone_call_notify_encryption_changed(LinphoneCall *call, bool_t on, const char *authentication_token) {
6158 NOTIFY_IF_EXIST(encryption_changed_cb, call, on, authentication_token)
6159 linphone_core_notify_call_encryption_changed(linphone_call_get_core(call), call, on, authentication_token);
6160 }
6161
6162 void linphone_call_notify_transfer_state_changed(LinphoneCall *call, LinphoneCallState cstate) {
6163 NOTIFY_IF_EXIST(transfer_state_changed_cb, call, cstate)
6164 linphone_core_notify_transfer_state_changed(linphone_call_get_core(call), call, cstate);
6165 }
6166
6167 void linphone_call_notify_stats_updated(LinphoneCall *call, const LinphoneCallStats *stats) {
6168 NOTIFY_IF_EXIST(stats_updated_cb, call, stats)
6169 linphone_core_notify_call_stats_updated(linphone_call_get_core(call), call, stats);
6170 }
6171
6172 void linphone_call_notify_info_message_received(LinphoneCall *call, const LinphoneInfoMessage *msg) {
6173 NOTIFY_IF_EXIST(info_message_received_cb, call, msg)
6174 linphone_core_notify_info_received(linphone_call_get_core(call), call, msg);
6175 }
6176
6177 void linphone_call_notify_ack_processing(LinphoneCall *call, void *msg, bool_t is_received) {
6178 NOTIFY_IF_EXIST(ack_processing, call, msg, is_received)
6179 }
6180
6181