linphone-ios/Classes/LinphoneCoreSettingsStore.m

808 lines
32 KiB
Objective-C

/* LinphoneCoreSettingsStore.m
*
* Copyright (C) 2012 Belledonne Comunications, Grenoble, France
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#import "LinphoneCoreSettingsStore.h"
#import "DTAlertView.h"
#include "linphone/lpconfig.h"
extern void linphone_iphone_log_handler(int lev, const char *fmt, va_list args);
@implementation LinphoneCoreSettingsStore
- (id)init {
self = [super init];
if (self) {
dict = [[NSMutableDictionary alloc] init];
changedDict = [[NSMutableDictionary alloc] init];
}
return self;
}
- (void)setCString:(const char *)value forKey:(NSString *)key {
id obj = Nil;
if (value)
obj = [[NSString alloc] initWithCString:value encoding:[NSString defaultCStringEncoding]];
[self setObject:obj forKey:key];
}
- (NSString *)stringForKey:(NSString *)key {
return [self objectForKey:key];
}
- (void)setObject:(id)value forKey:(NSString *)key {
[dict setValue:value forKey:key];
[changedDict setValue:[NSNumber numberWithBool:TRUE] forKey:key];
}
- (id)objectForKey:(NSString *)key {
return [dict valueForKey:key];
}
- (BOOL)valueChangedForKey:(NSString *)key {
return [[changedDict valueForKey:key] boolValue];
}
+ (int)validPort:(int)port {
if (port < 0) {
return 0;
}
if (port > 65535) {
return 65535;
}
return port;
}
+ (BOOL)parsePortRange:(NSString *)text minPort:(int *)minPort maxPort:(int *)maxPort {
NSError *error = nil;
*minPort = -1;
*maxPort = -1;
NSRegularExpression *regex =
[NSRegularExpression regularExpressionWithPattern:@"([0-9]+)(([^0-9]+)([0-9]+))?" options:0 error:&error];
if (error != NULL)
return FALSE;
NSArray *matches = [regex matchesInString:text options:0 range:NSMakeRange(0, [text length])];
if ([matches count] == 1) {
NSTextCheckingResult *match = [matches objectAtIndex:0];
bool range = [match rangeAtIndex:2].length > 0;
if (!range) {
NSRange rangeMinPort = [match rangeAtIndex:1];
*minPort = [LinphoneCoreSettingsStore validPort:[[text substringWithRange:rangeMinPort] intValue]];
*maxPort = *minPort;
return TRUE;
} else {
NSRange rangeMinPort = [match rangeAtIndex:1];
*minPort = [LinphoneCoreSettingsStore validPort:[[text substringWithRange:rangeMinPort] intValue]];
NSRange rangeMaxPort = [match rangeAtIndex:4];
*maxPort = [LinphoneCoreSettingsStore validPort:[[text substringWithRange:rangeMaxPort] intValue]];
if (*minPort > *maxPort) {
*minPort = *maxPort;
}
return TRUE;
}
}
return FALSE;
}
- (void)transformCodecsToKeys:(const MSList *)codecs {
LinphoneCore *lc = [LinphoneManager getLc];
const MSList *elem = codecs;
for (; elem != NULL; elem = elem->next) {
PayloadType *pt = (PayloadType *)elem->data;
NSString *pref = [LinphoneManager getPreferenceForCodec:pt->mime_type withRate:pt->clock_rate];
if (pref) {
bool_t value = linphone_core_payload_type_enabled(lc, pt);
[self setBool:value forKey:pref];
} else {
LOGW(@"Codec %s/%i supported by core is not shown in iOS app config view.", pt->mime_type, pt->clock_rate);
}
}
}
- (void)transformLinphoneCoreToKeys {
LinphoneManager *lm = [LinphoneManager instance];
LinphoneCore *lc = [LinphoneManager getLc];
// root section
{
LinphoneProxyConfig *cfg = NULL;
linphone_core_get_default_proxy(lc, &cfg);
if (cfg) {
const char *identity = linphone_proxy_config_get_identity(cfg);
LinphoneAddress *addr = linphone_address_new(identity);
if (addr) {
const char *proxy = linphone_proxy_config_get_addr(cfg);
LinphoneAddress *proxy_addr = linphone_address_new(proxy);
int port = linphone_address_get_port(proxy_addr);
[self setCString:linphone_address_get_username(addr) forKey:@"username_preference"];
[self setCString:linphone_address_get_domain(addr) forKey:@"domain_preference"];
if (strcmp(linphone_address_get_domain(addr), linphone_address_get_domain(proxy_addr)) != 0 ||
port > 0) {
char tmp[256] = {0};
if (port > 0) {
snprintf(tmp, sizeof(tmp) - 1, "%s:%i", linphone_address_get_domain(proxy_addr), port);
} else
snprintf(tmp, sizeof(tmp) - 1, "%s", linphone_address_get_domain(proxy_addr));
[self setCString:tmp forKey:@"proxy_preference"];
}
const char *tname = "udp";
switch (linphone_address_get_transport(proxy_addr)) {
case LinphoneTransportTcp:
tname = "tcp";
break;
case LinphoneTransportTls:
tname = "tls";
break;
default:
break;
}
linphone_address_destroy(addr);
linphone_address_destroy(proxy_addr);
[self setCString:tname forKey:@"transport_preference"];
[self setBool:(linphone_proxy_config_get_route(cfg) != NULL)forKey:@"outbound_proxy_preference"];
[self setBool:linphone_proxy_config_avpf_enabled(cfg) forKey:@"avpf_preference"];
[self setBool:linphone_core_video_enabled(lc) forKey:@"enable_video_preference"];
[self setBool:[LinphoneManager.instance lpConfigBoolForKey:@"auto_answer"]
forKey:@"enable_auto_answer_preference"];
// actually in Advanced section but proxy config dependent
[self setInteger:linphone_proxy_config_get_expires(cfg) forKey:@"expire_preference"];
// actually in Call section but proxy config dependent
[self setCString:linphone_proxy_config_get_dial_prefix(cfg) forKey:@"prefix_preference"];
// actually in Call section but proxy config dependent
[self setBool:linphone_proxy_config_get_dial_escape_plus(cfg) forKey:@"substitute_+_by_00_preference"];
}
} else {
[self setObject:@"" forKey:@"username_preference"];
[self setObject:@"" forKey:@"password_preference"];
[self setObject:@"" forKey:@"domain_preference"];
[self setObject:@"" forKey:@"proxy_preference"];
[self setCString:"udp" forKey:@"transport_preference"];
[self setBool:FALSE forKey:@"outbound_proxy_preference"];
[self setBool:FALSE forKey:@"avpf_preference"];
// actually in Advanced section but proxy config dependent
[self setInteger:[lm lpConfigIntForKey:@"reg_expires" forSection:@"default_values" withDefault:600]
forKey:@"expire_preference"];
}
LinphoneAuthInfo *ai;
const MSList *elem = linphone_core_get_auth_info_list(lc);
if (elem && (ai = (LinphoneAuthInfo *)elem->data)) {
[self setCString:linphone_auth_info_get_userid(ai) forKey:@"userid_preference"];
[self setCString:linphone_auth_info_get_passwd(ai) forKey:@"password_preference"];
// hidden but useful if provisioned
[self setCString:linphone_auth_info_get_ha1(ai) forKey:@"ha1_preference"];
}
[self setBool:[lm lpConfigBoolForKey:@"advanced_account_preference"] forKey:@"advanced_account_preference"];
}
// audio section
{
[self transformCodecsToKeys:linphone_core_get_audio_codecs(lc)];
[self setFloat:linphone_core_get_playback_gain_db(lc) forKey:@"playback_gain_preference"];
[self setFloat:linphone_core_get_mic_gain_db(lc) forKey:@"microphone_gain_preference"];
[self setInteger:[lm lpConfigIntForKey:@"codec_bitrate_limit"
forSection:@"audio"
withDefault:kLinphoneAudioVbrCodecDefaultBitrate]
forKey:@"audio_codec_bitrate_limit_preference"];
[self setInteger:[lm lpConfigIntForKey:@"voiceproc_preference" withDefault:1] forKey:@"voiceproc_preference"];
[self setInteger:[lm lpConfigIntForKey:@"eq_active" forSection:@"sound" withDefault:0] forKey:@"eq_active"];
}
// video section
{
[self transformCodecsToKeys:linphone_core_get_video_codecs(lc)];
const LinphoneVideoPolicy *pol;
pol = linphone_core_get_video_policy(lc);
[self setBool:(pol->automatically_initiate)forKey:@"start_video_preference"];
[self setBool:(pol->automatically_accept)forKey:@"accept_video_preference"];
[self setBool:linphone_core_self_view_enabled(lc) forKey:@"self_video_preference"];
BOOL previewEnabled = [lm lpConfigBoolForKey:@"preview_preference" withDefault:YES];
[self setBool:previewEnabled forKey:@"preview_preference"];
const char *preset = linphone_core_get_video_preset(lc);
[self setCString:preset ? preset : "default" forKey:@"video_preset_preference"];
MSVideoSize vsize = linphone_core_get_preferred_video_size(lc);
int index;
if ((vsize.width == MS_VIDEO_SIZE_720P_W) && (vsize.height == MS_VIDEO_SIZE_720P_H)) {
index = 0;
} else if ((vsize.width == MS_VIDEO_SIZE_VGA_W) && (vsize.height == MS_VIDEO_SIZE_VGA_H)) {
index = 1;
} else {
index = 2;
}
[self setInteger:index forKey:@"video_preferred_size_preference"];
[self setInteger:linphone_core_get_preferred_framerate(lc) forKey:@"video_preferred_fps_preference"];
[self setInteger:linphone_core_get_download_bandwidth(lc) forKey:@"download_bandwidth_preference"];
}
// call section
{
[self setBool:linphone_core_get_use_info_for_dtmf(lc) forKey:@"sipinfo_dtmf_preference"];
[self setBool:linphone_core_get_use_rfc2833_for_dtmf(lc) forKey:@"rfc_dtmf_preference"];
[self setInteger:linphone_core_get_inc_timeout(lc) forKey:@"incoming_call_timeout_preference"];
[self setInteger:linphone_core_get_in_call_timeout(lc) forKey:@"in_call_timeout_preference"];
[self setBool:[lm lpConfigBoolForKey:@"repeat_call_notification"]
forKey:@"repeat_call_notification_preference"];
}
// network section
{
[self setBool:[lm lpConfigBoolForKey:@"edge_opt_preference" withDefault:NO] forKey:@"edge_opt_preference"];
[self setBool:[lm lpConfigBoolForKey:@"wifi_only_preference" withDefault:NO] forKey:@"wifi_only_preference"];
[self setCString:linphone_core_get_stun_server(lc) forKey:@"stun_preference"];
[self setBool:linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce forKey:@"ice_preference"];
int random_port_preference = [lm lpConfigIntForKey:@"random_port_preference" withDefault:1];
[self setInteger:random_port_preference forKey:@"random_port_preference"];
int port = [lm lpConfigIntForKey:@"port_preference" withDefault:5060];
[self setInteger:port forKey:@"port_preference"];
{
int minPort, maxPort;
linphone_core_get_audio_port_range(lc, &minPort, &maxPort);
if (minPort != maxPort)
[self setObject:[NSString stringWithFormat:@"%d-%d", minPort, maxPort] forKey:@"audio_port_preference"];
else
[self setObject:[NSString stringWithFormat:@"%d", minPort] forKey:@"audio_port_preference"];
}
{
int minPort, maxPort;
linphone_core_get_video_port_range(lc, &minPort, &maxPort);
if (minPort != maxPort)
[self setObject:[NSString stringWithFormat:@"%d-%d", minPort, maxPort] forKey:@"video_port_preference"];
else
[self setObject:[NSString stringWithFormat:@"%d", minPort] forKey:@"video_port_preference"];
}
[self setBool:[lm lpConfigBoolForKey:@"use_ipv6" withDefault:NO] forKey:@"use_ipv6"];
LinphoneMediaEncryption menc = linphone_core_get_media_encryption(lc);
const char *val;
switch (menc) {
case LinphoneMediaEncryptionSRTP:
val = "SRTP";
break;
case LinphoneMediaEncryptionZRTP:
val = "ZRTP";
break;
case LinphoneMediaEncryptionDTLS:
val = "DTLS";
break;
case LinphoneMediaEncryptionNone:
val = "None";
break;
}
[self setCString:val forKey:@"media_encryption_preference"];
[self setBool:[lm lpConfigBoolForKey:@"pushnotification_preference" withDefault:NO]
forKey:@"pushnotification_preference"];
[self setInteger:linphone_core_get_upload_bandwidth(lc) forKey:@"upload_bandwidth_preference"];
[self setInteger:linphone_core_get_download_bandwidth(lc) forKey:@"download_bandwidth_preference"];
[self setBool:linphone_core_adaptive_rate_control_enabled(lc) forKey:@"adaptive_rate_control_preference"];
}
// tunnel section
if (linphone_core_tunnel_available()) {
LinphoneTunnel *tunnel = linphone_core_get_tunnel([LinphoneManager getLc]);
[self setObject:[lm lpConfigStringForKey:@"tunnel_mode_preference" withDefault:@"off"]
forKey:@"tunnel_mode_preference"];
const MSList *configs = linphone_tunnel_get_servers(tunnel);
if (configs != NULL) {
LinphoneTunnelConfig *ltc = (LinphoneTunnelConfig *)configs->data;
[self setCString:linphone_tunnel_config_get_host(ltc) forKey:@"tunnel_address_preference"];
[self setInteger:linphone_tunnel_config_get_port(ltc) forKey:@"tunnel_port_preference"];
} else {
[self setCString:"" forKey:@"tunnel_address_preference"];
[self setInteger:443 forKey:@"tunnel_port_preference"];
}
}
// advanced section
{
[self setBool:[lm lpConfigBoolForKey:@"debugenable_preference" withDefault:NO]
forKey:@"debugenable_preference"];
[self setBool:[lm lpConfigBoolForKey:@"animations_preference" withDefault:NO] forKey:@"animations_preference"];
[self setBool:[lm lpConfigBoolForKey:@"backgroundmode_preference" withDefault:NO]
forKey:@"backgroundmode_preference"];
[self setBool:[lm lpConfigBoolForKey:@"start_at_boot_preference" withDefault:NO]
forKey:@"start_at_boot_preference"];
[self setBool:[lm lpConfigBoolForKey:@"autoanswer_notif_preference" withDefault:NO]
forKey:@"autoanswer_notif_preference"];
[self setBool:[lm lpConfigBoolForKey:@"enable_first_login_view_preference" withDefault:NO]
forKey:@"enable_first_login_view_preference"];
LinphoneAddress *parsed = linphone_core_get_primary_contact_parsed(lc);
if (parsed != NULL) {
[self setCString:linphone_address_get_display_name(parsed) forKey:@"primary_displayname_preference"];
[self setCString:linphone_address_get_username(parsed) forKey:@"primary_username_preference"];
}
linphone_address_destroy(parsed);
[self setCString:linphone_core_get_file_transfer_server(lc) forKey:@"file_transfer_server_url_preference"];
}
changedDict = [[NSMutableDictionary alloc] init];
// Post event
NSDictionary *eventDic = [NSDictionary dictionaryWithObject:self forKey:@"settings"];
[[NSNotificationCenter defaultCenter] postNotificationName:kLinphoneLogsUpdate object:self userInfo:eventDic];
}
- (void)alertAccountError:(NSString *)error {
UIAlertView *alertview = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Error", nil)
message:error
delegate:nil
cancelButtonTitle:NSLocalizedString(@"OK", nil)
otherButtonTitles:nil];
[alertview show];
}
- (void)synchronizeAccount {
LinphoneManager *lm = [LinphoneManager instance];
LinphoneCore *lc = [LinphoneManager getLc];
LinphoneProxyConfig *proxyCfg = NULL;
BOOL isEditing = FALSE;
NSString *error = nil;
int port_preference = [self integerForKey:@"port_preference"];
BOOL random_port_preference = [self boolForKey:@"random_port_preference"];
[lm lpConfigSetInt:random_port_preference forKey:@"random_port_preference"];
if (random_port_preference) {
port_preference = -1;
}
LCSipTransports transportValue = {port_preference, port_preference, -1, -1};
// will also update the sip_*_port section of the config
if (linphone_core_set_sip_transports(lc, &transportValue)) {
LOGE(@"cannot set transport");
}
port_preference = linphone_core_get_sip_port(lc);
[self setInteger:port_preference forKey:@"port_preference"]; // Update back preference
BOOL enable_ipv6 = [self boolForKey:@"use_ipv6"];
[lm lpConfigSetBool:enable_ipv6 forKey:@"use_ipv6" forSection:@"sip"];
if (linphone_core_ipv6_enabled(lc) != enable_ipv6) {
LOGD(@"%@ IPV6", enable_ipv6 ? @"ENABLING" : @"DISABLING");
linphone_core_enable_ipv6(lc, enable_ipv6);
}
// configure sip account
// mandatory parameters
NSString *username = [self stringForKey:@"username_preference"];
NSString *userID = [self stringForKey:@"userid_preference"];
NSString *domain = [self stringForKey:@"domain_preference"];
NSString *transport = [self stringForKey:@"transport_preference"];
NSString *accountHa1 = [self stringForKey:@"ha1_preference"];
NSString *accountPassword = [self stringForKey:@"password_preference"];
bool isOutboundProxy = [self boolForKey:@"outbound_proxy_preference"];
BOOL use_avpf = [self boolForKey:@"avpf_preference"];
if (username && [username length] > 0 && domain && [domain length] > 0) {
int expire = [self integerForKey:@"expire_preference"];
BOOL isWifiOnly = [self boolForKey:@"wifi_only_preference"];
BOOL pushnotification = [self boolForKey:@"pushnotification_preference"];
NSString *prefix = [self stringForKey:@"prefix_preference"];
NSString *proxyAddress = [self stringForKey:@"proxy_preference"];
LinphoneAuthInfo *info = NULL;
const char *route = NULL;
if (isWifiOnly && [LinphoneManager instance].connectivity == wwan)
expire = 0;
if ((!proxyAddress || [proxyAddress length] < 1) && domain) {
proxyAddress = domain;
}
if (![proxyAddress hasPrefix:@"sip:"] && ![proxyAddress hasPrefix:@"sips:"]) {
proxyAddress = [NSString stringWithFormat:@"sip:%@", proxyAddress];
}
char *proxy = ms_strdup(proxyAddress.UTF8String);
LinphoneAddress *proxy_addr = linphone_address_new(proxy);
if (proxy_addr) {
LinphoneTransportType type = LinphoneTransportUdp;
if ([transport isEqualToString:@"tcp"])
type = LinphoneTransportTcp;
else if ([transport isEqualToString:@"tls"])
type = LinphoneTransportTls;
linphone_address_set_transport(proxy_addr, type);
ms_free(proxy);
proxy = linphone_address_as_string_uri_only(proxy_addr);
}
// possible valid config detected, try to modify current proxy or create new one if none existing
linphone_core_get_default_proxy(lc, &proxyCfg);
if (proxyCfg == NULL) {
proxyCfg = linphone_core_create_proxy_config(lc);
} else {
isEditing = TRUE;
linphone_proxy_config_edit(proxyCfg);
}
char normalizedUserName[256];
LinphoneAddress *linphoneAddress = linphone_address_new("sip:user@domain.com");
linphone_proxy_config_normalize_number(proxyCfg, username.UTF8String, normalizedUserName,
sizeof(normalizedUserName));
linphone_address_set_username(linphoneAddress, normalizedUserName);
linphone_address_set_domain(linphoneAddress, [domain UTF8String]);
const char *identity = linphone_address_as_string_uri_only(linphoneAddress);
const char *password = [accountPassword UTF8String];
const char *ha1 = [accountHa1 UTF8String];
if (linphone_proxy_config_set_identity(proxyCfg, identity) == -1) {
error = NSLocalizedString(@"Invalid username or domain", nil);
goto bad_proxy;
}
// use proxy as route if outbound_proxy is enabled
route = isOutboundProxy ? proxy : NULL;
if (linphone_proxy_config_set_server_addr(proxyCfg, proxy) == -1) {
error = NSLocalizedString(@"Invalid proxy address", nil);
goto bad_proxy;
}
if (linphone_proxy_config_set_route(proxyCfg, route) == -1) {
error = NSLocalizedString(@"Invalid route", nil);
goto bad_proxy;
}
if ([prefix length] > 0) {
linphone_proxy_config_set_dial_prefix(proxyCfg, [prefix UTF8String]);
}
if ([self objectForKey:@"substitute_+_by_00_preference"]) {
bool substitute_plus_by_00 = [self boolForKey:@"substitute_+_by_00_preference"];
linphone_proxy_config_set_dial_escape_plus(proxyCfg, substitute_plus_by_00);
}
[lm lpConfigSetInt:pushnotification forKey:@"pushnotification_preference"];
[[LinphoneManager instance] configurePushTokenForProxyConfig:proxyCfg];
linphone_proxy_config_enable_register(proxyCfg, true);
linphone_proxy_config_enable_avpf(proxyCfg, use_avpf);
linphone_proxy_config_set_expires(proxyCfg, expire);
// setup auth info
if (linphone_core_get_auth_info_list(lc)) {
info = linphone_auth_info_clone(linphone_core_get_auth_info_list(lc)->data);
linphone_auth_info_set_username(info, username.UTF8String);
if (password) {
linphone_auth_info_set_passwd(info, password);
linphone_auth_info_set_ha1(info, NULL);
}
linphone_auth_info_set_domain(info, linphone_proxy_config_get_domain(proxyCfg));
} else {
LinphoneAddress *from = linphone_address_new(identity);
if (from) {
const char *userid_str = (userID != nil) ? [userID UTF8String] : NULL;
info = linphone_auth_info_new(
linphone_address_get_username(from), userid_str, password ? password : NULL, password ? NULL : ha1,
linphone_proxy_config_get_realm(proxyCfg), linphone_proxy_config_get_domain(proxyCfg));
linphone_address_destroy(from);
}
}
// We reached here without hitting the goto: the new settings are correct, so replace the previous ones.
// setup new proxycfg
if (isEditing) {
linphone_proxy_config_done(proxyCfg);
} else {
// was a new proxy config, add it
linphone_core_add_proxy_config(lc, proxyCfg);
linphone_core_set_default_proxy_config(lc, proxyCfg);
}
// add auth info only after finishing editting the proxy config, so that
// UNREGISTER succeed
linphone_core_clear_all_auth_info(lc);
if (info) {
linphone_core_add_auth_info(lc, info);
}
bad_proxy:
if (linphoneAddress)
linphone_address_destroy(linphoneAddress);
if (proxy)
ms_free(proxy);
if (info)
linphone_auth_info_destroy(info);
// in case of error, show an alert to the user
if (error != nil) {
if (isEditing)
linphone_proxy_config_done(proxyCfg);
else
linphone_proxy_config_destroy(proxyCfg);
[[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Error", nil)
message:error
delegate:nil
cancelButtonTitle:NSLocalizedString(@"OK", nil)
otherButtonTitles:nil] show];
}
}
// reload address book to prepend proxy config domain to contacts' phone number
[[[LinphoneManager instance] fastAddressBook] reload];
}
- (void)synchronizeCodecs:(const MSList *)codecs {
LinphoneCore *lc = [LinphoneManager getLc];
PayloadType *pt;
const MSList *elem;
for (elem = codecs; elem != NULL; elem = elem->next) {
pt = (PayloadType *)elem->data;
NSString *pref = [LinphoneManager getPreferenceForCodec:pt->mime_type withRate:pt->clock_rate];
linphone_core_enable_payload_type(lc, pt, [self boolForKey:pref]);
}
}
- (BOOL)synchronize {
LinphoneManager *lm = [LinphoneManager instance];
LinphoneCore *lc = [LinphoneManager getLc];
// root section
{
BOOL account_changed =
[self valueChangedForKey:@"username_preference"] || [self valueChangedForKey:@"password_preference"] ||
[self valueChangedForKey:@"domain_preference"] || [self valueChangedForKey:@"expire_preference"] ||
[self valueChangedForKey:@"proxy_preference"] || [self valueChangedForKey:@"outbound_proxy_preference"] ||
[self valueChangedForKey:@"transport_preference"] || [self valueChangedForKey:@"port_preference"] ||
[self valueChangedForKey:@"random_port_preference"] || [self valueChangedForKey:@"prefix_preference"] ||
[self valueChangedForKey:@"substitute_+_by_00_preference"] || [self valueChangedForKey:@"use_ipv6"] ||
[self valueChangedForKey:@"avpf_preference"] || [self valueChangedForKey:@"pushnotification_preference"];
if (account_changed)
[self synchronizeAccount];
bool enableVideo = [self boolForKey:@"enable_video_preference"];
linphone_core_enable_video(lc, enableVideo, enableVideo);
bool enableAutoAnswer = [self boolForKey:@"enable_auto_answer_preference"];
[LinphoneManager.instance lpConfigSetBool:enableAutoAnswer forKey:@"auto_answer"];
}
// audio section
{
[self synchronizeCodecs:linphone_core_get_audio_codecs(lc)];
float playback_gain = [self floatForKey:@"playback_gain_preference"];
linphone_core_set_playback_gain_db(lc, playback_gain);
float mic_gain = [self floatForKey:@"microphone_gain_preference"];
linphone_core_set_mic_gain_db(lc, mic_gain);
[lm lpConfigSetInt:[self integerForKey:@"audio_codec_bitrate_limit_preference"]
forKey:@"codec_bitrate_limit"
forSection:@"audio"];
BOOL voice_processing = [self boolForKey:@"voiceproc_preference"];
[lm lpConfigSetInt:voice_processing forKey:@"voiceproc_preference"];
BOOL equalizer = [self boolForKey:@"eq_active"];
[lm lpConfigSetBool:equalizer forKey:@"eq_active" forSection:@"sound"];
[[LinphoneManager instance] configureVbrCodecs];
NSString *au_device = @"AU: Audio Unit Receiver";
if (!voice_processing) {
au_device = @"AU: Audio Unit NoVoiceProc";
}
linphone_core_set_capture_device(lc, [au_device UTF8String]);
linphone_core_set_playback_device(lc, [au_device UTF8String]);
}
// video section
{
[self synchronizeCodecs:linphone_core_get_video_codecs(lc)];
LinphoneVideoPolicy policy;
policy.automatically_initiate = [self boolForKey:@"start_video_preference"];
policy.automatically_accept = [self boolForKey:@"accept_video_preference"];
linphone_core_set_video_policy(lc, &policy);
linphone_core_enable_self_view(lc, [self boolForKey:@"self_video_preference"]);
BOOL preview_preference = [self boolForKey:@"preview_preference"];
[lm lpConfigSetInt:preview_preference forKey:@"preview_preference"];
NSString *videoPreset = [self stringForKey:@"video_preset_preference"];
linphone_core_set_video_preset(lc, [videoPreset UTF8String]);
int bw;
MSVideoSize vsize;
switch ([self integerForKey:@"video_preferred_size_preference"]) {
case 0:
MS_VIDEO_SIZE_ASSIGN(vsize, 720P);
// 128 = margin for audio, the BW includes both video and audio
bw = 1024 + 128;
break;
case 1:
MS_VIDEO_SIZE_ASSIGN(vsize, VGA);
// no margin for VGA or QVGA, because video encoders can encode the
// target resulution in less than the asked bandwidth
bw = 660;
break;
case 2:
default:
MS_VIDEO_SIZE_ASSIGN(vsize, QVGA);
bw = 380;
break;
}
linphone_core_set_preferred_video_size(lc, vsize);
if (![videoPreset isEqualToString:@"custom"]) {
[self setInteger:0 forKey:@"video_preferred_fps_preference"];
[self setInteger:bw forKey:@"download_bandwidth_preference"];
}
linphone_core_set_preferred_framerate(lc, [self integerForKey:@"video_preferred_fps_preference"]);
linphone_core_set_download_bandwidth(lc, [self integerForKey:@"download_bandwidth_preference"]);
linphone_core_set_upload_bandwidth(lc, [self integerForKey:@"download_bandwidth_preference"]);
}
// call section
{
linphone_core_set_use_rfc2833_for_dtmf(lc, [self boolForKey:@"rfc_dtmf_preference"]);
linphone_core_set_use_info_for_dtmf(lc, [self boolForKey:@"sipinfo_dtmf_preference"]);
linphone_core_set_inc_timeout(lc, [self integerForKey:@"incoming_call_timeout_preference"]);
linphone_core_set_in_call_timeout(lc, [self integerForKey:@"in_call_timeout_preference"]);
[lm lpConfigSetString:[self stringForKey:@"voice_mail_uri_preference"] forKey:@"voice_mail_uri"];
[lm lpConfigSetBool:[self boolForKey:@"repeat_call_notification_preference"]
forKey:@"repeat_call_notification"];
}
// network section
{
BOOL edgeOpt = [self boolForKey:@"edge_opt_preference"];
[lm lpConfigSetInt:edgeOpt forKey:@"edge_opt_preference"];
BOOL wifiOnly = [self boolForKey:@"wifi_only_preference"];
[lm lpConfigSetInt:wifiOnly forKey:@"wifi_only_preference"];
if ([self valueChangedForKey:@"wifi_only_preference"]) {
[[LinphoneManager instance] setupNetworkReachabilityCallback];
}
NSString *stun_server = [self stringForKey:@"stun_preference"];
if ([stun_server length] > 0) {
linphone_core_set_stun_server(lc, [stun_server UTF8String]);
BOOL ice_preference = [self boolForKey:@"ice_preference"];
if (ice_preference) {
linphone_core_set_firewall_policy(lc, LinphonePolicyUseIce);
} else {
linphone_core_set_firewall_policy(lc, LinphonePolicyUseStun);
}
} else {
linphone_core_set_stun_server(lc, NULL);
linphone_core_set_firewall_policy(lc, LinphonePolicyNoFirewall);
}
{
NSString *audio_port_preference = [self stringForKey:@"audio_port_preference"];
int minPort, maxPort;
[LinphoneCoreSettingsStore parsePortRange:audio_port_preference minPort:&minPort maxPort:&maxPort];
linphone_core_set_audio_port_range(lc, minPort, maxPort);
}
{
NSString *video_port_preference = [self stringForKey:@"video_port_preference"];
int minPort, maxPort;
[LinphoneCoreSettingsStore parsePortRange:video_port_preference minPort:&minPort maxPort:&maxPort];
linphone_core_set_video_port_range(lc, minPort, maxPort);
}
NSString *menc = [self stringForKey:@"media_encryption_preference"];
if (menc && [menc compare:@"SRTP"] == NSOrderedSame)
linphone_core_set_media_encryption(lc, LinphoneMediaEncryptionSRTP);
else if (menc && [menc compare:@"ZRTP"] == NSOrderedSame)
linphone_core_set_media_encryption(lc, LinphoneMediaEncryptionZRTP);
else if (menc && [menc compare:@"DTLS"] == NSOrderedSame)
linphone_core_set_media_encryption(lc, LinphoneMediaEncryptionDTLS);
else
linphone_core_set_media_encryption(lc, LinphoneMediaEncryptionNone);
linphone_core_enable_adaptive_rate_control(lc, [self boolForKey:@"adaptive_rate_control_preference"]);
}
// tunnel section
{
if (linphone_core_tunnel_available()) {
NSString *lTunnelPrefMode = [self stringForKey:@"tunnel_mode_preference"];
NSString *lTunnelPrefAddress = [self stringForKey:@"tunnel_address_preference"];
int lTunnelPrefPort = [self integerForKey:@"tunnel_port_preference"];
LinphoneTunnel *tunnel = linphone_core_get_tunnel([LinphoneManager getLc]);
TunnelMode mode = tunnel_off;
int lTunnelPort = 443;
if (lTunnelPrefPort) {
lTunnelPort = lTunnelPrefPort;
}
linphone_tunnel_clean_servers(tunnel);
if (lTunnelPrefAddress && [lTunnelPrefAddress length]) {
LinphoneTunnelConfig *ltc = linphone_tunnel_config_new();
linphone_tunnel_config_set_host(ltc, [lTunnelPrefAddress UTF8String]);
linphone_tunnel_config_set_port(ltc, lTunnelPort);
linphone_tunnel_add_server(tunnel, ltc);
if ([lTunnelPrefMode isEqualToString:@"off"]) {
mode = tunnel_off;
} else if ([lTunnelPrefMode isEqualToString:@"on"]) {
mode = tunnel_on;
} else if ([lTunnelPrefMode isEqualToString:@"wwan"]) {
mode = tunnel_wwan;
} else if ([lTunnelPrefMode isEqualToString:@"auto"]) {
mode = tunnel_auto;
} else {
LOGE(@"Unexpected tunnel mode [%s]", [lTunnelPrefMode UTF8String]);
}
}
[lm lpConfigSetString:lTunnelPrefMode forKey:@"tunnel_mode_preference"];
[[LinphoneManager instance] setTunnelMode:mode];
}
}
// advanced section
{
BOOL debugmode = [self boolForKey:@"debugenable_preference"];
[lm lpConfigSetInt:debugmode forKey:@"debugenable_preference"];
[[LinphoneManager instance] setLogsEnabled:debugmode];
BOOL animations = [self boolForKey:@"animations_preference"];
[lm lpConfigSetInt:animations forKey:@"animations_preference"];
UIDevice *device = [UIDevice currentDevice];
bool backgroundSupported =
[device respondsToSelector:@selector(isMultitaskingSupported)] && [device isMultitaskingSupported];
BOOL isbackgroundModeEnabled = backgroundSupported && [self boolForKey:@"backgroundmode_preference"];
[lm lpConfigSetInt:isbackgroundModeEnabled forKey:@"backgroundmode_preference"];
[lm lpConfigSetInt:[self integerForKey:@"start_at_boot_preference"] forKey:@"start_at_boot_preference"];
[lm lpConfigSetInt:[self integerForKey:@"autoanswer_notif_preference"] forKey:@"autoanswer_notif_preference"];
BOOL firstloginview = [self boolForKey:@"enable_first_login_view_preference"];
[lm lpConfigSetInt:firstloginview forKey:@"enable_first_login_view_preference"];
NSString *displayname = [self stringForKey:@"primary_displayname_preference"];
NSString *username = [self stringForKey:@"primary_username_preference"];
LinphoneAddress *parsed = linphone_core_get_primary_contact_parsed(lc);
if (parsed != NULL) {
linphone_address_set_display_name(parsed, [displayname UTF8String]);
linphone_address_set_username(parsed, [username UTF8String]);
char *contact = linphone_address_as_string(parsed);
linphone_core_set_primary_contact(lc, contact);
ms_free(contact);
linphone_address_destroy(parsed);
}
[lm lpConfigSetInt:[self integerForKey:@"advanced_account_preference"] forKey:@"advanced_account_preference"];
linphone_core_set_file_transfer_server(lc,
[[self stringForKey:@"file_transfer_server_url_preference"] UTF8String]);
}
changedDict = [[NSMutableDictionary alloc] init];
// Post event
NSDictionary *eventDic = [NSDictionary dictionaryWithObject:self forKey:@"settings"];
[[NSNotificationCenter defaultCenter] postNotificationName:kLinphoneSettingsUpdate object:self userInfo:eventDic];
return YES;
}
@end