1 /*
2 linphone
3 Copyright (C) 2000 Simon MORLAT (simon.morlat@linphone.org)
4 Copyright (C) 2010 Belledonne Communications SARL
5
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20
21 #include "linphone/core.h"
22 #include "linphone/sipsetup.h"
23 #include "linphone/lpconfig.h"
24 #include "private.h"
25 #include "quality_reporting.h"
26 #include "lime.h"
27 #include "conference_private.h"
28
29 #ifdef SQLITE_STORAGE_ENABLED
30 #include "sqlite3_bctbx_vfs.h"
31 #endif
32
33 #include <math.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <ortp/telephonyevents.h>
37 #include <mediastreamer2/zrtp.h>
38 #include <mediastreamer2/dtls_srtp.h>
39 #include <bctoolbox/defs.h>
40 #include "mediastreamer2/dtmfgen.h"
41 #include "mediastreamer2/mediastream.h"
42 #include "mediastreamer2/msequalizer.h"
43 #include "mediastreamer2/mseventqueue.h"
44 #include "mediastreamer2/msfactory.h"
45 #include "mediastreamer2/msjpegwriter.h"
46 #include "mediastreamer2/msogl.h"
47 #include "mediastreamer2/msvolume.h"
48
49 #ifdef INET6
50 #ifndef _WIN32
51 #include <netdb.h>
52 #endif
53 #endif
54
55 #ifdef HAVE_CONFIG_H
56 #include "config.h"
57 #include "gitversion.h"
58 #endif
59
60 #ifdef __APPLE__
61 #include "TargetConditionals.h"
62 #endif
63
64 #ifdef HAVE_ZLIB
65 #define COMPRESSED_LOG_COLLECTION_EXTENSION "gz"
66 #ifdef _WIN32
67 #include <fcntl.h>
68 #include <io.h>
69 #ifndef fileno
70 #define fileno _fileno
71 #endif
72 #define unlink _unlink
73 #define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
74 #else
75 #define SET_BINARY_MODE(file)
76 #endif
77 #include <zlib.h>
78 #else
79 #define COMPRESSED_LOG_COLLECTION_EXTENSION "txt"
80 #endif
81 #define LOG_COLLECTION_DEFAULT_PATH "."
82 #define LOG_COLLECTION_DEFAULT_PREFIX "linphone"
83 #define LOG_COLLECTION_DEFAULT_MAX_FILE_SIZE (10 * 1024 * 1024)
84
85
86 /*#define UNSTANDART_GSM_11K 1*/
87
88 static const char *liblinphone_version=
89 #ifdef LIBLINPHONE_GIT_VERSION
90 LIBLINPHONE_GIT_VERSION
91 #else
92 LIBLINPHONE_VERSION
93 #endif
94 ;
95 static OrtpLogFunc liblinphone_log_func = NULL;
96 static LinphoneLogCollectionState liblinphone_log_collection_state = LinphoneLogCollectionDisabled;
97 static char * liblinphone_log_collection_path = NULL;
98 static char * liblinphone_log_collection_prefix = NULL;
99 static size_t liblinphone_log_collection_max_file_size = LOG_COLLECTION_DEFAULT_MAX_FILE_SIZE;
100 static ortp_mutex_t liblinphone_log_collection_mutex;
101 static FILE * liblinphone_log_collection_file = NULL;
102 static size_t liblinphone_log_collection_file_size = 0;
103 static bool_t liblinphone_serialize_logs = FALSE;
104 static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t curtime);
105 static void set_sip_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t curtime);
106 static void set_media_network_reachable(LinphoneCore* lc,bool_t isReachable);
107 static void linphone_core_run_hooks(LinphoneCore *lc);
108 static void linphone_core_uninit(LinphoneCore *lc);
109 static void linphone_core_zrtp_cache_close(LinphoneCore *lc);
110 void linphone_core_zrtp_cache_db_init(LinphoneCore *lc, const char *fileName);
111
112 #include "enum.h"
113 #include "contact_providers_priv.h"
114
115
116 const char *linphone_core_get_nat_address_resolved(LinphoneCore *lc);
117 static void toggle_video_preview(LinphoneCore *lc, bool_t val);
118
119
120 /* relative path where is stored local ring*/
121 #define LOCAL_RING_WAV "oldphone-mono.wav"
122 #define LOCAL_RING_MKV "notes_of_the_optimistic.mkv"
123 /* same for remote ring (ringback)*/
124 #define REMOTE_RING_WAV "ringback.wav"
125
126 #define HOLD_MUSIC_WAV "toy-mono.wav"
127 #define HOLD_MUSIC_MKV "dont_wait_too_long.mkv"
128
129 extern SalCallbacks linphone_sal_callbacks;
130
131
132 static void _linphone_core_cbs_uninit(LinphoneCoreCbs *cbs);
133
134 typedef belle_sip_object_t_vptr_t LinphoneCoreCbs_vptr_t;
135 BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneCoreCbs);
136 BELLE_SIP_INSTANCIATE_VPTR(LinphoneCoreCbs, belle_sip_object_t,
137 _linphone_core_cbs_uninit, // destroy
138 NULL, // clone
139 NULL, // Marshall
140 FALSE
141 );
142
_linphone_core_cbs_new(void)143 LinphoneCoreCbs *_linphone_core_cbs_new(void) {
144 LinphoneCoreCbs *obj = belle_sip_object_new(LinphoneCoreCbs);
145 obj->vtable = ms_new0(LinphoneCoreVTable, 1);
146 obj->autorelease = TRUE;
147 return obj;
148 }
149
_linphone_core_cbs_uninit(LinphoneCoreCbs * cbs)150 static void _linphone_core_cbs_uninit(LinphoneCoreCbs *cbs) {
151 if (cbs->autorelease) ms_free(cbs->vtable);
152 }
153
_linphone_core_cbs_set_v_table(LinphoneCoreCbs * cbs,LinphoneCoreVTable * vtable,bool_t autorelease)154 void _linphone_core_cbs_set_v_table(LinphoneCoreCbs *cbs, LinphoneCoreVTable *vtable, bool_t autorelease) {
155 ms_free(cbs->vtable);
156 cbs->vtable = vtable;
157 cbs->autorelease = autorelease;
158 }
159
linphone_core_cbs_ref(LinphoneCoreCbs * cbs)160 LinphoneCoreCbs *linphone_core_cbs_ref(LinphoneCoreCbs *cbs) {
161 return (LinphoneCoreCbs *)belle_sip_object_ref(cbs);
162 }
163
linphone_core_cbs_unref(LinphoneCoreCbs * cbs)164 void linphone_core_cbs_unref(LinphoneCoreCbs *cbs) {
165 belle_sip_object_unref(cbs);
166 }
167
linphone_core_cbs_set_user_data(LinphoneCoreCbs * cbs,void * user_data)168 void linphone_core_cbs_set_user_data(LinphoneCoreCbs *cbs, void *user_data) {
169 cbs->vtable->user_data = user_data;
170 }
171
linphone_core_cbs_get_user_data(const LinphoneCoreCbs * cbs)172 void *linphone_core_cbs_get_user_data(const LinphoneCoreCbs *cbs) {
173 return cbs->vtable->user_data;
174 }
175
linphone_core_get_current_callbacks(const LinphoneCore * lc)176 LinphoneCoreCbs *linphone_core_get_current_callbacks(const LinphoneCore *lc) {
177 return lc->current_cbs;
178 }
179
linphone_core_cbs_get_global_state_changed(LinphoneCoreCbs * cbs)180 LinphoneCoreCbsGlobalStateChangedCb linphone_core_cbs_get_global_state_changed(LinphoneCoreCbs *cbs) {
181 return cbs->vtable->global_state_changed;
182 }
183
linphone_core_cbs_set_global_state_changed(LinphoneCoreCbs * cbs,LinphoneCoreCbsGlobalStateChangedCb cb)184 void linphone_core_cbs_set_global_state_changed(LinphoneCoreCbs *cbs, LinphoneCoreCbsGlobalStateChangedCb cb) {
185 cbs->vtable->global_state_changed = cb;
186 }
187
linphone_core_cbs_get_registration_state_changed(LinphoneCoreCbs * cbs)188 LinphoneCoreCbsRegistrationStateChangedCb linphone_core_cbs_get_registration_state_changed(LinphoneCoreCbs *cbs) {
189 return cbs->vtable->registration_state_changed;
190 }
191
linphone_core_cbs_set_registration_state_changed(LinphoneCoreCbs * cbs,LinphoneCoreCbsRegistrationStateChangedCb cb)192 void linphone_core_cbs_set_registration_state_changed(LinphoneCoreCbs *cbs, LinphoneCoreCbsRegistrationStateChangedCb cb) {
193 cbs->vtable->registration_state_changed = cb;
194 }
195
linphone_core_cbs_get_call_state_changed(LinphoneCoreCbs * cbs)196 LinphoneCoreCbsCallStateChangedCb linphone_core_cbs_get_call_state_changed(LinphoneCoreCbs *cbs) {
197 return cbs->vtable->call_state_changed;
198 }
199
linphone_core_cbs_set_call_state_changed(LinphoneCoreCbs * cbs,LinphoneCoreCbsCallStateChangedCb cb)200 void linphone_core_cbs_set_call_state_changed(LinphoneCoreCbs *cbs, LinphoneCoreCbsCallStateChangedCb cb) {
201 cbs->vtable->call_state_changed = cb;
202 }
203
linphone_core_cbs_get_notify_presence_received(LinphoneCoreCbs * cbs)204 LinphoneCoreCbsNotifyPresenceReceivedCb linphone_core_cbs_get_notify_presence_received(LinphoneCoreCbs *cbs) {
205 return cbs->vtable->notify_presence_received;
206 }
207
linphone_core_cbs_set_notify_presence_received(LinphoneCoreCbs * cbs,LinphoneCoreCbsNotifyPresenceReceivedCb cb)208 void linphone_core_cbs_set_notify_presence_received(LinphoneCoreCbs *cbs, LinphoneCoreCbsNotifyPresenceReceivedCb cb) {
209 cbs->vtable->notify_presence_received = cb;
210 }
211
linphone_core_cbs_get_notify_presence_received_for_uri_or_tel(LinphoneCoreCbs * cbs)212 LinphoneCoreCbsNotifyPresenceReceivedForUriOrTelCb linphone_core_cbs_get_notify_presence_received_for_uri_or_tel(LinphoneCoreCbs *cbs) {
213 return cbs->vtable->notify_presence_received_for_uri_or_tel;
214 }
215
linphone_core_cbs_set_notify_presence_received_for_uri_or_tel(LinphoneCoreCbs * cbs,LinphoneCoreCbsNotifyPresenceReceivedForUriOrTelCb cb)216 void linphone_core_cbs_set_notify_presence_received_for_uri_or_tel(LinphoneCoreCbs *cbs, LinphoneCoreCbsNotifyPresenceReceivedForUriOrTelCb cb) {
217 cbs->vtable->notify_presence_received_for_uri_or_tel = cb;
218 }
219
linphone_core_cbs_get_new_subscription_requested(LinphoneCoreCbs * cbs)220 LinphoneCoreCbsNewSubscriptionRequestedCb linphone_core_cbs_get_new_subscription_requested(LinphoneCoreCbs *cbs) {
221 return cbs->vtable->new_subscription_requested;
222 }
223
linphone_core_cbs_set_new_subscription_requested(LinphoneCoreCbs * cbs,LinphoneCoreCbsNewSubscriptionRequestedCb cb)224 void linphone_core_cbs_set_new_subscription_requested(LinphoneCoreCbs *cbs, LinphoneCoreCbsNewSubscriptionRequestedCb cb) {
225 cbs->vtable->new_subscription_requested = cb;
226 }
227
linphone_core_cbs_get_authentication_requested(LinphoneCoreCbs * cbs)228 LinphoneCoreCbsAuthenticationRequestedCb linphone_core_cbs_get_authentication_requested(LinphoneCoreCbs *cbs) {
229 return cbs->vtable->authentication_requested;
230 }
231
linphone_core_cbs_set_authentication_requested(LinphoneCoreCbs * cbs,LinphoneCoreCbsAuthenticationRequestedCb cb)232 void linphone_core_cbs_set_authentication_requested(LinphoneCoreCbs *cbs, LinphoneCoreCbsAuthenticationRequestedCb cb) {
233 cbs->vtable->authentication_requested = cb;
234 }
235
linphone_core_cbs_get_call_log_updated(LinphoneCoreCbs * cbs)236 LinphoneCoreCbsCallLogUpdatedCb linphone_core_cbs_get_call_log_updated(LinphoneCoreCbs *cbs) {
237 return cbs->vtable->call_log_updated;
238 }
239
linphone_core_cbs_set_call_log_updated(LinphoneCoreCbs * cbs,LinphoneCoreCbsCallLogUpdatedCb cb)240 void linphone_core_cbs_set_call_log_updated(LinphoneCoreCbs *cbs, LinphoneCoreCbsCallLogUpdatedCb cb) {
241 cbs->vtable->call_log_updated = cb;
242 }
243
linphone_core_cbs_get_message_received(LinphoneCoreCbs * cbs)244 LinphoneCoreCbsMessageReceivedCb linphone_core_cbs_get_message_received(LinphoneCoreCbs *cbs) {
245 return cbs->vtable->message_received;
246 }
247
linphone_core_cbs_set_message_received(LinphoneCoreCbs * cbs,LinphoneCoreCbsMessageReceivedCb cb)248 void linphone_core_cbs_set_message_received(LinphoneCoreCbs *cbs, LinphoneCoreCbsMessageReceivedCb cb) {
249 cbs->vtable->message_received = cb;
250 }
251
linphone_core_cbs_get_message_received_unable_decrypt(LinphoneCoreCbs * cbs)252 LinphoneCoreCbsMessageReceivedUnableDecryptCb linphone_core_cbs_get_message_received_unable_decrypt(LinphoneCoreCbs *cbs) {
253 return cbs->vtable->message_received_unable_decrypt;
254 }
255
linphone_core_cbs_set_message_received_unable_decrypt(LinphoneCoreCbs * cbs,LinphoneCoreCbsMessageReceivedUnableDecryptCb cb)256 void linphone_core_cbs_set_message_received_unable_decrypt(LinphoneCoreCbs *cbs, LinphoneCoreCbsMessageReceivedUnableDecryptCb cb) {
257 cbs->vtable->message_received_unable_decrypt = cb;
258 }
259
linphone_core_cbs_get_is_composing_received(LinphoneCoreCbs * cbs)260 LinphoneCoreCbsIsComposingReceivedCb linphone_core_cbs_get_is_composing_received(LinphoneCoreCbs *cbs) {
261 return cbs->vtable->is_composing_received;
262 }
263
linphone_core_cbs_set_is_composing_received(LinphoneCoreCbs * cbs,LinphoneCoreCbsIsComposingReceivedCb cb)264 void linphone_core_cbs_set_is_composing_received(LinphoneCoreCbs *cbs, LinphoneCoreCbsIsComposingReceivedCb cb) {
265 cbs->vtable->is_composing_received = cb;
266 }
267
linphone_core_cbs_get_dtmf_received(LinphoneCoreCbs * cbs)268 LinphoneCoreCbsDtmfReceivedCb linphone_core_cbs_get_dtmf_received(LinphoneCoreCbs *cbs) {
269 return cbs->vtable->dtmf_received;
270 }
271
linphone_core_cbs_set_dtmf_received(LinphoneCoreCbs * cbs,LinphoneCoreCbsDtmfReceivedCb cb)272 void linphone_core_cbs_set_dtmf_received(LinphoneCoreCbs *cbs, LinphoneCoreCbsDtmfReceivedCb cb) {
273 cbs->vtable->dtmf_received = cb;
274 }
275
linphone_core_cbs_get_refer_received(LinphoneCoreCbs * cbs)276 LinphoneCoreCbsReferReceivedCb linphone_core_cbs_get_refer_received(LinphoneCoreCbs *cbs) {
277 return cbs->vtable->refer_received;
278 }
279
linphone_core_cbs_set_refer_received(LinphoneCoreCbs * cbs,LinphoneCoreCbsReferReceivedCb cb)280 void linphone_core_cbs_set_refer_received(LinphoneCoreCbs *cbs, LinphoneCoreCbsReferReceivedCb cb) {
281 cbs->vtable->refer_received = cb;
282 }
283
linphone_core_cbs_get_call_encryption_changed(LinphoneCoreCbs * cbs)284 LinphoneCoreCbsCallEncryptionChangedCb linphone_core_cbs_get_call_encryption_changed(LinphoneCoreCbs *cbs) {
285 return cbs->vtable->call_encryption_changed;
286 }
287
linphone_core_cbs_set_call_encryption_changed(LinphoneCoreCbs * cbs,LinphoneCoreCbsCallEncryptionChangedCb cb)288 void linphone_core_cbs_set_call_encryption_changed(LinphoneCoreCbs *cbs, LinphoneCoreCbsCallEncryptionChangedCb cb) {
289 cbs->vtable->call_encryption_changed = cb;
290 }
291
linphone_core_cbs_get_transfer_state_changed(LinphoneCoreCbs * cbs)292 LinphoneCoreCbsTransferStateChangedCb linphone_core_cbs_get_transfer_state_changed(LinphoneCoreCbs *cbs) {
293 return cbs->vtable->transfer_state_changed;
294 }
295
linphone_core_cbs_set_transfer_state_changed(LinphoneCoreCbs * cbs,LinphoneCoreCbsTransferStateChangedCb cb)296 void linphone_core_cbs_set_transfer_state_changed(LinphoneCoreCbs *cbs, LinphoneCoreCbsTransferStateChangedCb cb) {
297 cbs->vtable->transfer_state_changed = cb;
298 }
299
linphone_core_cbs_get_buddy_info_updated(LinphoneCoreCbs * cbs)300 LinphoneCoreCbsBuddyInfoUpdatedCb linphone_core_cbs_get_buddy_info_updated(LinphoneCoreCbs *cbs) {
301 return cbs->vtable->buddy_info_updated;
302 }
303
linphone_core_cbs_set_buddy_info_updated(LinphoneCoreCbs * cbs,LinphoneCoreCbsBuddyInfoUpdatedCb cb)304 void linphone_core_cbs_set_buddy_info_updated(LinphoneCoreCbs *cbs, LinphoneCoreCbsBuddyInfoUpdatedCb cb) {
305 cbs->vtable->buddy_info_updated = cb;
306 }
307
linphone_core_cbs_get_call_stats_updated(LinphoneCoreCbs * cbs)308 LinphoneCoreCbsCallStatsUpdatedCb linphone_core_cbs_get_call_stats_updated(LinphoneCoreCbs *cbs) {
309 return cbs->vtable->call_stats_updated;
310 }
311
linphone_core_cbs_set_call_stats_updated(LinphoneCoreCbs * cbs,LinphoneCoreCbsCallStatsUpdatedCb cb)312 void linphone_core_cbs_set_call_stats_updated(LinphoneCoreCbs *cbs, LinphoneCoreCbsCallStatsUpdatedCb cb) {
313 cbs->vtable->call_stats_updated = cb;
314 }
315
linphone_core_cbs_get_info_received(LinphoneCoreCbs * cbs)316 LinphoneCoreCbsInfoReceivedCb linphone_core_cbs_get_info_received(LinphoneCoreCbs *cbs) {
317 return cbs->vtable->info_received;
318 }
319
linphone_core_cbs_set_info_received(LinphoneCoreCbs * cbs,LinphoneCoreCbsInfoReceivedCb cb)320 void linphone_core_cbs_set_info_received(LinphoneCoreCbs *cbs, LinphoneCoreCbsInfoReceivedCb cb) {
321 cbs->vtable->info_received = cb;
322 }
323
linphone_core_cbs_get_subscription_state_changed(LinphoneCoreCbs * cbs)324 LinphoneCoreCbsSubscriptionStateChangedCb linphone_core_cbs_get_subscription_state_changed(LinphoneCoreCbs *cbs) {
325 return cbs->vtable->subscription_state_changed;
326 }
327
linphone_core_cbs_set_subscription_state_changed(LinphoneCoreCbs * cbs,LinphoneCoreCbsSubscriptionStateChangedCb cb)328 void linphone_core_cbs_set_subscription_state_changed(LinphoneCoreCbs *cbs, LinphoneCoreCbsSubscriptionStateChangedCb cb) {
329 cbs->vtable->subscription_state_changed = cb;
330 }
331
linphone_core_cbs_get_notify_received(LinphoneCoreCbs * cbs)332 LinphoneCoreCbsNotifyReceivedCb linphone_core_cbs_get_notify_received(LinphoneCoreCbs *cbs) {
333 return cbs->vtable->notify_received;
334 }
335
linphone_core_cbs_set_notify_received(LinphoneCoreCbs * cbs,LinphoneCoreCbsNotifyReceivedCb cb)336 void linphone_core_cbs_set_notify_received(LinphoneCoreCbs *cbs, LinphoneCoreCbsNotifyReceivedCb cb) {
337 cbs->vtable->notify_received = cb;
338 }
339
linphone_core_cbs_get_rpublish_state_changed(LinphoneCoreCbs * cbs)340 LinphoneCoreCbsPublishStateChangedCb linphone_core_cbs_get_rpublish_state_changed(LinphoneCoreCbs *cbs) {
341 return cbs->vtable->publish_state_changed;
342 }
343
linphone_core_cbs_set_publish_state_changed(LinphoneCoreCbs * cbs,LinphoneCoreCbsPublishStateChangedCb cb)344 void linphone_core_cbs_set_publish_state_changed(LinphoneCoreCbs *cbs, LinphoneCoreCbsPublishStateChangedCb cb) {
345 cbs->vtable->publish_state_changed = cb;
346 }
347
linphone_core_cbs_get_configuring_status(LinphoneCoreCbs * cbs)348 LinphoneCoreCbsConfiguringStatusCb linphone_core_cbs_get_configuring_status(LinphoneCoreCbs *cbs) {
349 return cbs->vtable->configuring_status;
350 }
351
linphone_core_cbs_set_configuring_status(LinphoneCoreCbs * cbs,LinphoneCoreCbsConfiguringStatusCb cb)352 void linphone_core_cbs_set_configuring_status(LinphoneCoreCbs *cbs, LinphoneCoreCbsConfiguringStatusCb cb) {
353 cbs->vtable->configuring_status = cb;
354 }
355
linphone_core_cbs_get_network_reachable(LinphoneCoreCbs * cbs)356 LinphoneCoreCbsNetworkReachableCb linphone_core_cbs_get_network_reachable(LinphoneCoreCbs *cbs) {
357 return cbs->vtable->network_reachable;
358 }
359
linphone_core_cbs_set_network_reachable(LinphoneCoreCbs * cbs,LinphoneCoreCbsNetworkReachableCb cb)360 void linphone_core_cbs_set_network_reachable(LinphoneCoreCbs *cbs, LinphoneCoreCbsNetworkReachableCb cb) {
361 cbs->vtable->network_reachable = cb;
362 }
363
linphone_core_cbs_log_collection_upload_state_changed(LinphoneCoreCbs * cbs)364 LinphoneCoreCbsLogCollectionUploadStateChangedCb linphone_core_cbs_log_collection_upload_state_changed(LinphoneCoreCbs *cbs) {
365 return cbs->vtable->log_collection_upload_state_changed;
366 }
367
linphone_core_cbs_set_log_collection_upload_state_changed(LinphoneCoreCbs * cbs,LinphoneCoreCbsLogCollectionUploadStateChangedCb cb)368 void linphone_core_cbs_set_log_collection_upload_state_changed(LinphoneCoreCbs *cbs, LinphoneCoreCbsLogCollectionUploadStateChangedCb cb) {
369 cbs->vtable->log_collection_upload_state_changed = cb;
370 }
371
linphone_core_cbs_get_rlog_collection_upload_progress_indication(LinphoneCoreCbs * cbs)372 LinphoneCoreCbsLogCollectionUploadProgressIndicationCb linphone_core_cbs_get_rlog_collection_upload_progress_indication(LinphoneCoreCbs *cbs) {
373 return cbs->vtable->log_collection_upload_progress_indication;
374 }
375
linphone_core_cbs_set_log_collection_upload_progress_indication(LinphoneCoreCbs * cbs,LinphoneCoreCbsLogCollectionUploadProgressIndicationCb cb)376 void linphone_core_cbs_set_log_collection_upload_progress_indication(LinphoneCoreCbs *cbs, LinphoneCoreCbsLogCollectionUploadProgressIndicationCb cb) {
377 cbs->vtable->log_collection_upload_progress_indication = cb;
378 }
379
linphone_core_cbs_get_friend_list_created(LinphoneCoreCbs * cbs)380 LinphoneCoreCbsFriendListCreatedCb linphone_core_cbs_get_friend_list_created(LinphoneCoreCbs *cbs) {
381 return cbs->vtable->friend_list_created;
382 }
383
linphone_core_cbs_set_friend_list_created(LinphoneCoreCbs * cbs,LinphoneCoreCbsFriendListCreatedCb cb)384 void linphone_core_cbs_set_friend_list_created(LinphoneCoreCbs *cbs, LinphoneCoreCbsFriendListCreatedCb cb) {
385 cbs->vtable->friend_list_created = cb;
386 }
387
linphone_core_cbs_get_friend_list_removed(LinphoneCoreCbs * cbs)388 LinphoneCoreCbsFriendListRemovedCb linphone_core_cbs_get_friend_list_removed(LinphoneCoreCbs *cbs) {
389 return cbs->vtable->friend_list_removed;
390 }
391
linphone_core_cbs_set_friend_list_removed(LinphoneCoreCbs * cbs,LinphoneCoreCbsFriendListRemovedCb cb)392 void linphone_core_cbs_set_friend_list_removed(LinphoneCoreCbs *cbs, LinphoneCoreCbsFriendListRemovedCb cb) {
393 cbs->vtable->friend_list_removed = cb;
394 }
395
linphone_core_cbs_get_call_created(LinphoneCoreCbs * cbs)396 LinphoneCoreCbsCallCreatedCb linphone_core_cbs_get_call_created(LinphoneCoreCbs *cbs) {
397 return cbs->vtable->call_created;
398 }
399
linphone_core_cbs_set_call_created(LinphoneCoreCbs * cbs,LinphoneCoreCbsCallCreatedCb cb)400 void linphone_core_cbs_set_call_created(LinphoneCoreCbs *cbs, LinphoneCoreCbsCallCreatedCb cb) {
401 cbs->vtable->call_created = cb;
402 }
403
linphone_core_cbs_get_version_update_check_result_received(LinphoneCoreCbs * cbs)404 LinphoneCoreCbsVersionUpdateCheckResultReceivedCb linphone_core_cbs_get_version_update_check_result_received(LinphoneCoreCbs *cbs) {
405 return cbs->vtable->version_update_check_result_received;
406 }
407
linphone_core_cbs_set_version_update_check_result_received(LinphoneCoreCbs * cbs,LinphoneCoreCbsVersionUpdateCheckResultReceivedCb cb)408 void linphone_core_cbs_set_version_update_check_result_received(LinphoneCoreCbs *cbs, LinphoneCoreCbsVersionUpdateCheckResultReceivedCb cb) {
409 cbs->vtable->version_update_check_result_received = cb;
410 }
411
412
413 typedef belle_sip_object_t_vptr_t LinphoneCore_vptr_t;
414 BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneCore);
415 BELLE_SIP_INSTANCIATE_VPTR(LinphoneCore, belle_sip_object_t,
416 linphone_core_uninit, // destroy
417 NULL, // clone
418 NULL, // Marshall
419 FALSE
420 );
421
lc_callback_obj_init(LCCallbackObj * obj,LinphoneCoreCbFunc func,void * ud)422 void lc_callback_obj_init(LCCallbackObj *obj,LinphoneCoreCbFunc func,void* ud) {
423 obj->_func=func;
424 obj->_user_data=ud;
425 }
426
lc_callback_obj_invoke(LCCallbackObj * obj,LinphoneCore * lc)427 int lc_callback_obj_invoke(LCCallbackObj *obj, LinphoneCore *lc){
428 if (obj->_func!=NULL) obj->_func(lc,obj->_user_data);
429 return 0;
430 }
431
linphone_call_asked_to_autoanswer(LinphoneCall * call)432 bool_t linphone_call_asked_to_autoanswer(LinphoneCall *call){
433 //return TRUE if the unique(for the moment) incoming call asked to be autoanswered
434 if(call)
435 return sal_call_autoanswer_asked(call->op);
436 else
437 return FALSE;
438 }
439
linphone_core_get_current_call_duration(const LinphoneCore * lc)440 int linphone_core_get_current_call_duration(const LinphoneCore *lc){
441 LinphoneCall *call=linphone_core_get_current_call((LinphoneCore *)lc);
442 if (call) return linphone_call_get_duration(call);
443 return -1;
444 }
445
linphone_core_get_current_call_remote_address(struct _LinphoneCore * lc)446 const LinphoneAddress *linphone_core_get_current_call_remote_address(struct _LinphoneCore *lc){
447 LinphoneCall *call=linphone_core_get_current_call(lc);
448 if (call==NULL) return NULL;
449 return linphone_call_get_remote_address(call);
450 }
451
452 static void linphone_core_log_collection_handler(const char *domain, OrtpLogLevel level, const char *fmt, va_list args);
453
linphone_core_set_log_handler(OrtpLogFunc logfunc)454 void linphone_core_set_log_handler(OrtpLogFunc logfunc) {
455 if (ortp_get_log_handler() == linphone_core_log_collection_handler) {
456 ms_message("There is already a log collection handler, keep it");
457 liblinphone_log_func = logfunc;
458 } else
459 ortp_set_log_handler(logfunc);
460 }
461
linphone_core_set_log_file(FILE * file)462 void linphone_core_set_log_file(FILE *file) {
463 if (file == NULL) file = stdout;
464 ortp_set_log_file(file);
465 }
466
linphone_core_set_log_level(OrtpLogLevel loglevel)467 void linphone_core_set_log_level(OrtpLogLevel loglevel) {
468 OrtpLogLevel mask = loglevel;
469 switch (loglevel) {
470 case ORTP_TRACE:
471 case ORTP_DEBUG:
472 mask |= ORTP_DEBUG;
473 BCTBX_NO_BREAK;
474 case ORTP_MESSAGE:
475 mask |= ORTP_MESSAGE;
476 BCTBX_NO_BREAK;
477 case ORTP_WARNING:
478 mask |= ORTP_WARNING;
479 BCTBX_NO_BREAK;
480 case ORTP_ERROR:
481 mask |= ORTP_ERROR;
482 BCTBX_NO_BREAK;
483 case ORTP_FATAL:
484 mask |= ORTP_FATAL;
485 break;
486 case ORTP_LOGLEV_END:
487 break;
488 }
489 linphone_core_set_log_level_mask(mask);
490 }
491
linphone_core_set_log_level_mask(unsigned int loglevel)492 void linphone_core_set_log_level_mask(unsigned int loglevel) {
493 ortp_set_log_level_mask(NULL, loglevel);
494 bctbx_set_log_level_mask(NULL, loglevel);
495 if (loglevel == 0) {
496 sal_disable_log();
497 } else {
498 sal_enable_log();
499 }
500 }
501
_open_log_collection_file_with_idx(int idx)502 static int _open_log_collection_file_with_idx(int idx) {
503 struct stat statbuf;
504 char *log_filename;
505
506 log_filename = ortp_strdup_printf("%s/%s%d.log",
507 liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH,
508 liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX,
509 idx);
510 liblinphone_log_collection_file = fopen(log_filename, "a");
511 ortp_free(log_filename);
512 if (liblinphone_log_collection_file == NULL) return -1;
513
514 fstat(fileno(liblinphone_log_collection_file), &statbuf);
515 if ((size_t)statbuf.st_size > liblinphone_log_collection_max_file_size) {
516 fclose(liblinphone_log_collection_file);
517 return -1;
518 }
519
520 liblinphone_log_collection_file_size = statbuf.st_size;
521 return 0;
522 }
523
_rotate_log_collection_files(void)524 static void _rotate_log_collection_files(void) {
525 char *log_filename1;
526 char *log_filename2;
527
528 log_filename1 = ortp_strdup_printf("%s/%s1.log",
529 liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH,
530 liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX);
531 log_filename2 = ortp_strdup_printf("%s/%s2.log",
532 liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH,
533 liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX);
534 unlink(log_filename1);
535 rename(log_filename2, log_filename1);
536 ortp_free(log_filename1);
537 ortp_free(log_filename2);
538 }
539
_open_log_collection_file(void)540 static void _open_log_collection_file(void) {
541 if (_open_log_collection_file_with_idx(1) < 0) {
542 if (_open_log_collection_file_with_idx(2) < 0) {
543 _rotate_log_collection_files();
544 _open_log_collection_file_with_idx(2);
545 }
546 }
547 }
548
_close_log_collection_file(void)549 static void _close_log_collection_file(void) {
550 if (liblinphone_log_collection_file) {
551 fclose(liblinphone_log_collection_file);
552 liblinphone_log_collection_file = NULL;
553 liblinphone_log_collection_file_size = 0;
554 }
555 }
556
linphone_core_log_collection_handler(const char * domain,OrtpLogLevel level,const char * fmt,va_list args)557 static void linphone_core_log_collection_handler(const char *domain, OrtpLogLevel level, const char *fmt, va_list args) {
558 const char *lname="undef";
559 char *msg;
560 struct timeval tp;
561 struct tm *lt;
562 time_t tt;
563 int ret;
564
565 if (liblinphone_log_func != NULL && liblinphone_log_func != linphone_core_log_collection_handler) {
566 #ifndef _WIN32
567 va_list args_copy;
568 va_copy(args_copy, args);
569 liblinphone_log_func(domain, level, fmt, args_copy);
570 va_end(args_copy);
571 #else
572 /* This works on 32 bits, luckily. */
573 /* TODO: va_copy is available in Visual Studio 2013. */
574 liblinphone_log_func(domain, level, fmt, args);
575 #endif
576 }
577
578 ortp_gettimeofday(&tp, NULL);
579 tt = (time_t)tp.tv_sec;
580 lt = localtime((const time_t*)&tt);
581
582 if ((level & ORTP_DEBUG) != 0) {
583 lname = "DEBUG";
584 } else if ((level & ORTP_MESSAGE) != 0) {
585 lname = "MESSAGE";
586 } else if ((level & ORTP_WARNING) != 0) {
587 lname = "WARNING";
588 } else if ((level & ORTP_ERROR) != 0) {
589 lname = "ERROR";
590 } else if ((level & ORTP_FATAL) != 0) {
591 lname = "FATAL";
592 } else {
593 ortp_fatal("Bad level !");
594 }
595 msg = ortp_strdup_vprintf(fmt, args);
596
597 if (liblinphone_log_collection_file == NULL) {
598 ortp_mutex_lock(&liblinphone_log_collection_mutex);
599 _open_log_collection_file();
600 ortp_mutex_unlock(&liblinphone_log_collection_mutex);
601 }
602 if (liblinphone_log_collection_file) {
603 ortp_mutex_lock(&liblinphone_log_collection_mutex);
604 ret = fprintf(liblinphone_log_collection_file,"%i-%.2i-%.2i %.2i:%.2i:%.2i:%.3i %s %s\n",
605 1900 + lt->tm_year, lt->tm_mon + 1, lt->tm_mday, lt->tm_hour, lt->tm_min, lt->tm_sec, (int)(tp.tv_usec / 1000), lname, msg);
606 fflush(liblinphone_log_collection_file);
607 if (ret > 0) {
608 liblinphone_log_collection_file_size += ret;
609 if (liblinphone_log_collection_file_size > liblinphone_log_collection_max_file_size) {
610 _close_log_collection_file();
611 _open_log_collection_file();
612 }
613 }
614 ortp_mutex_unlock(&liblinphone_log_collection_mutex);
615 }
616
617 ortp_free(msg);
618 }
619
linphone_core_get_log_collection_path(void)620 const char * linphone_core_get_log_collection_path(void) {
621 if (liblinphone_log_collection_path != NULL) {
622 return liblinphone_log_collection_path;
623 }
624 return LOG_COLLECTION_DEFAULT_PATH;
625 }
626
linphone_core_set_log_collection_path(const char * path)627 void linphone_core_set_log_collection_path(const char *path) {
628 if (liblinphone_log_collection_path != NULL) {
629 ms_free(liblinphone_log_collection_path);
630 liblinphone_log_collection_path = NULL;
631 }
632 if (path != NULL) {
633 liblinphone_log_collection_path = ms_strdup(path);
634 }
635 }
636
linphone_core_get_log_collection_prefix(void)637 const char * linphone_core_get_log_collection_prefix(void) {
638 if (liblinphone_log_collection_prefix != NULL) {
639 return liblinphone_log_collection_prefix;
640 }
641 return LOG_COLLECTION_DEFAULT_PREFIX;
642 }
643
linphone_core_set_log_collection_prefix(const char * prefix)644 void linphone_core_set_log_collection_prefix(const char *prefix) {
645 if (liblinphone_log_collection_prefix != NULL) {
646 ms_free(liblinphone_log_collection_prefix);
647 liblinphone_log_collection_prefix = NULL;
648 }
649 if (prefix != NULL) {
650 liblinphone_log_collection_prefix = ms_strdup(prefix);
651 }
652 }
653
linphone_core_get_log_collection_max_file_size(void)654 size_t linphone_core_get_log_collection_max_file_size(void) {
655 return liblinphone_log_collection_max_file_size;
656 }
657
linphone_core_set_log_collection_max_file_size(size_t size)658 void linphone_core_set_log_collection_max_file_size(size_t size) {
659 liblinphone_log_collection_max_file_size = size;
660 }
661
linphone_core_get_log_collection_upload_server_url(LinphoneCore * core)662 const char *linphone_core_get_log_collection_upload_server_url(LinphoneCore *core) {
663 return lp_config_get_string(core->config, "misc", "log_collection_upload_server_url", NULL);
664 }
665
linphone_core_set_log_collection_upload_server_url(LinphoneCore * core,const char * server_url)666 void linphone_core_set_log_collection_upload_server_url(LinphoneCore *core, const char *server_url) {
667 lp_config_set_string(core->config, "misc", "log_collection_upload_server_url", server_url);
668 }
669
linphone_core_log_collection_enabled(void)670 LinphoneLogCollectionState linphone_core_log_collection_enabled(void) {
671 return liblinphone_log_collection_state;
672 }
673
linphone_core_enable_log_collection(LinphoneLogCollectionState state)674 void linphone_core_enable_log_collection(LinphoneLogCollectionState state) {
675 if (liblinphone_log_collection_state == state) return;
676
677 /* at first call of this function, set liblinphone_log_func to the current
678 * ortp log function */
679 if( liblinphone_log_func == NULL ){
680 liblinphone_log_func = ortp_get_log_handler();
681 }
682 liblinphone_log_collection_state = state;
683 if (state != LinphoneLogCollectionDisabled) {
684 ortp_mutex_init(&liblinphone_log_collection_mutex, NULL);
685 if (state == LinphoneLogCollectionEnabledWithoutPreviousLogHandler) {
686 liblinphone_log_func = NULL;
687 } else {
688 liblinphone_log_func = ortp_get_log_handler();
689 }
690 ortp_set_log_handler(linphone_core_log_collection_handler);
691 } else {
692 ortp_set_log_handler(liblinphone_log_func);
693 }
694 }
695
clean_log_collection_upload_context(LinphoneCore * lc)696 static void clean_log_collection_upload_context(LinphoneCore *lc) {
697 char *filename = ms_strdup_printf("%s/%s_log.%s",
698 liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH,
699 liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX,
700 COMPRESSED_LOG_COLLECTION_EXTENSION);
701 unlink(filename);
702 ms_free(filename);
703 if (lc && lc->log_collection_upload_information) {
704 linphone_content_unref(lc->log_collection_upload_information);
705 lc->log_collection_upload_information=NULL;
706 }
707 }
708
process_io_error_upload_log_collection(void * data,const belle_sip_io_error_event_t * event)709 static void process_io_error_upload_log_collection(void *data, const belle_sip_io_error_event_t *event) {
710 LinphoneCore *core = (LinphoneCore *)data;
711 ms_error("I/O Error during log collection upload to %s", linphone_core_get_log_collection_upload_server_url(core));
712 linphone_core_notify_log_collection_upload_state_changed(core, LinphoneCoreLogCollectionUploadStateNotDelivered, "I/O Error");
713 clean_log_collection_upload_context(core);
714 }
715
process_auth_requested_upload_log_collection(void * data,belle_sip_auth_event_t * event)716 static void process_auth_requested_upload_log_collection(void *data, belle_sip_auth_event_t *event) {
717 LinphoneCore *core = (LinphoneCore *)data;
718 ms_error("Error during log collection upload: auth requested to connect %s", linphone_core_get_log_collection_upload_server_url(core));
719 linphone_core_notify_log_collection_upload_state_changed(core, LinphoneCoreLogCollectionUploadStateNotDelivered, "Auth requested");
720 clean_log_collection_upload_context(core);
721 }
722
723 /**
724 * Callback called when posting a log collection file to server (following rcs5.1 recommendation)
725 * @param[in] bh The body handler
726 * @param[in] msg The belle sip message
727 * @param[in] data The user data associated with the handler, contains the LinphoneCore object
728 * @param[in] offset The current position in the input buffer
729 * @param[in] buffer The ouput buffer where to copy the data to be uploaded
730 * @param[in,out] size The size in byte of the data requested, as output it will contain the effective copied size
731 */
log_collection_upload_on_send_body(belle_sip_user_body_handler_t * bh,belle_sip_message_t * msg,void * data,size_t offset,uint8_t * buffer,size_t * size)732 static int log_collection_upload_on_send_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *msg, void *data, size_t offset, uint8_t *buffer, size_t *size) {
733 LinphoneCore *core = (LinphoneCore *)data;
734
735 /* If we've not reach the end of file yet, fill the buffer with more data */
736 if (offset < linphone_content_get_size(core->log_collection_upload_information)) {
737 char *log_filename = ms_strdup_printf("%s/%s_log.%s",
738 liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH,
739 liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX,
740 COMPRESSED_LOG_COLLECTION_EXTENSION);
741 #ifdef HAVE_ZLIB
742 FILE *log_file = fopen(log_filename, "rb");
743 #else
744 FILE *log_file = fopen(log_filename, "r");
745 #endif
746 if (fseek(log_file, (long)offset, SEEK_SET)) {
747 ms_error("Cannot seek file [%s] at position [%lu] errno [%s]",log_filename,(unsigned long)offset,strerror(errno));
748
749 } else {
750 *size = fread(buffer, 1, *size, log_file);
751 }
752 fclose(log_file);
753 ms_free(log_filename);
754 return BELLE_SIP_CONTINUE;
755 } else {
756 *size=0;
757 return BELLE_SIP_STOP;
758 }
759 }
760
761 /**
762 * Callback called during upload of a log collection to server.
763 * It is just forwarding the call and some parameters to the vtable defined callback.
764 */
log_collection_upload_on_progress(belle_sip_body_handler_t * bh,belle_sip_message_t * msg,void * data,size_t offset,size_t total)765 static void log_collection_upload_on_progress(belle_sip_body_handler_t *bh, belle_sip_message_t *msg, void *data, size_t offset, size_t total) {
766 LinphoneCore *core = (LinphoneCore *)data;
767 linphone_core_notify_log_collection_upload_progress_indication(core, offset, total);
768 }
769
770 /**
771 * Callback function called when we have a response from server during the upload of the log collection to the server (rcs5.1 recommandation)
772 * Note: The first post is empty and the server shall reply a 204 (No content) message, this will trigger a new post request to the server
773 * to upload the file. The server response to this second post is processed by this same function
774 *
775 * @param[in] data The user-defined pointer associated with the request, it contains the LinphoneCore object
776 * @param[in] event The response from server
777 */
process_response_from_post_file_log_collection(void * data,const belle_http_response_event_t * event)778 static void process_response_from_post_file_log_collection(void *data, const belle_http_response_event_t *event) {
779 LinphoneCore *core = (LinphoneCore *)data;
780
781 /* Check the answer code */
782 if (event->response) {
783 int code = belle_http_response_get_status_code(event->response);
784 if (code == 204) { /* This is the reply to the first post to the server - an empty file */
785 /* Start uploading the file */
786 belle_http_request_listener_callbacks_t cbs = { 0 };
787 belle_http_request_listener_t *l;
788 belle_generic_uri_t *uri;
789 belle_http_request_t *req;
790 belle_sip_multipart_body_handler_t *bh;
791 char* ua;
792 char *first_part_header;
793 belle_sip_user_body_handler_t *first_part_bh;
794
795 linphone_core_notify_log_collection_upload_state_changed(core, LinphoneCoreLogCollectionUploadStateInProgress, NULL);
796
797 /* Temporary storage for the Content-disposition header value */
798 first_part_header = belle_sip_strdup_printf("form-data; name=\"File\"; filename=\"%s\"", linphone_content_get_name(core->log_collection_upload_information));
799
800 /* Create a user body handler to take care of the file and add the content disposition and content-type headers */
801 first_part_bh = belle_sip_user_body_handler_new(linphone_content_get_size(core->log_collection_upload_information), NULL, NULL, NULL, log_collection_upload_on_send_body, NULL, core);
802 belle_sip_body_handler_add_header((belle_sip_body_handler_t *)first_part_bh, belle_sip_header_create("Content-disposition", first_part_header));
803 belle_sip_free(first_part_header);
804 belle_sip_body_handler_add_header((belle_sip_body_handler_t *)first_part_bh,
805 (belle_sip_header_t *)belle_sip_header_content_type_create(linphone_content_get_type(core->log_collection_upload_information), linphone_content_get_subtype(core->log_collection_upload_information)));
806
807 /* Insert it in a multipart body handler which will manage the boundaries of multipart message */
808 bh = belle_sip_multipart_body_handler_new(log_collection_upload_on_progress, core, (belle_sip_body_handler_t *)first_part_bh, NULL);
809 ua = ms_strdup_printf("%s/%s", linphone_core_get_user_agent(core), linphone_core_get_version());
810 uri = belle_generic_uri_parse(linphone_core_get_log_collection_upload_server_url(core));
811 req = belle_http_request_create("POST", uri, belle_sip_header_create("User-Agent", ua), NULL);
812 ms_free(ua);
813 belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(req), BELLE_SIP_BODY_HANDLER(bh));
814 cbs.process_response = process_response_from_post_file_log_collection;
815 cbs.process_io_error = process_io_error_upload_log_collection;
816 cbs.process_auth_requested = process_auth_requested_upload_log_collection;
817 l = belle_http_request_listener_create_from_callbacks(&cbs, core);
818 belle_sip_object_data_set(BELLE_SIP_OBJECT(req), "http_request_listener", l, belle_sip_object_unref); // Ensure the listener object is destroyed when the request is destroyed
819 belle_http_provider_send_request(core->http_provider, req, l);
820 } else if (code == 200) { /* The file has been uploaded correctly, get the server reply */
821 xmlDocPtr xmlMessageBody;
822 xmlNodePtr cur;
823 xmlChar *file_url = NULL;
824 const char *body = belle_sip_message_get_body((belle_sip_message_t *)event->response);
825 xmlMessageBody = xmlParseDoc((const xmlChar *)body);
826 cur = xmlDocGetRootElement(xmlMessageBody);
827 if (cur != NULL) {
828 cur = cur->xmlChildrenNode;
829 while (cur != NULL) {
830 if (!xmlStrcmp(cur->name, (const xmlChar *)"file-info")) { /* we found a file info node, check it has a type="file" attribute */
831 xmlChar *typeAttribute = xmlGetProp(cur, (const xmlChar *)"type");
832 if (!xmlStrcmp(typeAttribute, (const xmlChar *)"file")) { /* this is the node we are looking for */
833 cur = cur->xmlChildrenNode; /* now loop on the content of the file-info node */
834 while (cur != NULL) {
835 if (!xmlStrcmp(cur->name, (const xmlChar *)"data")) {
836 file_url = xmlGetProp(cur, (const xmlChar *)"url");
837 }
838 cur=cur->next;
839 }
840 xmlFree(typeAttribute);
841 break;
842 }
843 xmlFree(typeAttribute);
844 }
845 cur = cur->next;
846 }
847 }
848 if (file_url != NULL) {
849 linphone_core_notify_log_collection_upload_state_changed(core, LinphoneCoreLogCollectionUploadStateDelivered, (const char *)file_url);
850 }
851 clean_log_collection_upload_context(core);
852 } else {
853 ms_error("Unexpected HTTP response code %i during log collection upload to %s", code, linphone_core_get_log_collection_upload_server_url(core));
854 linphone_core_notify_log_collection_upload_state_changed(core, LinphoneCoreLogCollectionUploadStateNotDelivered, "Unexpected HTTP response");
855 clean_log_collection_upload_context(core);
856 }
857 }
858 }
859
860 #ifdef HAVE_ZLIB
861 #define COMPRESS_FILE_PTR gzFile
862 #define COMPRESS_OPEN gzopen
863 #define COMPRESS_CLOSE gzclose
864 #else
865 #define COMPRESS_FILE_PTR FILE*
866 #define COMPRESS_OPEN fopen
867 #define COMPRESS_CLOSE fclose
868 #endif
869
870 /**
871 * If zlib is not available the two log files are simply concatenated.
872 */
compress_file(FILE * input_file,COMPRESS_FILE_PTR output_file)873 static int compress_file(FILE *input_file, COMPRESS_FILE_PTR output_file) {
874 char buffer[131072]; /* 128kB */
875 size_t bytes;
876 size_t total_bytes = 0;
877
878 while ((bytes = fread(buffer, 1, sizeof(buffer), input_file)) > 0) {
879 #ifdef HAVE_ZLIB
880 int res = gzwrite(output_file, buffer, (unsigned int)bytes);
881 if (res < 0) return 0;
882 total_bytes += (size_t)res;
883 #else
884 total_bytes += fwrite(buffer, 1, bytes, output_file);
885 #endif
886 }
887 return (int)total_bytes;
888 }
889
prepare_log_collection_file_to_upload(const char * filename)890 static int prepare_log_collection_file_to_upload(const char *filename) {
891 char *input_filename = NULL;
892 char *output_filename = NULL;
893 FILE *input_file = NULL;
894 COMPRESS_FILE_PTR output_file = NULL;
895 int ret = 0;
896
897 ortp_mutex_lock(&liblinphone_log_collection_mutex);
898 output_filename = ms_strdup_printf("%s/%s",
899 liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH, filename);
900 output_file = COMPRESS_OPEN(output_filename, "wb");
901 if (output_file == NULL) goto error;
902 input_filename = ms_strdup_printf("%s/%s1.log",
903 liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH,
904 liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX);
905 input_file = fopen(input_filename, "rb");
906 if (input_file == NULL) goto error;
907 ret = compress_file(input_file, output_file);
908 if (ret <= 0) goto error;
909 fclose(input_file);
910 ms_free(input_filename);
911 input_filename = ms_strdup_printf("%s/%s2.log",
912 liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH,
913 liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX);
914 input_file = fopen(input_filename, "rb");
915 if (input_file != NULL) {
916 ret = compress_file(input_file, output_file);
917 if (ret <= 0) goto error;
918 }
919
920 error:
921 if (input_file != NULL) fclose(input_file);
922 if (output_file != NULL) COMPRESS_CLOSE(output_file);
923 if (input_filename != NULL) ms_free(input_filename);
924 if (output_filename != NULL) ms_free(output_filename);
925 ortp_mutex_unlock(&liblinphone_log_collection_mutex);
926 return ret;
927 }
928
get_size_of_file_to_upload(const char * filename)929 static size_t get_size_of_file_to_upload(const char *filename) {
930 struct stat statbuf;
931 char *output_filename = ms_strdup_printf("%s/%s",
932 liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH, filename);
933 FILE *output_file = fopen(output_filename, "rb");
934 fstat(fileno(output_file), &statbuf);
935 fclose(output_file);
936 ms_free(output_filename);
937 return statbuf.st_size;
938 }
939
linphone_core_upload_log_collection(LinphoneCore * core)940 void linphone_core_upload_log_collection(LinphoneCore *core) {
941 if ((core->log_collection_upload_information == NULL) && (linphone_core_get_log_collection_upload_server_url(core) != NULL) && (liblinphone_log_collection_state != LinphoneLogCollectionDisabled)) {
942 /* open a transaction with the server and send an empty request(RCS5.1 section 3.5.4.8.3.1) */
943 belle_http_request_listener_callbacks_t cbs = { 0 };
944 belle_http_request_listener_t *l;
945 belle_generic_uri_t *uri;
946 belle_http_request_t *req;
947 char *name;
948
949 core->log_collection_upload_information = linphone_core_create_content(core);
950 #ifdef HAVE_ZLIB
951 linphone_content_set_type(core->log_collection_upload_information, "application");
952 linphone_content_set_subtype(core->log_collection_upload_information, "gzip");
953 #else
954 linphone_content_set_type(core->log_collection_upload_information, "text");
955 linphone_content_set_subtype(core->log_collection_upload_information,"plain");
956 #endif
957 name = ms_strdup_printf("%s_log.%s",
958 liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX,
959 COMPRESSED_LOG_COLLECTION_EXTENSION);
960 linphone_content_set_name(core->log_collection_upload_information, name);
961 if (prepare_log_collection_file_to_upload(name) <= 0) {
962 linphone_content_unref(core->log_collection_upload_information);
963 core->log_collection_upload_information = NULL;
964 ms_error("prepare_log_collection_file_to_upload(): error.");
965 linphone_core_notify_log_collection_upload_state_changed(core, LinphoneCoreLogCollectionUploadStateNotDelivered, "Error while preparing log collection upload");
966 return;
967 }
968 linphone_content_set_size(core->log_collection_upload_information, get_size_of_file_to_upload(name));
969 uri = belle_generic_uri_parse(linphone_core_get_log_collection_upload_server_url(core));
970 req = belle_http_request_create("POST", uri, NULL, NULL, NULL);
971 cbs.process_response = process_response_from_post_file_log_collection;
972 cbs.process_io_error = process_io_error_upload_log_collection;
973 cbs.process_auth_requested = process_auth_requested_upload_log_collection;
974 l = belle_http_request_listener_create_from_callbacks(&cbs, core);
975 belle_sip_object_data_set(BELLE_SIP_OBJECT(req), "http_request_listener", l, belle_sip_object_unref); // Ensure the listener object is destroyed when the request is destroyed
976 belle_http_provider_send_request(core->http_provider, req, l);
977 ms_free(name);
978 } else {
979 const char *msg = NULL;
980 ms_warning("Could not upload log collection: log_collection_upload_information=%p, server_url=%s, log_collection_state=%d",
981 core->log_collection_upload_information, linphone_core_get_log_collection_upload_server_url(core), liblinphone_log_collection_state);
982 if (core->log_collection_upload_information != NULL) {
983 msg = "Log collection upload already in progress";
984 } else if (linphone_core_get_log_collection_upload_server_url(core) == NULL) {
985 msg = "Log collection upload server not set";
986 } else if (liblinphone_log_collection_state == LinphoneLogCollectionDisabled) {
987 msg = "Log collection is disabled";
988 }
989 linphone_core_notify_log_collection_upload_state_changed(core, LinphoneCoreLogCollectionUploadStateNotDelivered, msg);
990 }
991 }
992
linphone_core_compress_log_collection(void)993 char * linphone_core_compress_log_collection(void) {
994 char *filename = NULL;
995 if (liblinphone_log_collection_state == LinphoneLogCollectionDisabled) return NULL;
996 filename = ms_strdup_printf("%s_log.%s",
997 liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX,
998 COMPRESSED_LOG_COLLECTION_EXTENSION);
999 if (prepare_log_collection_file_to_upload(filename) <= 0) {
1000 ms_free(filename);
1001 return NULL;
1002 }
1003 ms_free(filename);
1004 return ms_strdup_printf("%s/%s_log.%s",
1005 liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH,
1006 liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX,
1007 COMPRESSED_LOG_COLLECTION_EXTENSION);
1008 }
1009
linphone_core_reset_log_collection(void)1010 void linphone_core_reset_log_collection(void) {
1011 char *filename;
1012 ortp_mutex_lock(&liblinphone_log_collection_mutex);
1013 _close_log_collection_file();
1014 clean_log_collection_upload_context(NULL);
1015 filename = ms_strdup_printf("%s/%s1.log",
1016 liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH,
1017 liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX);
1018 unlink(filename);
1019 ms_free(filename);
1020 filename = ms_strdup_printf("%s/%s2.log",
1021 liblinphone_log_collection_path ? liblinphone_log_collection_path : LOG_COLLECTION_DEFAULT_PATH,
1022 liblinphone_log_collection_prefix ? liblinphone_log_collection_prefix : LOG_COLLECTION_DEFAULT_PREFIX);
1023 unlink(filename);
1024 ms_free(filename);
1025 liblinphone_log_collection_file = NULL;
1026 liblinphone_log_collection_file_size = 0;
1027 ortp_mutex_unlock(&liblinphone_log_collection_mutex);
1028 }
1029
linphone_core_enable_logs(FILE * file)1030 void linphone_core_enable_logs(FILE *file){
1031 if (file==NULL) file=stdout;
1032 ortp_set_log_file(file);
1033 linphone_core_set_log_level(ORTP_MESSAGE);
1034 }
1035
linphone_core_enable_logs_with_cb(OrtpLogFunc logfunc)1036 void linphone_core_enable_logs_with_cb(OrtpLogFunc logfunc){
1037 linphone_core_set_log_level(ORTP_MESSAGE);
1038 linphone_core_set_log_handler(logfunc);
1039 }
1040
linphone_core_disable_logs(void)1041 void linphone_core_disable_logs(void){
1042 linphone_core_set_log_level(ORTP_ERROR);
1043 }
1044
linphone_core_serialize_logs(void)1045 void linphone_core_serialize_logs(void) {
1046 liblinphone_serialize_logs = TRUE;
1047 }
1048
1049
net_config_read(LinphoneCore * lc)1050 static void net_config_read(LinphoneCore *lc) {
1051 int tmp;
1052 const char *tmpstr;
1053 LpConfig *config=lc->config;
1054 const char *nat_policy_ref;
1055
1056 nat_policy_ref = lp_config_get_string(lc->config, "net", "nat_policy_ref", NULL);
1057 if (nat_policy_ref != NULL) {
1058 lc->nat_policy = linphone_core_create_nat_policy_from_config(lc, nat_policy_ref);
1059 }
1060 if (lc->nat_policy == NULL){
1061 /*this will create a default nat policy according to deprecated config keys, or an empty nat policy otherwise*/
1062 linphone_core_set_firewall_policy(lc, linphone_core_get_firewall_policy(lc));
1063 }
1064
1065 lc->net_conf.nat_address_ip = NULL;
1066 tmp=lp_config_get_int(config,"net","download_bw",0);
1067 linphone_core_set_download_bandwidth(lc,tmp);
1068 tmp=lp_config_get_int(config,"net","upload_bw",0);
1069 linphone_core_set_upload_bandwidth(lc,tmp);
1070 tmp=lp_config_get_int(config, "net", "expected_bw", 0);
1071 linphone_core_set_expected_bandwidth(lc, tmp);
1072
1073 tmpstr=lp_config_get_string(lc->config,"net","nat_address",NULL);
1074 if (tmpstr!=NULL && (strlen(tmpstr)<1)) tmpstr=NULL;
1075 linphone_core_set_nat_address(lc,tmpstr);
1076 tmp=lp_config_get_int(lc->config,"net","nat_sdp_only",0);
1077 lc->net_conf.nat_sdp_only=tmp;
1078 tmp=lp_config_get_int(lc->config,"net","mtu",1300);
1079 linphone_core_set_mtu(lc,tmp);
1080 tmp=lp_config_get_int(lc->config,"net","download_ptime",-1);
1081 if (tmp !=-1 && linphone_core_get_download_ptime(lc) !=0) {
1082 /*legacy parameter*/
1083 linphone_core_set_download_ptime(lc,tmp);
1084 }
1085 tmp = lp_config_get_int(lc->config, "net", "dns_srv_enabled", 1);
1086 linphone_core_enable_dns_srv(lc, tmp);
1087 tmp = lp_config_get_int(lc->config, "net", "dns_search_enabled", 1);
1088 linphone_core_enable_dns_search(lc, tmp);
1089 }
1090
build_sound_devices_table(LinphoneCore * lc)1091 static void build_sound_devices_table(LinphoneCore *lc){
1092 const char **devices;
1093 const char **old;
1094 size_t ndev;
1095 int i;
1096 const bctbx_list_t *elem=ms_snd_card_manager_get_list(ms_factory_get_snd_card_manager(lc->factory));
1097 ndev=bctbx_list_size(elem);
1098 devices=ms_malloc((ndev+1)*sizeof(const char *));
1099 for (i=0;elem!=NULL;elem=elem->next,i++){
1100 devices[i]=ms_snd_card_get_string_id((MSSndCard *)elem->data);
1101 }
1102 devices[ndev]=NULL;
1103 old=lc->sound_conf.cards;
1104 lc->sound_conf.cards=devices;
1105 if (old!=NULL) ms_free((void *)old);
1106 }
1107
get_default_local_ring(LinphoneCore * lc)1108 static char *get_default_local_ring(LinphoneCore * lc) {
1109 LinphoneFactory *factory = linphone_factory_get();
1110 if (linphone_core_file_format_supported(lc, "mkv")) {
1111 return bctbx_strdup_printf("%s/%s", linphone_factory_get_ring_resources_dir(factory), LOCAL_RING_MKV);
1112 }
1113 return bctbx_strdup_printf("%s/%s", linphone_factory_get_ring_resources_dir(factory), LOCAL_RING_WAV);
1114 }
1115
get_default_onhold_music(LinphoneCore * lc)1116 static char *get_default_onhold_music(LinphoneCore * lc) {
1117 LinphoneFactory *factory = linphone_factory_get();
1118 if (linphone_core_file_format_supported(lc, "mkv")) {
1119 return bctbx_strdup_printf("%s/%s", linphone_factory_get_sound_resources_dir(factory), HOLD_MUSIC_MKV);
1120 }
1121 return bctbx_strdup_printf("%s/%s", linphone_factory_get_sound_resources_dir(factory), HOLD_MUSIC_WAV);
1122 }
1123
sound_config_read(LinphoneCore * lc)1124 static void sound_config_read(LinphoneCore *lc)
1125 {
1126 int tmp;
1127 char *default_remote_ring;
1128 const char *tmpbuf;
1129 const char *devid;
1130 LinphoneFactory *factory = linphone_factory_get();
1131
1132 #ifdef __linux
1133 /*alsadev let the user use custom alsa device within linphone*/
1134 devid=lp_config_get_string(lc->config,"sound","alsadev",NULL);
1135 if (devid){
1136 MSSndCard* card;
1137 const char* delim=",";
1138 size_t l=strlen(devid);
1139 char* d=malloc(l+1);
1140 char* i;
1141 memcpy(d,devid,l+1);
1142 for (l=0,i=strpbrk(d+l,delim);i;i=strpbrk(d+l,delim)){
1143 char s=*i;
1144 *i='\0';
1145 card=ms_alsa_card_new_custom(d+l,d+l);
1146 ms_snd_card_manager_add_card(ms_factory_get_snd_card_manager(lc->factory),card);
1147 *i=s;
1148 l=i-d+1;
1149 }
1150 if(d[l]!='\0') {
1151 card=ms_alsa_card_new_custom(d+l,d+l);
1152 ms_snd_card_manager_add_card(ms_factory_get_snd_card_manager(lc->factory),card);
1153 }
1154 free(d);
1155 }
1156 tmp=lp_config_get_int(lc->config,"sound","alsa_forced_rate",-1);
1157 if (tmp>0) ms_alsa_card_set_forced_sample_rate(tmp);
1158 #endif
1159 /* retrieve all sound devices */
1160 build_sound_devices_table(lc);
1161
1162 devid=lp_config_get_string(lc->config,"sound","playback_dev_id",NULL);
1163 linphone_core_set_playback_device(lc,devid);
1164
1165 devid=lp_config_get_string(lc->config,"sound","ringer_dev_id",NULL);
1166 linphone_core_set_ringer_device(lc,devid);
1167
1168 devid=lp_config_get_string(lc->config,"sound","capture_dev_id",NULL);
1169 linphone_core_set_capture_device(lc,devid);
1170
1171 /*
1172 tmp=lp_config_get_int(lc->config,"sound","play_lev",80);
1173 linphone_core_set_play_level(lc,tmp);
1174 tmp=lp_config_get_int(lc->config,"sound","ring_lev",80);
1175 linphone_core_set_ring_level(lc,tmp);
1176 tmp=lp_config_get_int(lc->config,"sound","rec_lev",80);
1177 linphone_core_set_rec_level(lc,tmp);
1178 tmpbuf=lp_config_get_string(lc->config,"sound","source","m");
1179 linphone_core_set_sound_source(lc,tmpbuf[0]);
1180 */
1181
1182 tmpbuf = lp_config_get_string(lc->config, "sound", "local_ring", NULL);
1183 if (tmpbuf) {
1184 if (bctbx_file_exist(tmpbuf) == 0) {
1185 linphone_core_set_ring(lc, tmpbuf);
1186 } else {
1187 ms_warning("'%s' ring file does not exist", tmpbuf);
1188 }
1189 } else {
1190 char *default_local_ring = get_default_local_ring(lc);
1191 linphone_core_set_ring(lc, default_local_ring);
1192 bctbx_free(default_local_ring);
1193 }
1194
1195 default_remote_ring = bctbx_strdup_printf("%s/%s", linphone_factory_get_sound_resources_dir(factory), REMOTE_RING_WAV);
1196 tmpbuf = default_remote_ring;
1197 tmpbuf = lp_config_get_string(lc->config, "sound", "remote_ring", tmpbuf);
1198 if (bctbx_file_exist(tmpbuf) == -1){
1199 tmpbuf = default_remote_ring;
1200 }
1201 if (strstr(tmpbuf, ".wav") == NULL) {
1202 /* It currently uses old sound files, so replace them */
1203 tmpbuf = default_remote_ring;
1204 }
1205 linphone_core_set_ringback(lc, tmpbuf);
1206 bctbx_free(default_remote_ring);
1207
1208 tmpbuf = lp_config_get_string(lc->config, "sound", "hold_music", NULL);
1209 if (tmpbuf) {
1210 if (bctbx_file_exist(tmpbuf) == 0) {
1211 linphone_core_set_play_file(lc, tmpbuf);
1212 } else {
1213 ms_warning("'%s' on-hold music file does not exist", tmpbuf);
1214 }
1215 } else {
1216 char *default_onhold_music = get_default_onhold_music(lc);
1217 linphone_core_set_play_file(lc, default_onhold_music);
1218 bctbx_free(default_onhold_music);
1219 }
1220
1221 lc->sound_conf.latency=0;
1222 #if !TARGET_OS_IPHONE
1223 tmp=TRUE;
1224 #else
1225 tmp=FALSE; /* on iOS we have builtin echo cancellation.*/
1226 #endif
1227 tmp=lp_config_get_int(lc->config,"sound","echocancellation",tmp);
1228 linphone_core_enable_echo_cancellation(lc,tmp);
1229 linphone_core_set_echo_canceller_filter_name(lc, linphone_core_get_echo_canceller_filter_name(lc));
1230 linphone_core_enable_echo_limiter(lc,
1231 lp_config_get_int(lc->config,"sound","echolimiter",0));
1232 linphone_core_enable_agc(lc,
1233 lp_config_get_int(lc->config,"sound","agc",0));
1234
1235 linphone_core_set_playback_gain_db (lc,lp_config_get_float(lc->config,"sound","playback_gain_db",0));
1236 linphone_core_set_mic_gain_db (lc,lp_config_get_float(lc->config,"sound","mic_gain_db",0));
1237
1238 linphone_core_set_remote_ringback_tone (lc,lp_config_get_string(lc->config,"sound","ringback_tone",NULL));
1239
1240 /*just parse requested stream feature once at start to print out eventual errors*/
1241 linphone_core_get_audio_features(lc);
1242
1243 _linphone_core_set_tone(lc,LinphoneReasonBusy,LinphoneToneBusy,NULL);
1244 }
1245
certificates_config_read(LinphoneCore * lc)1246 static void certificates_config_read(LinphoneCore *lc) {
1247 LinphoneFactory *factory = linphone_factory_get();
1248 const char *data_dir = linphone_factory_get_data_resources_dir(factory);
1249 char *root_ca_path = bctbx_strdup_printf("%s/rootca.pem", data_dir);
1250 const char *rootca = lp_config_get_string(lc->config,"sip","root_ca", NULL);
1251 // If rootca is not existing anymore, we reset it to the default value
1252 if (rootca == NULL || (bctbx_file_exist(rootca) != 0)) {
1253 #ifdef __linux
1254 struct stat sb;
1255 if (stat("/etc/ssl/certs", &sb) == 0 && S_ISDIR(sb.st_mode)) {
1256 rootca = "/etc/ssl/certs";
1257 } else
1258 #endif
1259 {
1260 if (bctbx_file_exist(root_ca_path) == 0) {
1261 rootca = root_ca_path;
1262 }
1263 }
1264 }
1265 linphone_core_set_root_ca(lc,rootca);
1266 linphone_core_verify_server_certificates(lc,lp_config_get_int(lc->config,"sip","verify_server_certs",TRUE));
1267 linphone_core_verify_server_cn(lc,lp_config_get_int(lc->config,"sip","verify_server_cn",TRUE));
1268 bctbx_free(root_ca_path);
1269 }
1270
sip_config_read(LinphoneCore * lc)1271 static void sip_config_read(LinphoneCore *lc) {
1272 char *contact;
1273 const char *tmpstr;
1274 LinphoneSipTransports tr;
1275 int i,tmp;
1276 int ipv6_default = TRUE;
1277
1278 if (lp_config_get_int(lc->config,"sip","use_session_timers",0)==1){
1279 sal_use_session_timers(lc->sal,200);
1280 }
1281
1282 sal_use_no_initial_route(lc->sal,lp_config_get_int(lc->config,"sip","use_no_initial_route",0));
1283 sal_use_rport(lc->sal,lp_config_get_int(lc->config,"sip","use_rport",1));
1284
1285 if (!lp_config_get_int(lc->config,"sip","ipv6_migration_done",FALSE) && lp_config_has_entry(lc->config,"sip","use_ipv6")) {
1286 lp_config_clean_entry(lc->config,"sip","use_ipv6");
1287 lp_config_set_int(lc->config, "sip", "ipv6_migration_done", TRUE);
1288 ms_message("IPV6 settings migration done.");
1289 }
1290
1291 lc->sip_conf.ipv6_enabled=lp_config_get_int(lc->config,"sip","use_ipv6",ipv6_default);
1292
1293 memset(&tr,0,sizeof(tr));
1294
1295 tr.udp_port=lp_config_get_int(lc->config,"sip","sip_port",5060);
1296 tr.tcp_port=lp_config_get_int(lc->config,"sip","sip_tcp_port",5060);
1297 /*we are not listening inbound connection for tls, port has no meaning*/
1298 tr.tls_port=lp_config_get_int(lc->config,"sip","sip_tls_port",LC_SIP_TRANSPORT_RANDOM);
1299
1300 certificates_config_read(lc);
1301 /*setting the dscp must be done before starting the transports, otherwise it is not taken into effect*/
1302 sal_set_dscp(lc->sal,linphone_core_get_sip_dscp(lc));
1303 /*start listening on ports*/
1304 linphone_core_set_sip_transports(lc,&tr);
1305
1306 tmpstr=lp_config_get_string(lc->config,"sip","contact",NULL);
1307 if (tmpstr==NULL || linphone_core_set_primary_contact(lc,tmpstr)==-1) {
1308 const char *hostname=NULL;
1309 const char *username=NULL;
1310 #if !defined(LINPHONE_WINDOWS_UNIVERSAL) && !defined(LINPHONE_WINDOWS_PHONE) // Using getenv is forbidden on Windows 10 and Windows Phone
1311 hostname=getenv("HOST");
1312 username=getenv("USER");
1313 if (hostname==NULL) hostname=getenv("HOSTNAME");
1314 #endif
1315 if (hostname==NULL)
1316 hostname="unknown-host";
1317 if (username==NULL){
1318 username="linphone";
1319 }
1320 contact=ortp_strdup_printf("sip:%s@%s",username,hostname);
1321 linphone_core_set_primary_contact(lc,contact);
1322 ms_free(contact);
1323 }
1324
1325 tmp=lp_config_get_int(lc->config,"sip","guess_hostname",1);
1326 linphone_core_set_guess_hostname(lc,tmp);
1327
1328 tmp=lp_config_get_int(lc->config,"sip","lime",FALSE);
1329 linphone_core_enable_lime(lc,tmp);
1330
1331 tmp=lp_config_get_int(lc->config,"sip","inc_timeout",30);
1332 linphone_core_set_inc_timeout(lc,tmp);
1333
1334 tmp=lp_config_get_int(lc->config,"sip","in_call_timeout",0);
1335 linphone_core_set_in_call_timeout(lc,tmp);
1336
1337 tmp=lp_config_get_int(lc->config,"sip","delayed_timeout",4);
1338 linphone_core_set_delayed_timeout(lc,tmp);
1339
1340 /* get proxies config */
1341 for(i=0;; i++){
1342 LinphoneProxyConfig *cfg=linphone_proxy_config_new_from_config_file(lc,i);
1343 if (cfg!=NULL){
1344 linphone_core_add_proxy_config(lc,cfg);
1345 linphone_proxy_config_unref(cfg);
1346 }else{
1347 break;
1348 }
1349 }
1350 /* get the default proxy */
1351 tmp=lp_config_get_int(lc->config,"sip","default_proxy",-1);
1352 linphone_core_set_default_proxy_index(lc,tmp);
1353
1354 /* read authentication information */
1355 for(i=0;; i++){
1356 LinphoneAuthInfo *ai=linphone_auth_info_new_from_config_file(lc->config,i);
1357 if (ai!=NULL){
1358 linphone_core_add_auth_info(lc,ai);
1359 linphone_auth_info_unref(ai);
1360 }else{
1361 break;
1362 }
1363 }
1364 /*this is to filter out unsupported encryption schemes*/
1365 linphone_core_set_media_encryption(lc,linphone_core_get_media_encryption(lc));
1366
1367 /*for tuning or test*/
1368 lc->sip_conf.sdp_200_ack=lp_config_get_int(lc->config,"sip","sdp_200_ack",0);
1369 lc->sip_conf.register_only_when_network_is_up=
1370 lp_config_get_int(lc->config,"sip","register_only_when_network_is_up",1);
1371 lc->sip_conf.register_only_when_upnp_is_ok=
1372 lp_config_get_int(lc->config,"sip","register_only_when_upnp_is_ok",1);
1373 lc->sip_conf.ping_with_options=lp_config_get_int(lc->config,"sip","ping_with_options",0);
1374 lc->sip_conf.auto_net_state_mon=lp_config_get_int(lc->config,"sip","auto_net_state_mon",1);
1375 lc->sip_conf.keepalive_period=lp_config_get_int(lc->config,"sip","keepalive_period",10000);
1376 lc->sip_conf.tcp_tls_keepalive=lp_config_get_int(lc->config,"sip","tcp_tls_keepalive",0);
1377 linphone_core_enable_keep_alive(lc, (lc->sip_conf.keepalive_period > 0));
1378 sal_use_one_matching_codec_policy(lc->sal,lp_config_get_int(lc->config,"sip","only_one_codec",0));
1379 sal_use_dates(lc->sal,lp_config_get_int(lc->config,"sip","put_date",0));
1380 sal_enable_sip_update_method(lc->sal,lp_config_get_int(lc->config,"sip","sip_update",1));
1381 lc->sip_conf.vfu_with_info=lp_config_get_int(lc->config,"sip","vfu_with_info",1);
1382 linphone_core_set_sip_transport_timeout(lc, lp_config_get_int(lc->config, "sip", "transport_timeout", 63000));
1383 sal_set_supported_tags(lc->sal,lp_config_get_string(lc->config,"sip","supported","replaces, outbound"));
1384 lc->sip_conf.save_auth_info = lp_config_get_int(lc->config, "sip", "save_auth_info", 1);
1385 linphone_core_create_im_notif_policy(lc);
1386 }
1387
rtp_config_read(LinphoneCore * lc)1388 static void rtp_config_read(LinphoneCore *lc) {
1389 int min_port, max_port;
1390 int jitt_comp;
1391 int nortp_timeout;
1392 bool_t rtp_no_xmit_on_audio_mute;
1393 bool_t adaptive_jitt_comp_enabled;
1394 const char* tmp;
1395 int tmp_int;
1396
1397 if (lp_config_get_range(lc->config, "rtp", "audio_rtp_port", &min_port, &max_port, 7078, 7078) == TRUE) {
1398 if (min_port <= 0) min_port = 1;
1399 if (max_port > 65535) max_port = 65535;
1400 linphone_core_set_audio_port_range(lc, min_port, max_port);
1401 } else {
1402 min_port = lp_config_get_int(lc->config, "rtp", "audio_rtp_port", 7078);
1403 linphone_core_set_audio_port(lc, min_port);
1404 }
1405
1406 if (lp_config_get_range(lc->config, "rtp", "video_rtp_port", &min_port, &max_port, 9078, 9078) == TRUE) {
1407 if (min_port <= 0) min_port = 1;
1408 if (max_port > 65535) max_port = 65535;
1409 linphone_core_set_video_port_range(lc, min_port, max_port);
1410 } else {
1411 min_port = lp_config_get_int(lc->config, "rtp", "video_rtp_port", 9078);
1412 linphone_core_set_video_port(lc, min_port);
1413 }
1414
1415 if (lp_config_get_range(lc->config, "rtp", "text_rtp_port", &min_port, &max_port, 11078, 11078) == TRUE) {
1416 if (min_port <= 0) min_port = 1;
1417 if (max_port > 65535) max_port = 65535;
1418 linphone_core_set_text_port_range(lc, min_port, max_port);
1419 } else {
1420 min_port = lp_config_get_int(lc->config, "rtp", "text_rtp_port", 11078);
1421 linphone_core_set_text_port(lc, min_port);
1422 }
1423
1424 jitt_comp=lp_config_get_int(lc->config,"rtp","audio_jitt_comp",60);
1425 linphone_core_set_audio_jittcomp(lc,jitt_comp);
1426 jitt_comp=lp_config_get_int(lc->config,"rtp","video_jitt_comp",60);
1427 if (jitt_comp==0) jitt_comp=60;
1428 linphone_core_set_video_jittcomp(lc,jitt_comp);
1429 nortp_timeout=lp_config_get_int(lc->config,"rtp","nortp_timeout",30);
1430 linphone_core_set_nortp_timeout(lc,nortp_timeout);
1431 rtp_no_xmit_on_audio_mute=lp_config_get_int(lc->config,"rtp","rtp_no_xmit_on_audio_mute",FALSE);
1432 linphone_core_set_rtp_no_xmit_on_audio_mute(lc,rtp_no_xmit_on_audio_mute);
1433 adaptive_jitt_comp_enabled = lp_config_get_int(lc->config, "rtp", "audio_adaptive_jitt_comp_enabled", TRUE);
1434 linphone_core_enable_audio_adaptive_jittcomp(lc, adaptive_jitt_comp_enabled);
1435 adaptive_jitt_comp_enabled = lp_config_get_int(lc->config, "rtp", "video_adaptive_jitt_comp_enabled", TRUE);
1436 linphone_core_enable_video_adaptive_jittcomp(lc, adaptive_jitt_comp_enabled);
1437 lc->rtp_conf.disable_upnp = lp_config_get_int(lc->config, "rtp", "disable_upnp", FALSE);
1438 linphone_core_set_avpf_mode(lc,lp_config_get_int(lc->config,"rtp","avpf",0));
1439 if ((tmp=lp_config_get_string(lc->config,"rtp","audio_multicast_addr",NULL)))
1440 linphone_core_set_audio_multicast_addr(lc,tmp);
1441 else
1442 lc->rtp_conf.audio_multicast_addr=ms_strdup("224.1.2.3");
1443 if ((tmp_int=lp_config_get_int(lc->config,"rtp","audio_multicast_enabled",-1)) >-1)
1444 linphone_core_enable_audio_multicast(lc,tmp_int);
1445 if ((tmp_int=lp_config_get_int(lc->config,"rtp","audio_multicast_ttl",-1))>0)
1446 linphone_core_set_audio_multicast_ttl(lc,tmp_int);
1447 else
1448 lc->rtp_conf.audio_multicast_ttl=1;/*local network*/
1449 if ((tmp=lp_config_get_string(lc->config,"rtp","video_multicast_addr",NULL)))
1450 linphone_core_set_video_multicast_addr(lc,tmp);
1451 else
1452 lc->rtp_conf.video_multicast_addr=ms_strdup("224.1.2.3");
1453 if ((tmp_int=lp_config_get_int(lc->config,"rtp","video_multicast_ttl",-1))>-1)
1454 linphone_core_set_video_multicast_ttl(lc,tmp_int);
1455 else
1456 lc->rtp_conf.video_multicast_ttl=1;/*local network*/
1457 if ((tmp_int=lp_config_get_int(lc->config,"rtp","video_multicast_enabled",-1)) >0)
1458 linphone_core_enable_video_multicast(lc,tmp_int);
1459 }
1460
find_payload(const bctbx_list_t * default_list,const char * mime_type,int clock_rate,int channels,const char * recv_fmtp)1461 static PayloadType * find_payload(const bctbx_list_t *default_list, const char *mime_type, int clock_rate, int channels, const char *recv_fmtp){
1462 PayloadType *candidate=NULL;
1463 PayloadType *it;
1464 const bctbx_list_t *elem;
1465
1466 for(elem=default_list;elem!=NULL;elem=elem->next){
1467 it=(PayloadType*)elem->data;
1468 if (it!=NULL && strcasecmp(mime_type,it->mime_type)==0
1469 && (clock_rate==it->clock_rate || clock_rate<=0)
1470 && (channels==it->channels || channels<=0) ){
1471 if ( (recv_fmtp && it->recv_fmtp && strstr(recv_fmtp,it->recv_fmtp)!=NULL) ||
1472 (recv_fmtp==NULL && it->recv_fmtp==NULL) ){
1473 /*exact match*/
1474 if (recv_fmtp) payload_type_set_recv_fmtp(it,recv_fmtp);
1475 return it;
1476 }else {
1477 if (candidate){
1478 if (it->recv_fmtp==NULL) candidate=it;
1479 }else candidate=it;
1480 }
1481 }
1482 }
1483 if (candidate && recv_fmtp){
1484 payload_type_set_recv_fmtp(candidate,recv_fmtp);
1485 }
1486 return candidate;
1487 }
1488
find_payload_type_from_list(const char * type,int rate,int channels,const bctbx_list_t * from)1489 static PayloadType* find_payload_type_from_list(const char* type, int rate, int channels, const bctbx_list_t* from) {
1490 const bctbx_list_t *elem;
1491 for(elem=from;elem!=NULL;elem=elem->next){
1492 PayloadType *pt=(PayloadType*)elem->data;
1493 if ((strcasecmp(type, payload_type_get_mime(pt)) == 0)
1494 && (rate == LINPHONE_FIND_PAYLOAD_IGNORE_RATE || rate==pt->clock_rate)
1495 && (channels == LINPHONE_FIND_PAYLOAD_IGNORE_CHANNELS || channels==pt->channels)) {
1496 return pt;
1497 }
1498 }
1499 return NULL;
1500 }
1501
linphone_core_codec_supported(LinphoneCore * lc,SalStreamType type,const char * mime)1502 static bool_t linphone_core_codec_supported(LinphoneCore *lc, SalStreamType type, const char *mime){
1503 if (type == SalVideo && lp_config_get_int(lc->config, "video", "rtp_io", FALSE)){
1504 return TRUE; /*in rtp io mode, we don't transcode video, thus we can support a format for which we have no encoder nor decoder.*/
1505 } else if (type == SalAudio && lp_config_get_int(lc->config, "sound", "rtp_io", FALSE)){
1506 return TRUE; /*in rtp io mode, we don't transcode video, thus we can support a format for which we have no encoder nor decoder.*/
1507 } else if (type == SalText) {
1508 return TRUE;
1509 }
1510 return ms_factory_codec_supported(lc->factory, mime);
1511 }
1512
1513
get_codec(LinphoneCore * lc,SalStreamType type,int index,PayloadType ** ret)1514 static bool_t get_codec(LinphoneCore *lc, SalStreamType type, int index, PayloadType **ret){
1515 char codeckey[50];
1516 const char *mime,*fmtp;
1517 int rate,channels,enabled;
1518 PayloadType *pt;
1519 LpConfig *config=lc->config;
1520
1521 *ret=NULL;
1522 snprintf(codeckey,50,"%s_codec_%i",type == SalAudio ? "audio" : type == SalVideo ? "video" : "text", index);
1523 mime=lp_config_get_string(config,codeckey,"mime",NULL);
1524 if (mime==NULL || strlen(mime)==0 ) return FALSE;
1525
1526 rate=lp_config_get_int(config,codeckey,"rate",8000);
1527 fmtp=lp_config_get_string(config,codeckey,"recv_fmtp",NULL);
1528 channels=lp_config_get_int(config,codeckey,"channels",0);
1529 enabled=lp_config_get_int(config,codeckey,"enabled",1);
1530 if (!linphone_core_codec_supported(lc, type, mime)){
1531 ms_warning("Codec %s/%i read from conf is not supported by mediastreamer2, ignored.",mime,rate);
1532 return TRUE;
1533 }
1534 pt = find_payload(type == SalAudio ? lc->default_audio_codecs : type == SalVideo ? lc->default_video_codecs : lc->default_text_codecs ,mime,rate,channels,fmtp);
1535 if (!pt){
1536 bctbx_list_t **default_list = (type==SalAudio) ? &lc->default_audio_codecs : type == SalVideo ? &lc->default_video_codecs : &lc->default_text_codecs;
1537 if (type == SalAudio)
1538 ms_warning("Codec %s/%i/%i read from conf is not in the default list.",mime,rate,channels);
1539 else if (type == SalVideo)
1540 ms_warning("Codec %s/%i read from conf is not in the default list.",mime,rate);
1541 else
1542 ms_warning("Codec %s read from conf is not in the default list.",mime);
1543 pt=payload_type_new();
1544 pt->type=(type==SalAudio) ? PAYLOAD_AUDIO_PACKETIZED : type == SalVideo ? PAYLOAD_VIDEO : PAYLOAD_TEXT;
1545 pt->mime_type=ortp_strdup(mime);
1546 pt->clock_rate=rate;
1547 pt->channels=channels;
1548 payload_type_set_number(pt,-1); /*dynamic assignment*/
1549 payload_type_set_recv_fmtp(pt,fmtp);
1550 *default_list=bctbx_list_append(*default_list, pt);
1551 }
1552 if (enabled ) pt->flags|=PAYLOAD_TYPE_ENABLED;
1553 else pt->flags&=~PAYLOAD_TYPE_ENABLED;
1554 *ret=pt;
1555 return TRUE;
1556 }
1557
payload_type_get_stream_type(const PayloadType * pt)1558 static SalStreamType payload_type_get_stream_type(const PayloadType *pt){
1559 switch(pt->type){
1560 case PAYLOAD_AUDIO_PACKETIZED:
1561 case PAYLOAD_AUDIO_CONTINUOUS:
1562 return SalAudio;
1563 break;
1564 case PAYLOAD_VIDEO:
1565 return SalVideo;
1566 break;
1567 case PAYLOAD_TEXT:
1568 return SalText;
1569 break;
1570 }
1571 return SalOther;
1572 }
1573
1574 /*this function merges the payload types from the codec default list with the list read from configuration file.
1575 * If a new codec becomes supported in Liblinphone or if the list from configuration file is empty or incomplete, all the supported codecs are added
1576 * automatically. This 'l' list is entirely destroyed and rewritten.*/
add_missing_supported_codecs(LinphoneCore * lc,const bctbx_list_t * default_list,bctbx_list_t * l)1577 static bctbx_list_t *add_missing_supported_codecs(LinphoneCore *lc, const bctbx_list_t *default_list, bctbx_list_t *l){
1578 const bctbx_list_t *elem;
1579 bctbx_list_t *newlist;
1580 PayloadType *last_seen = NULL;
1581
1582 for(elem=default_list; elem!=NULL; elem=elem->next){
1583 bctbx_list_t *elem2=bctbx_list_find(l,elem->data);
1584 if (!elem2){
1585 PayloadType *pt=(PayloadType*)elem->data;
1586 /*this codec from default list should be inserted in the list, with respect to the default_list order*/
1587
1588 if (!linphone_core_codec_supported(lc, payload_type_get_stream_type(pt), pt->mime_type)) continue;
1589 if (!last_seen){
1590 l=bctbx_list_prepend(l,pt);
1591 }else{
1592 const bctbx_list_t *after=bctbx_list_find(l,last_seen);
1593 l=bctbx_list_insert(l, after->next, pt);
1594 }
1595 last_seen = pt;
1596 ms_message("Supported codec %s/%i fmtp=%s automatically added to codec list.", pt->mime_type,
1597 pt->clock_rate, pt->recv_fmtp ? pt->recv_fmtp : "");
1598 }else{
1599 last_seen = (PayloadType*)elem2->data;
1600 }
1601 }
1602 newlist=bctbx_list_copy_with_data(l,(void *(*)(void*))payload_type_clone);
1603 bctbx_list_free(l);
1604 return newlist;
1605 }
1606
1607 /*
1608 * This function adds missing codecs, if required by configuration.
1609 * This 'l' list is entirely destroyed and a new list is returned.
1610 */
handle_missing_codecs(LinphoneCore * lc,const bctbx_list_t * default_list,bctbx_list_t * l,MSFormatType ft)1611 static bctbx_list_t *handle_missing_codecs(LinphoneCore *lc, const bctbx_list_t *default_list, bctbx_list_t *l, MSFormatType ft){
1612 const char *name = "unknown";
1613 int add_missing;
1614 bctbx_list_t *ret;
1615
1616 switch(ft){
1617 case MSAudio:
1618 name = "add_missing_audio_codecs";
1619 break;
1620 case MSVideo:
1621 name = "add_missing_video_codecs";
1622 break;
1623 case MSText:
1624 name = "add_missing_text_codecs";
1625 break;
1626 case MSUnknownMedia:
1627 break;
1628 }
1629 add_missing = lp_config_get_int(lc->config, "misc", name, 1);
1630 if (add_missing){
1631 ret = add_missing_supported_codecs(lc, default_list, l);
1632 }else{
1633 ret = bctbx_list_copy_with_data(l,(void *(*)(void*))payload_type_clone);
1634 bctbx_list_free(l);
1635 }
1636 return ret;
1637 }
1638
codec_append_if_new(bctbx_list_t * l,PayloadType * pt)1639 static bctbx_list_t *codec_append_if_new(bctbx_list_t *l, PayloadType *pt){
1640 bctbx_list_t *elem;
1641 for (elem=l;elem!=NULL;elem=elem->next){
1642 PayloadType *ept=(PayloadType*)elem->data;
1643 if (pt==ept)
1644 return l;
1645 }
1646 l=bctbx_list_append(l,pt);
1647 return l;
1648 }
1649
codecs_config_read(LinphoneCore * lc)1650 static void codecs_config_read(LinphoneCore *lc){
1651 int i;
1652 PayloadType *pt;
1653 bctbx_list_t *audio_codecs=NULL;
1654 bctbx_list_t *video_codecs=NULL;
1655 bctbx_list_t *text_codecs=NULL;
1656
1657 lc->codecs_conf.dyn_pt=96;
1658 lc->codecs_conf.telephone_event_pt=lp_config_get_int(lc->config,"misc","telephone_event_pt",101);
1659
1660 for (i=0;get_codec(lc,SalAudio,i,&pt);i++){
1661 if (pt){
1662 audio_codecs=codec_append_if_new(audio_codecs, pt);
1663 }
1664 }
1665 audio_codecs = handle_missing_codecs(lc, lc->default_audio_codecs,audio_codecs, MSAudio);
1666
1667 for (i=0;get_codec(lc,SalVideo,i,&pt);i++){
1668 if (pt){
1669 video_codecs=codec_append_if_new(video_codecs, pt);
1670 }
1671 }
1672
1673 video_codecs = handle_missing_codecs(lc, lc->default_video_codecs, video_codecs, MSVideo);
1674
1675 for (i=0;get_codec(lc,SalText,i,&pt);i++){
1676 if (pt){
1677 text_codecs=codec_append_if_new(text_codecs, pt);
1678 }
1679 }
1680 text_codecs = add_missing_supported_codecs(lc, lc->default_text_codecs, text_codecs);
1681
1682 linphone_core_set_audio_codecs(lc,audio_codecs);
1683 linphone_core_set_video_codecs(lc,video_codecs);
1684 linphone_core_set_text_codecs(lc, text_codecs);
1685 linphone_core_update_allocated_audio_bandwidth(lc);
1686 }
1687
build_video_devices_table(LinphoneCore * lc)1688 static void build_video_devices_table(LinphoneCore *lc){
1689 const bctbx_list_t *elem;
1690 int i;
1691 size_t ndev;
1692 const char **devices;
1693 if (lc->video_conf.cams)
1694 ms_free((void *)lc->video_conf.cams);
1695 /* retrieve all video devices */
1696 elem=ms_web_cam_manager_get_list(ms_factory_get_web_cam_manager(lc->factory));
1697 ndev=bctbx_list_size(elem);
1698 devices=ms_malloc((ndev+1)*sizeof(const char *));
1699 for (i=0;elem!=NULL;elem=elem->next,i++){
1700 devices[i]=ms_web_cam_get_string_id((MSWebCam *)elem->data);
1701 }
1702 devices[ndev]=NULL;
1703 lc->video_conf.cams=devices;
1704 }
1705
video_config_read(LinphoneCore * lc)1706 static void video_config_read(LinphoneCore *lc){
1707 #ifdef VIDEO_ENABLED
1708 int capture, display, self_view, reuse_source;
1709 int automatic_video=1;
1710 const char *str;
1711 LinphoneVideoPolicy vpol;
1712 memset(&vpol, 0, sizeof(LinphoneVideoPolicy));
1713 build_video_devices_table(lc);
1714
1715 str=lp_config_get_string(lc->config,"video","device",NULL);
1716 if (str && str[0]==0) str=NULL;
1717 linphone_core_set_video_device(lc,str);
1718
1719 linphone_core_set_preferred_video_size_by_name(lc,
1720 lp_config_get_string(lc->config,"video","size","vga"));
1721
1722 linphone_core_set_preview_video_size_by_name(lc,
1723 lp_config_get_string(lc->config,"video","preview_size",NULL));
1724
1725 linphone_core_set_preferred_framerate(lc,lp_config_get_float(lc->config,"video","framerate",0));
1726
1727 #if defined(__ANDROID__) || TARGET_OS_IPHONE
1728 automatic_video=0;
1729 #endif
1730 capture=lp_config_get_int(lc->config,"video","capture",1);
1731 display=lp_config_get_int(lc->config,"video","display",1);
1732 self_view=lp_config_get_int(lc->config,"video","self_view",1);
1733 reuse_source=lp_config_get_int(lc->config,"video","reuse_source",0);
1734 vpol.automatically_initiate=lp_config_get_int(lc->config,"video","automatically_initiate",automatic_video);
1735 vpol.automatically_accept=lp_config_get_int(lc->config,"video","automatically_accept",automatic_video);
1736 linphone_core_enable_video_capture(lc, capture);
1737 linphone_core_enable_video_display(lc, display);
1738 linphone_core_enable_video_preview(lc,lp_config_get_int(lc->config,"video","show_local",0));
1739 linphone_core_enable_self_view(lc,self_view);
1740 linphone_core_enable_video_source_reuse(lc, reuse_source);
1741 linphone_core_set_video_policy(lc,&vpol);
1742 #endif
1743 }
1744
read_friends_from_rc(LinphoneCore * lc)1745 static void read_friends_from_rc(LinphoneCore *lc)
1746 {
1747 LinphoneFriend *lf = NULL;
1748 int i;
1749 for (i = 0; (lf = linphone_friend_new_from_config_file(lc, i)) != NULL; i++) {
1750 linphone_core_add_friend(lc, lf);
1751 linphone_friend_unref(lf);
1752 }
1753 }
1754
ui_config_read(LinphoneCore * lc)1755 static void ui_config_read(LinphoneCore *lc)
1756 {
1757 #ifndef SQLITE_STORAGE_ENABLED
1758 read_friends_from_rc(lc);
1759 lc->call_logs = call_logs_read_from_config_file(lc);
1760 #else
1761 if (!lc->friends_db) {
1762 read_friends_from_rc(lc);
1763 }
1764 if (!lc->logs_db) {
1765 lc->call_logs = call_logs_read_from_config_file(lc);
1766 }
1767 #endif
1768 }
1769
1770 /*
1771 static void autoreplier_config_init(LinphoneCore *lc)
1772 {
1773 autoreplier_config_t *config=&lc->autoreplier_conf;
1774 config->enabled=lp_config_get_int(lc->config,"autoreplier","enabled",0);
1775 config->after_seconds=lp_config_get_int(lc->config,"autoreplier","after_seconds",6);
1776 config->max_users=lp_config_get_int(lc->config,"autoreplier","max_users",1);
1777 config->max_rec_time=lp_config_get_int(lc->config,"autoreplier","max_rec_time",60);
1778 config->max_rec_msg=lp_config_get_int(lc->config,"autoreplier","max_rec_msg",10);
1779 config->message=lp_config_get_string(lc->config,"autoreplier","message",NULL);
1780 }
1781 */
1782
linphone_core_tunnel_available(void)1783 bool_t linphone_core_tunnel_available(void){
1784 #ifdef TUNNEL_ENABLED
1785 return TRUE;
1786 #else
1787 return FALSE;
1788 #endif
1789 }
1790
linphone_core_enable_adaptive_rate_control(LinphoneCore * lc,bool_t enabled)1791 void linphone_core_enable_adaptive_rate_control(LinphoneCore *lc, bool_t enabled){
1792 lp_config_set_int(lc->config,"net","adaptive_rate_control",(int)enabled);
1793 }
1794
linphone_core_adaptive_rate_control_enabled(const LinphoneCore * lc)1795 bool_t linphone_core_adaptive_rate_control_enabled(const LinphoneCore *lc){
1796 return lp_config_get_int(lc->config,"net","adaptive_rate_control",TRUE);
1797 }
1798
linphone_core_set_adaptive_rate_algorithm(LinphoneCore * lc,const char * algorithm)1799 void linphone_core_set_adaptive_rate_algorithm(LinphoneCore *lc, const char* algorithm){
1800 if (strcasecmp(algorithm, "basic") != 0 && strcasecmp(algorithm, "advanced") != 0) {
1801 ms_warning("Unsupported adaptive rate algorithm [%s] on core [%p], using advanced",algorithm,lc);
1802 linphone_core_set_adaptive_rate_algorithm(lc, "advanced");
1803 return;
1804 }
1805 lp_config_set_string(lc->config,"net","adaptive_rate_algorithm",algorithm);
1806 }
1807
linphone_core_get_adaptive_rate_algorithm(const LinphoneCore * lc)1808 const char * linphone_core_get_adaptive_rate_algorithm(const LinphoneCore *lc){
1809 const char* saved_value = lp_config_get_string(lc->config, "net", "adaptive_rate_algorithm", "advanced");
1810 if (strcasecmp(saved_value, "basic") != 0 && strcasecmp(saved_value, "advanced") != 0) {
1811 ms_warning("Unsupported adaptive rate algorithm [%s] on core [%p]",saved_value,lc);
1812 }
1813 return saved_value;
1814 }
1815
linphone_core_rtcp_enabled(const LinphoneCore * lc)1816 bool_t linphone_core_rtcp_enabled(const LinphoneCore *lc){
1817 return lp_config_get_int(lc->config,"rtp","rtcp_enabled",TRUE);
1818 }
1819
linphone_core_set_download_bandwidth(LinphoneCore * lc,int bw)1820 void linphone_core_set_download_bandwidth(LinphoneCore *lc, int bw){
1821 lc->net_conf.download_bw=bw;
1822 linphone_core_update_allocated_audio_bandwidth(lc);
1823 if (linphone_core_ready(lc)) lp_config_set_int(lc->config,"net","download_bw",bw);
1824 }
1825
linphone_core_set_upload_bandwidth(LinphoneCore * lc,int bw)1826 void linphone_core_set_upload_bandwidth(LinphoneCore *lc, int bw){
1827 lc->net_conf.upload_bw=bw;
1828 linphone_core_update_allocated_audio_bandwidth(lc);
1829 if (linphone_core_ready(lc)) lp_config_set_int(lc->config,"net","upload_bw",bw);
1830 }
1831
linphone_core_set_expected_bandwidth(LinphoneCore * lc,int bw)1832 void linphone_core_set_expected_bandwidth(LinphoneCore *lc, int bw){
1833 ms_factory_set_expected_bandwidth(lc->factory, bw * 1000); // In linphone we use kbits/s, in ms2 bits/s
1834 if (linphone_core_ready(lc)) lp_config_set_int(lc->config,"net","expected_bw",bw);
1835 }
1836
linphone_core_set_sip_transport_timeout(LinphoneCore * lc,int timeout_ms)1837 void linphone_core_set_sip_transport_timeout(LinphoneCore *lc, int timeout_ms) {
1838 sal_set_transport_timeout(lc->sal, timeout_ms);
1839 if (linphone_core_ready(lc))
1840 lp_config_set_int(lc->config, "sip", "transport_timeout", timeout_ms);
1841 }
1842
linphone_core_get_sip_transport_timeout(LinphoneCore * lc)1843 int linphone_core_get_sip_transport_timeout(LinphoneCore *lc) {
1844 return sal_get_transport_timeout(lc->sal);
1845 }
1846
linphone_core_set_dns_servers(LinphoneCore * lc,const bctbx_list_t * servers)1847 void linphone_core_set_dns_servers(LinphoneCore *lc, const bctbx_list_t *servers){
1848 sal_set_dns_servers(lc->sal, servers);
1849 }
1850
linphone_core_enable_dns_srv(LinphoneCore * lc,bool_t enable)1851 void linphone_core_enable_dns_srv(LinphoneCore *lc, bool_t enable) {
1852 sal_enable_dns_srv(lc->sal, enable);
1853 if (linphone_core_ready(lc))
1854 lp_config_set_int(lc->config, "net", "dns_srv_enabled", enable ? 1 : 0);
1855 }
1856
linphone_core_dns_srv_enabled(const LinphoneCore * lc)1857 bool_t linphone_core_dns_srv_enabled(const LinphoneCore *lc) {
1858 return sal_dns_srv_enabled(lc->sal);
1859 }
1860
linphone_core_enable_dns_search(LinphoneCore * lc,bool_t enable)1861 void linphone_core_enable_dns_search(LinphoneCore *lc, bool_t enable) {
1862 sal_enable_dns_search(lc->sal, enable);
1863 if (linphone_core_ready(lc))
1864 lp_config_set_int(lc->config, "net", "dns_search_enabled", enable ? 1 : 0);
1865 }
1866
linphone_core_dns_search_enabled(const LinphoneCore * lc)1867 bool_t linphone_core_dns_search_enabled(const LinphoneCore *lc) {
1868 return sal_dns_search_enabled(lc->sal);
1869 }
1870
linphone_core_get_download_bandwidth(const LinphoneCore * lc)1871 int linphone_core_get_download_bandwidth(const LinphoneCore *lc){
1872 return lc->net_conf.download_bw;
1873 }
1874
linphone_core_get_upload_bandwidth(const LinphoneCore * lc)1875 int linphone_core_get_upload_bandwidth(const LinphoneCore *lc){
1876 return lc->net_conf.upload_bw;
1877 }
1878
linphone_core_set_download_ptime(LinphoneCore * lc,int ptime)1879 void linphone_core_set_download_ptime(LinphoneCore *lc, int ptime) {
1880 lp_config_set_int(lc->config,"rtp","download_ptime",ptime);
1881 }
1882
linphone_core_get_download_ptime(LinphoneCore * lc)1883 int linphone_core_get_download_ptime(LinphoneCore *lc) {
1884 return lp_config_get_int(lc->config,"rtp","download_ptime",0);
1885 }
1886
linphone_core_set_upload_ptime(LinphoneCore * lc,int ptime)1887 void linphone_core_set_upload_ptime(LinphoneCore *lc, int ptime){
1888 lp_config_set_int(lc->config,"rtp","upload_ptime",ptime);
1889 }
1890
linphone_core_get_upload_ptime(LinphoneCore * lc)1891 int linphone_core_get_upload_ptime(LinphoneCore *lc){
1892 return lp_config_get_int(lc->config,"rtp","upload_ptime",0);
1893 }
1894
linphone_core_get_version(void)1895 const char * linphone_core_get_version(void){
1896 return liblinphone_version;
1897 }
1898
linphone_core_register_payload_type(LinphoneCore * lc,const PayloadType * const_pt,const char * recv_fmtp,bool_t enabled)1899 static void linphone_core_register_payload_type(LinphoneCore *lc, const PayloadType *const_pt, const char *recv_fmtp, bool_t enabled){
1900 bctbx_list_t **codec_list = const_pt->type==PAYLOAD_VIDEO ? &lc->default_video_codecs : const_pt->type==PAYLOAD_TEXT ? &lc->default_text_codecs : &lc->default_audio_codecs;
1901 PayloadType *pt=payload_type_clone(const_pt);
1902 int number=-1;
1903 payload_type_set_enable(pt,enabled);
1904 if (recv_fmtp!=NULL) payload_type_set_recv_fmtp(pt,recv_fmtp);
1905 /*Set a number to the payload type from the statically defined (RFC3551) profile, if not static, -1 is returned
1906 and the payload type number will be determined dynamically later, at call time.*/
1907 payload_type_set_number(pt,
1908 (number=rtp_profile_find_payload_number(&av_profile, pt->mime_type, pt->clock_rate, pt->channels))
1909 );
1910 ms_message("Codec %s/%i fmtp=[%s] number=%i, default enablement: %i) added to the list of possible codecs.", pt->mime_type, pt->clock_rate,
1911 pt->recv_fmtp ? pt->recv_fmtp : "", number, (int)payload_type_enabled(pt));
1912 *codec_list=bctbx_list_append(*codec_list,pt);
1913 }
1914
linphone_core_register_static_payloads(LinphoneCore * lc)1915 static void linphone_core_register_static_payloads(LinphoneCore *lc){
1916 RtpProfile *prof=&av_profile;
1917 int i;
1918 for(i=0;i<RTP_PROFILE_MAX_PAYLOADS;++i){
1919 PayloadType *pt=rtp_profile_get_payload(prof,i);
1920 if (pt){
1921 #ifndef VIDEO_ENABLED
1922 if (pt->type==PAYLOAD_VIDEO) continue;
1923 #endif
1924 if (find_payload_type_from_list(
1925 pt->mime_type, pt->clock_rate, pt->type == PAYLOAD_VIDEO || pt->type == PAYLOAD_TEXT ? LINPHONE_FIND_PAYLOAD_IGNORE_CHANNELS : pt->channels,
1926 pt->type == PAYLOAD_VIDEO ? lc->default_video_codecs : pt->type == PAYLOAD_TEXT ? lc->default_text_codecs : lc->default_audio_codecs)==NULL){
1927 linphone_core_register_payload_type(lc,pt,NULL,FALSE);
1928 }
1929 }
1930 }
1931 }
1932
linphone_core_free_payload_types(LinphoneCore * lc)1933 static void linphone_core_free_payload_types(LinphoneCore *lc){
1934 bctbx_list_free_with_data(lc->default_audio_codecs, (void (*)(void*))payload_type_destroy);
1935 bctbx_list_free_with_data(lc->default_video_codecs, (void (*)(void*))payload_type_destroy);
1936 bctbx_list_free_with_data(lc->default_text_codecs, (void (*)(void*))payload_type_destroy);
1937 }
1938
linphone_core_set_state(LinphoneCore * lc,LinphoneGlobalState gstate,const char * message)1939 void linphone_core_set_state(LinphoneCore *lc, LinphoneGlobalState gstate, const char *message){
1940 lc->state=gstate;
1941 linphone_core_notify_global_state_changed(lc,gstate,message);
1942 }
1943
misc_config_read(LinphoneCore * lc)1944 static void misc_config_read(LinphoneCore *lc) {
1945 LpConfig *config=lc->config;
1946 const char *uuid;
1947
1948 lc->max_call_logs=lp_config_get_int(config,"misc","history_max_size",LINPHONE_MAX_CALL_HISTORY_SIZE);
1949 lc->max_calls=lp_config_get_int(config,"misc","max_calls",NB_MAX_CALLS);
1950
1951 uuid=lp_config_get_string(config,"misc","uuid",NULL);
1952 if (!uuid){
1953 char tmp[64];
1954 sal_create_uuid(lc->sal,tmp,sizeof(tmp));
1955 lp_config_set_string(config,"misc","uuid",tmp);
1956 }else if (strcmp(uuid,"0")!=0) /*to allow to disable sip.instance*/
1957 sal_set_uuid(lc->sal, uuid);
1958
1959 lc->user_certificates_path=ms_strdup(lp_config_get_string(config,"misc","user_certificates_path","."));
1960 }
1961
linphone_core_reload_ms_plugins(LinphoneCore * lc,const char * path)1962 void linphone_core_reload_ms_plugins(LinphoneCore *lc, const char *path){
1963 if (path) ms_factory_set_plugins_dir(lc->factory, path);
1964 ms_factory_init_plugins(lc->factory);
1965 codecs_config_read(lc);
1966 }
1967
linphone_core_start(LinphoneCore * lc)1968 static void linphone_core_start(LinphoneCore * lc) {
1969 LinphoneFriendList *list = linphone_core_create_friend_list(lc);
1970 linphone_friend_list_set_display_name(list, "_default");
1971 linphone_core_add_friend_list(lc, list);
1972 linphone_friend_list_unref(list);
1973
1974 sip_setup_register_all(lc->factory);
1975 sound_config_read(lc);
1976 net_config_read(lc);
1977 rtp_config_read(lc);
1978 codecs_config_read(lc);
1979 sip_config_read(lc);
1980 video_config_read(lc);
1981 //autoreplier_config_init(&lc->autoreplier_conf);
1982 lc->presence_model=linphone_presence_model_new();
1983 linphone_presence_model_set_basic_status(lc->presence_model, LinphonePresenceBasicStatusOpen);
1984 misc_config_read(lc);
1985 ui_config_read(lc);
1986 #ifdef TUNNEL_ENABLED
1987 if (lc->tunnel) {
1988 linphone_tunnel_configure(lc->tunnel);
1989 }
1990 #endif
1991
1992
1993 linphone_core_notify_display_status(lc,_("Ready"));
1994 lc->auto_net_state_mon=lc->sip_conf.auto_net_state_mon;
1995 linphone_core_set_state(lc,LinphoneGlobalOn,"Ready");
1996 }
1997
linphone_configuring_terminated(LinphoneCore * lc,LinphoneConfiguringState state,const char * message)1998 void linphone_configuring_terminated(LinphoneCore *lc, LinphoneConfiguringState state, const char *message) {
1999 linphone_core_notify_configuring_status(lc, state, message);
2000
2001 if (state == LinphoneConfiguringSuccessful) {
2002 if (linphone_core_is_provisioning_transient(lc) == TRUE)
2003 linphone_core_set_provisioning_uri(lc, NULL);
2004 }
2005 if (lc->provisioning_http_listener){
2006 belle_sip_object_unref(lc->provisioning_http_listener);
2007 lc->provisioning_http_listener = NULL;
2008 }
2009 linphone_core_start(lc);
2010 }
2011
2012
2013 static int linphone_core_serialization_ref = 0;
2014
linphone_core_activate_log_serialization_if_needed(void)2015 static void linphone_core_activate_log_serialization_if_needed(void) {
2016 if (liblinphone_serialize_logs == TRUE) {
2017 linphone_core_serialization_ref++;
2018 if (linphone_core_serialization_ref == 1)
2019 ortp_set_log_thread_id(ortp_thread_self());
2020 }
2021 }
2022
linphone_core_deactivate_log_serialization_if_needed(void)2023 static void linphone_core_deactivate_log_serialization_if_needed(void) {
2024 if (liblinphone_serialize_logs == TRUE) {
2025 --linphone_core_serialization_ref;
2026 if (linphone_core_serialization_ref == 0)
2027 ortp_set_log_thread_id(0);
2028 }
2029 }
2030
linphone_core_register_default_codecs(LinphoneCore * lc)2031 static void linphone_core_register_default_codecs(LinphoneCore *lc){
2032 const char *aac_fmtp162248, *aac_fmtp3244;
2033 bool_t opus_enabled=TRUE;
2034 /*default enabled audio codecs, in order of preference*/
2035 #if defined(__arm__) || defined(_M_ARM)
2036 /*hack for opus, that needs to be disabed by default on ARM single processor, otherwise there is no cpu left for video processing*/
2037 //if (ms_get_cpu_count()==1) opus_enabled=FALSE;
2038 if (ms_factory_get_cpu_count(lc->factory)==1) opus_enabled=FALSE;
2039 #endif
2040 linphone_core_register_payload_type(lc,&payload_type_opus,"useinbandfec=1",opus_enabled);
2041 linphone_core_register_payload_type(lc,&payload_type_silk_wb,NULL,TRUE);
2042 linphone_core_register_payload_type(lc,&payload_type_speex_wb,"vbr=on",TRUE);
2043 linphone_core_register_payload_type(lc,&payload_type_speex_nb,"vbr=on",TRUE);
2044 linphone_core_register_payload_type(lc,&payload_type_pcmu8000,NULL,TRUE);
2045 linphone_core_register_payload_type(lc,&payload_type_pcma8000,NULL,TRUE);
2046
2047 /* Text codecs in order or preference (RED first (more robust), then T140) */
2048 linphone_core_register_payload_type(lc, &payload_type_t140_red, NULL, TRUE);
2049 linphone_core_register_payload_type(lc, &payload_type_t140, NULL, TRUE);
2050
2051 /*other audio codecs, not enabled by default, in order of preference*/
2052 linphone_core_register_payload_type(lc,&payload_type_gsm,NULL,FALSE);
2053 linphone_core_register_payload_type(lc,&payload_type_g722,NULL,FALSE);
2054 linphone_core_register_payload_type(lc,&payload_type_ilbc,"mode=30",FALSE);
2055 linphone_core_register_payload_type(lc,&payload_type_amr,"octet-align=1",FALSE);
2056 linphone_core_register_payload_type(lc,&payload_type_amrwb,"octet-align=1",FALSE);
2057 linphone_core_register_payload_type(lc,&payload_type_g729,"annexb=yes",TRUE);
2058 /* For AAC, we use a config value to determine if we ought to support SBR. Since it is not offically supported
2059 * for the mpeg4-generic mime type, setting this flag to 1 will break compatibility with other clients. */
2060 if( lp_config_get_int(lc->config, "misc", "aac_use_sbr", FALSE) ) {
2061 ms_message("Using SBR for AAC");
2062 aac_fmtp162248 = "config=F8EE2000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=76; sizeLength=13; streamType=5; SBR-enabled=1";
2063 aac_fmtp3244 = "config=F8E82000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=76; sizeLength=13; streamType=5; SBR-enabled=1";
2064 } else {
2065 aac_fmtp162248 = "config=F8EE2000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=76; sizeLength=13; streamType=5";
2066 aac_fmtp3244 = "config=F8E82000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=76; sizeLength=13; streamType=5";
2067 }
2068 linphone_core_register_payload_type(lc,&payload_type_aaceld_16k,aac_fmtp162248,FALSE);
2069 linphone_core_register_payload_type(lc,&payload_type_aaceld_22k,aac_fmtp162248,FALSE);
2070 linphone_core_register_payload_type(lc,&payload_type_aaceld_32k,aac_fmtp3244,FALSE);
2071 linphone_core_register_payload_type(lc,&payload_type_aaceld_44k,aac_fmtp3244,FALSE);
2072 linphone_core_register_payload_type(lc,&payload_type_aaceld_48k,aac_fmtp162248,FALSE);
2073 linphone_core_register_payload_type(lc,&payload_type_isac,NULL,FALSE);
2074 linphone_core_register_payload_type(lc,&payload_type_speex_uwb,"vbr=on",FALSE);
2075 linphone_core_register_payload_type(lc,&payload_type_silk_nb,NULL,FALSE);
2076 linphone_core_register_payload_type(lc,&payload_type_silk_mb,NULL,FALSE);
2077 linphone_core_register_payload_type(lc,&payload_type_silk_swb,NULL,FALSE);
2078 linphone_core_register_payload_type(lc,&payload_type_g726_16,NULL,FALSE);
2079 linphone_core_register_payload_type(lc,&payload_type_g726_24,NULL,FALSE);
2080 linphone_core_register_payload_type(lc,&payload_type_g726_32,NULL,FALSE);
2081 linphone_core_register_payload_type(lc,&payload_type_g726_40,NULL,FALSE);
2082 linphone_core_register_payload_type(lc,&payload_type_aal2_g726_16,NULL,FALSE);
2083 linphone_core_register_payload_type(lc,&payload_type_aal2_g726_24,NULL,FALSE);
2084 linphone_core_register_payload_type(lc,&payload_type_aal2_g726_32,NULL,FALSE);
2085 linphone_core_register_payload_type(lc,&payload_type_aal2_g726_40,NULL,FALSE);
2086 linphone_core_register_payload_type(lc,&payload_type_codec2,NULL,FALSE);
2087 linphone_core_register_payload_type(lc,&payload_type_bv16,NULL,FALSE);
2088
2089
2090 #ifdef VIDEO_ENABLED
2091 /*default enabled video codecs, in order of preference*/
2092 linphone_core_register_payload_type(lc,&payload_type_vp8,NULL,TRUE);
2093 linphone_core_register_payload_type(lc,&payload_type_h264,"profile-level-id=42801F",TRUE);
2094 linphone_core_register_payload_type(lc,&payload_type_mp4v,"profile-level-id=3",TRUE);
2095 linphone_core_register_payload_type(lc,&payload_type_h263_1998,"CIF=1;QCIF=1",FALSE);
2096 linphone_core_register_payload_type(lc,&payload_type_h263,NULL,FALSE);
2097 #endif
2098 /*register all static payload types declared in av_profile of oRTP, if not already declared above*/
2099 linphone_core_register_static_payloads(lc);
2100 }
2101
linphone_core_internal_notify_received(LinphoneCore * lc,LinphoneEvent * lev,const char * notified_event,const LinphoneContent * body)2102 static void linphone_core_internal_notify_received(LinphoneCore *lc, LinphoneEvent *lev, const char *notified_event, const LinphoneContent *body) {
2103 if (strcmp(notified_event, "Presence") == 0) {
2104 const bctbx_list_t* friendLists = linphone_core_get_friends_lists(lc);
2105 while( friendLists != NULL ){
2106 LinphoneFriendList* list = friendLists->data;
2107 ms_message("notify presence for list %p", list);
2108 linphone_friend_list_notify_presence_received(list, lev, body);
2109 friendLists = friendLists->next;
2110 }
2111 }
2112 }
2113
linphone_core_internal_subscription_state_changed(LinphoneCore * lc,LinphoneEvent * lev,LinphoneSubscriptionState state)2114 static void linphone_core_internal_subscription_state_changed(LinphoneCore *lc, LinphoneEvent *lev, LinphoneSubscriptionState state) {
2115 if (strcasecmp(linphone_event_get_name(lev), "Presence") == 0) {
2116 linphone_friend_list_subscription_state_changed(lc, lev, state);
2117 }
2118 }
2119
linphone_core_internal_publish_state_changed(LinphoneCore * lc,LinphoneEvent * lev,LinphonePublishState state)2120 static void linphone_core_internal_publish_state_changed(LinphoneCore *lc, LinphoneEvent *lev, LinphonePublishState state) {
2121 if (strcasecmp(linphone_event_get_name(lev), "Presence") == 0) {
2122 const bctbx_list_t *cfgs = linphone_core_get_proxy_config_list(lc);
2123 const bctbx_list_t *item;
2124 for (item = cfgs; item != NULL; item = bctbx_list_next(item)) {
2125 LinphoneProxyConfig *cfg = (LinphoneProxyConfig *)bctbx_list_get_data(item);
2126 if (cfg->presence_publish_event == lev) {
2127 linphone_proxy_config_notify_publish_state_changed(cfg, state);
2128 break;
2129 }
2130 }
2131 }
2132 }
2133
_linphone_core_init_account_creator_service(LinphoneCore * lc)2134 static void _linphone_core_init_account_creator_service(LinphoneCore *lc) {
2135 LinphoneAccountCreatorService *service = linphone_account_creator_service_new();
2136 service->account_creator_service_constructor_cb = linphone_account_creator_constructor_linphone;
2137 service->account_creator_service_destructor_cb = NULL;
2138 service->create_account_request_cb = linphone_account_creator_create_account_linphone;
2139 service->is_account_exist_request_cb = linphone_account_creator_is_account_exist_linphone;
2140 service->activate_account_request_cb = linphone_account_creator_activate_account_linphone;
2141 service->is_account_activated_request_cb = linphone_account_creator_is_account_activated_linphone;
2142 service->link_account_request_cb = linphone_account_creator_link_phone_number_with_account_linphone;
2143 service->activate_alias_request_cb = linphone_account_creator_activate_phone_number_link_linphone;
2144 service->is_alias_used_request_cb = linphone_account_creator_is_phone_number_used_linphone;
2145 service->is_account_linked_request_cb = linphone_account_creator_is_account_linked_linphone;
2146 service->recover_account_request_cb = linphone_account_creator_recover_phone_account_linphone;
2147 service->update_account_request_cb = linphone_account_creator_update_password_linphone;
2148 linphone_core_set_account_creator_service(lc, service);
2149 }
2150
linphone_core_init(LinphoneCore * lc,LinphoneCoreCbs * cbs,LpConfig * config,void * userdata)2151 static void linphone_core_init(LinphoneCore * lc, LinphoneCoreCbs *cbs, LpConfig *config, void * userdata){
2152 const char *remote_provisioning_uri = NULL;
2153 LinphoneFactory *lfactory = linphone_factory_get();
2154 LinphoneCoreCbs *internal_cbs = _linphone_core_cbs_new();
2155 const char *msplugins_dir;
2156 const char *image_resources_dir;
2157
2158 ms_message("Initializing LinphoneCore %s", linphone_core_get_version());
2159
2160 lc->config=lp_config_ref(config);
2161 lc->data=userdata;
2162 lc->ringstream_autorelease=TRUE;
2163
2164 linphone_task_list_init(&lc->hooks);
2165
2166 _linphone_core_init_account_creator_service(lc);
2167
2168 linphone_core_cbs_set_notify_received(internal_cbs, linphone_core_internal_notify_received);
2169 linphone_core_cbs_set_subscription_state_changed(internal_cbs, linphone_core_internal_subscription_state_changed);
2170 linphone_core_cbs_set_publish_state_changed(internal_cbs, linphone_core_internal_publish_state_changed);
2171 _linphone_core_add_callbacks(lc, internal_cbs, TRUE);
2172 belle_sip_object_unref(internal_cbs);
2173
2174
2175 if (cbs != NULL) {
2176 _linphone_core_add_callbacks(lc, cbs, FALSE);
2177 } else {
2178 LinphoneCoreCbs *fallback_cbs = linphone_factory_create_core_cbs(linphone_factory_get());
2179 _linphone_core_add_callbacks(lc, fallback_cbs, FALSE);
2180 belle_sip_object_unref(fallback_cbs);
2181 }
2182
2183
2184 linphone_core_set_state(lc,LinphoneGlobalStartup,"Starting up");
2185 ortp_init();
2186 linphone_core_activate_log_serialization_if_needed();
2187
2188 msplugins_dir = linphone_factory_get_msplugins_dir(lfactory);
2189 image_resources_dir = linphone_factory_get_image_resources_dir(lfactory);
2190 lc->factory = ms_factory_new_with_voip_and_directories(msplugins_dir, image_resources_dir);
2191 linphone_core_register_default_codecs(lc);
2192 linphone_core_register_offer_answer_providers(lc);
2193 /* Get the mediastreamer2 event queue */
2194 /* This allows to run event's callback in linphone_core_iterate() */
2195 lc->msevq=ms_factory_create_event_queue(lc->factory);
2196
2197 lc->sal=sal_init(lc->factory);
2198 sal_set_http_proxy_host(lc->sal, linphone_core_get_http_proxy_host(lc));
2199 sal_set_http_proxy_port(lc->sal, linphone_core_get_http_proxy_port(lc));
2200
2201 sal_set_user_pointer(lc->sal,lc);
2202 sal_set_callbacks(lc->sal,&linphone_sal_callbacks);
2203
2204 #ifdef TUNNEL_ENABLED
2205 lc->tunnel=linphone_core_tunnel_new(lc);
2206 #endif
2207
2208 lc->network_last_check = 0;
2209 lc->network_last_status = FALSE;
2210
2211 /* Create the http provider in dual stack mode (ipv4 and ipv6.
2212 * If this creates problem, we may need to implement parallel ipv6/ ipv4 http requests in belle-sip.
2213 */
2214 lc->http_provider = belle_sip_stack_create_http_provider(sal_get_stack_impl(lc->sal), "::0");
2215 lc->http_crypto_config = belle_tls_crypto_config_new();
2216 belle_http_provider_set_tls_crypto_config(lc->http_provider,lc->http_crypto_config);
2217
2218 certificates_config_read(lc);
2219
2220 lc->ringtoneplayer = linphone_ringtoneplayer_new();
2221
2222 #ifdef SQLITE_STORAGE_ENABLED
2223 sqlite3_bctbx_vfs_register(0);
2224 #endif
2225
2226 lc->vcard_context = linphone_vcard_context_new();
2227 linphone_core_initialize_supported_content_types(lc);
2228
2229 remote_provisioning_uri = linphone_core_get_provisioning_uri(lc);
2230 if (remote_provisioning_uri == NULL) {
2231 linphone_configuring_terminated(lc, LinphoneConfiguringSkipped, NULL);
2232 } // else linphone_core_start will be called after the remote provisioning (see linphone_core_iterate)
2233 lc->bw_controller = ms_bandwidth_controller_new();
2234 }
2235
_linphone_core_new_with_config(LinphoneCoreCbs * cbs,struct _LpConfig * config,void * userdata)2236 LinphoneCore *_linphone_core_new_with_config(LinphoneCoreCbs *cbs, struct _LpConfig *config, void *userdata) {
2237 LinphoneCore *core = belle_sip_object_new(LinphoneCore);
2238 linphone_core_init(core, cbs, config, userdata);
2239 return core;
2240 }
2241
linphone_core_new_with_config(const LinphoneCoreVTable * vtable,struct _LpConfig * config,void * userdata)2242 LinphoneCore *linphone_core_new_with_config(const LinphoneCoreVTable *vtable, struct _LpConfig *config, void *userdata) {
2243 LinphoneCoreCbs *cbs = linphone_factory_create_core_cbs(linphone_factory_get());
2244 LinphoneCoreVTable *local_vtable = linphone_core_v_table_new();
2245 LinphoneCore *core = NULL;
2246 if (vtable != NULL) *local_vtable = *vtable;
2247 _linphone_core_cbs_set_v_table(cbs, local_vtable, TRUE);
2248 core = _linphone_core_new_with_config(cbs, config, userdata);
2249 linphone_core_cbs_unref(cbs);
2250 return core;
2251 }
2252
_linphone_core_new(const LinphoneCoreVTable * vtable,const char * config_path,const char * factory_config_path,void * userdata)2253 static LinphoneCore *_linphone_core_new(const LinphoneCoreVTable *vtable,
2254 const char *config_path, const char *factory_config_path, void * userdata) {
2255 LinphoneCore *lc;
2256 LpConfig *config = lp_config_new_with_factory(config_path, factory_config_path);
2257 lc=linphone_core_new_with_config(vtable, config, userdata);
2258 lp_config_unref(config);
2259 return lc;
2260 }
2261
linphone_core_new(const LinphoneCoreVTable * vtable,const char * config_path,const char * factory_config_path,void * userdata)2262 LinphoneCore *linphone_core_new(const LinphoneCoreVTable *vtable,
2263 const char *config_path, const char *factory_config_path, void * userdata) {
2264 return _linphone_core_new(vtable, config_path, factory_config_path, userdata);
2265 }
2266
linphone_core_ref(LinphoneCore * lc)2267 LinphoneCore *linphone_core_ref(LinphoneCore *lc) {
2268 return (LinphoneCore *)belle_sip_object_ref(BELLE_SIP_OBJECT(lc));
2269 }
2270
linphone_core_unref(LinphoneCore * lc)2271 void linphone_core_unref(LinphoneCore *lc) {
2272 belle_sip_object_unref(BELLE_SIP_OBJECT(lc));
2273 }
2274
ortp_payloads_to_linphone_payloads(const bctbx_list_t * ortp_payloads,LinphoneCore * lc)2275 static bctbx_list_t *ortp_payloads_to_linphone_payloads(const bctbx_list_t *ortp_payloads, LinphoneCore *lc) {
2276 bctbx_list_t *linphone_payloads = NULL;
2277 for (; ortp_payloads!=NULL; ortp_payloads=bctbx_list_next(ortp_payloads)) {
2278 LinphonePayloadType *pt = linphone_payload_type_new(lc, (OrtpPayloadType *)ortp_payloads->data);
2279 linphone_payloads = bctbx_list_append(linphone_payloads, pt);
2280 }
2281 return linphone_payloads;
2282 }
2283
sort_ortp_pt_list(bctbx_list_t ** ortp_pt_list,const bctbx_list_t * linphone_pt_list)2284 static void sort_ortp_pt_list(bctbx_list_t **ortp_pt_list, const bctbx_list_t *linphone_pt_list) {
2285 bctbx_list_t *new_list = NULL;
2286 const bctbx_list_t *it;
2287 for (it=bctbx_list_first_elem(linphone_pt_list); it; it=bctbx_list_next(it)) {
2288 OrtpPayloadType *ortp_pt = linphone_payload_type_get_ortp_pt((LinphonePayloadType *)it->data);
2289 bctbx_list_t *elem = bctbx_list_find(*ortp_pt_list, ortp_pt);
2290 if (elem) {
2291 *ortp_pt_list = bctbx_list_unlink(*ortp_pt_list, elem);
2292 new_list = bctbx_list_append_link(new_list, elem);
2293 }
2294 }
2295 *ortp_pt_list = bctbx_list_prepend_link(*ortp_pt_list, new_list);
2296 }
2297
linphone_core_get_audio_payload_types(LinphoneCore * lc)2298 bctbx_list_t *linphone_core_get_audio_payload_types(LinphoneCore *lc) {
2299 return ortp_payloads_to_linphone_payloads(lc->codecs_conf.audio_codecs, lc);
2300 }
2301
linphone_core_set_audio_payload_types(LinphoneCore * lc,const bctbx_list_t * payload_types)2302 void linphone_core_set_audio_payload_types(LinphoneCore *lc, const bctbx_list_t *payload_types) {
2303 sort_ortp_pt_list(&lc->codecs_conf.audio_codecs, payload_types);
2304 }
2305
linphone_core_get_video_payload_types(LinphoneCore * lc)2306 bctbx_list_t *linphone_core_get_video_payload_types(LinphoneCore *lc) {
2307 return ortp_payloads_to_linphone_payloads(lc->codecs_conf.video_codecs, lc);
2308 }
2309
linphone_core_set_video_payload_types(LinphoneCore * lc,const bctbx_list_t * payload_types)2310 void linphone_core_set_video_payload_types(LinphoneCore *lc, const bctbx_list_t *payload_types) {
2311 sort_ortp_pt_list(&lc->codecs_conf.video_codecs, payload_types);
2312 }
2313
linphone_core_get_text_payload_types(LinphoneCore * lc)2314 bctbx_list_t *linphone_core_get_text_payload_types(LinphoneCore *lc) {
2315 return ortp_payloads_to_linphone_payloads(lc->codecs_conf.text_codecs, lc);
2316 }
2317
linphone_core_set_text_payload_types(LinphoneCore * lc,const bctbx_list_t * payload_types)2318 void linphone_core_set_text_payload_types(LinphoneCore *lc, const bctbx_list_t *payload_types) {
2319 sort_ortp_pt_list(&lc->codecs_conf.text_codecs, payload_types);
2320 }
2321
linphone_core_get_audio_codecs(const LinphoneCore * lc)2322 const bctbx_list_t *linphone_core_get_audio_codecs(const LinphoneCore *lc) {
2323 return lc->codecs_conf.audio_codecs;
2324 }
2325
linphone_core_get_video_codecs(const LinphoneCore * lc)2326 const bctbx_list_t *linphone_core_get_video_codecs(const LinphoneCore *lc) {
2327 return lc->codecs_conf.video_codecs;
2328 }
2329
linphone_core_get_text_codecs(const LinphoneCore * lc)2330 const bctbx_list_t *linphone_core_get_text_codecs(const LinphoneCore *lc) {
2331 return lc->codecs_conf.text_codecs;
2332 }
2333
linphone_core_set_primary_contact(LinphoneCore * lc,const char * contact)2334 LinphoneStatus linphone_core_set_primary_contact(LinphoneCore *lc, const char *contact) {
2335 LinphoneAddress *ctt;
2336
2337 if( lc->sip_conf.contact != NULL && strcmp(lc->sip_conf.contact, contact) == 0){
2338 /* changing for the same contact: no need to do anything */
2339 return 0;
2340 }
2341
2342 if ((ctt=linphone_address_new(contact))==0) {
2343 ms_error("Bad contact url: %s",contact);
2344 return -1;
2345 }
2346
2347 if (lc->sip_conf.contact!=NULL) ms_free(lc->sip_conf.contact);
2348 lc->sip_conf.contact=ms_strdup(contact);
2349 lp_config_set_string(lc->config, "sip", "contact", lc->sip_conf.contact);
2350
2351 /* clean the guessed contact, we have to regenerate it */
2352 if (lc->sip_conf.guessed_contact!=NULL){
2353 ms_free(lc->sip_conf.guessed_contact);
2354 lc->sip_conf.guessed_contact=NULL;
2355 }
2356 linphone_address_unref(ctt);
2357 return 0;
2358 }
2359
2360
update_primary_contact(LinphoneCore * lc)2361 static void update_primary_contact(LinphoneCore *lc){
2362 char *guessed=NULL;
2363 char tmp[LINPHONE_IPADDR_SIZE];
2364 int port;
2365
2366 LinphoneAddress *url;
2367 if (lc->sip_conf.guessed_contact!=NULL){
2368 ms_free(lc->sip_conf.guessed_contact);
2369 lc->sip_conf.guessed_contact=NULL;
2370 }
2371 url=linphone_address_new(lc->sip_conf.contact);
2372 if (!url){
2373 ms_error("Could not parse identity contact !");
2374 url=linphone_address_new("sip:unknown@unkwownhost");
2375 }
2376 linphone_core_get_local_ip(lc, AF_UNSPEC, NULL, tmp);
2377 if (strcmp(tmp,"127.0.0.1")==0 || strcmp(tmp,"::1")==0 ){
2378 ms_warning("Local loopback network only !");
2379 lc->sip_conf.loopback_only=TRUE;
2380 }else lc->sip_conf.loopback_only=FALSE;
2381 linphone_address_set_domain(url,tmp);
2382 port = linphone_core_get_sip_port(lc);
2383 if (port > 0) linphone_address_set_port(url, port); /*if there is no listening socket the primary contact is somewhat useless,
2384 it won't work. But we prefer to return something in all cases. It at least shows username and ip address.*/
2385 guessed=linphone_address_as_string(url);
2386 lc->sip_conf.guessed_contact=guessed;
2387 linphone_address_unref(url);
2388 }
2389
linphone_core_get_primary_contact(LinphoneCore * lc)2390 const char *linphone_core_get_primary_contact(LinphoneCore *lc){
2391 char *identity;
2392
2393 if (lc->sip_conf.guess_hostname){
2394 if (lc->sip_conf.guessed_contact==NULL || lc->sip_conf.loopback_only){
2395 update_primary_contact(lc);
2396 }
2397 identity=lc->sip_conf.guessed_contact;
2398 }else{
2399 identity=lc->sip_conf.contact;
2400 }
2401 return identity;
2402 }
2403
linphone_core_set_guess_hostname(LinphoneCore * lc,bool_t val)2404 void linphone_core_set_guess_hostname(LinphoneCore *lc, bool_t val){
2405 lc->sip_conf.guess_hostname=val;
2406 }
2407
linphone_core_get_guess_hostname(LinphoneCore * lc)2408 bool_t linphone_core_get_guess_hostname(LinphoneCore *lc){
2409 return lc->sip_conf.guess_hostname;
2410 }
2411
linphone_core_enable_lime(LinphoneCore * lc,LinphoneLimeState val)2412 void linphone_core_enable_lime(LinphoneCore *lc, LinphoneLimeState val){
2413 LinphoneImEncryptionEngine *imee = linphone_im_encryption_engine_new();
2414 LinphoneImEncryptionEngineCbs *cbs = linphone_im_encryption_engine_get_callbacks(imee);
2415
2416 if(lime_is_available()){
2417 if (linphone_core_ready(lc)){
2418 lp_config_set_int(lc->config,"sip","lime",val);
2419 }
2420
2421 linphone_im_encryption_engine_cbs_set_process_incoming_message(cbs, lime_im_encryption_engine_process_incoming_message_cb);
2422 linphone_im_encryption_engine_cbs_set_process_downloading_file(cbs, lime_im_encryption_engine_process_downloading_file_cb);
2423
2424 if (val != LinphoneLimeDisabled) {
2425 linphone_im_encryption_engine_cbs_set_process_outgoing_message(cbs, lime_im_encryption_engine_process_outgoing_message_cb);
2426 linphone_im_encryption_engine_cbs_set_process_uploading_file(cbs, lime_im_encryption_engine_process_uploading_file_cb);
2427 linphone_im_encryption_engine_cbs_set_is_encryption_enabled_for_file_transfer(cbs, lime_im_encryption_engine_is_file_encryption_enabled_cb);
2428 linphone_im_encryption_engine_cbs_set_generate_file_transfer_key(cbs, lime_im_encryption_engine_generate_file_transfer_key_cb);
2429 } else {
2430 linphone_im_encryption_engine_cbs_set_process_outgoing_message(cbs, NULL);
2431 linphone_im_encryption_engine_cbs_set_process_uploading_file(cbs, NULL);
2432 linphone_im_encryption_engine_cbs_set_is_encryption_enabled_for_file_transfer(cbs, NULL);
2433 linphone_im_encryption_engine_cbs_set_generate_file_transfer_key(cbs, NULL);
2434 }
2435
2436 linphone_core_set_im_encryption_engine(lc, imee);
2437 }
2438 linphone_im_encryption_engine_unref(imee);
2439 }
2440
linphone_core_lime_available(const LinphoneCore * lc)2441 bool_t linphone_core_lime_available(const LinphoneCore *lc){
2442 return lime_is_available();
2443 }
2444
linphone_core_lime_enabled(const LinphoneCore * lc)2445 LinphoneLimeState linphone_core_lime_enabled(const LinphoneCore *lc){
2446 return linphone_core_lime_available(lc) ? lp_config_get_int(lc->config,"sip", "lime", LinphoneLimeDisabled) : LinphoneLimeDisabled;
2447 }
2448
linphone_core_lime_for_file_sharing_enabled(const LinphoneCore * lc)2449 LinphoneLimeState linphone_core_lime_for_file_sharing_enabled(const LinphoneCore *lc){
2450 LinphoneLimeState s = linphone_core_lime_enabled(lc);
2451 if (s != LinphoneLimeDisabled) {
2452 s = lp_config_get_int(lc->config,"sip", "lime_for_file_sharing", 1);
2453 }
2454 return s;
2455 }
2456
linphone_core_get_primary_contact_parsed(LinphoneCore * lc)2457 LinphoneAddress *linphone_core_get_primary_contact_parsed(LinphoneCore *lc){
2458 return linphone_address_new(linphone_core_get_primary_contact(lc));
2459 }
2460
linphone_core_set_audio_codecs(LinphoneCore * lc,bctbx_list_t * codecs)2461 LinphoneStatus linphone_core_set_audio_codecs(LinphoneCore *lc, bctbx_list_t *codecs){
2462 if (lc->codecs_conf.audio_codecs!=NULL) bctbx_list_free(lc->codecs_conf.audio_codecs);
2463 lc->codecs_conf.audio_codecs=codecs;
2464 _linphone_core_codec_config_write(lc);
2465 linphone_core_update_allocated_audio_bandwidth(lc);
2466 return 0;
2467 }
2468
linphone_core_set_video_codecs(LinphoneCore * lc,bctbx_list_t * codecs)2469 LinphoneStatus linphone_core_set_video_codecs(LinphoneCore *lc, bctbx_list_t *codecs){
2470 if (lc->codecs_conf.video_codecs!=NULL) bctbx_list_free(lc->codecs_conf.video_codecs);
2471 lc->codecs_conf.video_codecs=codecs;
2472 _linphone_core_codec_config_write(lc);
2473 return 0;
2474 }
2475
linphone_core_set_text_codecs(LinphoneCore * lc,bctbx_list_t * codecs)2476 LinphoneStatus linphone_core_set_text_codecs(LinphoneCore *lc, bctbx_list_t *codecs) {
2477 if (lc->codecs_conf.text_codecs != NULL)
2478 bctbx_list_free(lc->codecs_conf.text_codecs);
2479
2480 lc->codecs_conf.text_codecs = codecs;
2481 _linphone_core_codec_config_write(lc);
2482 return 0;
2483 }
2484
linphone_core_enable_generic_comfort_noise(LinphoneCore * lc,bool_t enabled)2485 void linphone_core_enable_generic_comfort_noise(LinphoneCore *lc, bool_t enabled){
2486 lp_config_set_int(lc->config, "misc", "use_cn", enabled);
2487 }
2488
linphone_core_generic_comfort_noise_enabled(const LinphoneCore * lc)2489 bool_t linphone_core_generic_comfort_noise_enabled(const LinphoneCore *lc){
2490 return lp_config_get_int(lc->config, "misc", "use_cn", FALSE);
2491 }
2492
linphone_core_get_friend_list(const LinphoneCore * lc)2493 const bctbx_list_t* linphone_core_get_friend_list(const LinphoneCore *lc) {
2494 bctbx_list_t *lists = lc->friends_lists;
2495 if (lists) {
2496 LinphoneFriendList *list = (LinphoneFriendList *)lists->data;
2497 if (list) {
2498 return list->friends;
2499 }
2500 }
2501 return NULL;
2502 }
2503
linphone_core_get_friends_lists(const LinphoneCore * lc)2504 const bctbx_list_t* linphone_core_get_friends_lists(const LinphoneCore *lc) {
2505 return lc->friends_lists;
2506 }
2507
linphone_core_get_default_friend_list(const LinphoneCore * lc)2508 LinphoneFriendList* linphone_core_get_default_friend_list(const LinphoneCore *lc) {
2509 if (lc && lc->friends_lists) {
2510 return (LinphoneFriendList *)lc->friends_lists->data;
2511 }
2512 return NULL;
2513 }
2514
linphone_core_remove_friend_list(LinphoneCore * lc,LinphoneFriendList * list)2515 void linphone_core_remove_friend_list(LinphoneCore *lc, LinphoneFriendList *list) {
2516 bctbx_list_t *elem = bctbx_list_find(lc->friends_lists, list);
2517 if (elem == NULL) return;
2518 #ifdef SQLITE_STORAGE_ENABLED
2519 linphone_core_remove_friends_list_from_db(lc, list);
2520 #endif
2521 linphone_core_notify_friend_list_removed(lc, list);
2522 list->lc = NULL;
2523 linphone_friend_list_unref(list);
2524 lc->friends_lists = bctbx_list_erase_link(lc->friends_lists, elem);
2525 }
2526
linphone_core_add_friend_list(LinphoneCore * lc,LinphoneFriendList * list)2527 void linphone_core_add_friend_list(LinphoneCore *lc, LinphoneFriendList *list) {
2528 if (!list->lc) {
2529 list->lc = lc;
2530 }
2531 lc->friends_lists = bctbx_list_append(lc->friends_lists, linphone_friend_list_ref(list));
2532 #ifdef SQLITE_STORAGE_ENABLED
2533 linphone_core_store_friends_list_in_db(lc, list);
2534 #endif
2535 linphone_core_notify_friend_list_created(lc, list);
2536 }
2537
linphone_core_enable_audio_adaptive_jittcomp(LinphoneCore * lc,bool_t val)2538 void linphone_core_enable_audio_adaptive_jittcomp(LinphoneCore* lc, bool_t val) {
2539 lc->rtp_conf.audio_adaptive_jitt_comp_enabled = val;
2540 }
2541
linphone_core_audio_adaptive_jittcomp_enabled(LinphoneCore * lc)2542 bool_t linphone_core_audio_adaptive_jittcomp_enabled(LinphoneCore* lc) {
2543 return lc->rtp_conf.audio_adaptive_jitt_comp_enabled;
2544 }
2545
linphone_core_get_audio_jittcomp(LinphoneCore * lc)2546 int linphone_core_get_audio_jittcomp(LinphoneCore *lc) {
2547 return lc->rtp_conf.audio_jitt_comp;
2548 }
2549
linphone_core_enable_video_adaptive_jittcomp(LinphoneCore * lc,bool_t val)2550 void linphone_core_enable_video_adaptive_jittcomp(LinphoneCore* lc, bool_t val) {
2551 lc->rtp_conf.video_adaptive_jitt_comp_enabled = val;
2552 }
2553
linphone_core_video_adaptive_jittcomp_enabled(LinphoneCore * lc)2554 bool_t linphone_core_video_adaptive_jittcomp_enabled(LinphoneCore* lc) {
2555 return lc->rtp_conf.video_adaptive_jitt_comp_enabled;
2556 }
2557
linphone_core_get_video_jittcomp(LinphoneCore * lc)2558 int linphone_core_get_video_jittcomp(LinphoneCore *lc) {
2559 return lc->rtp_conf.video_jitt_comp;
2560 }
2561
linphone_core_get_audio_port(const LinphoneCore * lc)2562 int linphone_core_get_audio_port(const LinphoneCore *lc) {
2563 return lc->rtp_conf.audio_rtp_min_port;
2564 }
2565
linphone_core_get_audio_port_range(const LinphoneCore * lc,int * min_port,int * max_port)2566 void linphone_core_get_audio_port_range(const LinphoneCore *lc, int *min_port, int *max_port) {
2567 *min_port = lc->rtp_conf.audio_rtp_min_port;
2568 *max_port = lc->rtp_conf.audio_rtp_max_port;
2569 }
2570
linphone_core_get_audio_ports_range(const LinphoneCore * lc)2571 LinphoneRange *linphone_core_get_audio_ports_range(const LinphoneCore *lc) {
2572 LinphoneRange *range = linphone_range_new();
2573 range->min = lc->rtp_conf.audio_rtp_min_port;
2574 range->max = lc->rtp_conf.audio_rtp_max_port;
2575 return range;
2576 }
2577
linphone_core_get_video_port(const LinphoneCore * lc)2578 int linphone_core_get_video_port(const LinphoneCore *lc){
2579 return lc->rtp_conf.video_rtp_min_port;
2580 }
2581
linphone_core_get_video_port_range(const LinphoneCore * lc,int * min_port,int * max_port)2582 void linphone_core_get_video_port_range(const LinphoneCore *lc, int *min_port, int *max_port) {
2583 *min_port = lc->rtp_conf.video_rtp_min_port;
2584 *max_port = lc->rtp_conf.video_rtp_max_port;
2585 }
2586
linphone_core_get_video_ports_range(const LinphoneCore * lc)2587 LinphoneRange *linphone_core_get_video_ports_range(const LinphoneCore *lc) {
2588 LinphoneRange *range = linphone_range_new();
2589 range->min = lc->rtp_conf.video_rtp_min_port;
2590 range->max = lc->rtp_conf.video_rtp_max_port;
2591 return range;
2592 }
2593
linphone_core_get_text_port(const LinphoneCore * lc)2594 int linphone_core_get_text_port(const LinphoneCore *lc) {
2595 return lc->rtp_conf.text_rtp_min_port;
2596 }
2597
linphone_core_get_text_port_range(const LinphoneCore * lc,int * min_port,int * max_port)2598 void linphone_core_get_text_port_range(const LinphoneCore *lc, int *min_port, int *max_port) {
2599 *min_port = lc->rtp_conf.text_rtp_min_port;
2600 *max_port = lc->rtp_conf.text_rtp_max_port;
2601 }
2602
linphone_core_get_text_ports_range(const LinphoneCore * lc)2603 LinphoneRange *linphone_core_get_text_ports_range(const LinphoneCore *lc) {
2604 LinphoneRange *range = linphone_range_new();
2605 range->min = lc->rtp_conf.text_rtp_min_port;
2606 range->max = lc->rtp_conf.text_rtp_max_port;
2607 return range;
2608 }
2609
linphone_core_get_nortp_timeout(const LinphoneCore * lc)2610 int linphone_core_get_nortp_timeout(const LinphoneCore *lc){
2611 return lc->rtp_conf.nortp_timeout;
2612 }
2613
linphone_core_get_rtp_no_xmit_on_audio_mute(const LinphoneCore * lc)2614 bool_t linphone_core_get_rtp_no_xmit_on_audio_mute(const LinphoneCore *lc){
2615 return lc->rtp_conf.rtp_no_xmit_on_audio_mute;
2616 }
2617
apply_jitter_value(LinphoneCore * lc,int value,MSFormatType stype)2618 static void apply_jitter_value(LinphoneCore *lc, int value, MSFormatType stype){
2619 LinphoneCall *call;
2620 bctbx_list_t *it;
2621 for (it=lc->calls;it!=NULL;it=it->next){
2622 MediaStream *ms;
2623 call=(LinphoneCall*)it->data;
2624 ms = stype==MSAudio ? (MediaStream*)call->audiostream : (MediaStream*)call->videostream;
2625 if (ms){
2626 RtpSession *s=ms->sessions.rtp_session;
2627 if (s){
2628 if (value>0){
2629 ms_message("Jitter buffer size set to [%i] ms on call [%p]",value,call);
2630 rtp_session_set_jitter_compensation(s,value);
2631 rtp_session_enable_jitter_buffer(s,TRUE);
2632 }else if (value==0){
2633 ms_warning("Jitter buffer is disabled per application request on call [%p]",call);
2634 rtp_session_enable_jitter_buffer(s,FALSE);
2635 }
2636 }
2637 }
2638 }
2639 }
2640
linphone_core_set_audio_jittcomp(LinphoneCore * lc,int milliseconds)2641 void linphone_core_set_audio_jittcomp(LinphoneCore *lc, int milliseconds) {
2642 lc->rtp_conf.audio_jitt_comp=milliseconds;
2643 apply_jitter_value(lc, milliseconds, MSAudio);
2644 }
2645
linphone_core_set_video_jittcomp(LinphoneCore * lc,int milliseconds)2646 void linphone_core_set_video_jittcomp(LinphoneCore *lc, int milliseconds) {
2647 lc->rtp_conf.video_jitt_comp=milliseconds;
2648 apply_jitter_value(lc, milliseconds, MSVideo);
2649 }
2650
linphone_core_set_rtp_no_xmit_on_audio_mute(LinphoneCore * lc,bool_t rtp_no_xmit_on_audio_mute)2651 void linphone_core_set_rtp_no_xmit_on_audio_mute(LinphoneCore *lc,bool_t rtp_no_xmit_on_audio_mute){
2652 lc->rtp_conf.rtp_no_xmit_on_audio_mute=rtp_no_xmit_on_audio_mute;
2653 }
2654
linphone_core_set_audio_port(LinphoneCore * lc,int port)2655 void linphone_core_set_audio_port(LinphoneCore *lc, int port) {
2656 lc->rtp_conf.audio_rtp_min_port=lc->rtp_conf.audio_rtp_max_port=port;
2657 }
2658
linphone_core_set_audio_port_range(LinphoneCore * lc,int min_port,int max_port)2659 void linphone_core_set_audio_port_range(LinphoneCore *lc, int min_port, int max_port) {
2660 lc->rtp_conf.audio_rtp_min_port=min_port;
2661 lc->rtp_conf.audio_rtp_max_port=max_port;
2662 }
2663
linphone_core_set_video_port(LinphoneCore * lc,int port)2664 void linphone_core_set_video_port(LinphoneCore *lc, int port){
2665 lc->rtp_conf.video_rtp_min_port=lc->rtp_conf.video_rtp_max_port=port;
2666 }
2667
linphone_core_set_video_port_range(LinphoneCore * lc,int min_port,int max_port)2668 void linphone_core_set_video_port_range(LinphoneCore *lc, int min_port, int max_port) {
2669 lc->rtp_conf.video_rtp_min_port=min_port;
2670 lc->rtp_conf.video_rtp_max_port=max_port;
2671 }
2672
linphone_core_set_text_port(LinphoneCore * lc,int port)2673 void linphone_core_set_text_port(LinphoneCore *lc, int port) {
2674 lc->rtp_conf.text_rtp_min_port = lc->rtp_conf.text_rtp_max_port = port;
2675 }
2676
linphone_core_set_text_port_range(LinphoneCore * lc,int min_port,int max_port)2677 void linphone_core_set_text_port_range(LinphoneCore *lc, int min_port, int max_port) {
2678 lc->rtp_conf.text_rtp_min_port = min_port;
2679 lc->rtp_conf.text_rtp_max_port = max_port;
2680 }
2681
linphone_core_set_nortp_timeout(LinphoneCore * lc,int nortp_timeout)2682 void linphone_core_set_nortp_timeout(LinphoneCore *lc, int nortp_timeout){
2683 lc->rtp_conf.nortp_timeout=nortp_timeout;
2684 }
2685
linphone_core_get_use_info_for_dtmf(LinphoneCore * lc)2686 bool_t linphone_core_get_use_info_for_dtmf(LinphoneCore *lc) {
2687 return lp_config_get_int(lc->config, "sip", "use_info", 0);
2688 }
2689
linphone_core_set_use_info_for_dtmf(LinphoneCore * lc,bool_t use_info)2690 void linphone_core_set_use_info_for_dtmf(LinphoneCore *lc,bool_t use_info) {
2691 if (linphone_core_ready(lc)) {
2692 lp_config_set_int(lc->config, "sip", "use_info", use_info);
2693 }
2694 }
2695
linphone_core_get_use_rfc2833_for_dtmf(LinphoneCore * lc)2696 bool_t linphone_core_get_use_rfc2833_for_dtmf(LinphoneCore *lc) {
2697 return lp_config_get_int(lc->config, "sip", "use_rfc2833", 1);
2698 }
2699
linphone_core_set_use_rfc2833_for_dtmf(LinphoneCore * lc,bool_t use_rfc2833)2700 void linphone_core_set_use_rfc2833_for_dtmf(LinphoneCore *lc,bool_t use_rfc2833) {
2701 if (linphone_core_ready(lc)) {
2702 lp_config_set_int(lc->config, "sip", "use_rfc2833", use_rfc2833);
2703 }
2704 }
2705
linphone_core_get_sip_port(LinphoneCore * lc)2706 int linphone_core_get_sip_port(LinphoneCore *lc){
2707 LinphoneSipTransports tr;
2708 linphone_core_get_sip_transports_used(lc,&tr);
2709 return tr.udp_port>0 ? tr.udp_port : (tr.tcp_port > 0 ? tr.tcp_port : tr.tls_port);
2710 }
2711
2712 static char _ua_name[64]="Linphone";
2713 static char _ua_version[64]=LIBLINPHONE_VERSION;
2714
linphone_core_set_user_agent(LinphoneCore * lc,const char * name,const char * ver)2715 void linphone_core_set_user_agent(LinphoneCore *lc, const char *name, const char *ver){
2716 char ua_string[256];
2717 snprintf(ua_string, sizeof(ua_string) - 1, "%s/%s", name?name:"", ver?ver:"");
2718 if (lc->sal) {
2719 sal_set_user_agent(lc->sal, ua_string);
2720 sal_append_stack_string_to_user_agent(lc->sal);
2721 }
2722 }
linphone_core_get_user_agent(LinphoneCore * lc)2723 const char *linphone_core_get_user_agent(LinphoneCore *lc){
2724 return sal_get_user_agent(lc->sal);
2725 }
2726
linphone_core_get_user_agent_name(void)2727 const char *linphone_core_get_user_agent_name(void){
2728 return _ua_name;
2729 }
2730
linphone_core_get_user_agent_version(void)2731 const char *linphone_core_get_user_agent_version(void){
2732 return _ua_version;
2733 }
2734
transport_error(LinphoneCore * lc,const char * transport,int port)2735 static void transport_error(LinphoneCore *lc, const char* transport, int port){
2736 char *msg=ortp_strdup_printf("Could not start %s transport on port %i, maybe this port is already used.",transport,port);
2737 ms_warning("%s",msg);
2738 linphone_core_notify_display_warning(lc,msg);
2739 ms_free(msg);
2740 }
2741
transports_unchanged(const LinphoneSipTransports * tr1,const LinphoneSipTransports * tr2)2742 static bool_t transports_unchanged(const LinphoneSipTransports * tr1, const LinphoneSipTransports * tr2){
2743 return
2744 tr2->udp_port==tr1->udp_port &&
2745 tr2->tcp_port==tr1->tcp_port &&
2746 tr2->dtls_port==tr1->dtls_port &&
2747 tr2->tls_port==tr1->tls_port;
2748 }
2749
__linphone_core_invalidate_registers(LinphoneCore * lc)2750 static void __linphone_core_invalidate_registers(LinphoneCore* lc){
2751 const bctbx_list_t *elem=linphone_core_get_proxy_config_list(lc);
2752 for(;elem!=NULL;elem=elem->next){
2753 LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;
2754 if (linphone_proxy_config_register_enabled(cfg)) {
2755 /*this will force a re-registration at next iterate*/
2756 cfg->commit = TRUE;
2757 }
2758 }
2759 }
2760
_linphone_core_apply_transports(LinphoneCore * lc)2761 int _linphone_core_apply_transports(LinphoneCore *lc){
2762 Sal *sal=lc->sal;
2763 const char *anyaddr;
2764 LinphoneSipTransports *tr=&lc->sip_conf.transports;
2765 const char* listening_address;
2766 /*first of all invalidate all current registrations so that we can register again with new transports*/
2767 __linphone_core_invalidate_registers(lc);
2768
2769 if (lc->sip_conf.ipv6_enabled)
2770 anyaddr="::0";
2771 else
2772 anyaddr="0.0.0.0";
2773
2774 sal_unlisten_ports(sal);
2775
2776 listening_address = lp_config_get_string(lc->config,"sip","bind_address",anyaddr);
2777 if (linphone_core_get_http_proxy_host(lc)) {
2778 sal_set_http_proxy_host(sal, linphone_core_get_http_proxy_host(lc));
2779 sal_set_http_proxy_port(sal,linphone_core_get_http_proxy_port(lc));
2780 }
2781 if (lc->tunnel && linphone_tunnel_sip_enabled(lc->tunnel) && linphone_tunnel_get_activated(lc->tunnel)){
2782 if (sal_listen_port(sal,anyaddr,tr->udp_port,SalTransportUDP,TRUE)!=0){
2783 transport_error(lc,"udp+tunnel",tr->udp_port);
2784 }
2785 }else{
2786 if (tr->udp_port!=0){
2787 if (sal_listen_port(sal,listening_address,tr->udp_port,SalTransportUDP,FALSE)!=0){
2788 transport_error(lc,"udp",tr->udp_port);
2789 }
2790 }
2791 if (tr->tcp_port!=0){
2792 if (sal_listen_port (sal,listening_address,tr->tcp_port,SalTransportTCP,FALSE)!=0){
2793 transport_error(lc,"tcp",tr->tcp_port);
2794 }
2795 }
2796 if (linphone_core_sip_transport_supported(lc,LinphoneTransportTls)){
2797 if (tr->tls_port!=0){
2798 if (sal_listen_port (sal,listening_address,tr->tls_port,SalTransportTLS,FALSE)!=0){
2799 transport_error(lc,"tls",tr->tls_port);
2800 }
2801 }
2802 }
2803 }
2804 return 0;
2805 }
2806
linphone_core_sip_transport_supported(const LinphoneCore * lc,LinphoneTransportType tp)2807 bool_t linphone_core_sip_transport_supported(const LinphoneCore *lc, LinphoneTransportType tp){
2808 return sal_transport_available(lc->sal,(SalTransport)tp);
2809 }
2810
2811 BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneTransports);
2812
2813 BELLE_SIP_INSTANCIATE_VPTR(LinphoneTransports, belle_sip_object_t,
2814 NULL, // destroy
2815 NULL, // clone
2816 NULL, // marshal
2817 FALSE
2818 );
2819
linphone_transports_new()2820 LinphoneTransports *linphone_transports_new() {
2821 LinphoneTransports *transports = belle_sip_object_new(LinphoneTransports);
2822 transports->udp_port = 0;
2823 transports->tcp_port = 0;
2824 transports->tls_port = 0;
2825 transports->dtls_port = 0;
2826 return transports;
2827 }
2828
linphone_transports_ref(LinphoneTransports * transports)2829 LinphoneTransports* linphone_transports_ref(LinphoneTransports* transports) {
2830 return (LinphoneTransports*) belle_sip_object_ref(transports);
2831 }
2832
linphone_transports_unref(LinphoneTransports * transports)2833 void linphone_transports_unref (LinphoneTransports* transports) {
2834 belle_sip_object_unref(transports);
2835 }
2836
linphone_transports_get_user_data(const LinphoneTransports * transports)2837 void *linphone_transports_get_user_data(const LinphoneTransports *transports) {
2838 return transports->user_data;
2839 }
2840
linphone_transports_set_user_data(LinphoneTransports * transports,void * data)2841 void linphone_transports_set_user_data(LinphoneTransports *transports, void *data) {
2842 transports->user_data = data;
2843 }
2844
linphone_transports_get_udp_port(const LinphoneTransports * transports)2845 int linphone_transports_get_udp_port(const LinphoneTransports* transports) {
2846 return transports->udp_port;
2847 }
2848
linphone_transports_get_tcp_port(const LinphoneTransports * transports)2849 int linphone_transports_get_tcp_port(const LinphoneTransports* transports) {
2850 return transports->tcp_port;
2851 }
2852
linphone_transports_get_tls_port(const LinphoneTransports * transports)2853 int linphone_transports_get_tls_port(const LinphoneTransports* transports) {
2854 return transports->tls_port;
2855 }
2856
linphone_transports_get_dtls_port(const LinphoneTransports * transports)2857 int linphone_transports_get_dtls_port(const LinphoneTransports* transports) {
2858 return transports->dtls_port;
2859 }
2860
linphone_transports_set_udp_port(LinphoneTransports * transports,int port)2861 void linphone_transports_set_udp_port(LinphoneTransports *transports, int port) {
2862 transports->udp_port = port;
2863 }
2864
linphone_transports_set_tcp_port(LinphoneTransports * transports,int port)2865 void linphone_transports_set_tcp_port(LinphoneTransports *transports, int port) {
2866 transports->tcp_port = port;
2867 }
2868
linphone_transports_set_tls_port(LinphoneTransports * transports,int port)2869 void linphone_transports_set_tls_port(LinphoneTransports *transports, int port) {
2870 transports->tls_port = port;
2871 }
2872
linphone_transports_set_dtls_port(LinphoneTransports * transports,int port)2873 void linphone_transports_set_dtls_port(LinphoneTransports *transports, int port) {
2874 transports->dtls_port = port;
2875 }
2876
linphone_core_set_sip_transports(LinphoneCore * lc,const LinphoneSipTransports * tr_config)2877 LinphoneStatus linphone_core_set_sip_transports(LinphoneCore *lc, const LinphoneSipTransports * tr_config /*config to be saved*/){
2878 LinphoneSipTransports tr=*tr_config;
2879
2880 if (lp_config_get_int(lc->config,"sip","sip_random_port",0)==1) {
2881 /*legacy random mode*/
2882 if (tr.udp_port>0){
2883 tr.udp_port=LC_SIP_TRANSPORT_RANDOM;
2884 }
2885 if (tr.tcp_port>0){
2886 tr.tcp_port=LC_SIP_TRANSPORT_RANDOM;
2887 }
2888 if (tr.tls_port>0){
2889 tr.tls_port=LC_SIP_TRANSPORT_RANDOM;
2890 }
2891 }
2892
2893 if (tr.udp_port==0 && tr.tcp_port==0 && tr.tls_port==0){
2894 tr.udp_port=5060;
2895 }
2896
2897 if (transports_unchanged(&tr,&lc->sip_conf.transports))
2898 return 0;
2899 memcpy(&lc->sip_conf.transports,&tr,sizeof(tr));
2900
2901 if (linphone_core_ready(lc)){
2902 lp_config_set_int(lc->config,"sip","sip_port",tr_config->udp_port);
2903 lp_config_set_int(lc->config,"sip","sip_tcp_port",tr_config->tcp_port);
2904 lp_config_set_int(lc->config,"sip","sip_tls_port",tr_config->tls_port);
2905 }
2906
2907 if (lc->sal==NULL) return 0;
2908 return _linphone_core_apply_transports(lc);
2909 }
2910
linphone_core_set_transports(LinphoneCore * lc,const LinphoneTransports * transports)2911 LinphoneStatus linphone_core_set_transports(LinphoneCore *lc, const LinphoneTransports * transports){
2912 if (transports->udp_port == lc->sip_conf.transports.udp_port &&
2913 transports->tcp_port == lc->sip_conf.transports.tcp_port &&
2914 transports->tls_port == lc->sip_conf.transports.tls_port &&
2915 transports->dtls_port == lc->sip_conf.transports.dtls_port) {
2916 return 0;
2917 }
2918 lc->sip_conf.transports.udp_port = transports->udp_port;
2919 lc->sip_conf.transports.tcp_port = transports->tcp_port;
2920 lc->sip_conf.transports.tls_port = transports->tls_port;
2921 lc->sip_conf.transports.dtls_port = transports->dtls_port;
2922
2923 if (linphone_core_ready(lc)) {
2924 lp_config_set_int(lc->config,"sip", "sip_port", transports->udp_port);
2925 lp_config_set_int(lc->config,"sip", "sip_tcp_port", transports->tcp_port);
2926 lp_config_set_int(lc->config,"sip", "sip_tls_port", transports->tls_port);
2927 }
2928
2929 if (lc->sal == NULL) return 0;
2930 return _linphone_core_apply_transports(lc);
2931 }
2932
linphone_core_get_sip_transports(LinphoneCore * lc,LinphoneSipTransports * tr)2933 LinphoneStatus linphone_core_get_sip_transports(LinphoneCore *lc, LinphoneSipTransports *tr){
2934 memcpy(tr,&lc->sip_conf.transports,sizeof(*tr));
2935 return 0;
2936 }
2937
linphone_core_get_transports(LinphoneCore * lc)2938 LinphoneTransports *linphone_core_get_transports(LinphoneCore *lc){
2939 LinphoneTransports *transports = linphone_transports_new();
2940 transports->udp_port = lc->sip_conf.transports.udp_port;
2941 transports->tcp_port = lc->sip_conf.transports.tcp_port;
2942 transports->tls_port = lc->sip_conf.transports.tls_port;
2943 transports->dtls_port = lc->sip_conf.transports.dtls_port;
2944 return transports;
2945 }
2946
linphone_core_get_sip_transports_used(LinphoneCore * lc,LinphoneSipTransports * tr)2947 void linphone_core_get_sip_transports_used(LinphoneCore *lc, LinphoneSipTransports *tr){
2948 tr->udp_port=sal_get_listening_port(lc->sal,SalTransportUDP);
2949 tr->tcp_port=sal_get_listening_port(lc->sal,SalTransportTCP);
2950 tr->tls_port=sal_get_listening_port(lc->sal,SalTransportTLS);
2951 }
2952
linphone_core_get_transports_used(LinphoneCore * lc)2953 LinphoneTransports *linphone_core_get_transports_used(LinphoneCore *lc){
2954 LinphoneTransports *transports = linphone_transports_new();
2955 transports->udp_port = sal_get_listening_port(lc->sal, SalTransportUDP);
2956 transports->tcp_port = sal_get_listening_port(lc->sal, SalTransportTCP);
2957 transports->tls_port = sal_get_listening_port(lc->sal, SalTransportTLS);
2958 transports->dtls_port = sal_get_listening_port(lc->sal, SalTransportDTLS);
2959 return transports;
2960 }
2961
linphone_core_set_sip_port(LinphoneCore * lc,int port)2962 void linphone_core_set_sip_port(LinphoneCore *lc,int port) {
2963 LinphoneSipTransports tr;
2964 memset(&tr,0,sizeof(tr));
2965 tr.udp_port=port;
2966 linphone_core_set_sip_transports (lc,&tr);
2967 }
2968
linphone_core_ipv6_enabled(LinphoneCore * lc)2969 bool_t linphone_core_ipv6_enabled(LinphoneCore *lc){
2970 return lc->sip_conf.ipv6_enabled;
2971 }
2972
linphone_core_enable_ipv6(LinphoneCore * lc,bool_t val)2973 void linphone_core_enable_ipv6(LinphoneCore *lc, bool_t val){
2974 if (lc->sip_conf.ipv6_enabled!=val){
2975 lc->sip_conf.ipv6_enabled=val;
2976 if (lc->sal){
2977 /* we need to update the sip stack */
2978 _linphone_core_apply_transports(lc);
2979 }
2980 /*update the localip immediately for the network monitor to avoid to "discover" later that we switched to ipv6*/
2981 linphone_core_get_local_ip(lc,AF_UNSPEC,NULL,lc->localip);
2982 if (linphone_core_ready(lc)){
2983 lp_config_set_int(lc->config,"sip","use_ipv6",(int)val);
2984 }
2985 }
2986 }
2987
linphone_core_content_encoding_supported(const LinphoneCore * lc,const char * content_encoding)2988 bool_t linphone_core_content_encoding_supported(const LinphoneCore *lc, const char *content_encoding) {
2989 const char *handle_content_encoding = lp_config_get_string(lc->config, "sip", "handle_content_encoding", "deflate");
2990 return (strcmp(handle_content_encoding, content_encoding) == 0) && sal_content_encoding_available(lc->sal, content_encoding);
2991 }
2992
monitor_network_state(LinphoneCore * lc,time_t curtime)2993 static void monitor_network_state(LinphoneCore *lc, time_t curtime){
2994 bool_t new_status=lc->network_last_status;
2995 char newip[LINPHONE_IPADDR_SIZE];
2996
2997 /* only do the network up checking every five seconds */
2998 if (lc->network_last_check==0 || (curtime-lc->network_last_check)>=5){
2999 linphone_core_get_local_ip(lc,AF_UNSPEC,NULL,newip);
3000 if (strcmp(newip,"::1")!=0 && strcmp(newip,"127.0.0.1")!=0){
3001 new_status=TRUE;
3002 }else new_status=FALSE; /*no network*/
3003
3004 if (new_status==lc->network_last_status && new_status==TRUE && strcmp(newip,lc->localip)!=0){
3005 /*IP address change detected*/
3006 ms_message("IP address change detected.");
3007 set_network_reachable(lc,FALSE,curtime);
3008 lc->network_last_status=FALSE;
3009 }
3010 strncpy(lc->localip,newip,sizeof(lc->localip));
3011
3012 if (new_status!=lc->network_last_status) {
3013 if (new_status){
3014 ms_message("New local ip address is %s",lc->localip);
3015 }
3016 set_network_reachable(lc,new_status, curtime);
3017 lc->network_last_status=new_status;
3018 }
3019 lc->network_last_check=curtime;
3020 }
3021 }
3022
proxy_update(LinphoneCore * lc)3023 static void proxy_update(LinphoneCore *lc){
3024 bctbx_list_t *elem,*next;
3025 bctbx_list_for_each(lc->sip_conf.proxies,(void (*)(void*))&linphone_proxy_config_update);
3026 for(elem=lc->sip_conf.deleted_proxies;elem!=NULL;elem=next){
3027 LinphoneProxyConfig* cfg = (LinphoneProxyConfig*)elem->data;
3028 next=elem->next;
3029 if (ms_time(NULL) - cfg->deletion_date > 32) {
3030 lc->sip_conf.deleted_proxies =bctbx_list_erase_link(lc->sip_conf.deleted_proxies,elem);
3031 ms_message("Proxy config for [%s] is definitely removed from core.",linphone_proxy_config_get_addr(cfg));
3032 _linphone_proxy_config_release_ops(cfg);
3033 linphone_proxy_config_unref(cfg);
3034 }
3035 }
3036 }
3037
assign_buddy_info(LinphoneCore * lc,BuddyInfo * info)3038 static void assign_buddy_info(LinphoneCore *lc, BuddyInfo *info){
3039 LinphoneFriend *lf=linphone_core_get_friend_by_address(lc,info->sip_uri);
3040 if (lf!=NULL){
3041 lf->info=info;
3042 ms_message("%s has a BuddyInfo assigned with image %p",info->sip_uri, info->image_data);
3043 linphone_core_notify_buddy_info_updated(lc,lf);
3044 }else{
3045 ms_warning("Could not any friend with uri %s",info->sip_uri);
3046 }
3047 }
3048
analyze_buddy_lookup_results(LinphoneCore * lc,LinphoneProxyConfig * cfg)3049 static void analyze_buddy_lookup_results(LinphoneCore *lc, LinphoneProxyConfig *cfg){
3050 bctbx_list_t *elem;
3051 SipSetupContext *ctx=linphone_proxy_config_get_sip_setup_context(cfg);
3052 for (elem=lc->bl_reqs;elem!=NULL;elem=bctbx_list_next(elem)){
3053 BuddyLookupRequest *req=(BuddyLookupRequest *)elem->data;
3054 if (req->status==BuddyLookupDone || req->status==BuddyLookupFailure){
3055 if (req->results!=NULL){
3056 BuddyInfo *i=(BuddyInfo*)req->results->data;
3057 bctbx_list_free(req->results);
3058 req->results=NULL;
3059 assign_buddy_info(lc,i);
3060 }
3061 sip_setup_context_buddy_lookup_free(ctx,req);
3062 elem->data=NULL;
3063 }
3064 }
3065 /*purge completed requests */
3066 while((elem=bctbx_list_find(lc->bl_reqs,NULL))!=NULL){
3067 lc->bl_reqs=bctbx_list_erase_link(lc->bl_reqs,elem);
3068 }
3069 }
3070
linphone_core_grab_buddy_infos(LinphoneCore * lc,LinphoneProxyConfig * cfg)3071 static void linphone_core_grab_buddy_infos(LinphoneCore *lc, LinphoneProxyConfig *cfg){
3072 const bctbx_list_t *elem;
3073 SipSetupContext *ctx=linphone_proxy_config_get_sip_setup_context(cfg);
3074 for(elem=linphone_core_get_friend_list(lc);elem!=NULL;elem=elem->next){
3075 LinphoneFriend *lf=(LinphoneFriend*)elem->data;
3076 if (lf->info==NULL){
3077 if (linphone_core_lookup_known_proxy(lc,lf->uri)==cfg){
3078 if (linphone_address_get_username(lf->uri)!=NULL){
3079 BuddyLookupRequest *req;
3080 char *tmp=linphone_address_as_string_uri_only(lf->uri);
3081 req=sip_setup_context_create_buddy_lookup_request(ctx);
3082 buddy_lookup_request_set_key(req,tmp);
3083 buddy_lookup_request_set_max_results(req,1);
3084 sip_setup_context_buddy_lookup_submit(ctx,req);
3085 lc->bl_reqs=bctbx_list_append(lc->bl_reqs,req);
3086 ms_free(tmp);
3087 }
3088 }
3089 }
3090 }
3091 }
3092
linphone_core_do_plugin_tasks(LinphoneCore * lc)3093 static void linphone_core_do_plugin_tasks(LinphoneCore *lc){
3094 LinphoneProxyConfig *cfg=linphone_core_get_default_proxy_config(lc);
3095 if (cfg){
3096 if (lc->bl_refresh){
3097 SipSetupContext *ctx=linphone_proxy_config_get_sip_setup_context(cfg);
3098 if (ctx && (sip_setup_context_get_capabilities(ctx) & SIP_SETUP_CAP_BUDDY_LOOKUP)){
3099 linphone_core_grab_buddy_infos(lc,cfg);
3100 lc->bl_refresh=FALSE;
3101 }
3102 }
3103 if (lc->bl_reqs) analyze_buddy_lookup_results(lc,cfg);
3104 }
3105 }
3106
linphone_core_iterate(LinphoneCore * lc)3107 void linphone_core_iterate(LinphoneCore *lc){
3108 bctbx_list_t *calls;
3109 LinphoneCall *call;
3110 uint64_t curtime_ms = ms_get_cur_time_ms(); /*monotonic time*/
3111 int elapsed;
3112 time_t current_real_time = ms_time(NULL);
3113 int64_t diff_time;
3114 bool_t one_second_elapsed=FALSE;
3115 const char *remote_provisioning_uri = NULL;
3116
3117 if (lc->network_reachable_to_be_notified) {
3118 lc->network_reachable_to_be_notified=FALSE;
3119 linphone_core_notify_network_reachable(lc,lc->sip_network_reachable);
3120 if (lc->sip_network_reachable) {
3121 linphone_core_resolve_stun_server(lc);
3122 }
3123 }
3124 if (linphone_core_get_global_state(lc) == LinphoneGlobalStartup) {
3125 if (sal_get_root_ca(lc->sal)) {
3126 belle_tls_crypto_config_set_root_ca(lc->http_crypto_config, sal_get_root_ca(lc->sal));
3127 belle_http_provider_set_tls_crypto_config(lc->http_provider, lc->http_crypto_config);
3128 }
3129
3130 linphone_core_notify_display_status(lc, _("Configuring"));
3131 linphone_core_set_state(lc, LinphoneGlobalConfiguring, "Configuring");
3132
3133 remote_provisioning_uri = linphone_core_get_provisioning_uri(lc);
3134 if (remote_provisioning_uri) {
3135 int err = linphone_remote_provisioning_download_and_apply(lc, remote_provisioning_uri);
3136 if (err == -1) {
3137 linphone_configuring_terminated(lc, LinphoneConfiguringFailed, "Bad URI");
3138 }
3139 } // else linphone_configuring_terminated has already been called in linphone_core_init
3140 }
3141 if (lc->prevtime_ms == 0){
3142 lc->prevtime_ms = curtime_ms;
3143 }
3144 if ((diff_time=curtime_ms-lc->prevtime_ms) >= 1000){
3145 one_second_elapsed=TRUE;
3146 if (diff_time>3000){
3147 /*since monotonic time doesn't increment while machine is sleeping, we don't want to catchup too much*/
3148 lc->prevtime_ms = curtime_ms;
3149 }else{
3150 lc->prevtime_ms += 1000;
3151
3152 }
3153 }
3154
3155 if (lc->ecc!=NULL){
3156 LinphoneEcCalibratorStatus ecs=ec_calibrator_get_status(lc->ecc);
3157 if (ecs!=LinphoneEcCalibratorInProgress){
3158 if (lc->ecc->cb)
3159 lc->ecc->cb(lc,ecs,lc->ecc->delay,lc->ecc->cb_data);
3160 if (ecs==LinphoneEcCalibratorDone){
3161 int len=lp_config_get_int(lc->config,"sound","ec_tail_len",0);
3162 int margin=len/2;
3163
3164 lp_config_set_int(lc->config, "sound", "ec_delay",MAX(lc->ecc->delay-margin,0));
3165 } else if (ecs == LinphoneEcCalibratorFailed) {
3166 lp_config_set_int(lc->config, "sound", "ec_delay", -1);/*use default value from soundcard*/
3167 } else if (ecs == LinphoneEcCalibratorDoneNoEcho) {
3168 linphone_core_enable_echo_cancellation(lc, FALSE);
3169 }
3170 ec_calibrator_destroy(lc->ecc);
3171 lc->ecc=NULL;
3172 }
3173 }
3174
3175 if (lc->preview_finished){
3176 lc->preview_finished=0;
3177 linphone_ringtoneplayer_stop(lc->ringtoneplayer);
3178 lc_callback_obj_invoke(&lc->preview_finished_cb,lc);
3179 }
3180
3181 if (lc->ringstream && lc->ringstream_autorelease && lc->dmfs_playing_start_time!=0
3182 && (curtime_ms/1000 - lc->dmfs_playing_start_time)>5){
3183 MSPlayerState state;
3184 bool_t stop=TRUE;
3185 if (lc->ringstream->source && ms_filter_call_method(lc->ringstream->source,MS_PLAYER_GET_STATE,&state)==0){
3186 if (state==MSPlayerPlaying) stop=FALSE;
3187 }
3188 if (stop) {
3189 ms_message("Releasing inactive tone player.");
3190 linphone_core_stop_dtmf_stream(lc);
3191 }
3192 }
3193
3194 sal_iterate(lc->sal);
3195 if (lc->msevq) ms_event_queue_pump(lc->msevq);
3196 if (lc->auto_net_state_mon) monitor_network_state(lc, current_real_time);
3197
3198 proxy_update(lc);
3199
3200 //we have to iterate for each call
3201 calls = lc->calls;
3202 while(calls!= NULL){
3203 call = (LinphoneCall *)calls->data;
3204 elapsed = (int)(current_real_time - call->log->start_date_time);
3205 /* get immediately a reference to next one in case the one
3206 we are going to examine is destroy and removed during
3207 linphone_call_start_invite() */
3208 calls=calls->next;
3209 linphone_call_background_tasks(call,one_second_elapsed);
3210 if (call->state==LinphoneCallOutgoingInit && (elapsed>=lc->sip_conf.delayed_timeout)){
3211 /*start the call even if the OPTIONS reply did not arrive*/
3212 if (call->ice_session != NULL) {
3213 ms_warning("ICE candidates gathering from [%s] has not finished yet, proceed with the call without ICE anyway."
3214 ,linphone_nat_policy_get_stun_server(call->nat_policy));
3215 linphone_call_delete_ice_session(call);
3216 linphone_call_stop_media_streams_for_ice_gathering(call);
3217 }
3218 #ifdef BUILD_UPNP
3219 if (call->upnp_session != NULL) {
3220 ms_warning("uPnP mapping has not finished yet, proceeded with the call without uPnP anyway.");
3221 linphone_call_delete_upnp_session(call);
3222 }
3223 #endif //BUILD_UPNP
3224 linphone_call_start_invite(call, NULL);
3225 }
3226 if (call->state==LinphoneCallIncomingReceived || call->state==LinphoneCallIncomingEarlyMedia){
3227 if (one_second_elapsed) ms_message("incoming call ringing for %i seconds",elapsed);
3228 if (elapsed>lc->sip_conf.inc_timeout){
3229 LinphoneReason decline_reason;
3230 ms_message("incoming call timeout (%i)",lc->sip_conf.inc_timeout);
3231 decline_reason = (lc->current_call != call) ? LinphoneReasonBusy : LinphoneReasonDeclined;
3232 call->log->status=LinphoneCallMissed;
3233 call->non_op_error = TRUE;
3234 linphone_error_info_set(call->ei, NULL, decline_reason, linphone_reason_to_error_code(decline_reason), "Not answered", NULL);
3235 linphone_call_decline(call, decline_reason);
3236 }
3237 }
3238 if ( (lc->sip_conf.in_call_timeout > 0)
3239 && (call->log->connected_date_time != 0)
3240 && ((current_real_time - call->log->connected_date_time) > lc->sip_conf.in_call_timeout))
3241 {
3242 ms_message("in call timeout (%i)",lc->sip_conf.in_call_timeout);
3243 linphone_call_terminate(call);
3244 }
3245 }
3246
3247 if (linphone_core_video_preview_enabled(lc)){
3248 if (lc->previewstream==NULL && lc->calls==NULL)
3249 toggle_video_preview(lc,TRUE);
3250 #ifdef VIDEO_ENABLED
3251 if (lc->previewstream) video_stream_iterate(lc->previewstream);
3252 #endif
3253 }else{
3254 if (lc->previewstream!=NULL)
3255 toggle_video_preview(lc,FALSE);
3256 }
3257
3258 linphone_core_run_hooks(lc);
3259 linphone_core_do_plugin_tasks(lc);
3260
3261 if (lc->sip_network_reachable && lc->netup_time!=0 && (current_real_time-lc->netup_time)>=2){
3262 /*not do that immediately, take your time.*/
3263 linphone_core_send_initial_subscribes(lc);
3264 }
3265
3266 if (one_second_elapsed) {
3267 bctbx_list_t *elem = NULL;
3268 if (lp_config_needs_commit(lc->config)) {
3269 lp_config_sync(lc->config);
3270 }
3271 for (elem = lc->friends_lists; elem != NULL; elem = bctbx_list_next(elem)) {
3272 LinphoneFriendList *list = (LinphoneFriendList *)elem->data;
3273 if (list->dirty_friends_to_update) {
3274 linphone_friend_list_update_dirty_friends(list);
3275 }
3276 }
3277 }
3278
3279 if (liblinphone_serialize_logs == TRUE) {
3280 ortp_logv_flush();
3281 }
3282 }
3283
linphone_core_interpret_url(LinphoneCore * lc,const char * url)3284 LinphoneAddress * linphone_core_interpret_url(LinphoneCore *lc, const char *url){
3285 LinphoneProxyConfig *proxy = linphone_core_get_default_proxy_config(lc);
3286 LinphoneAddress *result=NULL;
3287
3288 if (linphone_proxy_config_is_phone_number(proxy,url)) {
3289 char *normalized_number = linphone_proxy_config_normalize_phone_number(proxy, url);
3290 result = linphone_proxy_config_normalize_sip_uri(proxy, normalized_number);
3291 ms_free(normalized_number);
3292 } else {
3293 result = linphone_proxy_config_normalize_sip_uri(proxy, url);
3294 }
3295 return result;
3296 }
3297
linphone_core_get_identity(LinphoneCore * lc)3298 const char * linphone_core_get_identity(LinphoneCore *lc){
3299 LinphoneProxyConfig *proxy=linphone_core_get_default_proxy_config(lc);
3300 const char *from;
3301 if (proxy!=NULL) {
3302 from=linphone_proxy_config_get_identity(proxy);
3303 }else from=linphone_core_get_primary_contact(lc);
3304 return from;
3305 }
3306
linphone_core_get_route(LinphoneCore * lc)3307 const char * linphone_core_get_route(LinphoneCore *lc){
3308 LinphoneProxyConfig *proxy=linphone_core_get_default_proxy_config(lc);
3309 const char *route=NULL;
3310 if (proxy!=NULL) {
3311 route=linphone_proxy_config_get_route(proxy);
3312 }
3313 return route;
3314 }
3315
linphone_core_start_refered_call(LinphoneCore * lc,LinphoneCall * call,const LinphoneCallParams * params)3316 LinphoneCall * linphone_core_start_refered_call(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params){
3317 LinphoneCallParams *cp=params ? linphone_call_params_copy(params) : linphone_core_create_call_params(lc, NULL);
3318 LinphoneCall *newcall;
3319
3320 if (call->state!=LinphoneCallPaused){
3321 ms_message("Automatically pausing current call to accept transfer.");
3322 _linphone_call_pause(call);
3323 call->was_automatically_paused=TRUE;
3324 }
3325
3326 if (!params){
3327 cp->has_audio = call->current_params->has_audio;
3328 cp->has_video = call->current_params->has_video; /*start the call to refer-target with video enabled if original call had video*/
3329 }
3330 cp->referer=call;
3331 ms_message("Starting new call to refered address %s",call->refer_to);
3332 call->refer_pending=FALSE;
3333 newcall=linphone_core_invite_with_params(lc,call->refer_to,cp);
3334 linphone_call_params_unref(cp);
3335 if (newcall) {
3336 call->transfer_target=linphone_call_ref(newcall);
3337 linphone_core_notify_refer_state(lc,call,newcall);
3338 }
3339 return newcall;
3340 }
3341
linphone_core_notify_refer_state(LinphoneCore * lc,LinphoneCall * referer,LinphoneCall * newcall)3342 void linphone_core_notify_refer_state(LinphoneCore *lc, LinphoneCall *referer, LinphoneCall *newcall){
3343 if (referer->op!=NULL){
3344 sal_call_notify_refer_state(referer->op,newcall ? newcall->op : NULL);
3345 }
3346 }
3347
3348 /*
3349 returns the ideal route set for making an operation through this proxy.
3350 The list must be freed as well as the SalAddress content
3351
3352 rfc3608
3353 6.1. Procedures at the UA
3354
3355 /.../
3356 For example, some devices will use locally-configured
3357 explicit loose routing to reach a next-hop proxy, and others will use
3358 a default outbound-proxy routing rule. However, for the result to
3359 function, the combination MUST provide valid routing in the local
3360 environment. In general, the service route set is appended to any
3361 locally configured route needed to egress the access proxy chain.
3362 Systems designers must match the service routing policy of their
3363 nodes with the basic SIP routing policy in order to get a workable
3364 system.
3365 */
make_routes_for_proxy(LinphoneProxyConfig * proxy,const LinphoneAddress * dest)3366 static bctbx_list_t *make_routes_for_proxy(LinphoneProxyConfig *proxy, const LinphoneAddress *dest){
3367 bctbx_list_t *ret=NULL;
3368 const char *local_route=linphone_proxy_config_get_route(proxy);
3369 const LinphoneAddress *srv_route=linphone_proxy_config_get_service_route(proxy);
3370 if (local_route){
3371 ret=bctbx_list_append(ret,sal_address_new(local_route));
3372 }
3373 if (srv_route){
3374 ret=bctbx_list_append(ret,sal_address_clone((SalAddress*)srv_route));
3375 }
3376 if (ret==NULL){
3377 /*if the proxy address matches the domain part of the destination, then use the same transport
3378 * as the one used for registration. This is done by forcing a route to this proxy.*/
3379 SalAddress *proxy_addr=sal_address_new(linphone_proxy_config_get_addr(proxy));
3380 if (strcmp(sal_address_get_domain(proxy_addr),linphone_address_get_domain(dest))==0){
3381 ret=bctbx_list_append(ret,proxy_addr);
3382 }else sal_address_destroy(proxy_addr);
3383 }
3384 return ret;
3385 }
3386
linphone_core_lookup_known_proxy(LinphoneCore * lc,const LinphoneAddress * uri)3387 LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const LinphoneAddress *uri){
3388 const bctbx_list_t *elem;
3389 LinphoneProxyConfig *found_cfg=NULL;
3390 LinphoneProxyConfig *found_reg_cfg=NULL;
3391 LinphoneProxyConfig *found_noreg_cfg=NULL;
3392 LinphoneProxyConfig *default_cfg=lc->default_proxy;
3393
3394 if (linphone_address_get_domain(uri) == NULL) {
3395 ms_message("cannot seach for proxy for uri [%p] if no domain set. returning default",uri);
3396 return default_cfg;
3397 }
3398 /*return default proxy if it is matching the destination uri*/
3399 if (default_cfg){
3400 const char *domain=linphone_proxy_config_get_domain(default_cfg);
3401 if (strcmp(domain,linphone_address_get_domain(uri))==0){
3402 found_cfg=default_cfg;
3403 goto end;
3404 }
3405 }
3406
3407 /*otherwise return first registered, then first registering matching, otherwise first matching */
3408 for (elem=linphone_core_get_proxy_config_list(lc);elem!=NULL;elem=elem->next){
3409 LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;
3410 const char *domain=linphone_proxy_config_get_domain(cfg);
3411 if (domain!=NULL && strcmp(domain,linphone_address_get_domain(uri))==0){
3412 if (linphone_proxy_config_get_state(cfg) == LinphoneRegistrationOk ){
3413 found_cfg=cfg;
3414 break;
3415 } else if (!found_reg_cfg && linphone_proxy_config_register_enabled(cfg)) {
3416 found_reg_cfg=cfg;
3417 } else if (!found_noreg_cfg){
3418 found_noreg_cfg=cfg;
3419 }
3420 }
3421 }
3422 end:
3423 if ( !found_cfg && found_reg_cfg) found_cfg = found_reg_cfg;
3424 else if( !found_cfg && found_noreg_cfg ) found_cfg = found_noreg_cfg;
3425
3426 if (found_cfg && found_cfg!=default_cfg){
3427 ms_debug("Overriding default proxy setting for this call/message/subscribe operation.");
3428 }else if (!found_cfg) found_cfg=default_cfg; /*when no matching proxy config is found, use the default proxy config*/
3429 return found_cfg;
3430 }
3431
linphone_core_find_best_identity(LinphoneCore * lc,const LinphoneAddress * to)3432 const char *linphone_core_find_best_identity(LinphoneCore *lc, const LinphoneAddress *to){
3433 LinphoneProxyConfig *cfg=linphone_core_lookup_known_proxy(lc,to);
3434 if (cfg!=NULL){
3435 return linphone_proxy_config_get_identity (cfg);
3436 }
3437 return linphone_core_get_primary_contact(lc);
3438 }
3439
linphone_core_invite(LinphoneCore * lc,const char * url)3440 LinphoneCall * linphone_core_invite(LinphoneCore *lc, const char *url){
3441 LinphoneCall *call;
3442 LinphoneCallParams *p=linphone_core_create_call_params(lc, NULL);
3443 p->has_video &= !!lc->video_policy.automatically_initiate;
3444 call=linphone_core_invite_with_params(lc,url,p);
3445 linphone_call_params_unref(p);
3446 return call;
3447 }
3448
linphone_core_invite_with_params(LinphoneCore * lc,const char * url,const LinphoneCallParams * p)3449 LinphoneCall * linphone_core_invite_with_params(LinphoneCore *lc, const char *url, const LinphoneCallParams *p){
3450 LinphoneAddress *addr=linphone_core_interpret_url(lc,url);
3451 if (addr){
3452 LinphoneCall *call;
3453 call=linphone_core_invite_address_with_params(lc,addr,p);
3454 linphone_address_unref(addr);
3455 return call;
3456 }
3457 return NULL;
3458 }
3459
linphone_core_invite_address(LinphoneCore * lc,const LinphoneAddress * addr)3460 LinphoneCall * linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddress *addr){
3461 LinphoneCall *call;
3462 LinphoneCallParams *p=linphone_core_create_call_params(lc, NULL);
3463 p->has_video &= !!lc->video_policy.automatically_initiate;
3464 call=linphone_core_invite_address_with_params (lc,addr,p);
3465 linphone_call_params_unref(p);
3466 return call;
3467 }
3468
linphone_transfer_routes_to_op(bctbx_list_t * routes,SalOp * op)3469 static void linphone_transfer_routes_to_op(bctbx_list_t *routes, SalOp *op){
3470 bctbx_list_t *it;
3471 for(it=routes;it!=NULL;it=it->next){
3472 SalAddress *addr=(SalAddress*)it->data;
3473 sal_op_add_route_address(op,addr);
3474 sal_address_destroy(addr);
3475 }
3476 bctbx_list_free(routes);
3477 }
3478
linphone_configure_op_with_proxy(LinphoneCore * lc,SalOp * op,const LinphoneAddress * dest,SalCustomHeader * headers,bool_t with_contact,LinphoneProxyConfig * proxy)3479 void linphone_configure_op_with_proxy(LinphoneCore *lc, SalOp *op, const LinphoneAddress *dest, SalCustomHeader *headers, bool_t with_contact, LinphoneProxyConfig *proxy){
3480 bctbx_list_t *routes=NULL;
3481 const char *identity;
3482 if (proxy){
3483 identity=linphone_proxy_config_get_identity(proxy);
3484 if (linphone_proxy_config_get_privacy(proxy)!=LinphonePrivacyDefault) {
3485 sal_op_set_privacy(op,linphone_proxy_config_get_privacy(proxy));
3486 }
3487 }else identity=linphone_core_get_primary_contact(lc);
3488 /*sending out of calls*/
3489 if (proxy){
3490 routes=make_routes_for_proxy(proxy,dest);
3491 linphone_transfer_routes_to_op(routes,op);
3492 }
3493 sal_op_set_to_address(op,dest);
3494 sal_op_set_from(op,identity);
3495 sal_op_set_sent_custom_header(op,headers);
3496 sal_op_set_realm(op,linphone_proxy_config_get_realm(proxy));
3497 if (with_contact && proxy && proxy->op){
3498 const SalAddress *contact;
3499 if ((contact=sal_op_get_contact_address(proxy->op))){
3500 SalTransport tport=sal_address_get_transport((SalAddress*)contact);
3501 SalAddress *new_contact=sal_address_clone(contact);
3502 sal_address_clean(new_contact); /* clean out contact_params that come from proxy config*/
3503 sal_address_set_transport(new_contact,tport);
3504 sal_op_set_contact_address(op,new_contact);
3505 sal_address_destroy(new_contact);
3506 }
3507 }
3508 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)); /*also set in linphone_call_new_incoming*/
3509 }
linphone_configure_op(LinphoneCore * lc,SalOp * op,const LinphoneAddress * dest,SalCustomHeader * headers,bool_t with_contact)3510 void linphone_configure_op(LinphoneCore *lc, SalOp *op, const LinphoneAddress *dest, SalCustomHeader *headers, bool_t with_contact) {
3511 linphone_configure_op_with_proxy(lc, op, dest, headers,with_contact,linphone_core_lookup_known_proxy(lc,dest));
3512 }
3513
linphone_core_invite_address_with_params(LinphoneCore * lc,const LinphoneAddress * addr,const LinphoneCallParams * params)3514 LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const LinphoneAddress *addr, const LinphoneCallParams *params){
3515 const char *from=NULL;
3516 LinphoneProxyConfig *proxy=NULL;
3517 LinphoneAddress *parsed_url2=NULL;
3518 char *real_url=NULL;
3519 LinphoneCall *call;
3520 bool_t defer = FALSE;
3521 LinphoneCallParams *cp;
3522
3523 if (!(!linphone_call_params_audio_enabled(params) ||
3524 linphone_call_params_get_audio_direction(params) == LinphoneMediaDirectionInactive ||
3525 linphone_call_params_get_local_conference_mode(params) == TRUE
3526 )
3527 && linphone_core_preempt_sound_resources(lc) == -1) {
3528 ms_error("linphone_core_invite_address_with_params(): sound is required for this call but another call is already locking the sound resource. Call attempt is rejected.");
3529 return NULL;
3530 }
3531
3532 if(!linphone_core_can_we_add_call(lc)){
3533 linphone_core_notify_display_warning(lc,_("Sorry, we have reached the maximum number of simultaneous calls"));
3534 return NULL;
3535 }
3536
3537 cp = linphone_call_params_copy(params);
3538
3539 real_url=linphone_address_as_string(addr);
3540 proxy=linphone_core_lookup_known_proxy(lc,addr);
3541
3542 if (proxy!=NULL) {
3543 from=linphone_proxy_config_get_identity(proxy);
3544 cp->avpf_enabled = linphone_proxy_config_avpf_enabled(proxy);
3545 cp->avpf_rr_interval = linphone_proxy_config_get_avpf_rr_interval(proxy) * 1000;
3546 }else{
3547 cp->avpf_enabled=linphone_core_get_avpf_mode(lc)==LinphoneAVPFEnabled;
3548 if (cp->avpf_enabled) cp->avpf_rr_interval=linphone_core_get_avpf_rr_interval(lc) * 1000;
3549 }
3550
3551 /* if no proxy or no identity defined for this proxy, default to primary contact*/
3552 if (from==NULL) from=linphone_core_get_primary_contact(lc);
3553
3554 parsed_url2=linphone_address_new(from);
3555
3556 call=linphone_call_new_outgoing(lc,parsed_url2,linphone_address_clone(addr),cp,proxy);
3557
3558 if(linphone_core_add_call(lc,call)!= 0)
3559 {
3560 ms_warning("we had a problem in adding the call into the invite ... weird");
3561 linphone_call_unref(call);
3562 linphone_call_params_unref(cp);
3563 return NULL;
3564 }
3565
3566 /* Unless this call is for a conference, it becomes now the current one*/
3567 if (linphone_call_params_get_local_conference_mode(params) == FALSE) lc->current_call=call;
3568 linphone_call_set_state (call,LinphoneCallOutgoingInit,"Starting outgoing call");
3569 call->log->start_date_time=ms_time(NULL);
3570 linphone_call_init_media_streams(call);
3571
3572 if (linphone_nat_policy_ice_enabled(call->nat_policy)) {
3573 if (lc->sip_conf.sdp_200_ack){
3574 ms_warning("ICE is not supported when sending INVITE without SDP");
3575 }else{
3576 /* Defer the start of the call after the ICE gathering process. */
3577 if (linphone_call_prepare_ice(call,FALSE)==1)
3578 defer=TRUE;
3579 }
3580 }
3581 else if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseUpnp) {
3582 #ifdef BUILD_UPNP
3583 if (linphone_call_update_upnp(call) < 0) {
3584 /* uPnP port mappings failed, proceed with the call anyway. */
3585 linphone_call_delete_upnp_session(call);
3586 } else {
3587 defer = TRUE;
3588 }
3589 #endif // BUILD_UPNP
3590 }
3591
3592 if (call->dest_proxy==NULL && lc->sip_conf.ping_with_options==TRUE){
3593 #ifdef BUILD_UPNP
3594 if (lc->upnp != NULL && linphone_core_get_firewall_policy(lc)==LinphonePolicyUseUpnp &&
3595 linphone_upnp_context_get_state(lc->upnp) == LinphoneUpnpStateOk) {
3596 #else //BUILD_UPNP
3597 {
3598 #endif //BUILD_UPNP
3599 /*defer the start of the call after the OPTIONS ping*/
3600 call->ping_replied=FALSE;
3601 call->ping_op=sal_op_new(lc->sal);
3602 sal_ping(call->ping_op,from,real_url);
3603 sal_op_set_user_pointer(call->ping_op,call);
3604 defer = TRUE;
3605 }
3606 }
3607
3608 if (defer==FALSE) {
3609 if (linphone_call_start_invite(call,NULL) != 0){
3610 /*the call has already gone to error and released state, so do not return it*/
3611 call = NULL;
3612 }
3613 }
3614
3615 if (real_url!=NULL) ms_free(real_url);
3616 linphone_call_params_unref(cp);
3617 return call;
3618 }
3619
3620 LinphoneStatus linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall *call, const char *url) {
3621 if (call == NULL) {
3622 ms_warning("No established call to refer.");
3623 return -1;
3624 }
3625 return linphone_call_transfer(call, url);
3626 }
3627
3628 LinphoneStatus linphone_core_transfer_call_to_another(LinphoneCore *lc, LinphoneCall *call, LinphoneCall *dest) {
3629 return linphone_call_transfer_to_another(call, dest);
3630 }
3631
3632 bool_t linphone_core_is_incoming_invite_pending(LinphoneCore*lc){
3633 LinphoneCall *call = linphone_core_get_current_call(lc);
3634 if(call != NULL)
3635 {
3636 if(call->dir==LinphoneCallIncoming
3637 && (call->state == LinphoneCallIncomingReceived || call->state == LinphoneCallIncomingEarlyMedia))
3638 return TRUE;
3639 }
3640 return FALSE;
3641 }
3642
3643 bool_t linphone_core_incompatible_security(LinphoneCore *lc, SalMediaDescription *md){
3644 return linphone_core_is_media_encryption_mandatory(lc) && linphone_core_get_media_encryption(lc)==LinphoneMediaEncryptionSRTP && !sal_media_description_has_srtp(md);
3645 }
3646
3647 void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){
3648 char *barmesg;
3649 char *tmp;
3650 LinphoneAddress *from_parsed;
3651 bool_t propose_early_media=lp_config_get_int(lc->config,"sip","incoming_calls_early_media",FALSE);
3652
3653 from_parsed=linphone_address_new(sal_op_get_from(call->op));
3654 linphone_address_clean(from_parsed);
3655 tmp=linphone_address_as_string(from_parsed);
3656 linphone_address_unref(from_parsed);
3657 barmesg=ortp_strdup_printf("%s %s%s",tmp,_("is contacting you"),
3658 (sal_call_autoanswer_asked(call->op)) ?_(" and asked autoanswer."):".");
3659 linphone_core_notify_show_interface(lc);
3660 linphone_core_notify_display_status(lc,barmesg);
3661
3662 /* play the ring if this is the only call*/
3663 if (bctbx_list_size(lc->calls)==1){
3664 MSSndCard *ringcard=lc->sound_conf.lsd_card ?lc->sound_conf.lsd_card : lc->sound_conf.ring_sndcard;
3665 lc->current_call=call;
3666 if (lc->ringstream && lc->dmfs_playing_start_time!=0){
3667 linphone_core_stop_dtmf_stream(lc);
3668 }
3669 linphone_ringtoneplayer_start(lc->factory, lc->ringtoneplayer, ringcard, lc->sound_conf.local_ring, 2000);
3670 }else{
3671 /* else play a tone within the context of the current call */
3672 call->ringing_beep=TRUE;
3673 linphone_core_play_named_tone(lc,LinphoneToneCallWaiting);
3674 }
3675
3676 linphone_call_set_state(call,LinphoneCallIncomingReceived,"Incoming call");
3677 /*from now on, the application is aware of the call and supposed to take background task or already submitted notification to the user.
3678 We can then drop our background task.*/
3679 if (call->bg_task_id!=0) {
3680 sal_end_background_task(call->bg_task_id);
3681 call->bg_task_id=0;
3682 }
3683
3684 if (call->state==LinphoneCallIncomingReceived){
3685 /*try to be best-effort in giving real local or routable contact address for 100Rel case*/
3686 linphone_call_set_contact_op(call);
3687
3688 if (propose_early_media){
3689 linphone_call_accept_early_media(call);
3690 }else sal_call_notify_ringing(call->op,FALSE);
3691
3692 if (sal_call_get_replaces(call->op)!=NULL && lp_config_get_int(lc->config,"sip","auto_answer_replacing_calls",1)){
3693 linphone_call_accept(call);
3694 }
3695 }
3696 linphone_call_unref(call);
3697
3698 ms_free(barmesg);
3699 ms_free(tmp);
3700 }
3701
3702 LinphoneStatus linphone_core_accept_early_media_with_params(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params) {
3703 return linphone_call_accept_early_media_with_params(call, params);
3704 }
3705
3706 LinphoneStatus linphone_core_accept_early_media(LinphoneCore *lc, LinphoneCall *call) {
3707 return linphone_call_accept_early_media(call);
3708 }
3709
3710 LinphoneStatus linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params) {
3711 return linphone_call_update(call, params);
3712 }
3713
3714 LinphoneStatus linphone_core_defer_call_update(LinphoneCore *lc, LinphoneCall *call) {
3715 return linphone_call_defer_update(call);
3716 }
3717
3718 LinphoneStatus linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params) {
3719 return linphone_call_accept_update(call, params);
3720 }
3721
3722 static LinphoneCall * get_unique_call(LinphoneCore *lc) {
3723 LinphoneCall *call = linphone_core_get_current_call(lc);
3724 if ((call == NULL) && (linphone_core_get_calls_nb(lc) == 1)) {
3725 call = (LinphoneCall *)bctbx_list_get_data(linphone_core_get_calls(lc));
3726 }
3727 return call;
3728 }
3729
3730 LinphoneStatus linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *call) {
3731 return linphone_call_accept_with_params(call, NULL);
3732 }
3733
3734 LinphoneStatus linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params) {
3735 if (call == NULL) {
3736 call = get_unique_call(lc);
3737 if (call == NULL) {
3738 ms_warning("No unique call to accept!");
3739 return -1;
3740 }
3741 }
3742 return linphone_call_accept_with_params(call, params);
3743 }
3744
3745 LinphoneStatus linphone_core_redirect_call(LinphoneCore *lc, LinphoneCall *call, const char *redirect_uri) {
3746 return linphone_call_redirect(call, redirect_uri);
3747 }
3748
3749 LinphoneStatus linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *call) {
3750 if (call == NULL) {
3751 call = get_unique_call(lc);
3752 if (call == NULL) {
3753 ms_warning("No unique call to terminate!");
3754 return -1;
3755 }
3756 }
3757 return linphone_call_terminate(call);
3758 }
3759
3760 LinphoneStatus linphone_core_terminate_all_calls(LinphoneCore *lc) {
3761 bctbx_list_t *calls=lc->calls;
3762 while(calls) {
3763 LinphoneCall *c=(LinphoneCall*)calls->data;
3764 calls=calls->next;
3765 linphone_call_terminate(c);
3766 }
3767 return 0;
3768 }
3769
3770 LinphoneStatus linphone_core_decline_call(LinphoneCore *lc, LinphoneCall *call, LinphoneReason reason) {
3771 return linphone_call_decline(call, reason);
3772 }
3773
3774 const bctbx_list_t *linphone_core_get_calls(LinphoneCore *lc) {
3775 return lc->calls;
3776 }
3777
3778 bool_t linphone_core_in_call(const LinphoneCore *lc){
3779 return linphone_core_get_current_call((LinphoneCore *)lc)!=NULL || linphone_core_is_in_conference(lc);
3780 }
3781
3782 LinphoneCall *linphone_core_get_current_call(const LinphoneCore *lc){
3783 return lc->current_call;
3784 }
3785
3786 LinphoneStatus linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call) {
3787 return linphone_call_pause(call);
3788 }
3789
3790 LinphoneStatus linphone_core_pause_all_calls(LinphoneCore *lc){
3791 const bctbx_list_t *elem;
3792 for(elem=lc->calls;elem!=NULL;elem=elem->next){
3793 LinphoneCall *call=(LinphoneCall *)elem->data;
3794 LinphoneCallState cs=linphone_call_get_state(call);
3795 if (cs==LinphoneCallStreamsRunning || cs==LinphoneCallPausedByRemote){
3796 _linphone_call_pause(call);
3797 }
3798 }
3799 return 0;
3800 }
3801
3802 int linphone_core_preempt_sound_resources(LinphoneCore *lc){
3803 LinphoneCall *current_call;
3804 int err = 0;
3805
3806 if (linphone_core_is_in_conference(lc)){
3807 linphone_core_leave_conference(lc);
3808 return 0;
3809 }
3810
3811 current_call=linphone_core_get_current_call(lc);
3812 if(current_call != NULL){
3813 ms_message("Pausing automatically the current call.");
3814 err = _linphone_call_pause(current_call);
3815 }
3816 if (lc->ringstream){
3817 linphone_core_stop_ringing(lc);
3818 }
3819 return err;
3820 }
3821
3822 LinphoneStatus linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *call) {
3823 return linphone_call_resume(call);
3824 }
3825
3826 static int remote_address_compare(LinphoneCall *call, const LinphoneAddress *raddr){
3827 const LinphoneAddress *addr=linphone_call_get_remote_address (call);
3828 return !linphone_address_weak_equal (addr,raddr);
3829 }
3830
3831 LinphoneCall *linphone_core_get_call_by_remote_address(const LinphoneCore *lc, const char *remote_address){
3832 LinphoneCall *call=NULL;
3833 LinphoneAddress *raddr=linphone_address_new(remote_address);
3834 if (raddr) {
3835 call=linphone_core_get_call_by_remote_address2(lc, raddr);
3836 linphone_address_unref(raddr);
3837 }
3838 return call;
3839 }
3840
3841 LinphoneCall *linphone_core_find_call_from_uri(const LinphoneCore *lc, const char *remote_address){
3842 return linphone_core_get_call_by_remote_address(lc, remote_address);
3843 }
3844
3845 LinphoneCall *linphone_core_get_call_by_remote_address2(const LinphoneCore *lc, const LinphoneAddress *raddr){
3846 const bctbx_list_t *elem=bctbx_list_find_custom(lc->calls,(int (*)(const void*,const void *))remote_address_compare,raddr);
3847
3848 if (elem) return (LinphoneCall*) elem->data;
3849 return NULL;
3850 }
3851
3852 int linphone_core_send_publish(LinphoneCore *lc, LinphonePresenceModel *presence) {
3853 const bctbx_list_t *elem;
3854 for (elem=linphone_core_get_proxy_config_list(lc);elem!=NULL;elem=bctbx_list_next(elem)){
3855 LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;
3856 if (cfg->publish) linphone_proxy_config_send_publish(cfg,presence);
3857 }
3858 return 0;
3859 }
3860
3861 void linphone_core_set_inc_timeout(LinphoneCore *lc, int seconds){
3862 lc->sip_conf.inc_timeout=seconds;
3863 if (linphone_core_ready(lc)){
3864 lp_config_set_int(lc->config,"sip","inc_timeout",seconds);
3865 }
3866 }
3867
3868 int linphone_core_get_inc_timeout(LinphoneCore *lc){
3869 return lc->sip_conf.inc_timeout;
3870 }
3871
3872 void linphone_core_set_in_call_timeout(LinphoneCore *lc, int seconds){
3873 lc->sip_conf.in_call_timeout=seconds;
3874 if( linphone_core_ready(lc)){
3875 lp_config_set_int(lc->config, "sip", "in_call_timeout", seconds);
3876 }
3877 }
3878
3879 int linphone_core_get_in_call_timeout(LinphoneCore *lc){
3880 return lc->sip_conf.in_call_timeout;
3881 }
3882
3883 int linphone_core_get_delayed_timeout(LinphoneCore *lc){
3884 return lc->sip_conf.delayed_timeout;
3885 }
3886
3887 void linphone_core_set_delayed_timeout(LinphoneCore *lc, int seconds){
3888 lc->sip_conf.delayed_timeout=seconds;
3889 }
3890
3891 void linphone_core_set_presence_info(LinphoneCore *lc, int minutes_away, const char *contact, LinphoneOnlineStatus os) {
3892 LinphonePresenceModel *presence = NULL;
3893 LinphonePresenceActivity *activity = NULL;
3894 char *description = NULL;
3895 LinphonePresenceActivityType acttype = LinphonePresenceActivityUnknown;
3896
3897 if (minutes_away>0) lc->minutes_away=minutes_away;
3898
3899 presence = linphone_presence_model_new();
3900 linphone_presence_model_set_basic_status(presence, LinphonePresenceBasicStatusOpen);
3901 switch (os) {
3902 case LinphoneStatusOffline:
3903 linphone_presence_model_set_basic_status(presence, LinphonePresenceBasicStatusClosed);
3904 goto end;
3905 case LinphoneStatusOnline:
3906 goto end;
3907 case LinphoneStatusBusy:
3908 acttype = LinphonePresenceActivityBusy;
3909 break;
3910 case LinphoneStatusBeRightBack:
3911 acttype = LinphonePresenceActivityInTransit;
3912 break;
3913 case LinphoneStatusAway:
3914 acttype = LinphonePresenceActivityAway;
3915 break;
3916 case LinphoneStatusOnThePhone:
3917 acttype = LinphonePresenceActivityOnThePhone;
3918 break;
3919 case LinphoneStatusOutToLunch:
3920 acttype = LinphonePresenceActivityLunch;
3921 break;
3922 case LinphoneStatusDoNotDisturb:
3923 acttype = LinphonePresenceActivityBusy;
3924 description = "Do not disturb";
3925 linphone_presence_model_set_basic_status(presence, LinphonePresenceBasicStatusClosed);
3926 break;
3927 case LinphoneStatusMoved:
3928 acttype = LinphonePresenceActivityPermanentAbsence;
3929 break;
3930 case LinphoneStatusAltService:
3931 acttype = LinphonePresenceActivityBusy;
3932 description = "Using another messaging service";
3933 break;
3934 case LinphoneStatusPending:
3935 acttype = LinphonePresenceActivityOther;
3936 description = "Waiting for user acceptance";
3937 break;
3938 case LinphoneStatusVacation:
3939 acttype = LinphonePresenceActivityVacation;
3940 break;
3941 case LinphoneStatusEnd:
3942 ms_warning("Invalid status LinphoneStatusEnd");
3943 return;
3944 }
3945 activity = linphone_presence_activity_new(acttype, description);
3946 linphone_presence_model_add_activity(presence, activity);
3947 linphone_presence_activity_unref(activity);
3948
3949 end:
3950 linphone_presence_model_set_contact(presence, contact);
3951 linphone_core_set_presence_model(lc, presence);
3952 linphone_presence_model_unref(presence);
3953 }
3954
3955 void linphone_core_send_presence(LinphoneCore *lc, LinphonePresenceModel *presence){
3956 linphone_core_notify_all_friends(lc,presence);
3957 linphone_core_send_publish(lc,presence);
3958 }
3959
3960 void linphone_core_set_presence_model(LinphoneCore *lc, LinphonePresenceModel *presence) {
3961 linphone_presence_model_ref(presence);
3962 linphone_core_send_presence(lc, presence);
3963 if (lc->presence_model != NULL) linphone_presence_model_unref(lc->presence_model);
3964 lc->presence_model = presence;
3965 }
3966
3967 LinphoneOnlineStatus linphone_core_get_presence_info(const LinphoneCore *lc){
3968 LinphonePresenceActivity *activity = NULL;
3969 const char *description = NULL;
3970
3971 activity = linphone_presence_model_get_activity(lc->presence_model);
3972 if (activity) {
3973 description = linphone_presence_activity_get_description(activity);
3974 switch (linphone_presence_activity_get_type(activity)) {
3975 case LinphonePresenceActivityBusy:
3976 if (description != NULL) {
3977 if (strcmp(description, "Do not disturb") == 0)
3978 return LinphoneStatusDoNotDisturb;
3979 else if (strcmp(description, "Using another messaging service") == 0)
3980 return LinphoneStatusAltService;
3981 }
3982 return LinphoneStatusBusy;
3983 case LinphonePresenceActivityInTransit:
3984 case LinphonePresenceActivitySteering:
3985 return LinphoneStatusBeRightBack;
3986 case LinphonePresenceActivityAway:
3987 return LinphoneStatusAway;
3988 case LinphonePresenceActivityOnThePhone:
3989 return LinphoneStatusOnThePhone;
3990 case LinphonePresenceActivityBreakfast:
3991 case LinphonePresenceActivityDinner:
3992 case LinphonePresenceActivityLunch:
3993 case LinphonePresenceActivityMeal:
3994 return LinphoneStatusOutToLunch;
3995 case LinphonePresenceActivityPermanentAbsence:
3996 return LinphoneStatusMoved;
3997 case LinphonePresenceActivityOther:
3998 if (description != NULL) {
3999 if (strcmp(description, "Waiting for user acceptance") == 0)
4000 return LinphoneStatusPending;
4001 }
4002 return LinphoneStatusBusy;
4003 case LinphonePresenceActivityVacation:
4004 return LinphoneStatusVacation;
4005 case LinphonePresenceActivityAppointment:
4006 case LinphonePresenceActivityMeeting:
4007 case LinphonePresenceActivityWorship:
4008 return LinphoneStatusDoNotDisturb;
4009 default:
4010 return LinphoneStatusBusy;
4011 }
4012 } else {
4013 if (linphone_presence_model_get_basic_status(lc->presence_model) == LinphonePresenceBasicStatusOpen)
4014 return LinphoneStatusOnline;
4015 else
4016 return LinphoneStatusOffline;
4017 }
4018 }
4019
4020 LinphonePresenceModel * linphone_core_get_presence_model(const LinphoneCore *lc) {
4021 return lc->presence_model;
4022 }
4023
4024 LinphoneConsolidatedPresence linphone_core_get_consolidated_presence(const LinphoneCore *lc) {
4025 LinphoneProxyConfig *cfg = lc->default_proxy;
4026 LinphonePresenceModel *model = linphone_core_get_presence_model(lc);
4027
4028 return ((cfg && !linphone_proxy_config_publish_enabled(cfg)) || !model)
4029 ? LinphoneConsolidatedPresenceOffline
4030 : linphone_presence_model_get_consolidated_presence(model);
4031 }
4032
4033 void linphone_core_set_consolidated_presence(LinphoneCore *lc, LinphoneConsolidatedPresence presence) {
4034 const bctbx_list_t *cfg_list;
4035 const bctbx_list_t *item;
4036 LinphoneProxyConfig *cfg;
4037 LinphonePresenceModel *model;
4038 LinphonePresenceActivity *activity = NULL;
4039
4040 cfg_list = linphone_core_get_proxy_config_list(lc);
4041 for (item = cfg_list; item != NULL; item = bctbx_list_next(item)) {
4042 cfg = (LinphoneProxyConfig *)bctbx_list_get_data(item);
4043 if ((cfg != NULL) && (presence == LinphoneConsolidatedPresenceOffline) && linphone_proxy_config_publish_enabled(cfg)) {
4044 /* Unpublish when going offline before changing the presence model. */
4045 linphone_proxy_config_edit(cfg);
4046 linphone_proxy_config_enable_publish(cfg, FALSE);
4047 linphone_proxy_config_done(cfg);
4048 }
4049 }
4050 model = linphone_presence_model_new();
4051 switch (presence) {
4052 case LinphoneConsolidatedPresenceOnline:
4053 linphone_presence_model_set_basic_status(model, LinphonePresenceBasicStatusOpen);
4054 break;
4055 case LinphoneConsolidatedPresenceBusy:
4056 linphone_presence_model_set_basic_status(model, LinphonePresenceBasicStatusOpen);
4057 activity = linphone_presence_activity_new(LinphonePresenceActivityAway, NULL);
4058 break;
4059 case LinphoneConsolidatedPresenceDoNotDisturb:
4060 linphone_presence_model_set_basic_status(model, LinphonePresenceBasicStatusClosed);
4061 activity = linphone_presence_activity_new(LinphonePresenceActivityAway, NULL);
4062 break;
4063 case LinphoneConsolidatedPresenceOffline:
4064 default:
4065 linphone_presence_model_set_basic_status(model, LinphonePresenceBasicStatusClosed);
4066 break;
4067 }
4068 if (activity != NULL) linphone_presence_model_add_activity(model, activity);
4069 linphone_core_set_presence_model(lc, model);
4070 linphone_presence_model_unref(model);
4071 for (item = cfg_list; item != NULL; item = bctbx_list_next(item)) {
4072 cfg = (LinphoneProxyConfig *)bctbx_list_get_data(item);
4073 if ((cfg != NULL) && (presence != LinphoneConsolidatedPresenceOffline) && !linphone_proxy_config_publish_enabled(cfg)) {
4074 /* When going online or busy, publish after changing the presence model. */
4075 linphone_proxy_config_edit(cfg);
4076 linphone_proxy_config_enable_publish(cfg, TRUE);
4077 linphone_proxy_config_done(cfg);
4078 }
4079 }
4080 }
4081
4082 int linphone_core_get_play_level(LinphoneCore *lc) {
4083 return lc->sound_conf.play_lev;
4084 }
4085
4086 int linphone_core_get_ring_level(LinphoneCore *lc) {
4087 return lc->sound_conf.ring_lev;
4088 }
4089
4090 int linphone_core_get_rec_level(LinphoneCore *lc) {
4091 return lc->sound_conf.rec_lev;
4092 }
4093
4094 void linphone_core_set_ring_level(LinphoneCore *lc, int level){
4095 MSSndCard *sndcard;
4096 lc->sound_conf.ring_lev=level;
4097 sndcard=lc->sound_conf.ring_sndcard;
4098 if (sndcard) ms_snd_card_set_level(sndcard,MS_SND_CARD_PLAYBACK,level);
4099 }
4100
4101 void linphone_core_set_mic_gain_db (LinphoneCore *lc, float gaindb){
4102 float gain=gaindb;
4103 LinphoneCall *call=linphone_core_get_current_call (lc);
4104 AudioStream *st;
4105
4106 lc->sound_conf.soft_mic_lev=gaindb;
4107
4108 if (linphone_core_ready(lc)){
4109 lp_config_set_float(lc->config,"sound","mic_gain_db",lc->sound_conf.soft_mic_lev);
4110 }
4111
4112 if (call==NULL || (st=call->audiostream)==NULL){
4113 ms_message("linphone_core_set_mic_gain_db(): no active call.");
4114 return;
4115 }
4116 set_mic_gain_db(st,gain);
4117 }
4118
4119 float linphone_core_get_mic_gain_db(LinphoneCore *lc) {
4120 return lc->sound_conf.soft_mic_lev;
4121 }
4122
4123 void linphone_core_set_playback_gain_db (LinphoneCore *lc, float gaindb){
4124 float gain=gaindb;
4125 LinphoneCall *call=linphone_core_get_current_call (lc);
4126 AudioStream *st;
4127
4128 lc->sound_conf.soft_play_lev=gaindb;
4129 if (linphone_core_ready(lc)){
4130 lp_config_set_float(lc->config,"sound","playback_gain_db",lc->sound_conf.soft_play_lev);
4131 }
4132
4133 if (call==NULL || (st=call->audiostream)==NULL){
4134 ms_message("linphone_core_set_playback_gain_db(): no active call.");
4135 return;
4136 }
4137 set_playback_gain_db(st,gain);
4138 }
4139
4140 float linphone_core_get_playback_gain_db(LinphoneCore *lc) {
4141 return lc->sound_conf.soft_play_lev;
4142 }
4143
4144 void linphone_core_set_play_level(LinphoneCore *lc, int level){
4145 MSSndCard *sndcard;
4146 lc->sound_conf.play_lev=level;
4147 sndcard=lc->sound_conf.play_sndcard;
4148 if (sndcard) ms_snd_card_set_level(sndcard,MS_SND_CARD_PLAYBACK,level);
4149 }
4150
4151 void linphone_core_set_rec_level(LinphoneCore *lc, int level) {
4152 MSSndCard *sndcard;
4153 lc->sound_conf.rec_lev=level;
4154 sndcard=lc->sound_conf.capt_sndcard;
4155 if (sndcard) ms_snd_card_set_level(sndcard,MS_SND_CARD_CAPTURE,level);
4156 }
4157
4158 static MSSndCard *get_card_from_string_id(const char *devid, unsigned int cap, MSFactory *f){
4159 MSSndCard *sndcard=NULL;
4160 if (devid!=NULL){
4161 sndcard=ms_snd_card_manager_get_card(ms_factory_get_snd_card_manager(f),devid);
4162 if (sndcard!=NULL &&
4163 (ms_snd_card_get_capabilities(sndcard) & cap)==0 ){
4164 ms_warning("%s card does not have the %s capability, ignoring.",
4165 devid,
4166 cap==MS_SND_CARD_CAP_CAPTURE ? "capture" : "playback");
4167 sndcard=NULL;
4168 }
4169 }
4170 if (sndcard==NULL) {
4171 if ((cap & MS_SND_CARD_CAP_CAPTURE) && (cap & MS_SND_CARD_CAP_PLAYBACK)){
4172 sndcard=ms_snd_card_manager_get_default_card(ms_factory_get_snd_card_manager(f));
4173 }else if (cap & MS_SND_CARD_CAP_CAPTURE){
4174 sndcard=ms_snd_card_manager_get_default_capture_card(ms_factory_get_snd_card_manager(f));
4175 }
4176 else if (cap & MS_SND_CARD_CAP_PLAYBACK){
4177 sndcard=ms_snd_card_manager_get_default_playback_card(ms_factory_get_snd_card_manager(f));
4178 }
4179 if (sndcard==NULL){/*looks like a bug! take the first one !*/
4180 const bctbx_list_t *elem=ms_snd_card_manager_get_list(ms_factory_get_snd_card_manager(f));
4181 if (elem) sndcard=(MSSndCard*)elem->data;
4182 }
4183 }
4184 if (sndcard==NULL) ms_error("Could not find a suitable soundcard !");
4185 return sndcard;
4186 }
4187
4188 bool_t linphone_core_sound_device_can_capture(LinphoneCore *lc, const char *devid){
4189 return ms_snd_card_manager_get_capture_card(ms_factory_get_snd_card_manager(lc->factory),devid) != NULL;
4190 }
4191
4192 bool_t linphone_core_sound_device_can_playback(LinphoneCore *lc, const char *devid){
4193 return ms_snd_card_manager_get_playback_card(ms_factory_get_snd_card_manager(lc->factory),devid) != NULL;
4194 }
4195
4196 LinphoneStatus linphone_core_set_ringer_device(LinphoneCore *lc, const char * devid){
4197 MSSndCard *card=get_card_from_string_id(devid,MS_SND_CARD_CAP_PLAYBACK, lc->factory);
4198 lc->sound_conf.ring_sndcard=card;
4199 if (card && linphone_core_ready(lc))
4200 lp_config_set_string(lc->config,"sound","ringer_dev_id",ms_snd_card_get_string_id(card));
4201 return 0;
4202 }
4203
4204 LinphoneStatus linphone_core_set_playback_device(LinphoneCore *lc, const char * devid){
4205 MSSndCard *card=get_card_from_string_id(devid,MS_SND_CARD_CAP_PLAYBACK, lc->factory);
4206 lc->sound_conf.play_sndcard=card;
4207 if (card && linphone_core_ready(lc))
4208 lp_config_set_string(lc->config,"sound","playback_dev_id",ms_snd_card_get_string_id(card));
4209 return 0;
4210 }
4211
4212 LinphoneStatus linphone_core_set_capture_device(LinphoneCore *lc, const char * devid){
4213 MSSndCard *card=get_card_from_string_id(devid,MS_SND_CARD_CAP_CAPTURE, lc->factory);
4214 lc->sound_conf.capt_sndcard=card;
4215 if (card && linphone_core_ready(lc))
4216 lp_config_set_string(lc->config,"sound","capture_dev_id",ms_snd_card_get_string_id(card));
4217 return 0;
4218 }
4219
4220 const char * linphone_core_get_ringer_device(LinphoneCore *lc) {
4221 if (lc->sound_conf.ring_sndcard) return ms_snd_card_get_string_id(lc->sound_conf.ring_sndcard);
4222 return NULL;
4223 }
4224
4225 const char * linphone_core_get_playback_device(LinphoneCore *lc) {
4226 return lc->sound_conf.play_sndcard ? ms_snd_card_get_string_id(lc->sound_conf.play_sndcard) : NULL;
4227 }
4228
4229 const char * linphone_core_get_capture_device(LinphoneCore *lc) {
4230 return lc->sound_conf.capt_sndcard ? ms_snd_card_get_string_id(lc->sound_conf.capt_sndcard) : NULL;
4231 }
4232
4233 const char** linphone_core_get_sound_devices(LinphoneCore *lc){
4234 return lc->sound_conf.cards;
4235 }
4236
4237 const char** linphone_core_get_video_devices(const LinphoneCore *lc){
4238 return lc->video_conf.cams;
4239 }
4240
4241 void linphone_core_set_default_sound_devices(LinphoneCore *lc){
4242 linphone_core_set_ringer_device(lc, NULL);
4243 linphone_core_set_playback_device(lc, NULL);
4244 linphone_core_set_capture_device(lc, NULL);
4245 }
4246
4247 void linphone_core_reload_sound_devices(LinphoneCore *lc){
4248 const char *ringer;
4249 const char *playback;
4250 const char *capture;
4251 char *ringer_copy = NULL;
4252 char *playback_copy = NULL;
4253 char *capture_copy = NULL;
4254
4255 ringer = linphone_core_get_ringer_device(lc);
4256 if (ringer != NULL) {
4257 ringer_copy = ms_strdup(ringer);
4258 }
4259 playback = linphone_core_get_playback_device(lc);
4260 if (playback != NULL) {
4261 playback_copy = ms_strdup(playback);
4262 }
4263 capture = linphone_core_get_capture_device(lc);
4264 if (capture != NULL) {
4265 capture_copy = ms_strdup(capture);
4266 }
4267 ms_snd_card_manager_reload(ms_factory_get_snd_card_manager(lc->factory));
4268 build_sound_devices_table(lc);
4269 if (ringer_copy != NULL) {
4270 linphone_core_set_ringer_device(lc, ringer_copy);
4271 ms_free(ringer_copy);
4272 }
4273 if (playback_copy != NULL) {
4274 linphone_core_set_playback_device(lc, playback_copy);
4275 ms_free(playback_copy);
4276 }
4277 if (capture_copy != NULL) {
4278 linphone_core_set_capture_device(lc, capture_copy);
4279 ms_free(capture_copy);
4280 }
4281 }
4282
4283 void linphone_core_reload_video_devices(LinphoneCore *lc){
4284 char *devid_copy = NULL;
4285 const char *devid = linphone_core_get_video_device(lc);
4286 if (devid != NULL) {
4287 devid_copy = ms_strdup(devid);
4288 }
4289 ms_web_cam_manager_reload(ms_factory_get_web_cam_manager(lc->factory));
4290 build_video_devices_table(lc);
4291 if (devid_copy != NULL) {
4292 linphone_core_set_video_device(lc, devid_copy);
4293 ms_free(devid_copy);
4294 }
4295 }
4296
4297 char linphone_core_get_sound_source(LinphoneCore *lc) {
4298 return lc->sound_conf.source;
4299 }
4300
4301 void linphone_core_set_sound_source(LinphoneCore *lc, char source) {
4302 MSSndCard *sndcard=lc->sound_conf.capt_sndcard;
4303 lc->sound_conf.source=source;
4304 if (!sndcard) return;
4305 switch(source){
4306 case 'm':
4307 ms_snd_card_set_capture(sndcard,MS_SND_CARD_MIC);
4308 break;
4309 case 'l':
4310 ms_snd_card_set_capture(sndcard,MS_SND_CARD_LINE);
4311 break;
4312 }
4313
4314 }
4315
4316
4317 void linphone_core_set_ring(LinphoneCore *lc,const char *path){
4318 if (lc->sound_conf.local_ring!=0){
4319 ms_free(lc->sound_conf.local_ring);
4320 lc->sound_conf.local_ring=NULL;
4321 }
4322 if (path)
4323 lc->sound_conf.local_ring=ms_strdup(path);
4324 if ( linphone_core_ready(lc) && lc->sound_conf.local_ring)
4325 lp_config_set_string(lc->config,"sound","local_ring",lc->sound_conf.local_ring);
4326 }
4327
4328 const char *linphone_core_get_ring(const LinphoneCore *lc){
4329 return lc->sound_conf.local_ring;
4330 }
4331
4332 void linphone_core_set_root_ca(LinphoneCore *lc, const char *path) {
4333 sal_set_root_ca(lc->sal, path);
4334 if (lc->http_crypto_config) {
4335 belle_tls_crypto_config_set_root_ca(lc->http_crypto_config, path);
4336 }
4337 lp_config_set_string(lc->config,"sip", "root_ca", path);
4338 }
4339
4340 void linphone_core_set_root_ca_data(LinphoneCore *lc, const char *data) {
4341 sal_set_root_ca(lc->sal, NULL);
4342 sal_set_root_ca_data(lc->sal, data);
4343 if (lc->http_crypto_config) {
4344 belle_tls_crypto_config_set_root_ca_data(lc->http_crypto_config, data);
4345 }
4346 }
4347
4348 const char *linphone_core_get_root_ca(LinphoneCore *lc){
4349 return lp_config_get_string(lc->config,"sip","root_ca",NULL);
4350 }
4351
4352 void linphone_core_verify_server_certificates(LinphoneCore *lc, bool_t yesno){
4353 sal_verify_server_certificates(lc->sal,yesno);
4354 if (lc->http_crypto_config){
4355 belle_tls_crypto_config_set_verify_exceptions(lc->http_crypto_config, yesno ? 0 : BELLE_TLS_VERIFY_ANY_REASON);
4356 }
4357 lp_config_set_int(lc->config,"sip","verify_server_certs",yesno);
4358 }
4359
4360 void linphone_core_verify_server_cn(LinphoneCore *lc, bool_t yesno){
4361 sal_verify_server_cn(lc->sal,yesno);
4362 if (lc->http_crypto_config){
4363 belle_tls_crypto_config_set_verify_exceptions(lc->http_crypto_config, yesno ? 0 : BELLE_TLS_VERIFY_CN_MISMATCH);
4364 }
4365 lp_config_set_int(lc->config,"sip","verify_server_cn",yesno);
4366 }
4367
4368 void linphone_core_set_ssl_config(LinphoneCore *lc, void *ssl_config) {
4369 sal_set_ssl_config(lc->sal, ssl_config);
4370 if (lc->http_crypto_config) {
4371 belle_tls_crypto_config_set_ssl_config(lc->http_crypto_config, ssl_config);
4372 }
4373 }
4374
4375 static void notify_end_of_ringtone( LinphoneRingtonePlayer* rp, void* user_data, int status) {
4376 LinphoneCore *lc=(LinphoneCore*)user_data;
4377 lc->preview_finished=1;
4378 }
4379
4380 LinphoneStatus linphone_core_preview_ring(LinphoneCore *lc, const char *ring,LinphoneCoreCbFunc end_of_ringtone,void * userdata)
4381 {
4382 int err;
4383 MSSndCard *ringcard=lc->sound_conf.lsd_card ? lc->sound_conf.lsd_card : lc->sound_conf.ring_sndcard;
4384 if (linphone_ringtoneplayer_is_started(lc->ringtoneplayer)){
4385 ms_warning("Cannot start ring now,there's already a ring being played");
4386 return -1;
4387 }
4388 lc_callback_obj_init(&lc->preview_finished_cb,end_of_ringtone,userdata);
4389 lc->preview_finished=0;
4390 err = linphone_ringtoneplayer_start_with_cb(lc->factory, lc->ringtoneplayer, ringcard, ring, -1, notify_end_of_ringtone,(void *)lc);
4391 if (err) {
4392 lc->preview_finished=1;
4393 }
4394 return err;
4395 }
4396
4397 MSFactory *linphone_core_get_ms_factory(LinphoneCore *lc){
4398 return lc->factory;
4399 }
4400
4401 void linphone_core_set_ringback(LinphoneCore *lc, const char *path){
4402 if (lc->sound_conf.remote_ring!=0){
4403 ms_free(lc->sound_conf.remote_ring);
4404 }
4405 lc->sound_conf.remote_ring=path?ms_strdup(path):NULL;
4406 }
4407
4408 const char * linphone_core_get_ringback(const LinphoneCore *lc){
4409 return lc->sound_conf.remote_ring;
4410 }
4411
4412 void linphone_core_enable_echo_cancellation(LinphoneCore *lc, bool_t val){
4413 lc->sound_conf.ec=val;
4414 if ( linphone_core_ready(lc))
4415 lp_config_set_int(lc->config,"sound","echocancellation",val);
4416 }
4417
4418 bool_t linphone_core_echo_cancellation_enabled(const LinphoneCore *lc){
4419 return lc->sound_conf.ec;
4420 }
4421
4422 void linphone_core_enable_echo_limiter(LinphoneCore *lc, bool_t val){
4423 lc->sound_conf.ea=val;
4424 }
4425
4426 bool_t linphone_core_echo_limiter_enabled(const LinphoneCore *lc){
4427 return lc->sound_conf.ea;
4428 }
4429
4430 static void linphone_core_mute_audio_stream(LinphoneCore *lc, AudioStream *st, bool_t val) {
4431 if (val) {
4432 audio_stream_set_mic_gain(st, 0);
4433 } else {
4434 audio_stream_set_mic_gain_db(st, lc->sound_conf.soft_mic_lev);
4435 }
4436
4437 if ( linphone_core_get_rtp_no_xmit_on_audio_mute(lc) ){
4438 audio_stream_mute_rtp(st,val);
4439 }
4440 }
4441
4442 void linphone_core_mute_mic(LinphoneCore *lc, bool_t val){
4443 linphone_core_enable_mic(lc, !val);
4444 }
4445
4446 bool_t linphone_core_is_mic_muted(LinphoneCore *lc) {
4447 return !linphone_core_mic_enabled(lc);
4448 }
4449
4450 void linphone_core_enable_mic(LinphoneCore *lc, bool_t enable) {
4451 LinphoneCall *call;
4452 const bctbx_list_t *list;
4453 const bctbx_list_t *elem;
4454
4455 if (linphone_core_is_in_conference(lc)){
4456 linphone_conference_mute_microphone(lc->conf_ctx, !enable);
4457 }
4458 list = linphone_core_get_calls(lc);
4459 for (elem = list; elem != NULL; elem = elem->next) {
4460 call = (LinphoneCall *)elem->data;
4461 call->audio_muted = !enable;
4462 if (call->audiostream)
4463 linphone_core_mute_audio_stream(lc, call->audiostream, call->audio_muted);
4464 }
4465 }
4466
4467 bool_t linphone_core_mic_enabled(LinphoneCore *lc) {
4468 LinphoneCall *call=linphone_core_get_current_call(lc);
4469 if (linphone_core_is_in_conference(lc)){
4470 return !linphone_conference_microphone_is_muted(lc->conf_ctx);
4471 }else if (call==NULL){
4472 ms_warning("%s(): No current call!", __FUNCTION__);
4473 return TRUE;
4474 }
4475 return !call->audio_muted;
4476 }
4477
4478 bool_t linphone_core_is_rtp_muted(LinphoneCore *lc){
4479 LinphoneCall *call=linphone_core_get_current_call(lc);
4480 if (call==NULL){
4481 ms_warning("linphone_core_is_rtp_muted(): No current call !");
4482 return FALSE;
4483 }
4484 if( linphone_core_get_rtp_no_xmit_on_audio_mute(lc)){
4485 return call->audio_muted;
4486 }
4487 return FALSE;
4488 }
4489
4490 void linphone_core_enable_agc(LinphoneCore *lc, bool_t val){
4491 lc->sound_conf.agc=val;
4492 }
4493
4494 bool_t linphone_core_agc_enabled(const LinphoneCore *lc){
4495 return lc->sound_conf.agc;
4496 }
4497
4498 void linphone_core_send_dtmf(LinphoneCore *lc, char dtmf) {
4499 LinphoneCall *call=linphone_core_get_current_call(lc);
4500 linphone_call_send_dtmf(call, dtmf);
4501 }
4502
4503 void linphone_core_set_stun_server(LinphoneCore *lc, const char *server) {
4504 if (lc->nat_policy != NULL) {
4505 linphone_nat_policy_set_stun_server(lc->nat_policy, server);
4506 linphone_nat_policy_save_to_config(lc->nat_policy);
4507 } else {
4508 lp_config_set_string(lc->config, "net", "stun_server", server);
4509 }
4510 }
4511
4512 const char * linphone_core_get_stun_server(const LinphoneCore *lc){
4513 if (lc->nat_policy != NULL)
4514 return linphone_nat_policy_get_stun_server(lc->nat_policy);
4515 else
4516 return lp_config_get_string(lc->config, "net", "stun_server", NULL);
4517 }
4518
4519
4520 bool_t linphone_core_upnp_available(){
4521 #ifdef BUILD_UPNP
4522 return TRUE;
4523 #else
4524 return FALSE;
4525 #endif //BUILD_UPNP
4526 }
4527
4528 LinphoneUpnpState linphone_core_get_upnp_state(const LinphoneCore *lc){
4529 #ifdef BUILD_UPNP
4530 return linphone_upnp_context_get_state(lc->upnp);
4531 #else
4532 return LinphoneUpnpStateNotAvailable;
4533 #endif //BUILD_UPNP
4534 }
4535
4536 const char * linphone_core_get_upnp_external_ipaddress(const LinphoneCore *lc){
4537 #ifdef BUILD_UPNP
4538 return linphone_upnp_context_get_external_ipaddress(lc->upnp);
4539 #else
4540 return NULL;
4541 #endif //BUILD_UPNP
4542 }
4543
4544 void linphone_core_set_nat_address(LinphoneCore *lc, const char *addr) {
4545 if (lc->net_conf.nat_address!=NULL){
4546 ms_free(lc->net_conf.nat_address);
4547 }
4548 if (addr!=NULL) lc->net_conf.nat_address=ms_strdup(addr);
4549 else lc->net_conf.nat_address=NULL;
4550 if (lc->sip_conf.contact) update_primary_contact(lc);
4551 }
4552
4553 const char *linphone_core_get_nat_address(const LinphoneCore *lc) {
4554 return lc->net_conf.nat_address;
4555 }
4556
4557 const char *linphone_core_get_nat_address_resolved(LinphoneCore *lc) {
4558 struct sockaddr_storage ss;
4559 socklen_t ss_len;
4560 int error;
4561 char ipstring [INET6_ADDRSTRLEN];
4562
4563 if (lc->net_conf.nat_address==NULL) return NULL;
4564
4565 if (parse_hostname_to_addr (lc->net_conf.nat_address, &ss, &ss_len, 5060)<0) {
4566 return lc->net_conf.nat_address;
4567 }
4568
4569 error = bctbx_getnameinfo((struct sockaddr *)&ss, ss_len,
4570 ipstring, sizeof(ipstring), NULL, 0, NI_NUMERICHOST);
4571 if (error) {
4572 return lc->net_conf.nat_address;
4573 }
4574
4575 if (lc->net_conf.nat_address_ip!=NULL){
4576 ms_free(lc->net_conf.nat_address_ip);
4577 }
4578 lc->net_conf.nat_address_ip = ms_strdup (ipstring);
4579 return lc->net_conf.nat_address_ip;
4580 }
4581
4582 void linphone_core_set_firewall_policy(LinphoneCore *lc, LinphoneFirewallPolicy pol) {
4583 LinphoneNatPolicy *nat_policy;
4584 char *stun_server = NULL;
4585 char *stun_server_username = NULL;
4586
4587 if (lc->nat_policy != NULL) {
4588 nat_policy = linphone_nat_policy_ref(lc->nat_policy);
4589 stun_server = ms_strdup(linphone_nat_policy_get_stun_server(nat_policy));
4590 stun_server_username = ms_strdup(linphone_nat_policy_get_stun_server_username(nat_policy));
4591 linphone_nat_policy_clear(nat_policy);
4592 } else {
4593 nat_policy = linphone_core_create_nat_policy(lc);
4594 stun_server = ms_strdup(linphone_core_get_stun_server(lc));
4595 }
4596
4597 switch (pol) {
4598 default:
4599 case LinphonePolicyNoFirewall:
4600 case LinphonePolicyUseNatAddress:
4601 break;
4602 case LinphonePolicyUseStun:
4603 linphone_nat_policy_enable_stun(nat_policy, TRUE);
4604 break;
4605 case LinphonePolicyUseIce:
4606 linphone_nat_policy_enable_ice(nat_policy, TRUE);
4607 linphone_nat_policy_enable_stun(nat_policy, TRUE);
4608 break;
4609 case LinphonePolicyUseUpnp:
4610 #ifdef BUILD_UPNP
4611 linphone_nat_policy_enable_upnp(nat_policy, TRUE);
4612 #else
4613 ms_warning("UPNP is not available, reset firewall policy to no firewall");
4614 #endif //BUILD_UPNP
4615 break;
4616 }
4617
4618 if (stun_server_username != NULL) {
4619 linphone_nat_policy_set_stun_server_username(nat_policy, stun_server_username);
4620 ms_free(stun_server_username);
4621 }
4622 if (stun_server != NULL) {
4623 linphone_nat_policy_set_stun_server(nat_policy, stun_server);
4624 ms_free(stun_server);
4625 }
4626 linphone_core_set_nat_policy(lc, nat_policy);
4627 linphone_nat_policy_unref(nat_policy);
4628
4629 /* Ensure that the firewall policy is cleared in the config because it has been replaced by the nat_policy. */
4630 lp_config_set_string(lc->config, "net", "firewall_policy", NULL);
4631 }
4632
4633 LinphoneFirewallPolicy linphone_core_get_firewall_policy(const LinphoneCore *lc) {
4634 const char *policy;
4635
4636 policy = lp_config_get_string(lc->config, "net", "firewall_policy", NULL);
4637 if (policy == NULL) {
4638 LinphoneNatPolicy *nat_policy = linphone_core_get_nat_policy(lc);
4639 if (nat_policy == NULL) {
4640 return LinphonePolicyNoFirewall;
4641 } else if (linphone_nat_policy_upnp_enabled(nat_policy))
4642 return LinphonePolicyUseUpnp;
4643 else if (linphone_nat_policy_ice_enabled(nat_policy))
4644 return LinphonePolicyUseIce;
4645 else if (linphone_nat_policy_stun_enabled(nat_policy))
4646 return LinphonePolicyUseStun;
4647 else
4648 return LinphonePolicyNoFirewall;
4649 } else if (strcmp(policy, "0") == 0)
4650 return LinphonePolicyNoFirewall;
4651 else if ((strcmp(policy, "nat_address") == 0) || (strcmp(policy, "1") == 0))
4652 return LinphonePolicyUseNatAddress;
4653 else if ((strcmp(policy, "stun") == 0) || (strcmp(policy, "2") == 0))
4654 return LinphonePolicyUseStun;
4655 else if ((strcmp(policy, "ice") == 0) || (strcmp(policy, "3") == 0))
4656 return LinphonePolicyUseIce;
4657 else if ((strcmp(policy, "upnp") == 0) || (strcmp(policy, "4") == 0))
4658 return LinphonePolicyUseUpnp;
4659 else
4660 return LinphonePolicyNoFirewall;
4661 }
4662
4663 void linphone_core_set_nat_policy(LinphoneCore *lc, LinphoneNatPolicy *policy) {
4664 if (policy != NULL) policy = linphone_nat_policy_ref(policy); /* Prevent object destruction if the same policy is used */
4665 else{
4666 ms_error("linphone_core_set_nat_policy() setting to NULL is not allowed");
4667 return ;
4668 }
4669 if (lc->nat_policy != NULL) {
4670 linphone_nat_policy_unref(lc->nat_policy);
4671 lc->nat_policy = NULL;
4672 }
4673 if (policy != NULL){
4674 lc->nat_policy = policy;
4675 /*start an immediate (but asynchronous) resolution.*/
4676 linphone_nat_policy_resolve_stun_server(policy);
4677 lp_config_set_string(lc->config, "net", "nat_policy_ref", lc->nat_policy->ref);
4678 linphone_nat_policy_save_to_config(lc->nat_policy);
4679 }
4680
4681 #ifdef BUILD_UPNP
4682 linphone_core_enable_keep_alive(lc, (lc->sip_conf.keepalive_period > 0));
4683 if (linphone_nat_policy_upnp_enabled(policy)) {
4684 if (lc->upnp == NULL) {
4685 lc->upnp = linphone_upnp_context_new(lc);
4686 }
4687 sal_nat_helper_enable(lc->sal, FALSE);
4688 sal_enable_auto_contacts(lc->sal, FALSE);
4689 sal_use_rport(lc->sal, FALSE);
4690 } else {
4691 if (lc->upnp != NULL) {
4692 linphone_upnp_context_destroy(lc->upnp);
4693 lc->upnp = NULL;
4694 }
4695 #endif
4696 sal_nat_helper_enable(lc->sal, lp_config_get_int(lc->config, "net", "enable_nat_helper", 1));
4697 sal_enable_auto_contacts(lc->sal, TRUE);
4698 sal_use_rport(lc->sal, lp_config_get_int(lc->config, "sip", "use_rport", 1));
4699 if (lc->sip_conf.contact) update_primary_contact(lc);
4700 #ifdef BUILD_UPNP
4701 }
4702 #endif
4703 }
4704
4705 LinphoneNatPolicy * linphone_core_get_nat_policy(const LinphoneCore *lc) {
4706 return lc->nat_policy;
4707 }
4708
4709
4710 /*******************************************************************************
4711 * Call log related functions *
4712 ******************************************************************************/
4713
4714 void linphone_core_set_call_logs_database_path(LinphoneCore *lc, const char *path) {
4715 if (lc->logs_db_file){
4716 ms_free(lc->logs_db_file);
4717 lc->logs_db_file = NULL;
4718 }
4719 if (path) {
4720 lc->logs_db_file = ms_strdup(path);
4721 linphone_core_call_log_storage_init(lc);
4722
4723 linphone_core_migrate_logs_from_rc_to_db(lc);
4724 }
4725 }
4726
4727 const char * linphone_core_get_call_logs_database_path(LinphoneCore *lc) {
4728 return lc->logs_db_file;
4729 }
4730
4731 const bctbx_list_t* linphone_core_get_call_logs(LinphoneCore *lc) {
4732 #ifdef SQLITE_STORAGE_ENABLED
4733 if (lc->logs_db) {
4734 linphone_core_get_call_history(lc);
4735 }
4736 #endif
4737 return lc->call_logs;
4738 }
4739
4740 void linphone_core_clear_call_logs(LinphoneCore *lc) {
4741 bool_t call_logs_sqlite_db_found = FALSE;
4742 lc->missed_calls=0;
4743 #ifdef SQLITE_STORAGE_ENABLED
4744 if (lc->logs_db) {
4745 call_logs_sqlite_db_found = TRUE;
4746 linphone_core_delete_call_history(lc);
4747 }
4748 #endif
4749 if (!call_logs_sqlite_db_found) {
4750 bctbx_list_for_each(lc->call_logs, (void (*)(void*))linphone_call_log_unref);
4751 lc->call_logs = bctbx_list_free(lc->call_logs);
4752 call_logs_write_to_config_file(lc);
4753 }
4754 }
4755
4756 int linphone_core_get_missed_calls_count(LinphoneCore *lc) {
4757 return lc->missed_calls;
4758 }
4759
4760 void linphone_core_reset_missed_calls_count(LinphoneCore *lc) {
4761 lc->missed_calls=0;
4762 }
4763
4764 void linphone_core_remove_call_log(LinphoneCore *lc, LinphoneCallLog *cl) {
4765 bool_t call_logs_sqlite_db_found = FALSE;
4766 #ifdef SQLITE_STORAGE_ENABLED
4767 if (lc->logs_db) {
4768 call_logs_sqlite_db_found = TRUE;
4769 linphone_core_delete_call_log(lc, cl);
4770 }
4771 #endif
4772 lc->call_logs = bctbx_list_remove(lc->call_logs, cl);
4773 if (!call_logs_sqlite_db_found) {
4774 call_logs_write_to_config_file(lc);
4775 linphone_call_log_unref(cl);
4776 }
4777 }
4778
4779 void linphone_core_migrate_logs_from_rc_to_db(LinphoneCore *lc) {
4780 bctbx_list_t *logs_to_migrate = NULL;
4781 LpConfig *lpc = NULL;
4782 size_t original_logs_count, migrated_logs_count;
4783 int i;
4784
4785 #ifndef SQLITE_STORAGE_ENABLED
4786 ms_warning("linphone has been compiled without sqlite, can't migrate call logs");
4787 return;
4788 #endif
4789 if (!lc) {
4790 return;
4791 }
4792
4793 lpc = linphone_core_get_config(lc);
4794 if (!lpc) {
4795 ms_warning("this core has been started without a rc file, nothing to migrate");
4796 return;
4797 }
4798 if (lp_config_get_int(lpc, "misc", "call_logs_migration_done", 0) == 1) {
4799 ms_warning("the call logs migration has already been done, skipping...");
4800 return;
4801 }
4802
4803 logs_to_migrate = call_logs_read_from_config_file(lc);
4804 if (!logs_to_migrate) {
4805 ms_warning("nothing to migrate, skipping...");
4806 return;
4807 }
4808
4809 // This is because there must have been a call previously to linphone_core_call_log_storage_init
4810 lc->call_logs = bctbx_list_free_with_data(lc->call_logs, (void (*)(void*))linphone_call_log_unref);
4811 lc->call_logs = NULL;
4812
4813 // We can't use bctbx_list_for_each because logs_to_migrate are listed in the wrong order (latest first), and we want to store the logs latest last
4814 for (i = (int)bctbx_list_size(logs_to_migrate) - 1; i >= 0; i--) {
4815 LinphoneCallLog *log = (LinphoneCallLog *) bctbx_list_nth_data(logs_to_migrate, i);
4816 linphone_core_store_call_log(lc, log);
4817 }
4818
4819 original_logs_count = bctbx_list_size(logs_to_migrate);
4820 migrated_logs_count = bctbx_list_size(lc->call_logs);
4821 if (original_logs_count == migrated_logs_count) {
4822 size_t i = 0;
4823 ms_debug("call logs migration successful: %u logs migrated", (unsigned int)bctbx_list_size(lc->call_logs));
4824 lp_config_set_int(lpc, "misc", "call_logs_migration_done", 1);
4825
4826 for (; i < original_logs_count; i++) {
4827 char logsection[32];
4828 snprintf(logsection, sizeof(logsection), "call_log_%u", (unsigned int)i);
4829 lp_config_clean_section(lpc, logsection);
4830 }
4831 } else {
4832 ms_error("not as many logs saved in db has logs read from rc ("FORMAT_SIZE_T" in rc against "FORMAT_SIZE_T" in db)!", original_logs_count, migrated_logs_count);
4833 }
4834
4835 bctbx_list_free_with_data(logs_to_migrate, (void (*)(void*))linphone_call_log_unref);
4836 }
4837
4838
4839 /*******************************************************************************
4840 * Video related functions *
4841 ******************************************************************************/
4842
4843 #ifdef VIDEO_ENABLED
4844 static void snapshot_taken(void *userdata, struct _MSFilter *f, unsigned int id, void *arg) {
4845 if (id == MS_JPEG_WRITER_SNAPSHOT_TAKEN) {
4846 LinphoneCore *lc = (LinphoneCore *)userdata;
4847 linphone_core_enable_video_preview(lc, FALSE);
4848 }
4849 }
4850 #endif
4851
4852 LinphoneStatus linphone_core_take_preview_snapshot(LinphoneCore *lc, const char *file) {
4853 LinphoneCall *call = linphone_core_get_current_call(lc);
4854
4855 if (!file) return -1;
4856 if (call) {
4857 return linphone_call_take_preview_snapshot(call, file);
4858 } else {
4859 #ifdef VIDEO_ENABLED
4860 if (lc->previewstream == NULL) {
4861 MSVideoSize vsize=lc->video_conf.preview_vsize.width != 0 ? lc->video_conf.preview_vsize : lc->video_conf.vsize;
4862 lc->previewstream = video_preview_new(lc->factory);
4863 video_preview_set_size(lc->previewstream, vsize);
4864 video_preview_set_display_filter_name(lc->previewstream, NULL);
4865 video_preview_set_fps(lc->previewstream,linphone_core_get_preferred_framerate(lc));
4866 video_preview_start(lc->previewstream, lc->video_conf.device);
4867 lc->previewstream->ms.factory = lc->factory;
4868 linphone_core_enable_video_preview(lc, TRUE);
4869
4870 ms_filter_add_notify_callback(lc->previewstream->local_jpegwriter, snapshot_taken, lc, TRUE);
4871 ms_filter_call_method(lc->previewstream->local_jpegwriter, MS_JPEG_WRITER_TAKE_SNAPSHOT, (void*)file);
4872 } else {
4873 ms_filter_call_method(lc->previewstream->local_jpegwriter, MS_JPEG_WRITER_TAKE_SNAPSHOT, (void*)file);
4874 }
4875 return 0;
4876 #endif
4877 }
4878 return -1;
4879 }
4880
4881 static void toggle_video_preview(LinphoneCore *lc, bool_t val){
4882 #ifdef VIDEO_ENABLED
4883 if (val){
4884 if (lc->previewstream==NULL){
4885 const char *display_filter=linphone_core_get_video_display_filter(lc);
4886 MSVideoSize vsize = { 0 };
4887 const LinphoneVideoDefinition *vdef = linphone_core_get_preview_video_definition(lc);
4888 if (!vdef || linphone_video_definition_is_undefined(vdef)) {
4889 vdef = linphone_core_get_preferred_video_definition(lc);
4890 }
4891 vsize.width = linphone_video_definition_get_width(vdef);
4892 vsize.height = linphone_video_definition_get_height(vdef);
4893 lc->previewstream=video_preview_new(lc->factory);
4894 video_preview_set_size(lc->previewstream,vsize);
4895 if (display_filter)
4896 video_preview_set_display_filter_name(lc->previewstream,display_filter);
4897 if (lc->preview_window_id != NULL)
4898 video_preview_set_native_window_id(lc->previewstream,lc->preview_window_id);
4899 video_preview_set_fps(lc->previewstream,linphone_core_get_preferred_framerate(lc));
4900 video_preview_start(lc->previewstream,lc->video_conf.device);
4901 }
4902 }else{
4903 if (lc->previewstream!=NULL){
4904 video_preview_stop(lc->previewstream);
4905 lc->previewstream=NULL;
4906 }
4907 }
4908 #endif
4909 }
4910
4911 static void relaunch_video_preview(LinphoneCore *lc){
4912 if (lc->previewstream){
4913 toggle_video_preview(lc,FALSE);
4914 }
4915 /* And nothing else, because linphone_core_iterate() will restart the preview stream if necessary.
4916 * This code will need to be revisited when linphone_core_iterate() will no longer be required*/
4917 }
4918
4919 bool_t linphone_core_video_supported(LinphoneCore *lc){
4920 #ifdef VIDEO_ENABLED
4921 return TRUE;
4922 #else
4923 return FALSE;
4924 #endif
4925 }
4926
4927 void linphone_core_enable_video(LinphoneCore *lc, bool_t vcap_enabled, bool_t display_enabled) {
4928 linphone_core_enable_video_capture(lc, vcap_enabled);
4929 linphone_core_enable_video_display(lc, display_enabled);
4930 }
4931
4932 bool_t linphone_core_video_enabled(LinphoneCore *lc){
4933 return (lc->video_conf.display || lc->video_conf.capture);
4934 }
4935
4936 static void reapply_network_bandwidth_settings(LinphoneCore *lc) {
4937 linphone_core_set_download_bandwidth(lc, linphone_core_get_download_bandwidth(lc));
4938 linphone_core_set_upload_bandwidth(lc, linphone_core_get_upload_bandwidth(lc));
4939 }
4940
4941 void linphone_core_enable_video_capture(LinphoneCore *lc, bool_t enable) {
4942 #ifndef VIDEO_ENABLED
4943 if (enable == TRUE) {
4944 ms_warning("Cannot enable video capture, this version of linphone was built without video support.");
4945 }
4946 #endif
4947 lc->video_conf.capture = enable;
4948 if (linphone_core_ready(lc)) {
4949 lp_config_set_int(lc->config, "video", "capture", lc->video_conf.capture);
4950 }
4951 /* Need to re-apply network bandwidth settings. */
4952 reapply_network_bandwidth_settings(lc);
4953 }
4954
4955 void linphone_core_enable_video_display(LinphoneCore *lc, bool_t enable) {
4956 #ifndef VIDEO_ENABLED
4957 if (enable == TRUE) {
4958 ms_warning("Cannot enable video display, this version of linphone was built without video support.");
4959 }
4960 #endif
4961 lc->video_conf.display = enable;
4962 if (linphone_core_ready(lc)) {
4963 lp_config_set_int(lc->config, "video", "display", lc->video_conf.display);
4964 }
4965 /* Need to re-apply network bandwidth settings. */
4966 reapply_network_bandwidth_settings(lc);
4967 }
4968
4969 void linphone_core_enable_video_source_reuse(LinphoneCore* lc, bool_t enable){
4970 #ifndef VIDEO_ENABLED
4971 if (enable == TRUE) {
4972 ms_warning("Cannot enable video display, this version of linphone was built without video support.");
4973 }
4974 #endif
4975 lc->video_conf.reuse_preview_source = enable;
4976 if( linphone_core_ready(lc) ){
4977 lp_config_set_int(lc->config, "video", "reuse_source", lc->video_conf.reuse_preview_source);
4978 }
4979 }
4980
4981 bool_t linphone_core_video_capture_enabled(LinphoneCore *lc) {
4982 return lc->video_conf.capture;
4983 }
4984
4985 bool_t linphone_core_video_display_enabled(LinphoneCore *lc) {
4986 return lc->video_conf.display;
4987 }
4988
4989 void linphone_core_set_video_policy(LinphoneCore *lc, const LinphoneVideoPolicy *policy){
4990 lc->video_policy=*policy;
4991 if (linphone_core_ready(lc)){
4992 lp_config_set_int(lc->config,"video","automatically_initiate",policy->automatically_initiate);
4993 lp_config_set_int(lc->config,"video","automatically_accept",policy->automatically_accept);
4994 }
4995 }
4996
4997 const LinphoneVideoPolicy *linphone_core_get_video_policy(const LinphoneCore *lc){
4998 return &lc->video_policy;
4999 }
5000
5001 BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneVideoActivationPolicy);
5002
5003 BELLE_SIP_INSTANCIATE_VPTR(LinphoneVideoActivationPolicy, belle_sip_object_t,
5004 NULL, // destroy
5005 NULL, // clone
5006 NULL, // marshal
5007 FALSE
5008 );
5009
5010 LinphoneVideoActivationPolicy *linphone_video_activation_policy_new() {
5011 LinphoneVideoActivationPolicy *policy = belle_sip_object_new(LinphoneVideoActivationPolicy);
5012 policy->automatically_accept = FALSE;
5013 policy->automatically_initiate = FALSE;
5014 return policy;
5015 }
5016
5017 LinphoneVideoActivationPolicy* linphone_video_activation_policy_ref(LinphoneVideoActivationPolicy* policy) {
5018 return (LinphoneVideoActivationPolicy*) belle_sip_object_ref(policy);
5019 }
5020
5021 void linphone_video_activation_policy_unref(LinphoneVideoActivationPolicy* policy) {
5022 belle_sip_object_unref(policy);
5023 }
5024
5025 void *linphone_video_activation_policy_get_user_data(const LinphoneVideoActivationPolicy *policy) {
5026 return policy->user_data;
5027 }
5028
5029 void linphone_video_activation_policy_set_user_data(LinphoneVideoActivationPolicy *policy, void *data) {
5030 policy->user_data = data;
5031 }
5032
5033 bool_t linphone_video_activation_policy_get_automatically_accept(const LinphoneVideoActivationPolicy *policy) {
5034 return policy->automatically_accept;
5035 }
5036
5037 bool_t linphone_video_activation_policy_get_automatically_initiate(const LinphoneVideoActivationPolicy *policy) {
5038 return policy->automatically_initiate;
5039 }
5040
5041 void linphone_video_activation_policy_set_automatically_accept(LinphoneVideoActivationPolicy *policy, bool_t enable) {
5042 policy->automatically_accept = enable;
5043 }
5044
5045 void linphone_video_activation_policy_set_automatically_initiate(LinphoneVideoActivationPolicy *policy, bool_t enable) {
5046 policy->automatically_initiate = enable;
5047 }
5048
5049 void linphone_core_set_video_activation_policy(LinphoneCore *lc, const LinphoneVideoActivationPolicy *policy) {
5050 lc->video_policy.automatically_accept = policy->automatically_accept;
5051 lc->video_policy.automatically_initiate = policy->automatically_initiate;
5052 if (linphone_core_ready(lc)) {
5053 lp_config_set_int(lc->config, "video", "automatically_initiate", policy->automatically_initiate);
5054 lp_config_set_int(lc->config, "video", "automatically_accept", policy->automatically_accept);
5055 }
5056 }
5057
5058 LinphoneVideoActivationPolicy *linphone_core_get_video_activation_policy(const LinphoneCore *lc){
5059 LinphoneVideoActivationPolicy *policy = linphone_video_activation_policy_new();
5060 policy->automatically_accept = lc->video_policy.automatically_accept;
5061 policy->automatically_initiate = lc->video_policy.automatically_initiate;
5062 return policy;
5063 }
5064
5065 void linphone_core_enable_video_preview(LinphoneCore *lc, bool_t val){
5066 lc->video_conf.show_local=val;
5067 if (linphone_core_ready(lc))
5068 lp_config_set_int(lc->config,"video","show_local",val);
5069 }
5070
5071 bool_t linphone_core_video_preview_enabled(const LinphoneCore *lc){
5072 return lc->video_conf.show_local;
5073 }
5074
5075 void linphone_core_enable_self_view(LinphoneCore *lc, bool_t val){
5076 #ifdef VIDEO_ENABLED
5077 LinphoneCall *call=linphone_core_get_current_call (lc);
5078 lc->video_conf.selfview=val;
5079 if (linphone_core_ready(lc)) {
5080 lp_config_set_int(lc->config,"video","self_view",linphone_core_self_view_enabled(lc));
5081 }
5082 if (call && call->videostream){
5083 video_stream_enable_self_view(call->videostream,val);
5084 }
5085 if (linphone_core_ready(lc)){
5086 lp_config_set_int(lc->config,"video","self_view",val);
5087 }
5088 #endif
5089 }
5090
5091 bool_t linphone_core_self_view_enabled(const LinphoneCore *lc){
5092 return lc->video_conf.selfview;
5093 }
5094
5095 LinphoneStatus linphone_core_set_video_device(LinphoneCore *lc, const char *id){
5096 MSWebCam *olddev=lc->video_conf.device;
5097 const char *vd;
5098 if (id!=NULL){
5099 lc->video_conf.device=ms_web_cam_manager_get_cam(ms_factory_get_web_cam_manager(lc->factory),id);
5100 if (lc->video_conf.device==NULL){
5101 ms_warning("Could not find video device %s",id);
5102 }
5103 }
5104 if (lc->video_conf.device==NULL)
5105 lc->video_conf.device=ms_web_cam_manager_get_default_cam(ms_factory_get_web_cam_manager(lc->factory));
5106 if (olddev!=NULL && olddev!=lc->video_conf.device){
5107 relaunch_video_preview(lc);
5108 }
5109 if ( linphone_core_ready(lc) && lc->video_conf.device){
5110 vd=ms_web_cam_get_string_id(lc->video_conf.device);
5111 if (vd && strstr(vd,"Static picture")!=NULL){
5112 vd=NULL;
5113 }
5114 lp_config_set_string(lc->config,"video","device",vd);
5115 }
5116 return 0;
5117 }
5118
5119 const char *linphone_core_get_video_device(const LinphoneCore *lc){
5120 if (lc->video_conf.device) return ms_web_cam_get_string_id(lc->video_conf.device);
5121 return NULL;
5122 }
5123
5124 #ifdef VIDEO_ENABLED
5125 static VideoStream * get_active_video_stream(LinphoneCore *lc){
5126 VideoStream *vs = NULL;
5127 LinphoneCall *call=linphone_core_get_current_call (lc);
5128 /* Select the video stream from the call in the first place */
5129 if (call && call->videostream) {
5130 vs = call->videostream;
5131 }
5132 /* If not in call, select the video stream from the preview */
5133 if (vs == NULL && lc->previewstream) {
5134 vs = lc->previewstream;
5135 }
5136 return vs;
5137 }
5138 #endif
5139
5140 LinphoneStatus linphone_core_set_static_picture(LinphoneCore *lc, const char *path) {
5141 #ifdef VIDEO_ENABLED
5142 VideoStream *vs=get_active_video_stream(lc);
5143 /* If we have a video stream (either preview, either from call), we
5144 have a source and it is using the static picture filter, then
5145 force the filter to use that picture. */
5146 if (vs && vs->source) {
5147 if (ms_filter_get_id(vs->source) == MS_STATIC_IMAGE_ID) {
5148 ms_filter_call_method(vs->source, MS_STATIC_IMAGE_SET_IMAGE,
5149 (void *)path);
5150 }
5151 }
5152 /* Tell the static image filter to use that image from now on so
5153 that the image will be used next time it has to be read */
5154 ms_static_image_set_default_image(path);
5155 #else
5156 ms_warning("Video support not compiled.");
5157 #endif
5158 return 0;
5159 }
5160
5161 const char *linphone_core_get_static_picture(LinphoneCore *lc) {
5162 const char *path=NULL;
5163 #ifdef VIDEO_ENABLED
5164 path=ms_static_image_get_default_image();
5165 #else
5166 ms_warning("Video support not compiled.");
5167 #endif
5168 return path;
5169 }
5170
5171 LinphoneStatus linphone_core_set_static_picture_fps(LinphoneCore *lc, float fps) {
5172 #ifdef VIDEO_ENABLED
5173 VideoStream *vs = NULL;
5174
5175 vs=get_active_video_stream(lc);
5176
5177 /* If we have a video stream (either preview, either from call), we
5178 have a source and it is using the static picture filter, then
5179 force the filter to use that picture. */
5180 if (vs && vs->source) {
5181 if (ms_filter_get_id(vs->source) == MS_STATIC_IMAGE_ID) {
5182 ms_filter_call_method(vs->source, MS_FILTER_SET_FPS,(void *)&fps);
5183 }
5184 }
5185 #else
5186 ms_warning("Video support not compiled.");
5187 #endif
5188 return 0;
5189 }
5190
5191 float linphone_core_get_static_picture_fps(LinphoneCore *lc) {
5192 #ifdef VIDEO_ENABLED
5193 VideoStream *vs = NULL;
5194 vs=get_active_video_stream(lc);
5195 /* If we have a video stream (either preview, either from call), we
5196 have a source and it is using the static picture filter, then
5197 force the filter to use that picture. */
5198 if (vs && vs->source) {
5199 if (ms_filter_get_id(vs->source) == MS_STATIC_IMAGE_ID) {
5200
5201 float fps;
5202
5203 ms_filter_call_method(vs->source, MS_FILTER_GET_FPS,(void *)&fps);
5204 return fps;
5205 }
5206 }
5207 #else
5208 ms_warning("Video support not compiled.");
5209 #endif
5210 return 0;
5211 }
5212
5213 void * linphone_core_get_native_video_window_id(const LinphoneCore *lc){
5214 if (lc->video_window_id) {
5215 /* case where the video id was previously set by the app*/
5216 return lc->video_window_id;
5217 }else{
5218 #ifdef VIDEO_ENABLED
5219 /*case where it was not set but we want to get the one automatically created by mediastreamer2 (desktop versions only)*/
5220 LinphoneCall *call=linphone_core_get_current_call (lc);
5221 if (call && call->videostream)
5222 return video_stream_get_native_window_id(call->videostream);
5223 #endif
5224 }
5225 return 0;
5226 }
5227
5228 /* unsets the video id for all calls (indeed it may be kept by filters or videostream object itself by paused calls)*/
5229 static void unset_video_window_id(LinphoneCore *lc, bool_t preview, void *id){
5230 #ifdef VIDEO_ENABLED
5231 LinphoneCall *call;
5232 bctbx_list_t *elem;
5233 #endif
5234
5235 if ((id != NULL)
5236 #ifndef _WIN32
5237 && ((unsigned long)id != (unsigned long)-1)
5238 #endif
5239 ){
5240 ms_error("Invalid use of unset_video_window_id()");
5241 return;
5242 }
5243 #ifdef VIDEO_ENABLED
5244 for(elem=lc->calls;elem!=NULL;elem=elem->next){
5245 call=(LinphoneCall *) elem->data;
5246 if (call->videostream){
5247 if (preview)
5248 video_stream_set_native_preview_window_id(call->videostream,id);
5249 else
5250 video_stream_set_native_window_id(call->videostream,id);
5251 }
5252 }
5253 #endif
5254 }
5255
5256 void linphone_core_set_native_video_window_id(LinphoneCore *lc, void *id){
5257 if ((id == NULL)
5258 #ifndef _WIN32
5259 || ((unsigned long)id == (unsigned long)-1)
5260 #endif
5261 ){
5262 unset_video_window_id(lc,FALSE,id);
5263 }
5264 lc->video_window_id=id;
5265 #ifdef VIDEO_ENABLED
5266 {
5267 LinphoneCall *call=linphone_core_get_current_call(lc);
5268 if (call!=NULL && call->videostream){
5269 video_stream_set_native_window_id(call->videostream,id);
5270 }
5271 }
5272 #endif
5273 }
5274
5275 void * linphone_core_get_native_preview_window_id(const LinphoneCore *lc){
5276 if (lc->preview_window_id){
5277 /*case where the id was set by the app previously*/
5278 return lc->preview_window_id;
5279 }else{
5280 /*case where we want the id automatically created by mediastreamer2 (desktop versions only)*/
5281 #ifdef VIDEO_ENABLED
5282 LinphoneCall *call=linphone_core_get_current_call(lc);
5283 if (call && call->videostream)
5284 return video_stream_get_native_preview_window_id(call->videostream);
5285 if (lc->previewstream)
5286 return video_preview_get_native_window_id(lc->previewstream);
5287 #endif
5288 }
5289 return 0;
5290 }
5291
5292 void linphone_core_set_native_preview_window_id(LinphoneCore *lc, void *id){
5293 if ((id == NULL)
5294 #ifndef _WIN32
5295 || ((unsigned long)id == (unsigned long)-1)
5296 #endif
5297 ) {
5298 unset_video_window_id(lc,TRUE,id);
5299 }
5300 lc->preview_window_id=id;
5301 #ifdef VIDEO_ENABLED
5302 {
5303 LinphoneCall *call=linphone_core_get_current_call(lc);
5304 if (call!=NULL && call->videostream){
5305 video_stream_set_native_preview_window_id(call->videostream,id);
5306 }else if (lc->previewstream){
5307 video_preview_set_native_window_id(lc->previewstream,id);
5308 }
5309 }
5310 #endif
5311 }
5312
5313 void linphone_core_show_video(LinphoneCore *lc, bool_t show){
5314 #ifdef VIDEO_ENABLED
5315 LinphoneCall *call=linphone_core_get_current_call(lc);
5316 ms_error("linphone_core_show_video %d", show);
5317 if (call!=NULL && call->videostream){
5318 video_stream_show_video(call->videostream,show);
5319 }
5320 #endif
5321 }
5322
5323 void linphone_core_use_preview_window(LinphoneCore *lc, bool_t yesno){
5324 lc->use_preview_window=yesno;
5325 }
5326
5327 int linphone_core_get_device_rotation(LinphoneCore *lc ) {
5328 return lc->device_rotation;
5329 }
5330
5331 void linphone_core_set_device_rotation(LinphoneCore *lc, int rotation) {
5332 if (rotation!=lc->device_rotation) ms_message("%s : rotation=%d\n", __FUNCTION__, rotation);
5333 lc->device_rotation = rotation;
5334 #ifdef VIDEO_ENABLED
5335 {
5336 LinphoneCall *call=linphone_core_get_current_call(lc);
5337 if (call!=NULL && call->videostream){
5338 video_stream_set_device_rotation(call->videostream,rotation);
5339 }
5340 }
5341 #endif
5342 }
5343
5344 int linphone_core_get_camera_sensor_rotation(LinphoneCore *lc) {
5345 #ifdef VIDEO_ENABLED
5346 LinphoneCall *call = linphone_core_get_current_call(lc);
5347 if ((call != NULL) && (call->videostream != NULL)) {
5348 return video_stream_get_camera_sensor_rotation(call->videostream);
5349 }
5350 #endif
5351 return -1;
5352 }
5353
5354 static MSVideoSizeDef supported_resolutions[] = {
5355 #if !defined(__ANDROID__) && !TARGET_OS_IPHONE
5356 { { MS_VIDEO_SIZE_1080P_W, MS_VIDEO_SIZE_1080P_H }, "1080p" },
5357 #endif
5358 #if !defined(__ANDROID__) && !TARGET_OS_MAC /*limit to most common sizes because mac video API cannot list supported resolutions*/
5359 { { MS_VIDEO_SIZE_UXGA_W, MS_VIDEO_SIZE_UXGA_H }, "uxga" },
5360 { { MS_VIDEO_SIZE_SXGA_MINUS_W, MS_VIDEO_SIZE_SXGA_MINUS_H }, "sxga-" },
5361 #endif
5362 { { MS_VIDEO_SIZE_720P_W, MS_VIDEO_SIZE_720P_H }, "720p" },
5363 #if !defined(__ANDROID__) && !TARGET_OS_MAC
5364 { { MS_VIDEO_SIZE_XGA_W, MS_VIDEO_SIZE_XGA_H }, "xga" },
5365 #endif
5366 #if !defined(__ANDROID__) && !TARGET_OS_IPHONE
5367 { { MS_VIDEO_SIZE_SVGA_W, MS_VIDEO_SIZE_SVGA_H }, "svga" },
5368 { { MS_VIDEO_SIZE_4CIF_W, MS_VIDEO_SIZE_4CIF_H }, "4cif" },
5369 #endif
5370 { { MS_VIDEO_SIZE_VGA_W, MS_VIDEO_SIZE_VGA_H }, "vga" },
5371 #if TARGET_OS_IPHONE
5372 { { MS_VIDEO_SIZE_IOS_MEDIUM_H, MS_VIDEO_SIZE_IOS_MEDIUM_W }, "ios-medium" },
5373 #endif
5374 { { MS_VIDEO_SIZE_CIF_W, MS_VIDEO_SIZE_CIF_H }, "cif" },
5375 #if !TARGET_OS_MAC || TARGET_OS_IPHONE /* OS_MAC is 1 for iPhone, but we need QVGA */
5376 { { MS_VIDEO_SIZE_QVGA_W, MS_VIDEO_SIZE_QVGA_H } , "qvga" },
5377 #endif
5378 { { MS_VIDEO_SIZE_QCIF_W, MS_VIDEO_SIZE_QCIF_H }, "qcif" },
5379 { { 0, 0 }, NULL }
5380 };
5381
5382 const MSVideoSizeDef *linphone_core_get_supported_video_sizes(LinphoneCore *lc){
5383 return supported_resolutions;
5384 }
5385
5386 static MSVideoSize video_size_get_by_name(const char *name){
5387 MSVideoSizeDef *pdef=supported_resolutions;
5388 MSVideoSize null_vsize={0,0};
5389 MSVideoSize parsed;
5390 if (!name) return null_vsize;
5391 for(;pdef->name!=NULL;pdef++){
5392 if (strcasecmp(name,pdef->name)==0){
5393 return pdef->vsize;
5394 }
5395 }
5396 if (sscanf(name,"%ix%i",&parsed.width,&parsed.height)==2){
5397 return parsed;
5398 }
5399 ms_warning("Video resolution %s is not supported in linphone.",name);
5400 return null_vsize;
5401 }
5402
5403 static bool_t video_definition_supported(const LinphoneVideoDefinition *vdef) {
5404 const bctbx_list_t *item;
5405 const bctbx_list_t *supported_definitions = linphone_factory_get_supported_video_definitions(linphone_factory_get());
5406 for (item = supported_definitions; item != NULL; item = bctbx_list_next(item)) {
5407 LinphoneVideoDefinition *supported_vdef = (LinphoneVideoDefinition *)bctbx_list_get_data(item);
5408 if (linphone_video_definition_equals(vdef, supported_vdef)) return TRUE;
5409 }
5410 ms_warning("Video definition %ix%i is not supported", linphone_video_definition_get_width(vdef), linphone_video_definition_get_height(vdef));
5411 return FALSE;
5412 }
5413
5414 void linphone_core_set_preferred_video_definition(LinphoneCore *lc, LinphoneVideoDefinition *vdef) {
5415 if (video_definition_supported(vdef)) {
5416 LinphoneVideoDefinition *oldvdef = lc->video_conf.vdef;
5417 lc->video_conf.vdef = linphone_video_definition_ref(vdef);
5418
5419 if ((lc->previewstream != NULL) && (lc->video_conf.preview_vdef == NULL)
5420 && (oldvdef != NULL) && !linphone_video_definition_equals(oldvdef, vdef)) {
5421 relaunch_video_preview(lc);
5422 }
5423
5424 if (oldvdef != NULL) linphone_video_definition_unref(oldvdef);
5425 if (linphone_core_ready(lc)) {
5426 lp_config_set_string(lc->config, "video", "size", linphone_video_definition_get_name(vdef));
5427 }
5428 }
5429 }
5430
5431 void linphone_core_set_preferred_video_size(LinphoneCore *lc, MSVideoSize vsize) {
5432 linphone_core_set_preferred_video_definition(lc,
5433 linphone_factory_find_supported_video_definition(linphone_factory_get(), vsize.width, vsize.height));
5434 }
5435
5436 void linphone_core_set_preview_video_definition(LinphoneCore *lc, LinphoneVideoDefinition *vdef) {
5437 if (!vdef || linphone_video_definition_is_undefined(vdef)) {
5438 /* Reset the forced preview video definition mode */
5439 if (lc->video_conf.preview_vdef != NULL) linphone_video_definition_unref(lc->video_conf.preview_vdef);
5440 lc->video_conf.preview_vdef = NULL;
5441 if (linphone_core_ready(lc)) {
5442 lp_config_set_string(lc->config, "video", "preview_size", NULL);
5443 }
5444 return;
5445 }
5446
5447 if (!linphone_video_definition_equals(lc->video_conf.preview_vdef, vdef)) {
5448 LinphoneVideoDefinition *oldvdef = lc->video_conf.preview_vdef;
5449 lc->video_conf.preview_vdef = linphone_video_definition_ref(vdef);
5450 if (oldvdef != NULL) linphone_video_definition_unref(oldvdef);
5451 if (lc->previewstream != NULL) {
5452 relaunch_video_preview(lc);
5453 }
5454 }
5455 if (linphone_core_ready(lc)) {
5456 lp_config_set_string(lc->config, "video", "preview_size", linphone_video_definition_get_name(vdef));
5457 }
5458 }
5459
5460 void linphone_core_set_preview_video_size(LinphoneCore *lc, MSVideoSize vsize) {
5461 linphone_core_set_preview_video_definition(lc,
5462 linphone_factory_find_supported_video_definition(linphone_factory_get(), vsize.width, vsize.height));
5463 }
5464
5465 const LinphoneVideoDefinition * linphone_core_get_preview_video_definition(const LinphoneCore *lc) {
5466 return lc->video_conf.preview_vdef;
5467 }
5468
5469 MSVideoSize linphone_core_get_preview_video_size(const LinphoneCore *lc) {
5470 MSVideoSize vsize = { 0 };
5471 vsize.width = linphone_video_definition_get_width(lc->video_conf.preview_vdef);
5472 vsize.height = linphone_video_definition_get_height(lc->video_conf.preview_vdef);
5473 return vsize;
5474 }
5475
5476 MSVideoSize linphone_core_get_current_preview_video_size(const LinphoneCore *lc){
5477 MSVideoSize ret={0};
5478 #ifndef VIDEO_ENABLED
5479 ms_error("linphone_core_get_current_preview_video_size() fail. Support for video is disabled");
5480 #else
5481 if (lc->previewstream){
5482 ret=video_preview_get_current_size(lc->previewstream);
5483 }
5484 #endif
5485 return ret;
5486 }
5487
5488 LinphoneVideoDefinition * linphone_core_get_current_preview_video_definition(const LinphoneCore *lc) {
5489 #ifdef VIDEO_ENABLED
5490 MSVideoSize vsize;
5491 if (lc->previewstream) {
5492 vsize = video_preview_get_current_size(lc->previewstream);
5493 }
5494 return linphone_factory_find_supported_video_definition(linphone_factory_get(), vsize.width, vsize.height);
5495 #else
5496 ms_error("Video support is disabled");
5497 return NULL;
5498 #endif
5499 }
5500
5501 void linphone_core_set_preview_video_size_by_name(LinphoneCore *lc, const char *name){
5502 MSVideoSize vsize=video_size_get_by_name(name);
5503 linphone_core_set_preview_video_size(lc,vsize);
5504 }
5505
5506 void linphone_core_set_preview_video_definition_by_name(LinphoneCore *lc, const char *name) {
5507 LinphoneVideoDefinition *vdef = linphone_factory_find_supported_video_definition_by_name(linphone_factory_get(), name);
5508 if (vdef == NULL) {
5509 ms_error("Video definition '%s' is not supported", name);
5510 } else {
5511 linphone_core_set_preview_video_definition(lc, vdef);
5512 }
5513 }
5514
5515 void linphone_core_set_preferred_video_size_by_name(LinphoneCore *lc, const char *name){
5516 MSVideoSize vsize=video_size_get_by_name(name);
5517 MSVideoSize default_vsize={MS_VIDEO_SIZE_CIF_W,MS_VIDEO_SIZE_CIF_H};
5518 if (vsize.width!=0) linphone_core_set_preferred_video_size(lc,vsize);
5519 else linphone_core_set_preferred_video_size(lc,default_vsize);
5520 }
5521
5522 void linphone_core_set_preferred_video_definition_by_name(LinphoneCore *lc, const char *name) {
5523 LinphoneVideoDefinition *vdef = linphone_factory_find_supported_video_definition_by_name(linphone_factory_get(), name);
5524 if (vdef == NULL) {
5525 ms_error("Video definition '%s' is not supported", name);
5526 } else {
5527 linphone_core_set_preferred_video_definition(lc, vdef);
5528 }
5529 }
5530
5531 const LinphoneVideoDefinition * linphone_core_get_preferred_video_definition(const LinphoneCore *lc) {
5532 return lc->video_conf.vdef;
5533 }
5534
5535 MSVideoSize linphone_core_get_preferred_video_size(const LinphoneCore *lc) {
5536 MSVideoSize vsize = { 0 };
5537 vsize.width = linphone_video_definition_get_width(lc->video_conf.vdef);
5538 vsize.height = linphone_video_definition_get_height(lc->video_conf.vdef);
5539 return vsize;
5540 }
5541
5542 char * linphone_core_get_preferred_video_size_name(const LinphoneCore *lc) {
5543 return ms_strdup(linphone_video_definition_get_name(lc->video_conf.vdef));
5544 }
5545
5546 void linphone_core_set_preferred_framerate(LinphoneCore *lc, float fps){
5547 lc->video_conf.fps=fps;
5548 if (linphone_core_ready(lc))
5549 lp_config_set_float(lc->config,"video","framerate",fps);
5550 }
5551
5552 float linphone_core_get_preferred_framerate(LinphoneCore *lc){
5553 return lc->video_conf.fps;
5554 }
5555
5556 void linphone_core_preview_ogl_render(const LinphoneCore *lc) {
5557 #ifdef VIDEO_ENABLED
5558
5559 LinphoneCall *call = linphone_core_get_current_call(lc);
5560 VideoStream *stream = call ? call->videostream : lc->previewstream;
5561
5562 if (stream && stream->output2 && ms_filter_get_id(stream->output2) == MS_OGL_ID) {
5563 int mirroring = TRUE;
5564 ms_filter_call_method(stream->output2, MS_VIDEO_DISPLAY_ENABLE_MIRRORING, &mirroring);
5565 ms_filter_call_method(stream->output2, MS_OGL_RENDER, NULL);
5566 }
5567
5568 #endif
5569 }
5570
5571 void linphone_core_set_use_files(LinphoneCore *lc, bool_t yesno){
5572 lc->use_files=yesno;
5573 }
5574
5575 bool_t linphone_core_get_use_files(LinphoneCore *lc) {
5576 return lc->use_files;
5577 }
5578
5579 const char * linphone_core_get_play_file(const LinphoneCore *lc) {
5580 return lc->play_file;
5581 }
5582
5583 void linphone_core_set_play_file(LinphoneCore *lc, const char *file){
5584 LinphoneCall *call=linphone_core_get_current_call(lc);
5585 if (lc->play_file!=NULL){
5586 ms_free(lc->play_file);
5587 lc->play_file=NULL;
5588 }
5589 if (file!=NULL) {
5590 lc->play_file=ms_strdup(file);
5591 if (call && call->audiostream && call->audiostream->ms.state==MSStreamStarted)
5592 audio_stream_play(call->audiostream,file);
5593 }
5594 }
5595
5596 const char * linphone_core_get_record_file(const LinphoneCore *lc) {
5597 return lc->rec_file;
5598 }
5599
5600 void linphone_core_set_record_file(LinphoneCore *lc, const char *file){
5601 LinphoneCall *call=linphone_core_get_current_call(lc);
5602 if (lc->rec_file!=NULL){
5603 ms_free(lc->rec_file);
5604 lc->rec_file=NULL;
5605 }
5606 if (file!=NULL) {
5607 lc->rec_file=ms_strdup(file);
5608 if (call && call->audiostream)
5609 audio_stream_record(call->audiostream,file);
5610 }
5611 }
5612
5613 typedef enum{
5614 LinphoneToneGenerator,
5615 LinphoneLocalPlayer
5616 }LinphoneAudioResourceType;
5617
5618 static MSFilter *get_audio_resource(LinphoneCore *lc, LinphoneAudioResourceType rtype){
5619 LinphoneCall *call=linphone_core_get_current_call(lc);
5620 AudioStream *stream=NULL;
5621 RingStream *ringstream;
5622 if (call){
5623 stream=call->audiostream;
5624 }else if (linphone_core_is_in_conference(lc)){
5625 stream=linphone_conference_get_audio_stream(lc->conf_ctx);
5626 }
5627 if (stream){
5628 if (rtype==LinphoneToneGenerator) return stream->dtmfgen;
5629 if (rtype==LinphoneLocalPlayer) return stream->local_player;
5630 return NULL;
5631 }
5632 if (lc->ringstream==NULL){
5633 float amp=lp_config_get_float(lc->config,"sound","dtmf_player_amp",0.1f);
5634 MSSndCard *ringcard=lc->sound_conf.lsd_card ?lc->sound_conf.lsd_card : lc->sound_conf.ring_sndcard;
5635 if (ringcard == NULL)
5636 return NULL;
5637
5638 ringstream=lc->ringstream=ring_start(lc->factory, NULL,0,ringcard);
5639 ms_filter_call_method(lc->ringstream->gendtmf,MS_DTMF_GEN_SET_DEFAULT_AMPLITUDE,&);
5640 lc->dmfs_playing_start_time = ms_get_cur_time_ms()/1000;
5641 }else{
5642 ringstream=lc->ringstream;
5643 if (lc->dmfs_playing_start_time!=0)
5644 lc->dmfs_playing_start_time = ms_get_cur_time_ms()/1000;
5645 }
5646 if (rtype==LinphoneToneGenerator) return ringstream->gendtmf;
5647 if (rtype==LinphoneLocalPlayer) return ringstream->source;
5648 return NULL;
5649 }
5650
5651 static MSFilter *get_dtmf_gen(LinphoneCore *lc){
5652 return get_audio_resource(lc,LinphoneToneGenerator);
5653 }
5654
5655 void linphone_core_play_dtmf(LinphoneCore *lc, char dtmf, int duration_ms){
5656 MSFilter *f=get_dtmf_gen(lc);
5657 if (f==NULL){
5658 ms_error("No dtmf generator at this time !");
5659 return;
5660 }
5661
5662 if (duration_ms > 0)
5663 ms_filter_call_method(f, MS_DTMF_GEN_PLAY, &dtmf);
5664 else ms_filter_call_method(f, MS_DTMF_GEN_START, &dtmf);
5665 }
5666
5667 LinphoneStatus linphone_core_play_local(LinphoneCore *lc, const char *audiofile){
5668 MSFilter *f=get_audio_resource(lc,LinphoneLocalPlayer);
5669 int loopms=-1;
5670 if (!f) return -1;
5671 ms_filter_call_method(f,MS_PLAYER_SET_LOOP,&loopms);
5672 if (ms_filter_call_method(f,MS_PLAYER_OPEN,(void*)audiofile)!=0){
5673 return -1;
5674 }
5675 ms_filter_call_method_noarg(f,MS_PLAYER_START);
5676 return 0;
5677 }
5678
5679 void linphone_core_play_named_tone(LinphoneCore *lc, LinphoneToneID toneid){
5680 if (linphone_core_tone_indications_enabled(lc)){
5681 const char *audiofile=linphone_core_get_tone_file(lc,toneid);
5682 if (!audiofile){
5683 MSFilter *f=get_dtmf_gen(lc);
5684 MSDtmfGenCustomTone def;
5685 if (f==NULL){
5686 ms_error("No dtmf generator at this time !");
5687 return;
5688 }
5689 memset(&def,0,sizeof(def));
5690 def.amplitude=1;
5691 /*these are french tones, excepted the failed one, which is USA congestion tone (does not exist in France)*/
5692 switch(toneid){
5693 case LinphoneToneCallOnHold:
5694 case LinphoneToneCallWaiting:
5695 def.duration=300;
5696 def.frequencies[0]=440;
5697 def.interval=2000;
5698 break;
5699 case LinphoneToneBusy:
5700 def.duration=500;
5701 def.frequencies[0]=440;
5702 def.interval=500;
5703 def.repeat_count=3;
5704 break;
5705 case LinphoneToneCallLost:
5706 def.duration=250;
5707 def.frequencies[0]=480;
5708 def.frequencies[0]=620;
5709 def.interval=250;
5710 def.repeat_count=3;
5711
5712 break;
5713 default:
5714 ms_warning("Unhandled tone id.");
5715 }
5716 if (def.duration>0)
5717 ms_filter_call_method(f, MS_DTMF_GEN_PLAY_CUSTOM,&def);
5718 }else{
5719 linphone_core_play_local(lc,audiofile);
5720 }
5721 }
5722 }
5723
5724 void linphone_core_play_call_error_tone(LinphoneCore *lc, LinphoneReason reason){
5725 if (linphone_core_tone_indications_enabled(lc)){
5726 LinphoneToneDescription *tone=linphone_core_get_call_error_tone(lc,reason);
5727 if (tone){
5728 if (tone->audiofile){
5729 linphone_core_play_local(lc,tone->audiofile);
5730 }else if (tone->toneid != LinphoneToneUndefined){
5731 linphone_core_play_named_tone(lc,tone->toneid);
5732 }
5733 }
5734 }
5735 }
5736
5737 void linphone_core_stop_dtmf(LinphoneCore *lc){
5738 MSFilter *f=get_dtmf_gen(lc);
5739 if (f!=NULL)
5740 ms_filter_call_method_noarg (f, MS_DTMF_GEN_STOP);
5741 }
5742
5743 void *linphone_core_get_user_data(const LinphoneCore *lc){
5744 return lc->data;
5745 }
5746
5747 void linphone_core_set_user_data(LinphoneCore *lc, void *userdata){
5748 lc->data=userdata;
5749 }
5750
5751 int linphone_core_get_mtu(const LinphoneCore *lc){
5752 return lc->net_conf.mtu;
5753 }
5754
5755 void linphone_core_set_mtu(LinphoneCore *lc, int mtu){
5756 lc->net_conf.mtu=mtu;
5757 if (mtu>0){
5758 if (mtu<500){
5759 ms_error("MTU too small !");
5760 mtu=500;
5761 }
5762 ms_factory_set_mtu(lc->factory, mtu);
5763 ms_message("MTU is supposed to be %i, rtp payload max size will be %i",mtu, ms_factory_get_payload_max_size(lc->factory));
5764 }else ms_factory_set_mtu(lc->factory, 0);//use mediastreamer2 default value
5765 }
5766
5767 void linphone_core_set_waiting_callback(LinphoneCore *lc, LinphoneCoreWaitingCallback cb, void *user_context){
5768 lc->wait_cb=cb;
5769 lc->wait_ctx=user_context;
5770 }
5771
5772 void linphone_core_start_waiting(LinphoneCore *lc, const char *purpose){
5773 if (lc->wait_cb){
5774 lc->wait_ctx=lc->wait_cb(lc,lc->wait_ctx,LinphoneWaitingStart,purpose,0);
5775 }
5776 }
5777
5778 void linphone_core_update_progress(LinphoneCore *lc, const char *purpose, float progress){
5779 if (lc->wait_cb){
5780 lc->wait_ctx=lc->wait_cb(lc,lc->wait_ctx,LinphoneWaitingProgress,purpose,progress);
5781 }else{
5782 ms_usleep(50000);
5783 }
5784 }
5785
5786 void linphone_core_stop_waiting(LinphoneCore *lc){
5787 if (lc->wait_cb){
5788 lc->wait_ctx=lc->wait_cb(lc,lc->wait_ctx,LinphoneWaitingFinished,NULL,0);
5789 }
5790 }
5791
5792 void linphone_core_set_rtp_transport_factories(LinphoneCore* lc, LinphoneRtpTransportFactories *factories){
5793 lc->rtptf=factories;
5794 }
5795
5796 int linphone_core_get_current_call_stats(LinphoneCore *lc, rtp_stats_t *local, rtp_stats_t *remote){
5797 LinphoneCall *call=linphone_core_get_current_call (lc);
5798 if (call!=NULL){
5799 if (call->audiostream!=NULL){
5800 memset(remote,0,sizeof(*remote));
5801 audio_stream_get_local_rtp_stats (call->audiostream,local);
5802 return 0;
5803 }
5804 }
5805 return -1;
5806 }
5807
5808 void net_config_uninit(LinphoneCore *lc)
5809 {
5810 net_config_t *config=&lc->net_conf;
5811
5812 if (config->nat_address!=NULL){
5813 lp_config_set_string(lc->config,"net","nat_address",config->nat_address);
5814 ms_free(lc->net_conf.nat_address);
5815 }
5816 if (lc->net_conf.nat_address_ip !=NULL){
5817 ms_free(lc->net_conf.nat_address_ip);
5818 }
5819 lp_config_set_int(lc->config,"net","mtu",config->mtu);
5820 if (lc->nat_policy != NULL) {
5821 linphone_nat_policy_unref(lc->nat_policy);
5822 lc->nat_policy = NULL;
5823 }
5824 }
5825
5826 void sip_config_uninit(LinphoneCore *lc)
5827 {
5828 bctbx_list_t *elem;
5829 int i;
5830 sip_config_t *config=&lc->sip_conf;
5831 bool_t still_registered=TRUE;
5832
5833 lp_config_set_int(lc->config,"sip","guess_hostname",config->guess_hostname);
5834 lp_config_set_string(lc->config,"sip","contact",config->contact);
5835 lp_config_set_int(lc->config,"sip","inc_timeout",config->inc_timeout);
5836 lp_config_set_int(lc->config,"sip","in_call_timeout",config->in_call_timeout);
5837 lp_config_set_int(lc->config,"sip","delayed_timeout",config->delayed_timeout);
5838 lp_config_set_int(lc->config,"sip","register_only_when_network_is_up",config->register_only_when_network_is_up);
5839 lp_config_set_int(lc->config,"sip","register_only_when_upnp_is_ok",config->register_only_when_upnp_is_ok);
5840
5841 if (lc->sip_network_reachable) {
5842 for(elem=config->proxies;elem!=NULL;elem=bctbx_list_next(elem)){
5843 LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)(elem->data);
5844 _linphone_proxy_config_unpublish(cfg); /* to unpublish without changing the stored flag enable_publish */
5845 _linphone_proxy_config_unregister(cfg); /* to unregister without changing the stored flag enable_register */
5846 }
5847
5848 ms_message("Unregistration started.");
5849
5850 for (i=0;i<20&&still_registered;i++){
5851 still_registered=FALSE;
5852 sal_iterate(lc->sal);
5853 for(elem=config->proxies;elem!=NULL;elem=bctbx_list_next(elem)){
5854 LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)(elem->data);
5855 LinphoneRegistrationState state = linphone_proxy_config_get_state(cfg);
5856 still_registered|=(state==LinphoneRegistrationOk||state==LinphoneRegistrationProgress);
5857 }
5858 ms_usleep(100000);
5859 }
5860 if (i>=20) ms_warning("Cannot complete unregistration, giving up");
5861 }
5862 elem = config->proxies;
5863 config->proxies=NULL; /*to make sure proxies cannot be refferenced during deletion*/
5864 bctbx_list_free_with_data(elem,(void (*)(void*)) _linphone_proxy_config_release);
5865
5866 config->deleted_proxies=bctbx_list_free_with_data(config->deleted_proxies,(void (*)(void*)) _linphone_proxy_config_release);
5867
5868 /*no longuer need to write proxy config if not changedlinphone_proxy_config_write_to_config_file(lc->config,NULL,i);*/ /*mark the end */
5869
5870 lc->auth_info=bctbx_list_free_with_data(lc->auth_info,(void (*)(void*))linphone_auth_info_unref);
5871
5872 if (lc->vcard_context) {
5873 linphone_vcard_context_destroy(lc->vcard_context);
5874 }
5875
5876 sal_reset_transports(lc->sal);
5877 sal_unlisten_ports(lc->sal); /*to make sure no new messages are received*/
5878 if (lc->http_provider) {
5879 belle_sip_object_unref(lc->http_provider);
5880 lc->http_provider=NULL;
5881 }
5882 if (lc->http_crypto_config){
5883 belle_sip_object_unref(lc->http_crypto_config);
5884 lc->http_crypto_config=NULL;
5885 }
5886
5887 /*now that we are unregisted, there is no more channel using tunnel socket we no longer need the tunnel.*/
5888 #ifdef TUNNEL_ENABLED
5889 if (lc->tunnel) {
5890 linphone_tunnel_unref(lc->tunnel);
5891 lc->tunnel=NULL;
5892 ms_message("Tunnel destroyed.");
5893 }
5894 #endif
5895
5896 sal_iterate(lc->sal); /*make sure event are purged*/
5897 sal_uninit(lc->sal);
5898 lc->sal=NULL;
5899
5900 if (lc->sip_conf.guessed_contact)
5901 ms_free(lc->sip_conf.guessed_contact);
5902 if (config->contact)
5903 ms_free(config->contact);
5904 if (lc->default_rls_addr)
5905 linphone_address_unref(lc->default_rls_addr);
5906
5907 linphone_im_notif_policy_unref(lc->im_notif_policy);
5908 }
5909
5910 void rtp_config_uninit(LinphoneCore *lc)
5911 {
5912 rtp_config_t *config=&lc->rtp_conf;
5913 if (config->audio_rtp_min_port == config->audio_rtp_max_port) {
5914 lp_config_set_int(lc->config, "rtp", "audio_rtp_port", config->audio_rtp_min_port);
5915 } else {
5916 lp_config_set_range(lc->config, "rtp", "audio_rtp_port", config->audio_rtp_min_port, config->audio_rtp_max_port);
5917 }
5918 if (config->video_rtp_min_port == config->video_rtp_max_port) {
5919 lp_config_set_int(lc->config, "rtp", "video_rtp_port", config->video_rtp_min_port);
5920 } else {
5921 lp_config_set_range(lc->config, "rtp", "video_rtp_port", config->video_rtp_min_port, config->video_rtp_max_port);
5922 }
5923 if (config->text_rtp_min_port == config->text_rtp_max_port) {
5924 lp_config_set_int(lc->config, "rtp", "text_rtp_port", config->text_rtp_min_port);
5925 } else {
5926 lp_config_set_range(lc->config, "rtp", "text_rtp_port", config->text_rtp_min_port, config->text_rtp_max_port);
5927 }
5928 lp_config_set_int(lc->config,"rtp","audio_jitt_comp",config->audio_jitt_comp);
5929 lp_config_set_int(lc->config,"rtp","video_jitt_comp",config->video_jitt_comp);
5930 lp_config_set_int(lc->config,"rtp","nortp_timeout",config->nortp_timeout);
5931 lp_config_set_int(lc->config,"rtp","audio_adaptive_jitt_comp_enabled",config->audio_adaptive_jitt_comp_enabled);
5932 lp_config_set_int(lc->config,"rtp","video_adaptive_jitt_comp_enabled",config->video_adaptive_jitt_comp_enabled);
5933 ms_free(lc->rtp_conf.audio_multicast_addr);
5934 ms_free(lc->rtp_conf.video_multicast_addr);
5935 ms_free(config->srtp_suites);
5936 }
5937
5938 static void sound_config_uninit(LinphoneCore *lc)
5939 {
5940 sound_config_t *config=&lc->sound_conf;
5941 ms_free((void *)config->cards);
5942
5943 lp_config_set_string(lc->config,"sound","remote_ring",config->remote_ring);
5944 lp_config_set_float(lc->config,"sound","playback_gain_db",config->soft_play_lev);
5945 lp_config_set_float(lc->config,"sound","mic_gain_db",config->soft_mic_lev);
5946
5947 if (config->local_ring) ms_free(config->local_ring);
5948 if (config->remote_ring) ms_free(config->remote_ring);
5949 lc->tones=bctbx_list_free_with_data(lc->tones, (void (*)(void*))linphone_tone_description_destroy);
5950 }
5951
5952 static void video_config_uninit(LinphoneCore *lc)
5953 {
5954 const LinphoneVideoDefinition *vdef = linphone_core_get_preferred_video_definition(lc);
5955 lp_config_set_string(lc->config,"video","size",vdef ? linphone_video_definition_get_name(vdef) : NULL);
5956 lp_config_set_int(lc->config,"video","display",lc->video_conf.display);
5957 lp_config_set_int(lc->config,"video","capture",lc->video_conf.capture);
5958 if (lc->video_conf.cams)
5959 ms_free((void *)lc->video_conf.cams);
5960 if (lc->video_conf.vdef) linphone_video_definition_unref(lc->video_conf.vdef);
5961 if (lc->video_conf.preview_vdef) linphone_video_definition_unref(lc->video_conf.preview_vdef);
5962 }
5963
5964 void _linphone_core_codec_config_write(LinphoneCore *lc){
5965 if (linphone_core_ready(lc)){
5966 PayloadType *pt;
5967 codecs_config_t *config=&lc->codecs_conf;
5968 bctbx_list_t *node;
5969 char key[50];
5970 int index;
5971 index=0;
5972 for(node=config->audio_codecs;node!=NULL;node=bctbx_list_next(node)){
5973 pt=(PayloadType*)(node->data);
5974 sprintf(key,"audio_codec_%i",index);
5975 lp_config_set_string(lc->config,key,"mime",pt->mime_type);
5976 lp_config_set_int(lc->config,key,"rate",pt->clock_rate);
5977 lp_config_set_int(lc->config,key,"channels",pt->channels);
5978 lp_config_set_int(lc->config,key,"enabled",payload_type_enabled(pt));
5979 index++;
5980 }
5981 sprintf(key,"audio_codec_%i",index);
5982 lp_config_clean_section (lc->config,key);
5983
5984 index=0;
5985 for(node=config->video_codecs;node!=NULL;node=bctbx_list_next(node)){
5986 pt=(PayloadType*)(node->data);
5987 sprintf(key,"video_codec_%i",index);
5988 lp_config_set_string(lc->config,key,"mime",pt->mime_type);
5989 lp_config_set_int(lc->config,key,"rate",pt->clock_rate);
5990 lp_config_set_int(lc->config,key,"enabled",payload_type_enabled(pt));
5991 lp_config_set_string(lc->config,key,"recv_fmtp",pt->recv_fmtp);
5992 index++;
5993 }
5994 sprintf(key,"video_codec_%i",index);
5995 lp_config_clean_section (lc->config,key);
5996 }
5997 }
5998
5999 static void codecs_config_uninit(LinphoneCore *lc)
6000 {
6001 _linphone_core_codec_config_write(lc);
6002 bctbx_list_free_with_data(lc->codecs_conf.audio_codecs, (void (*)(void*))payload_type_destroy);
6003 bctbx_list_free_with_data(lc->codecs_conf.video_codecs, (void (*)(void*))payload_type_destroy);
6004 bctbx_list_free_with_data(lc->codecs_conf.text_codecs, (void (*)(void*))payload_type_destroy);
6005 }
6006
6007 void friends_config_uninit(LinphoneCore* lc)
6008 {
6009 ms_message("Destroying friends.");
6010 lc->friends_lists = bctbx_list_free_with_data(lc->friends_lists, (void (*)(void*))_linphone_friend_list_release);
6011 if (lc->subscribers) {
6012 lc->subscribers = bctbx_list_free_with_data(lc->subscribers, (void (*)(void *))_linphone_friend_release);
6013 }
6014 if (lc->presence_model) {
6015 linphone_presence_model_unref(lc->presence_model);
6016 lc->presence_model = NULL;
6017 }
6018 ms_message("Destroying friends done.");
6019 }
6020
6021 LpConfig * linphone_core_get_config(LinphoneCore *lc){
6022 return lc->config;
6023 }
6024
6025 LpConfig * linphone_core_create_lp_config(LinphoneCore *lc, const char *filename) {
6026 return lp_config_new(filename);
6027 }
6028
6029 LinphoneConfig * linphone_core_create_config(LinphoneCore *lc, const char *filename) {
6030 return lp_config_new(filename);
6031 }
6032
6033 static void linphone_core_uninit(LinphoneCore *lc)
6034 {
6035 bctbx_list_t *elem = NULL;
6036 int i=0;
6037 bool_t wait_until_unsubscribe = FALSE;
6038 linphone_task_list_free(&lc->hooks);
6039 lc->video_conf.show_local = FALSE;
6040
6041 while(lc->calls) {
6042 LinphoneCall *the_call = lc->calls->data;
6043 linphone_call_terminate(the_call);
6044 linphone_core_iterate(lc);
6045 ms_usleep(10000);
6046 }
6047
6048 for (elem = lc->friends_lists; elem != NULL; elem = bctbx_list_next(elem)) {
6049 LinphoneFriendList *list = (LinphoneFriendList *)elem->data;
6050 linphone_friend_list_enable_subscriptions(list,FALSE);
6051 if (list->event)
6052 wait_until_unsubscribe = TRUE;
6053 }
6054 /*give a chance to unsubscribe, might be optimized*/
6055 for (i=0; wait_until_unsubscribe && i<50; i++) {
6056 linphone_core_iterate(lc);
6057 ms_usleep(10000);
6058 }
6059
6060 lc->chatrooms = bctbx_list_free_with_data(lc->chatrooms, (MSIterateFunc)linphone_chat_room_release);
6061
6062 linphone_core_set_state(lc,LinphoneGlobalShutdown,"Shutting down");
6063 #ifdef VIDEO_ENABLED
6064 if (lc->previewstream!=NULL){
6065 video_preview_stop(lc->previewstream);
6066 lc->previewstream=NULL;
6067 }
6068 #endif
6069
6070 lc->msevq=NULL;
6071
6072 /* save all config */
6073 friends_config_uninit(lc);
6074 sip_config_uninit(lc);
6075 net_config_uninit(lc);
6076 rtp_config_uninit(lc);
6077 linphone_core_stop_ringing(lc);
6078 sound_config_uninit(lc);
6079 video_config_uninit(lc);
6080 codecs_config_uninit(lc);
6081
6082 sip_setup_unregister_all();
6083
6084 #ifdef BUILD_UPNP
6085 if(lc->upnp != NULL) {
6086 linphone_upnp_context_destroy(lc->upnp);
6087 lc->upnp = NULL;
6088 }
6089 #endif //BUILD_UPNP
6090
6091 if (lp_config_needs_commit(lc->config)) lp_config_sync(lc->config);
6092 lp_config_destroy(lc->config);
6093 lc->config = NULL; /* Mark the config as NULL to block further calls */
6094
6095 bctbx_list_for_each(lc->call_logs,(void (*)(void*))linphone_call_log_unref);
6096 lc->call_logs=bctbx_list_free(lc->call_logs);
6097
6098 if(lc->zrtp_secrets_cache != NULL) {
6099 ms_free(lc->zrtp_secrets_cache);
6100 }
6101
6102 if(lc->user_certificates_path != NULL) {
6103 ms_free(lc->user_certificates_path);
6104 }
6105 if(lc->play_file!=NULL){
6106 ms_free(lc->play_file);
6107 }
6108 if(lc->rec_file!=NULL){
6109 ms_free(lc->rec_file);
6110 }
6111 if (lc->chat_db_file){
6112 ms_free(lc->chat_db_file);
6113 }
6114 if (lc->logs_db_file) {
6115 ms_free(lc->logs_db_file);
6116 }
6117 if (lc->friends_db_file) {
6118 ms_free(lc->friends_db_file);
6119 }
6120 if (lc->ringtoneplayer) {
6121 linphone_ringtoneplayer_destroy(lc->ringtoneplayer);
6122 }
6123 if (lc->im_encryption_engine) {
6124 linphone_im_encryption_engine_unref(lc->im_encryption_engine);
6125 }
6126 if (lc->default_ac_service) {
6127 linphone_account_creator_service_unref(lc->default_ac_service);
6128 }
6129
6130 linphone_core_free_payload_types(lc);
6131 if (lc->supported_formats) ms_free((void *)lc->supported_formats);
6132 linphone_core_message_storage_close(lc);
6133 linphone_core_call_log_storage_close(lc);
6134 linphone_core_friends_storage_close(lc);
6135 linphone_core_zrtp_cache_close(lc);
6136
6137 linphone_core_set_state(lc,LinphoneGlobalOff,"Off");
6138 linphone_core_deactivate_log_serialization_if_needed();
6139 bctbx_list_free_with_data(lc->vtable_refs,(void (*)(void *))v_table_reference_destroy);
6140 ms_bandwidth_controller_destroy(lc->bw_controller);
6141 ms_factory_destroy(lc->factory);
6142 }
6143
6144 static void stop_refreshing_proxy_config(bool_t is_sip_reachable, LinphoneProxyConfig* cfg) {
6145 if (linphone_proxy_config_register_enabled(cfg) ) {
6146 if (!is_sip_reachable) {
6147 linphone_proxy_config_stop_refreshing(cfg);
6148 linphone_proxy_config_set_state(cfg, LinphoneRegistrationNone,"Registration impossible (network down)");
6149 }else{
6150 cfg->commit=TRUE;
6151 }
6152 }
6153 }
6154
6155 static void set_sip_network_reachable(LinphoneCore* lc,bool_t is_sip_reachable, time_t curtime){
6156 // second get the list of available proxies
6157 const bctbx_list_t *elem = NULL;
6158
6159 if (lc->sip_network_reachable==is_sip_reachable) return; // no change, ignore.
6160 lc->network_reachable_to_be_notified=TRUE;
6161 ms_message("SIP network reachability state is now [%s]",is_sip_reachable?"UP":"DOWN");
6162 for(elem=linphone_core_get_proxy_config_list(lc);elem!=NULL;elem=elem->next){
6163 LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;
6164 stop_refreshing_proxy_config(is_sip_reachable, cfg);
6165 }
6166 for(elem=lc->sip_conf.deleted_proxies;elem!=NULL;elem=elem->next){
6167 LinphoneProxyConfig *deleted_cfg=(LinphoneProxyConfig*)elem->data;
6168 stop_refreshing_proxy_config(is_sip_reachable, deleted_cfg);
6169 }
6170
6171 lc->netup_time=curtime;
6172 lc->sip_network_reachable=is_sip_reachable;
6173
6174 if (!lc->sip_network_reachable){
6175 linphone_core_invalidate_friend_subscriptions(lc);
6176 sal_reset_transports(lc->sal);
6177 /*mark all calls as broken, so that they can be either dropped immediately or restaured when network will be back*/
6178 bctbx_list_for_each(lc->calls, (MSIterateFunc) linphone_call_set_broken);
6179 }
6180 #ifdef BUILD_UPNP
6181 if(lc->upnp == NULL) {
6182 if(is_sip_reachable && linphone_core_get_firewall_policy(lc) == LinphonePolicyUseUpnp) {
6183 lc->upnp = linphone_upnp_context_new(lc);
6184 }
6185 } else {
6186 if(!is_sip_reachable && linphone_core_get_firewall_policy(lc) == LinphonePolicyUseUpnp) {
6187 linphone_upnp_context_destroy(lc->upnp);
6188 lc->upnp = NULL;
6189 }
6190 }
6191 #endif
6192 }
6193
6194 void linphone_core_repair_calls(LinphoneCore *lc){
6195 if (lc->calls && lp_config_get_int(lc->config, "sip", "repair_broken_calls", 1) && lc->media_network_reachable){
6196 /*if we are registered and there were broken calls due to a past network disconnection, attempt to repair them*/
6197 bctbx_list_for_each(lc->calls, (MSIterateFunc) linphone_call_repair_if_broken);
6198 }
6199 }
6200
6201 static void set_media_network_reachable(LinphoneCore* lc, bool_t is_media_reachable){
6202 if (lc->media_network_reachable==is_media_reachable) return; // no change, ignore.
6203 ms_message("Media network reachability state is now [%s]",is_media_reachable?"UP":"DOWN");
6204 lc->media_network_reachable=is_media_reachable;
6205
6206 if (!lc->media_network_reachable){
6207 /*mark all calls as broken, so that they can be either dropped immediately or restaured when network will be back*/
6208 bctbx_list_for_each(lc->calls, (MSIterateFunc) linphone_call_set_broken);
6209 }else{
6210 if (lp_config_get_int(lc->config, "net", "recreate_sockets_when_network_is_up", 0)){
6211 bctbx_list_for_each(lc->calls, (MSIterateFunc)linphone_call_refresh_sockets);
6212 }
6213 linphone_core_repair_calls(lc);
6214 }
6215 }
6216
6217 static void set_network_reachable(LinphoneCore *lc, bool_t is_network_reachable, time_t curtime){
6218 set_sip_network_reachable(lc, is_network_reachable, curtime);
6219 set_media_network_reachable(lc, is_network_reachable);
6220 }
6221
6222 void linphone_core_refresh_registers(LinphoneCore* lc) {
6223 const bctbx_list_t *elem;
6224 if (!lc->sip_network_reachable) {
6225 ms_warning("Refresh register operation not available (network unreachable)");
6226 return;
6227 }
6228 elem=linphone_core_get_proxy_config_list(lc);
6229 for(;elem!=NULL;elem=elem->next){
6230 LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;
6231 if (linphone_proxy_config_register_enabled(cfg) && linphone_proxy_config_get_expires(cfg)>0) {
6232 linphone_proxy_config_refresh_register(cfg);
6233 }
6234 }
6235 }
6236
6237 static void disable_internal_network_reachability_detection(LinphoneCore *lc){
6238 if (lc->auto_net_state_mon) {
6239 ms_message("Disabling automatic network state monitoring");
6240 lc->auto_net_state_mon=FALSE;
6241 }
6242 }
6243
6244 void linphone_core_set_network_reachable(LinphoneCore* lc,bool_t isReachable) {
6245 disable_internal_network_reachability_detection(lc);
6246 set_network_reachable(lc, isReachable, ms_time(NULL));
6247 }
6248
6249 void linphone_core_set_media_network_reachable(LinphoneCore *lc, bool_t is_reachable){
6250 disable_internal_network_reachability_detection(lc);
6251 set_media_network_reachable(lc, is_reachable);
6252 }
6253
6254 void linphone_core_set_sip_network_reachable(LinphoneCore *lc, bool_t is_reachable){
6255 disable_internal_network_reachability_detection(lc);
6256 set_sip_network_reachable(lc, is_reachable, ms_time(NULL));
6257 }
6258
6259 bool_t linphone_core_is_network_reachable(LinphoneCore* lc) {
6260 return lc->sip_network_reachable;
6261 }
6262
6263 ortp_socket_t linphone_core_get_sip_socket(LinphoneCore *lc){
6264 return sal_get_socket(lc->sal);
6265 }
6266
6267 void linphone_core_destroy(LinphoneCore *lc){
6268 linphone_core_unref(lc);
6269 }
6270
6271 int linphone_core_get_calls_nb(const LinphoneCore *lc){
6272 return (int)bctbx_list_size(lc->calls);
6273 }
6274
6275 /**
6276 * Check if we do not have exceed the number of simultaneous call
6277 * @ingroup call_control
6278 **/
6279 bool_t linphone_core_can_we_add_call(LinphoneCore *lc)
6280 {
6281 if(linphone_core_get_calls_nb(lc) < lc->max_calls)
6282 return TRUE;
6283 ms_message("Maximum amount of simultaneous calls reached !");
6284 return FALSE;
6285 }
6286
6287 static void notify_soundcard_usage(LinphoneCore *lc, bool_t used){
6288 MSSndCard *card=lc->sound_conf.capt_sndcard;
6289 if (card && ms_snd_card_get_capabilities(card) & MS_SND_CARD_CAP_IS_SLOW){
6290 ms_snd_card_set_usage_hint(card,used);
6291 }
6292 }
6293
6294 void linphone_core_soundcard_hint_check( LinphoneCore* lc){
6295 bctbx_list_t* the_calls = lc->calls;
6296 LinphoneCall* call = NULL;
6297 bool_t dont_need_sound = TRUE;
6298 bool_t use_rtp_io = lp_config_get_int(lc->config, "sound", "rtp_io", FALSE);
6299 bool_t use_rtp_io_enable_local_output = lp_config_get_int(lc->config, "sound", "rtp_io_enable_local_output", FALSE);
6300
6301 /* check if the remaining calls are paused */
6302 while( the_calls ){
6303 call = the_calls->data;
6304 if( call->state != LinphoneCallPausing && call->state != LinphoneCallPaused && call->state != LinphoneCallEnd && call->state != LinphoneCallError){
6305 dont_need_sound = FALSE;
6306 break;
6307 }
6308 the_calls = the_calls->next;
6309 }
6310 /* if no more calls or all calls are paused, we can free the soundcard */
6311 if ( (lc->calls==NULL || dont_need_sound) && !lc->use_files && (!use_rtp_io || (use_rtp_io && use_rtp_io_enable_local_output))){
6312 ms_message("Notifying soundcard that we don't need it anymore for calls.");
6313 notify_soundcard_usage(lc,FALSE);
6314 }
6315 }
6316
6317 int linphone_core_add_call( LinphoneCore *lc, LinphoneCall *call) {
6318 if (linphone_core_can_we_add_call(lc)){
6319 if (lc->calls==NULL) notify_soundcard_usage(lc,TRUE);
6320 lc->calls = bctbx_list_append(lc->calls,call);
6321 linphone_core_notify_call_created(lc, call);
6322 return 0;
6323 }
6324 return -1;
6325 }
6326
6327 int linphone_core_del_call( LinphoneCore *lc, LinphoneCall *call) {
6328 bctbx_list_t *it;
6329 bctbx_list_t *the_calls = lc->calls;
6330
6331 it=bctbx_list_find(the_calls,call);
6332 if (it)
6333 {
6334 the_calls = bctbx_list_erase_link(the_calls,it);
6335 }
6336 else
6337 {
6338 ms_warning("could not find the call into the list\n");
6339 return -1;
6340 }
6341 lc->calls = the_calls;
6342
6343 return 0;
6344 }
6345
6346 void linphone_core_set_remote_ringback_tone(LinphoneCore *lc, const char *file){
6347 if (lc->sound_conf.ringback_tone){
6348 ms_free(lc->sound_conf.ringback_tone);
6349 lc->sound_conf.ringback_tone=NULL;
6350 }
6351 if (file)
6352 lc->sound_conf.ringback_tone=ms_strdup(file);
6353 }
6354
6355 const char *linphone_core_get_remote_ringback_tone(const LinphoneCore *lc){
6356 return lc->sound_conf.ringback_tone;
6357 }
6358
6359 void linphone_core_set_ring_during_incoming_early_media(LinphoneCore *lc, bool_t enable) {
6360 lp_config_set_int(lc->config, "sound", "ring_during_incoming_early_media", (int)enable);
6361 }
6362
6363 bool_t linphone_core_get_ring_during_incoming_early_media(const LinphoneCore *lc) {
6364 return (bool_t)lp_config_get_int(lc->config, "sound", "ring_during_incoming_early_media", 0);
6365 }
6366
6367 static OrtpPayloadType* _linphone_core_find_payload_type(LinphoneCore* lc, const char* type, int rate, int channels) {
6368 OrtpPayloadType* result = find_payload_type_from_list(type, rate, channels, lc->codecs_conf.audio_codecs);
6369 if (result) {
6370 return result;
6371 } else {
6372 result = find_payload_type_from_list(type, rate, 0, lc->codecs_conf.video_codecs);
6373 if (result) {
6374 return result;
6375 } else {
6376 result = find_payload_type_from_list(type, rate, 0, lc->codecs_conf.text_codecs);
6377 if (result) {
6378 return result;
6379 }
6380 }
6381 }
6382 /*not found*/
6383 return NULL;
6384 }
6385
6386 OrtpPayloadType* linphone_core_find_payload_type(LinphoneCore* lc, const char* type, int rate, int channels) {
6387 return _linphone_core_find_payload_type(lc, type, rate, channels);
6388 }
6389
6390 LinphonePayloadType *linphone_core_get_payload_type(LinphoneCore *lc, const char *type, int rate, int channels) {
6391 OrtpPayloadType *pt = _linphone_core_find_payload_type(lc, type, rate, channels);
6392 return pt ? linphone_payload_type_new(lc, pt) : NULL;
6393 }
6394
6395 const char* linphone_configuring_state_to_string(LinphoneConfiguringState cs){
6396 switch(cs){
6397 case LinphoneConfiguringSuccessful:
6398 return "LinphoneConfiguringSuccessful";
6399 break;
6400 case LinphoneConfiguringFailed:
6401 return "LinphoneConfiguringFailed";
6402 break;
6403 case LinphoneConfiguringSkipped:
6404 return "LinphoneConfiguringSkipped";
6405 break;
6406 }
6407 return NULL;
6408 }
6409
6410 const char *linphone_global_state_to_string(LinphoneGlobalState gs){
6411 switch(gs){
6412 case LinphoneGlobalOff:
6413 return "LinphoneGlobalOff";
6414 break;
6415 case LinphoneGlobalOn:
6416 return "LinphoneGlobalOn";
6417 break;
6418 case LinphoneGlobalStartup:
6419 return "LinphoneGlobalStartup";
6420 break;
6421 case LinphoneGlobalShutdown:
6422 return "LinphoneGlobalShutdown";
6423 case LinphoneGlobalConfiguring:
6424 return "LinphoneGlobalConfiguring";
6425 break;
6426 }
6427 return NULL;
6428 }
6429
6430 LinphoneGlobalState linphone_core_get_global_state(const LinphoneCore *lc){
6431 return lc->state;
6432 }
6433
6434
6435 static LinphoneCallParams *_create_call_params(LinphoneCore *lc){
6436 LinphoneCallParams *p=linphone_call_params_new();
6437 linphone_core_init_default_params(lc, p);
6438 return p;
6439 }
6440
6441 LinphoneCallParams *linphone_core_create_call_params(LinphoneCore *lc, LinphoneCall *call){
6442 if (!call) return _create_call_params(lc);
6443 if (call->params){
6444 return linphone_call_params_copy(call->params);
6445 }
6446 ms_error("linphone_core_create_call_params(): call [%p] is not in a state where call params can be created or used.", call);
6447 return NULL;
6448 }
6449
6450 const char *linphone_error_to_string(LinphoneReason err){
6451 return linphone_reason_to_string(err);
6452 }
6453
6454 void linphone_core_enable_keep_alive(LinphoneCore* lc,bool_t enable) {
6455 #ifdef BUILD_UPNP
6456 if (linphone_core_get_firewall_policy(lc)==LinphonePolicyUseUpnp) {
6457 enable = FALSE;
6458 }
6459 #endif //BUILD_UPNP
6460 if (enable > 0) {
6461 sal_use_tcp_tls_keepalive(lc->sal,lc->sip_conf.tcp_tls_keepalive);
6462 sal_set_keepalive_period(lc->sal,lc->sip_conf.keepalive_period);
6463 } else {
6464 sal_set_keepalive_period(lc->sal,0);
6465 }
6466 }
6467
6468 bool_t linphone_core_keep_alive_enabled(LinphoneCore* lc) {
6469 return sal_get_keepalive_period(lc->sal) > 0;
6470 }
6471
6472 void linphone_core_start_dtmf_stream(LinphoneCore* lc) {
6473 get_dtmf_gen(lc); /*make sure ring stream is started*/
6474 lc->ringstream_autorelease=FALSE; /*disable autorelease mode*/
6475 }
6476
6477 void linphone_core_stop_ringing(LinphoneCore* lc) {
6478 LinphoneCall *call=linphone_core_get_current_call(lc);
6479 if (linphone_ringtoneplayer_is_started(lc->ringtoneplayer)) {
6480 linphone_ringtoneplayer_stop(lc->ringtoneplayer);
6481 }
6482 if (lc->ringstream) {
6483 ring_stop(lc->ringstream);
6484 lc->ringstream=NULL;
6485 lc->dmfs_playing_start_time=0;
6486 lc->ringstream_autorelease=TRUE;
6487 }
6488 if (call && call->ringing_beep){
6489 linphone_core_stop_dtmf(lc);
6490 call->ringing_beep=FALSE;
6491 }
6492 }
6493
6494 void linphone_core_stop_dtmf_stream(LinphoneCore* lc) {
6495 if (lc->dmfs_playing_start_time!=0) {
6496 linphone_core_stop_ringing(lc);
6497 }
6498 }
6499
6500 int linphone_core_get_max_calls(LinphoneCore *lc) {
6501 return lc->max_calls;
6502 }
6503
6504 void linphone_core_set_max_calls(LinphoneCore *lc, int max) {
6505 lc->max_calls=max;
6506 }
6507
6508 void linphone_core_add_iterate_hook(LinphoneCore *lc, LinphoneCoreIterateHook hook, void *hook_data){
6509 linphone_task_list_add(&lc->hooks, hook, hook_data);
6510 }
6511
6512 static void linphone_core_run_hooks(LinphoneCore *lc){
6513 linphone_task_list_run(&lc->hooks);
6514 }
6515
6516 void linphone_core_remove_iterate_hook(LinphoneCore *lc, LinphoneCoreIterateHook hook, void *hook_data){
6517 linphone_task_list_remove(&lc->hooks, hook, hook_data);
6518
6519 }
6520
6521 void linphone_core_set_zrtp_secrets_file(LinphoneCore *lc, const char* file){
6522 if (lc->zrtp_secrets_cache != NULL) {
6523 ms_free(lc->zrtp_secrets_cache);
6524 }
6525
6526 lc->zrtp_secrets_cache=file ? ms_strdup(file) : NULL;
6527
6528 /* shall we perform cache migration ? */
6529 if (!lp_config_get_int(lc->config,"sip","zrtp_cache_migration_done",FALSE)) {
6530 char *tmpFile = bctbx_malloc(strlen(file)+6);
6531 /* check we have a valid xml cache file given in path */
6532 FILE *CACHEFD = NULL;
6533 /* load the xml cache */
6534 if (file != NULL) {
6535 int ret=0;
6536 CACHEFD = fopen(file, "rb+");
6537 xmlDocPtr cacheXml = NULL;
6538 if (CACHEFD) {
6539 size_t cacheSize;
6540 char *cacheString = ms_load_file_content(CACHEFD, &cacheSize);
6541 if (!cacheString) {
6542 ms_warning("Unable to load content of ZRTP ZID cache");
6543 bctbx_free(tmpFile);
6544 return;
6545 }
6546 cacheString[cacheSize] = '\0';
6547 cacheSize += 1;
6548 fclose(CACHEFD);
6549 cacheXml = xmlParseDoc((xmlChar*)cacheString);
6550 ms_free(cacheString);
6551 }
6552
6553 /* create a temporary file for the sqlite base and initialise it */
6554 sprintf(tmpFile,"%s.tmp", file);
6555 linphone_core_zrtp_cache_db_init(lc, tmpFile);
6556
6557 /* migrate */
6558 char *bkpFile = bctbx_malloc(strlen(file)+6);
6559 sprintf(bkpFile,"%s.bkp", file);
6560
6561 if ((ret = ms_zrtp_cache_migration((void *)cacheXml, linphone_core_get_zrtp_cache_db(lc), linphone_core_get_identity(lc))) == 0) {
6562 ms_message("LIME/ZRTP cache migration successfull, obsolete xml file kept as backup in %s", bkpFile);
6563 } else {
6564 ms_error("LIME/ZRTP cache migration failed(returned -%x), start with a fresh cache, old one kept as backup in %s", -ret, bkpFile);
6565 }
6566
6567 /* rename the newly created sqlite3 file in to the given file name */
6568 rename(file, bkpFile);
6569 if (rename(tmpFile, file)==0) { /* set the flag if we were able to set the sqlite file in the correct place (even if migration failed) */
6570 lp_config_set_int(lc->config, "sip", "zrtp_cache_migration_done", TRUE);
6571 }
6572
6573 /* clean up */
6574 bctbx_free(bkpFile);
6575 xmlFree(cacheXml);
6576 }
6577 bctbx_free(tmpFile);
6578 } else {
6579 linphone_core_zrtp_cache_db_init(lc, file);
6580 }
6581 }
6582
6583 const char *linphone_core_get_zrtp_secrets_file(LinphoneCore *lc){
6584 return lc->zrtp_secrets_cache;
6585 }
6586
6587 void *linphone_core_get_zrtp_cache_db(LinphoneCore *lc){
6588 #ifdef SQLITE_STORAGE_ENABLED
6589 return (void *)lc->zrtp_cache_db;
6590 #else /* SQLITE_STORAGE_ENABLED */
6591 return NULL;
6592 #endif /* SQLITE_STORAGE_ENABLED */
6593 }
6594
6595 static void linphone_core_zrtp_cache_close(LinphoneCore *lc) {
6596 #ifdef SQLITE_STORAGE_ENABLED
6597 if (lc->zrtp_cache_db) {
6598 sqlite3_close(lc->zrtp_cache_db);
6599 lc->zrtp_cache_db = NULL;
6600 }
6601 #endif /* SQLITE_STORAGE_ENABLED */
6602 }
6603
6604
6605 void linphone_core_zrtp_cache_db_init(LinphoneCore *lc, const char *fileName) {
6606 #ifdef SQLITE_STORAGE_ENABLED
6607 int ret;
6608 const char *errmsg;
6609 const char *backupExtension = "_backup";
6610 char *backupName = malloc(snprintf(NULL, 0, "%s%s", fileName, backupExtension) + 1);
6611 sprintf(backupName, "%s%s", fileName, backupExtension);
6612 sqlite3 *db;
6613
6614 linphone_core_zrtp_cache_close(lc);
6615
6616 ret = _linphone_sqlite3_open(fileName, &db);
6617 if (ret != SQLITE_OK) {
6618 errmsg = sqlite3_errmsg(db);
6619 ms_error("Error in the opening zrtp_cache_db_file(%s): %s.\n", fileName, errmsg);
6620 sqlite3_close(db);
6621 unlink(backupName);
6622 rename(fileName, backupName);
6623 lc->zrtp_cache_db=NULL;
6624 return;
6625 }
6626
6627 ret = ms_zrtp_initCache((void *)db); /* this may perform an update, check return value */
6628
6629 if (ret == MSZRTP_CACHE_SETUP || ret == MSZRTP_CACHE_UPDATE) {
6630 /* After updating schema, database need to be closed/reopenned */
6631 sqlite3_close(db);
6632 _linphone_sqlite3_open(fileName, &db);
6633 } else if(ret != 0) { /* something went wrong */
6634 ms_error("Zrtp cache failed to initialise(returned -%x), run cacheless", -ret);
6635 sqlite3_close(db);
6636 unlink(backupName);
6637 rename(fileName, backupName);
6638 lc->zrtp_cache_db = NULL;
6639 return;
6640 }
6641
6642 /* everything ok, set the db pointer into core */
6643 lc->zrtp_cache_db = db;
6644 #endif /* SQLITE_STORAGE_ENABLED */
6645 }
6646
6647 void linphone_core_set_user_certificates_path(LinphoneCore *lc, const char* path){
6648 char* new_value;
6649 new_value = path?ms_strdup(path):NULL;
6650 if (lc->user_certificates_path) ms_free(lc->user_certificates_path);
6651 lp_config_set_string(lc->config,"misc","user_certificates_path",lc->user_certificates_path=new_value);
6652 return ;
6653 }
6654
6655 const char *linphone_core_get_user_certificates_path(LinphoneCore *lc){
6656 return lc->user_certificates_path;
6657 }
6658
6659 bool_t linphone_core_sound_resources_locked(LinphoneCore *lc){
6660 bctbx_list_t *elem;
6661 for(elem=lc->calls;elem!=NULL;elem=elem->next) {
6662 LinphoneCall *c=(LinphoneCall*)elem->data;
6663
6664 if (linphone_call_media_in_progress(c)) {
6665 return TRUE;
6666 }
6667
6668 switch (c->state) {
6669 case LinphoneCallOutgoingInit:
6670 case LinphoneCallOutgoingProgress:
6671 case LinphoneCallOutgoingRinging:
6672 case LinphoneCallOutgoingEarlyMedia:
6673 case LinphoneCallConnected:
6674 case LinphoneCallRefered:
6675 case LinphoneCallIncomingEarlyMedia:
6676 case LinphoneCallUpdating:
6677 ms_message("Call %p is locking sound resources.",c);
6678 return TRUE;
6679 default:
6680 break;
6681 }
6682 }
6683 return FALSE;
6684 }
6685
6686 void linphone_core_set_srtp_enabled(LinphoneCore *lc, bool_t enabled) {
6687 lp_config_set_int(lc->config,"sip","srtp",(int)enabled);
6688 }
6689
6690 const char *linphone_media_encryption_to_string(LinphoneMediaEncryption menc){
6691 switch(menc){
6692 case LinphoneMediaEncryptionSRTP:
6693 return "LinphoneMediaEncryptionSRTP";
6694 case LinphoneMediaEncryptionDTLS:
6695 return "LinphoneMediaEncryptionDTLS";
6696 case LinphoneMediaEncryptionZRTP:
6697 return "LinphoneMediaEncryptionZRTP";
6698 case LinphoneMediaEncryptionNone:
6699 return "LinphoneMediaEncryptionNone";
6700 }
6701 ms_error("Invalid LinphoneMediaEncryption value %i",(int)menc);
6702 return "INVALID";
6703 }
6704
6705
6706 bool_t linphone_core_media_encryption_supported(const LinphoneCore *lc, LinphoneMediaEncryption menc){
6707 switch(menc){
6708 case LinphoneMediaEncryptionSRTP:
6709 return ms_srtp_supported();
6710 case LinphoneMediaEncryptionDTLS:
6711 return ms_dtls_srtp_available();
6712 case LinphoneMediaEncryptionZRTP:
6713 return ms_zrtp_available() && !lc->zrtp_not_available_simulation;
6714 case LinphoneMediaEncryptionNone:
6715 return TRUE;
6716 }
6717 return FALSE;
6718 }
6719
6720 LinphoneStatus linphone_core_set_media_encryption(LinphoneCore *lc, LinphoneMediaEncryption menc) {
6721 const char *type="none";
6722 int ret=-1;
6723
6724 switch(menc){
6725 case LinphoneMediaEncryptionSRTP:
6726 if (!ms_srtp_supported()){
6727 ms_warning("SRTP not supported by library.");
6728 type="none";
6729 ret=-1;
6730 }else{
6731 type="srtp";
6732 ret = 0;
6733 }
6734 break;
6735 case LinphoneMediaEncryptionZRTP:
6736 if (!linphone_core_media_encryption_supported(lc, LinphoneMediaEncryptionZRTP)){
6737 ms_warning("ZRTP not supported by library.");
6738 type="none";
6739 ret=-1;
6740 }else {
6741 type="zrtp";
6742 ret = 0;
6743 }
6744 break;
6745 case LinphoneMediaEncryptionDTLS:
6746 if (!ms_dtls_srtp_available()){
6747 ms_warning("DTLS not supported by library.");
6748 type="none";
6749 ret=-1;
6750 }else {
6751 type="dtls";
6752 ret = 0;
6753 }
6754 break;
6755 case LinphoneMediaEncryptionNone:
6756 type = "none";
6757 ret = 0;
6758 break;
6759 }
6760 lp_config_set_string(lc->config,"sip","media_encryption",type);
6761 return ret;
6762 }
6763
6764 LinphoneMediaEncryption linphone_core_get_media_encryption(LinphoneCore *lc) {
6765 const char* menc = lp_config_get_string(lc->config, "sip", "media_encryption", NULL);
6766
6767 if (menc == NULL)
6768 return LinphoneMediaEncryptionNone;
6769 else if (strcmp(menc, "srtp")==0)
6770 return LinphoneMediaEncryptionSRTP;
6771 else if (strcmp(menc, "dtls")==0)
6772 return LinphoneMediaEncryptionDTLS;
6773 else if (strcmp(menc, "zrtp")==0)
6774 return LinphoneMediaEncryptionZRTP;
6775 else
6776 return LinphoneMediaEncryptionNone;
6777 }
6778
6779 bool_t linphone_core_is_media_encryption_mandatory(LinphoneCore *lc) {
6780 return (bool_t)lp_config_get_int(lc->config, "sip", "media_encryption_mandatory", 0);
6781 }
6782
6783 void linphone_core_set_media_encryption_mandatory(LinphoneCore *lc, bool_t m) {
6784 lp_config_set_int(lc->config, "sip", "media_encryption_mandatory", (int)m);
6785 }
6786
6787 void linphone_core_init_default_params(LinphoneCore*lc, LinphoneCallParams *params) {
6788 params->has_audio = TRUE;
6789 params->has_video=linphone_core_video_enabled(lc) && lc->video_policy.automatically_initiate;
6790 if (!linphone_core_video_enabled(lc) && lc->video_policy.automatically_initiate){
6791 ms_error("LinphoneCore has video disabled for both capture and display, but video policy is to start the call with video. "
6792 "This is a possible mis-use of the API. In this case, video is disabled in default LinphoneCallParams");
6793 }
6794 params->media_encryption=linphone_core_get_media_encryption(lc);
6795 params->in_conference=FALSE;
6796 params->realtimetext_enabled = linphone_core_realtime_text_enabled(lc);
6797 params->privacy=LinphonePrivacyDefault;
6798 params->avpf_enabled=linphone_core_get_avpf_mode(lc);
6799 params->implicit_rtcp_fb = lp_config_get_int(lc->config,"rtp","rtcp_fb_implicit_rtcp_fb",TRUE);
6800 params->avpf_rr_interval = linphone_core_get_avpf_rr_interval(lc);
6801 params->audio_dir=LinphoneMediaDirectionSendRecv;
6802 params->video_dir=LinphoneMediaDirectionSendRecv;
6803 params->real_early_media=lp_config_get_int(lc->config,"misc","real_early_media",FALSE);
6804 params->audio_multicast_enabled=linphone_core_audio_multicast_enabled(lc);
6805 params->video_multicast_enabled=linphone_core_video_multicast_enabled(lc);
6806 params->update_call_when_ice_completed = lp_config_get_int(lc->config, "sip", "update_call_when_ice_completed", TRUE);
6807 params->encryption_mandatory = linphone_core_is_media_encryption_mandatory(lc);
6808 }
6809
6810 void linphone_core_set_device_identifier(LinphoneCore *lc,const char* device_id) {
6811 if (lc->device_id) ms_free(lc->device_id);
6812 lc->device_id=ms_strdup(device_id);
6813 }
6814
6815 const char* linphone_core_get_device_identifier(const LinphoneCore *lc) {
6816 return lc->device_id;
6817 }
6818
6819 void linphone_core_set_sip_dscp(LinphoneCore *lc, int dscp){
6820 sal_set_dscp(lc->sal,dscp);
6821 if (linphone_core_ready(lc)){
6822 lp_config_set_int_hex(lc->config,"sip","dscp",dscp);
6823 _linphone_core_apply_transports(lc);
6824 }
6825 }
6826
6827 int linphone_core_get_sip_dscp(const LinphoneCore *lc){
6828 return lp_config_get_int(lc->config,"sip","dscp",0x1a);
6829 }
6830
6831 void linphone_core_set_audio_dscp(LinphoneCore *lc, int dscp){
6832 if (linphone_core_ready(lc))
6833 lp_config_set_int_hex(lc->config,"rtp","audio_dscp",dscp);
6834 }
6835
6836 int linphone_core_get_audio_dscp(const LinphoneCore *lc){
6837 return lp_config_get_int(lc->config,"rtp","audio_dscp",0x2e);
6838 }
6839
6840 void linphone_core_set_video_dscp(LinphoneCore *lc, int dscp){
6841 if (linphone_core_ready(lc))
6842 lp_config_set_int_hex(lc->config,"rtp","video_dscp",dscp);
6843
6844 }
6845
6846 int linphone_core_get_video_dscp(const LinphoneCore *lc){
6847 return lp_config_get_int(lc->config,"rtp","video_dscp",0);
6848 }
6849
6850 void linphone_core_set_chat_database_path(LinphoneCore *lc, const char *path){
6851 if (lc->chat_db_file){
6852 ms_free(lc->chat_db_file);
6853 lc->chat_db_file=NULL;
6854 }
6855 if (path) {
6856 lc->chat_db_file=ms_strdup(path);
6857 linphone_core_message_storage_init(lc);
6858 }
6859 }
6860
6861 const char* linphone_core_get_chat_database_path(const LinphoneCore *lc) {
6862 return lc->chat_db_file;
6863 }
6864
6865 void linphone_core_enable_sdp_200_ack(LinphoneCore *lc, bool_t enable) {
6866 lp_config_set_int(lc->config,"sip","sdp_200_ack",lc->sip_conf.sdp_200_ack=enable);
6867 }
6868
6869 bool_t linphone_core_sdp_200_ack_enabled(const LinphoneCore *lc) {
6870 return lc->sip_conf.sdp_200_ack!=0;
6871 }
6872
6873 void linphone_core_set_file_transfer_server(LinphoneCore *core, const char * server_url) {
6874 lp_config_set_string(core->config, "misc", "file_transfer_server_url", server_url);
6875 }
6876
6877 const char * linphone_core_get_file_transfer_server(LinphoneCore *core) {
6878 return lp_config_get_string(core->config, "misc", "file_transfer_server_url", NULL);
6879 }
6880
6881 void linphone_core_add_supported_tag(LinphoneCore *lc, const char *tag){
6882 sal_add_supported_tag(lc->sal,tag);
6883 lp_config_set_string(lc->config,"sip","supported",sal_get_supported_tags(lc->sal));
6884 }
6885
6886 void linphone_core_remove_supported_tag(LinphoneCore *lc, const char *tag){
6887 sal_remove_supported_tag(lc->sal,tag);
6888 lp_config_set_string(lc->config,"sip","supported",sal_get_supported_tags(lc->sal));
6889 }
6890
6891 void linphone_core_set_avpf_mode(LinphoneCore *lc, LinphoneAVPFMode mode){
6892 if (mode==LinphoneAVPFDefault) mode=LinphoneAVPFDisabled;
6893 lc->rtp_conf.avpf_mode=mode;
6894 if (linphone_core_ready(lc)) lp_config_set_int(lc->config,"rtp","avpf",mode);
6895 }
6896
6897 LinphoneAVPFMode linphone_core_get_avpf_mode(const LinphoneCore *lc){
6898 return lc->rtp_conf.avpf_mode;
6899 }
6900
6901 int linphone_core_get_avpf_rr_interval(const LinphoneCore *lc){
6902 return lp_config_get_int(lc->config,"rtp","avpf_rr_interval",5);
6903 }
6904
6905 void linphone_core_set_avpf_rr_interval(LinphoneCore *lc, int interval){
6906 lp_config_set_int(lc->config,"rtp","avpf_rr_interval",interval);
6907 }
6908
6909 LinphoneStatus linphone_core_set_audio_multicast_addr(LinphoneCore *lc, const char* ip) {
6910 char* new_value;
6911 if (ip && !ms_is_multicast(ip)) {
6912 ms_error("Cannot set multicast audio addr to core [%p] because [%s] is not multicast",lc,ip);
6913 return -1;
6914 }
6915 new_value = ip?ms_strdup(ip):NULL;
6916 if (lc->rtp_conf.audio_multicast_addr) ms_free(lc->rtp_conf.audio_multicast_addr);
6917 lp_config_set_string(lc->config,"rtp","audio_multicast_addr",lc->rtp_conf.audio_multicast_addr=new_value);
6918 return 0;
6919 }
6920
6921 LinphoneStatus linphone_core_set_video_multicast_addr(LinphoneCore *lc, const char* ip) {
6922 char* new_value;
6923 if (ip && !ms_is_multicast(ip)) {
6924 ms_error("Cannot set multicast video addr to core [%p] because [%s] is not multicast",lc,ip);
6925 return -1;
6926 }
6927 new_value = ip?ms_strdup(ip):NULL;
6928 if (lc->rtp_conf.video_multicast_addr) ms_free(lc->rtp_conf.video_multicast_addr);
6929 lp_config_set_string(lc->config,"rtp","video_multicast_addr",lc->rtp_conf.video_multicast_addr=new_value);
6930 return 0;
6931 }
6932
6933 const char* linphone_core_get_audio_multicast_addr(const LinphoneCore *lc) {
6934 return lc->rtp_conf.audio_multicast_addr;
6935 }
6936
6937 const char* linphone_core_get_video_multicast_addr(const LinphoneCore *lc){
6938 return lc->rtp_conf.video_multicast_addr;
6939 }
6940
6941 LinphoneStatus linphone_core_set_audio_multicast_ttl(LinphoneCore *lc, int ttl) {
6942 if (ttl>255) {
6943 ms_error("Cannot set multicast audio ttl to core [%p] to [%i] value must be <256",lc,ttl);
6944 return -1;
6945 }
6946
6947 lp_config_set_int(lc->config,"rtp","audio_multicast_ttl",lc->rtp_conf.audio_multicast_ttl=ttl);
6948 return 0;
6949 }
6950
6951 LinphoneStatus linphone_core_set_video_multicast_ttl(LinphoneCore *lc, int ttl) {
6952 if (ttl>255) {
6953 ms_error("Cannot set multicast video ttl to core [%p] to [%i] value must be <256",lc,ttl);
6954 return -1;
6955 }
6956
6957 lp_config_set_int(lc->config,"rtp","video_multicast_ttl",lc->rtp_conf.video_multicast_ttl=ttl);
6958 return 0;
6959 }
6960
6961 int linphone_core_get_audio_multicast_ttl(const LinphoneCore *lc) {
6962 return lc->rtp_conf.audio_multicast_ttl;
6963 }
6964
6965
6966 int linphone_core_get_video_multicast_ttl(const LinphoneCore *lc){
6967 return lc->rtp_conf.video_multicast_ttl;
6968 }
6969
6970 void linphone_core_enable_audio_multicast(LinphoneCore *lc, bool_t yesno) {
6971 lp_config_set_int(lc->config,"rtp","audio_multicast_enabled",lc->rtp_conf.audio_multicast_enabled=yesno);
6972 }
6973
6974 bool_t linphone_core_audio_multicast_enabled(const LinphoneCore *lc) {
6975 return lc->rtp_conf.audio_multicast_enabled;
6976 }
6977
6978 void linphone_core_enable_video_multicast(LinphoneCore *lc, bool_t yesno) {
6979 lp_config_set_int(lc->config,"rtp","video_multicast_enabled",lc->rtp_conf.video_multicast_enabled=yesno);
6980 }
6981
6982 bool_t linphone_core_video_multicast_enabled(const LinphoneCore *lc) {
6983 return lc->rtp_conf.video_multicast_enabled;
6984 }
6985
6986 void linphone_core_set_video_preset(LinphoneCore *lc, const char *preset) {
6987 lp_config_set_string(lc->config, "video", "preset", preset);
6988 }
6989
6990 const char * linphone_core_get_video_preset(const LinphoneCore *lc) {
6991 return lp_config_get_string(lc->config, "video", "preset", NULL);
6992 }
6993
6994 #ifdef __ANDROID__
6995 static int linphone_core_call_void_method(jobject obj, jmethodID id) {
6996 JNIEnv *env=ms_get_jni_env();
6997 if (env && obj) {
6998 (*env)->CallVoidMethod(env,obj,id);
6999 if ((*env)->ExceptionCheck(env)) {
7000 (*env)->ExceptionClear(env);
7001 return -1;
7002 } else
7003 return 0;
7004 } else
7005 return -1;
7006 }
7007
7008 void linphone_core_wifi_lock_acquire(LinphoneCore *lc) {
7009 if (linphone_core_call_void_method(lc->wifi_lock,lc->wifi_lock_acquire_id))
7010 ms_warning("No wifi lock configured or not usable for core [%p]",lc);
7011 }
7012
7013 void linphone_core_wifi_lock_release(LinphoneCore *lc) {
7014 if (linphone_core_call_void_method(lc->wifi_lock,lc->wifi_lock_release_id))
7015 ms_warning("No wifi lock configured or not usable for core [%p]",lc);
7016 }
7017
7018 void linphone_core_multicast_lock_acquire(LinphoneCore *lc) {
7019 if (linphone_core_call_void_method(lc->multicast_lock,lc->multicast_lock_acquire_id))
7020 ms_warning("No multicast lock configured or not usable for core [%p]",lc);
7021 }
7022
7023 void linphone_core_multicast_lock_release(LinphoneCore *lc) {
7024 if (linphone_core_call_void_method(lc->multicast_lock,lc->multicast_lock_release_id))
7025 ms_warning("No wifi lock configured or not usable for core [%p]",lc);
7026 }
7027 #endif
7028
7029
7030 LINPHONE_PUBLIC const char *linphone_core_log_collection_upload_state_to_string(const LinphoneCoreLogCollectionUploadState lcus) {
7031 switch (lcus) {
7032 case LinphoneCoreLogCollectionUploadStateInProgress : return "LinphoneCoreLogCollectionUploadStateInProgress";
7033 case LinphoneCoreLogCollectionUploadStateDelivered : return "LinphoneCoreLogCollectionUploadStateDelivered";
7034 case LinphoneCoreLogCollectionUploadStateNotDelivered : return "LinphoneCoreLogCollectionUploadStateNotDelivered";
7035 }
7036 return "UNKNOWN";
7037 }
7038
7039 bool_t linphone_core_realtime_text_enabled(LinphoneCore *lc) {
7040 return lc->text_conf.enabled;
7041 }
7042
7043 void linphone_core_set_http_proxy_host(LinphoneCore *lc, const char *host) {
7044 lp_config_set_string(lc->config,"sip","http_proxy_host",host);
7045 if (lc->sal) {
7046 sal_set_http_proxy_host(lc->sal,host);
7047 sal_set_http_proxy_port(lc->sal,linphone_core_get_http_proxy_port(lc)); /*to make sure default value is set*/
7048 }
7049 }
7050
7051 void linphone_core_set_http_proxy_port(LinphoneCore *lc, int port) {
7052 lp_config_set_int(lc->config,"sip","http_proxy_port",port);
7053 if (lc->sal)
7054 sal_set_http_proxy_port(lc->sal,port);
7055 }
7056
7057 const char *linphone_core_get_http_proxy_host(const LinphoneCore *lc) {
7058 return lp_config_get_string(lc->config,"sip","http_proxy_host",NULL);
7059 }
7060
7061 int linphone_core_get_http_proxy_port(const LinphoneCore *lc) {
7062 return lp_config_get_int(lc->config,"sip","http_proxy_port",3128);
7063 }
7064
7065 const char* linphone_transport_to_string(LinphoneTransportType transport) {
7066 return sal_transport_to_string((SalTransport)transport);
7067 }
7068
7069 LinphoneTransportType linphone_transport_parse(const char* transport) {
7070 return (LinphoneTransportType)sal_transport_parse(transport);
7071 }
7072
7073 const char *linphone_stream_type_to_string(const LinphoneStreamType type) {
7074 switch (type) {
7075 case LinphoneStreamTypeAudio: return "LinphoneStreamTypeAudio";
7076 case LinphoneStreamTypeVideo: return "LinphoneStreamTypeVideo";
7077 case LinphoneStreamTypeText: return "LinphoneStreamTypeText";
7078 case LinphoneStreamTypeUnknown: return "LinphoneStreamTypeUnknown";
7079 }
7080 return "INVALID";
7081 }
7082
7083 LinphoneRingtonePlayer *linphone_core_get_ringtoneplayer(LinphoneCore *lc) {
7084 return lc->ringtoneplayer;
7085 }
7086
7087 static int _linphone_core_delayed_conference_destruction_cb(void *user_data, unsigned int event) {
7088 LinphoneConference *conf = (LinphoneConference *)user_data;
7089 linphone_conference_unref(conf);
7090 return 0;
7091 }
7092
7093 static void _linphone_core_conference_state_changed(LinphoneConference *conf, LinphoneConferenceState cstate, void *user_data) {
7094 LinphoneCore *lc = (LinphoneCore *)user_data;
7095 if(cstate == LinphoneConferenceStartingFailed || cstate == LinphoneConferenceStopped) {
7096 linphone_core_queue_task(lc, _linphone_core_delayed_conference_destruction_cb, conf, "Conference destruction task");
7097 lc->conf_ctx = NULL;
7098 }
7099 }
7100
7101 /*This function sets the "unique" conference object for the LinphoneCore - which is necessary as long as
7102 * liblinphone is used in a client app. When liblinphone will be used in a server app, this shall not be done anymore.*/
7103 static void linphone_core_set_conference(LinphoneCore *lc, LinphoneConference *conf){
7104 lc->conf_ctx = linphone_conference_ref(conf);
7105 }
7106
7107 LinphoneConference *linphone_core_create_conference_with_params(LinphoneCore *lc, const LinphoneConferenceParams *params) {
7108 const char *conf_method_name;
7109 LinphoneConference *conf;
7110 if(lc->conf_ctx == NULL) {
7111 LinphoneConferenceParams *params2 = linphone_conference_params_clone(params);
7112 linphone_conference_params_set_state_changed_callback(params2, _linphone_core_conference_state_changed, lc);
7113 conf_method_name = lp_config_get_string(lc->config, "misc", "conference_type", "local");
7114 if(strcasecmp(conf_method_name, "local") == 0) {
7115 conf = linphone_local_conference_new_with_params(lc, params2);
7116 } else if(strcasecmp(conf_method_name, "remote") == 0) {
7117 conf = linphone_remote_conference_new_with_params(lc, params2);
7118 } else {
7119 ms_error("'%s' is not a valid conference method", conf_method_name);
7120 linphone_conference_params_unref(params2);
7121 return NULL;
7122 }
7123 linphone_conference_params_unref(params2);
7124 linphone_core_set_conference(lc, conf);
7125 } else {
7126 ms_error("Could not create a conference: a conference instance already exists");
7127 return NULL;
7128 }
7129 return lc->conf_ctx;
7130 }
7131
7132 LinphoneConferenceParams * linphone_core_create_conference_params(LinphoneCore *lc){
7133 return linphone_conference_params_new(lc);
7134 }
7135
7136 LinphoneStatus linphone_core_add_to_conference(LinphoneCore *lc, LinphoneCall *call) {
7137 LinphoneConference *conference = linphone_core_get_conference(lc);
7138 if(conference == NULL) {
7139 LinphoneConferenceParams *params = linphone_conference_params_new(lc);
7140 conference = linphone_core_create_conference_with_params(lc, params);
7141 linphone_conference_params_unref(params);
7142 linphone_conference_unref(conference); /*actually linphone_core_create_conference_with_params() takes a ref for lc->conf_ctx */
7143 }
7144 if(conference) return linphone_conference_add_participant(lc->conf_ctx, call);
7145 else return -1;
7146 }
7147
7148 LinphoneStatus linphone_core_add_all_to_conference(LinphoneCore *lc) {
7149 bctbx_list_t *calls=lc->calls;
7150 while (calls) {
7151 LinphoneCall *call=(LinphoneCall*)calls->data;
7152 calls=calls->next;
7153 if(linphone_call_get_conference(call) == NULL) { // Prevent the call to the conference server from being added to the conference
7154 linphone_core_add_to_conference(lc, call);
7155 }
7156 }
7157 if(lc->conf_ctx && linphone_conference_check_class(lc->conf_ctx, LinphoneConferenceClassLocal)) {
7158 linphone_core_enter_conference(lc);
7159 }
7160 return 0;
7161 }
7162
7163 LinphoneStatus linphone_core_remove_from_conference(LinphoneCore *lc, LinphoneCall *call) {
7164 if(lc->conf_ctx) return linphone_conference_remove_participant_with_call(lc->conf_ctx, call);
7165 else return -1;
7166 }
7167
7168 int linphone_core_terminate_conference(LinphoneCore *lc) {
7169 if(lc->conf_ctx == NULL) {
7170 ms_error("Could not terminate conference: no conference context");
7171 return -1;
7172 }
7173 linphone_conference_terminate(lc->conf_ctx);
7174 lc->conf_ctx = NULL;
7175 return 0;
7176 }
7177
7178 LinphoneStatus linphone_core_enter_conference(LinphoneCore *lc) {
7179 if(lc->conf_ctx) return linphone_conference_enter(lc->conf_ctx);
7180 else return -1;
7181 }
7182
7183 LinphoneStatus linphone_core_leave_conference(LinphoneCore *lc) {
7184 if(lc->conf_ctx) return linphone_conference_leave(lc->conf_ctx);
7185 else return -1;
7186 }
7187
7188 bool_t linphone_core_is_in_conference(const LinphoneCore *lc) {
7189 if(lc->conf_ctx) return linphone_conference_is_in(lc->conf_ctx);
7190 else return FALSE;
7191 }
7192
7193 int linphone_core_get_conference_size(LinphoneCore *lc) {
7194 if(lc->conf_ctx) return linphone_conference_get_size(lc->conf_ctx);
7195 return 0;
7196 }
7197
7198 float linphone_core_get_conference_local_input_volume(LinphoneCore *lc) {
7199 if(lc->conf_ctx) return linphone_conference_get_input_volume(lc->conf_ctx);
7200 else return -1.0;
7201 }
7202
7203 LinphoneStatus linphone_core_start_conference_recording(LinphoneCore *lc, const char *path) {
7204 if(lc->conf_ctx) return linphone_conference_start_recording(lc->conf_ctx, path);
7205 return -1;
7206 }
7207
7208 LinphoneStatus linphone_core_stop_conference_recording(LinphoneCore *lc) {
7209 if(lc->conf_ctx) return linphone_conference_stop_recording(lc->conf_ctx);
7210 return -1;
7211 }
7212
7213 LinphoneConference *linphone_core_get_conference(LinphoneCore *lc) {
7214 return lc->conf_ctx;
7215 }
7216
7217 void linphone_core_set_tls_cert(LinphoneCore *lc, const char *tls_cert) {
7218 if (lc->tls_cert) {
7219 ms_free(lc->tls_cert);
7220 lc->tls_cert = NULL;
7221 }
7222 if (tls_cert && strlen(tls_cert) > 0) lc->tls_cert = ms_strdup(tls_cert);
7223 }
7224
7225 void linphone_core_set_tls_key(LinphoneCore *lc, const char *tls_key) {
7226 if (lc->tls_key) {
7227 ms_free(lc->tls_key);
7228 lc->tls_key = NULL;
7229 }
7230 if (tls_key && strlen(tls_key) > 0) lc->tls_key = ms_strdup(tls_key);
7231 }
7232
7233 void linphone_core_set_tls_cert_path(LinphoneCore *lc, const char *tls_cert_path) {
7234 lp_config_set_string(lc->config, "sip", "client_cert_chain", tls_cert_path);
7235 }
7236
7237 void linphone_core_set_tls_key_path(LinphoneCore *lc, const char *tls_key_path) {
7238 lp_config_set_string(lc->config, "sip", "client_cert_key", tls_key_path);
7239 }
7240
7241 const char *linphone_core_get_tls_cert(const LinphoneCore *lc) {
7242 return lc->tls_cert;
7243 }
7244
7245 const char *linphone_core_get_tls_key(const LinphoneCore *lc) {
7246 return lc->tls_key;
7247 }
7248
7249 const char *linphone_core_get_tls_cert_path(const LinphoneCore *lc) {
7250 const char *tls_cert_path = lp_config_get_string(lc->config, "sip", "client_cert_chain", NULL);
7251 return tls_cert_path;
7252 }
7253
7254 const char *linphone_core_get_tls_key_path(const LinphoneCore *lc) {
7255 const char *tls_key_path = lp_config_get_string(lc->config, "sip", "client_cert_key", NULL);
7256 return tls_key_path;
7257 }
7258
7259 void linphone_core_set_im_encryption_engine(LinphoneCore *lc, LinphoneImEncryptionEngine *imee) {
7260 if (lc->im_encryption_engine) {
7261 linphone_im_encryption_engine_unref(lc->im_encryption_engine);
7262 lc->im_encryption_engine = NULL;
7263 }
7264 if (imee) {
7265 imee->lc = lc;
7266 lc->im_encryption_engine = linphone_im_encryption_engine_ref(imee);
7267 }
7268 }
7269
7270 LinphoneImEncryptionEngine *linphone_core_get_im_encryption_engine(const LinphoneCore *lc) {
7271 return lc->im_encryption_engine;
7272 }
7273
7274 void linphone_core_initialize_supported_content_types(LinphoneCore *lc) {
7275 sal_add_content_type_support(lc->sal, "text/plain");
7276 sal_add_content_type_support(lc->sal, "message/external-body");
7277 sal_add_content_type_support(lc->sal, "application/vnd.gsma.rcs-ft-http+xml");
7278 sal_add_content_type_support(lc->sal, "application/im-iscomposing+xml");
7279 sal_add_content_type_support(lc->sal, "message/imdn+xml");
7280 }
7281
7282 bool_t linphone_core_is_content_type_supported(const LinphoneCore *lc, const char *content_type) {
7283 return sal_is_content_type_supported(lc->sal, content_type);
7284 }
7285
7286 void linphone_core_add_content_type_support(LinphoneCore *lc, const char *content_type) {
7287 sal_add_content_type_support(lc->sal, content_type);
7288 }
7289
7290 #ifdef ENABLE_UPDATE_CHECK
7291 static void update_check_process_terminated(LinphoneCore *lc, LinphoneVersionUpdateCheckResult result, const char *version, const char *url) {
7292 linphone_core_notify_version_update_check_result_received(lc, result, version, url);
7293 if (lc->update_check_http_listener) {
7294 belle_sip_object_unref(lc->update_check_http_listener);
7295 lc->update_check_http_listener = NULL;
7296 }
7297 bctbx_free(lc->update_check_current_version);
7298 lc->update_check_current_version = NULL;
7299 }
7300
7301 typedef struct _parsed_version_st {
7302 int major;
7303 int minor;
7304 int patch;
7305 } parsed_version_t;
7306
7307 static int compare_parsed_versions(parsed_version_t current_version, parsed_version_t last_version) {
7308 if (last_version.major > current_version.major) return 1;
7309 if (last_version.minor > current_version.minor) return 1;
7310 if (last_version.patch > current_version.patch) return 1;
7311 return -1;
7312 }
7313
7314 static void parse_version(const char *version, parsed_version_t *parsed_version) {
7315 char *copy = bctbx_strdup(version);
7316 char *ptr = copy;
7317 char *next;
7318 memset(parsed_version, 0, sizeof(parsed_version_t));
7319 next = strchr(ptr, '.');
7320 parsed_version->major = atoi(ptr);
7321 ptr = next + 1;
7322 next = strchr(ptr, '.');
7323 parsed_version->minor = atoi(ptr);
7324 if (next != NULL) {
7325 ptr = next + 1;
7326 parsed_version->patch = atoi(ptr);
7327 }
7328 bctbx_free(copy);
7329 }
7330
7331 static bool_t update_is_available(const char *current_version, const char *last_version) {
7332 parsed_version_t current_parsed_version;
7333 parsed_version_t last_parsed_version;
7334 parse_version(current_version, ¤t_parsed_version);
7335 parse_version(last_version, &last_parsed_version);
7336 return (compare_parsed_versions(current_parsed_version, last_parsed_version) > 0) ? TRUE : FALSE;
7337 }
7338
7339 static void update_check_process_response_event(void *ctx, const belle_http_response_event_t *event) {
7340 LinphoneCore *lc = (LinphoneCore *)ctx;
7341
7342 if (belle_http_response_get_status_code(event->response) == 200) {
7343 belle_sip_message_t *message = BELLE_SIP_MESSAGE(event->response);
7344 char *body = bctbx_strdup(belle_sip_message_get_body(message));
7345 char *last_version = body;
7346 char *url = strchr(body, '\t');
7347 char *ptr;
7348 if (url == NULL) {
7349 update_check_process_terminated(lc, LinphoneVersionUpdateCheckError, NULL, NULL);
7350 bctbx_free(body);
7351 return;
7352 }
7353 *url = '\0';
7354 url++;
7355 ptr = strrchr(url, '\r');
7356 if (ptr != NULL) *ptr = '\0';
7357 ptr = strrchr(url, '\n');
7358 if (ptr != NULL) *ptr = '\0';
7359 if (update_is_available(lc->update_check_current_version, last_version)) {
7360 update_check_process_terminated(lc, LinphoneVersionUpdateCheckNewVersionAvailable, last_version, url);
7361 } else {
7362 update_check_process_terminated(lc, LinphoneVersionUpdateCheckUpToDate, NULL, NULL);
7363 }
7364 bctbx_free(body);
7365 } else {
7366 update_check_process_terminated(lc, LinphoneVersionUpdateCheckError, NULL, NULL);
7367 }
7368 }
7369
7370 static void update_check_process_io_error(void *ctx, const belle_sip_io_error_event_t *event) {
7371 LinphoneCore *lc = (LinphoneCore *)ctx;
7372 update_check_process_terminated(lc, LinphoneVersionUpdateCheckError, NULL, NULL);
7373 }
7374
7375 static void update_check_process_timeout(void *ctx, const belle_sip_timeout_event_t *event) {
7376 LinphoneCore *lc = (LinphoneCore *)ctx;
7377 update_check_process_terminated(lc, LinphoneVersionUpdateCheckError, NULL, NULL);
7378 }
7379
7380 static void update_check_process_auth_requested(void *ctx, belle_sip_auth_event_t *event) {
7381 LinphoneCore *lc = (LinphoneCore *)ctx;
7382 update_check_process_terminated(lc, LinphoneVersionUpdateCheckError, NULL, NULL);
7383 }
7384 #endif /* ENABLE_UPDATE_CHECK */
7385
7386 void linphone_core_check_for_update(LinphoneCore *lc, const char *current_version) {
7387 #ifdef ENABLE_UPDATE_CHECK
7388 int err;
7389 bool_t is_desktop = FALSE;
7390 const char *platform = NULL;
7391 const char *version_check_url_root = lp_config_get_string(lc->config, "misc", "version_check_url_root", NULL);
7392
7393 if (version_check_url_root != NULL) {
7394 belle_http_request_listener_callbacks_t belle_request_listener = { 0 };
7395 belle_http_request_t *request;
7396 belle_generic_uri_t *uri;
7397 char *version_check_url;
7398 MSList *item;
7399 MSList *platform_tags = ms_factory_get_platform_tags(linphone_core_get_ms_factory(lc));
7400
7401 for (item = platform_tags; item != NULL; item = ms_list_next(item)) {
7402 const char *tag = (const char *)item->data;
7403 if (strcmp(tag, "win32") == 0) platform = "windows";
7404 else if (strcmp(tag, "apple") == 0) platform = "macosx";
7405 else if (strcmp(tag, "linux") == 0) platform = "linux";
7406 else if (strcmp(tag, "desktop") == 0) is_desktop = TRUE;
7407 }
7408 if ((is_desktop == FALSE) || (platform == NULL)) {
7409 ms_warning("Update checking is not supported on this platform");
7410 return;
7411 }
7412 version_check_url = bctbx_strdup_printf("%s/%s/RELEASE", version_check_url_root, platform);
7413 uri = belle_generic_uri_parse(version_check_url);
7414 ms_message("Checking for new version at: %s", version_check_url);
7415 bctbx_free(version_check_url);
7416
7417 belle_request_listener.process_response = update_check_process_response_event;
7418 belle_request_listener.process_auth_requested = update_check_process_auth_requested;
7419 belle_request_listener.process_io_error = update_check_process_io_error;
7420 belle_request_listener.process_timeout = update_check_process_timeout;
7421
7422 lc->update_check_current_version = bctbx_strdup(current_version);
7423 lc->update_check_http_listener = belle_http_request_listener_create_from_callbacks(&belle_request_listener, lc);
7424 request = belle_http_request_create("GET", uri, belle_sip_header_create("User-Agent", linphone_core_get_user_agent(lc)), NULL);
7425 err = belle_http_provider_send_request(lc->http_provider, request, lc->update_check_http_listener);
7426 }
7427 #endif
7428 }
7429