//
|
// LinphoneManager.m
|
// VoipTest
|
//
|
// Created by StevStark on 2020/11/11.
|
//
|
|
#import "HDLLinphoneManager.h"
|
#import "HDLLinPhoneSDK-Swift.h"
|
#import "HDLAudioHelper.h"
|
#import "HDLLinPhoneCommon.h"
|
//#include "linphone/linphonecore.h"
|
NSString *const kLinphoneBluetoothAvailabilityUpdate = @"LinphoneBluetoothAvailabilityUpdate";
|
NSString *const kLinphoneGlobalStateUpdate = @"LinphoneGlobalStateUpdate";
|
NSString *const kLinphoneConfiguringStateUpdate = @"LinphoneConfiguringStateUpdate";
|
NSString *const kLinphoneCoreUpdate = @"LinphoneCoreUpdate";
|
NSString *const kLinphoneRegistrationUpdate = @"LinphoneRegistrationUpdate";
|
NSString *const kLinphoneNotifyPresenceReceivedForUriOrTel = @"LinphoneNotifyPresenceReceivedForUriOrTel";
|
NSString *const kLinphoneNotifyReceived = @"LinphoneNotifyReceived";
|
NSString *const kLinphoneCallEncryptionChanged = @"LinphoneCallEncryptionChanged";
|
NSString *const kLinphoneMessageReceived = @"LinphoneMessageReceived";
|
NSString *const kLinphoneTextComposeEvent = @"LinphoneTextComposeStarted";
|
|
NSString *const kLinphoneOldChatDBFilename = @"chat_database.sqlite";
|
NSString *const kLinphoneInternalChatDBFilename = @"linphone_chats.db";
|
NSString *const LINPHONERC_APPLICATION_KEY = @"app";
|
|
extern void libmsamr_init(MSFactory *factory);
|
extern void libmsx264_init(MSFactory *factory);
|
extern void libmsopenh264_init(MSFactory *factory);
|
extern void libmssilk_init(MSFactory *factory);
|
extern void libmswebrtc_init(MSFactory *factory);
|
extern void libmscodec2_init(MSFactory *factory);
|
|
@interface HDLLinphoneManager (){
|
LinphoneAccountCreator *account_creator;
|
UIBackgroundTaskIdentifier pausedCallBgTask;
|
UIBackgroundTaskIdentifier incallBgTask;
|
NSDate *mLastKeepAliveDate;
|
|
}
|
@property(strong, nonatomic) AVAudioPlayer* messagePlayer;
|
@end
|
|
@implementation HDLLinphoneManager
|
- (id)init {
|
if ((self = [super init])) {
|
[NSNotificationCenter.defaultCenter addObserver:self
|
selector:@selector(audioRouteChangeListenerCallback:)
|
name:AVAudioSessionRouteChangeNotification
|
object:nil];
|
|
NSString *path = [[NSBundle mainBundle] pathForResource:@"msg" ofType:@"wav"];
|
self.messagePlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL URLWithString:path] error:nil];
|
|
|
_sounds.vibrate = kSystemSoundID_Vibrate;
|
[self migrateImportantFiles];
|
[self renameDefaultSettings];
|
[self copyDefaultSettings];
|
[self overrideDefaultSettings];
|
|
[HDLConfigManager.instance lpConfigSetStringWithValue:[HDLLinphoneManager dataFile:@"linphone.db"] key:@"uri" section:@"storage"];
|
[HDLConfigManager.instance lpConfigSetStringWithValue:[HDLLinphoneManager dataFile:@"x3dh.c25519.sqlite3"] key:@"x3dh_db_path" section:@"lime"];
|
// set default values for first boot
|
|
|
if ([HDLConfigManager.instance lpConfigStringForKeyWithKey:@"debugenable_preference"] == nil) {
|
#ifdef DEBUG
|
[HDLConfigManager.instance lpConfigSetIntWithValue:1 key:@"debugenable_preference"];
|
|
#else
|
[HDLConfigManager.instance lpConfigSetIntWithValue:0 key:@"debugenable_preference"];
|
|
#endif
|
}
|
|
|
// by default if handle_content_encoding is not set, we use plain text for debug purposes only
|
if ( [HDLConfigManager.instance lpConfigStringForKeyWithKey:@"handle_content_encoding" section:@"misc"] == nil) {
|
#ifdef DEBUG
|
[HDLConfigManager.instance lpConfigSetStringWithValue:@"none" key:@"handle_content_encoding" section:@"misc"];
|
|
#else
|
[HDLConfigManager.instance lpConfigSetStringWithValue:@"conflate" key:@"handle_content_encoding" section:@"misc"];
|
#endif
|
}
|
[self migrateFromUserPrefs];
|
|
}
|
return self;
|
}
|
|
+ (HDLLinphoneManager *)instance {
|
@synchronized(self) {
|
if (theLinphoneManager == nil) {
|
theLinphoneManager = [[HDLLinphoneManager alloc] init];
|
}
|
}
|
return theLinphoneManager;
|
}
|
|
+ (LinphoneCore *)getLc {
|
if (theLinphoneCore == nil) {
|
@throw([NSException exceptionWithName:@"LinphoneCoreException"
|
reason:@"Linphone core not initialized yet"
|
userInfo:nil]);
|
}
|
return theLinphoneCore;
|
}
|
- (void)migrateImportantFiles {
|
if ([HDLLinphoneManager copyFile:[HDLLinphoneManager oldPreferenceFile:@"linphonerc"] destination:[HDLLinphoneManager preferenceFile:@"linphonerc"] override:TRUE ignore:TRUE]) {
|
[NSFileManager.defaultManager
|
removeItemAtPath:[HDLLinphoneManager oldPreferenceFile:@"linphonerc"]
|
error:nil];
|
} else if ([HDLLinphoneManager copyFile:[HDLLinphoneManager documentFile:@"linphonerc"] destination:[HDLLinphoneManager preferenceFile:@"linphonerc"] override:TRUE ignore:TRUE]) {
|
[NSFileManager.defaultManager
|
removeItemAtPath:[HDLLinphoneManager documentFile:@"linphonerc"]
|
error:nil];
|
}
|
|
if ([HDLLinphoneManager copyFile:[HDLLinphoneManager oldDataFile:@"linphone.db"] destination:[HDLLinphoneManager dataFile:@"linphone.db"] override:TRUE ignore:TRUE]) {
|
[NSFileManager.defaultManager
|
removeItemAtPath:[HDLLinphoneManager oldDataFile:@"linphone.db"]
|
error:nil];
|
}
|
|
if ([HDLLinphoneManager copyFile:[HDLLinphoneManager oldDataFile:@"x3dh.c25519.sqlite3"] destination:[HDLLinphoneManager dataFile:@"x3dh.c25519.sqlite3"] override:TRUE ignore:TRUE]) {
|
[NSFileManager.defaultManager
|
removeItemAtPath:[HDLLinphoneManager oldDataFile:@"x3dh.c25519.sqlite3"]
|
error:nil];
|
}
|
|
// call history
|
if ([HDLLinphoneManager copyFile:[HDLLinphoneManager oldDataFile:kLinphoneInternalChatDBFilename] destination:[HDLLinphoneManager dataFile:kLinphoneInternalChatDBFilename] override:TRUE ignore:TRUE]) {
|
[NSFileManager.defaultManager
|
removeItemAtPath:[HDLLinphoneManager oldDataFile:kLinphoneInternalChatDBFilename]
|
error:nil];
|
}
|
|
if ([HDLLinphoneManager copyFile:[HDLLinphoneManager oldDataFile:@"zrtp_secrets"] destination:[HDLLinphoneManager dataFile:@"zrtp_secrets"] override:TRUE ignore:TRUE]) {
|
[NSFileManager.defaultManager
|
removeItemAtPath:[HDLLinphoneManager oldDataFile:@"zrtp_secrets"]
|
error:nil];
|
}
|
}
|
|
- (void)renameDefaultSettings {
|
// rename .linphonerc to linphonerc to ease debugging: when downloading
|
// containers from MacOSX, Finder do not display hidden files leading
|
// to useless painful operations to display the .linphonerc file
|
NSString *src = [HDLLinphoneManager documentFile:@".linphonerc"];
|
NSString *dst = [HDLLinphoneManager preferenceFile:@"linphonerc"];
|
NSFileManager *fileManager = [NSFileManager defaultManager];
|
NSError *fileError = nil;
|
if ([fileManager fileExistsAtPath:src]) {
|
if ([fileManager fileExistsAtPath:dst]) {
|
[fileManager removeItemAtPath:src error:&fileError];
|
|
} else {
|
[fileManager moveItemAtPath:src toPath:dst error:&fileError];
|
|
}
|
}
|
}
|
|
- (void)copyDefaultSettings {
|
NSString *src = [HDLLinphoneManager bundleFile:@"linphonerc"];
|
NSString *dst = [HDLLinphoneManager preferenceFile:@"linphonerc"];
|
[HDLLinphoneManager copyFile:src destination:dst override:FALSE ignore:FALSE];
|
}
|
|
- (void)overrideDefaultSettings {
|
NSString *linphonecfg = [HDLLinphoneManager bundleFile:@"linphonerc"];
|
NSString *fileStr = [NSString stringWithContentsOfFile:linphonecfg encoding:NSUTF8StringEncoding error:nil];
|
_configDb = linphone_config_new_from_buffer(fileStr.UTF8String);
|
//linphone_config_new_with_factory(linphonecfg.UTF8String, factory.UTF8String);
|
lp_config_clean_entry(_configDb, "misc", "max_calls");
|
}
|
|
|
|
+ (NSString *)dataFile:(NSString *)file {
|
LinphoneFactory *factory = linphone_factory_get();
|
|
NSString *fullPath = [NSString stringWithUTF8String:linphone_factory_get_data_dir(factory,nil)];
|
|
return [fullPath stringByAppendingPathComponent:file];
|
}
|
|
- (void)migrateFromUserPrefs {
|
static NSString *migration_flag = @"userpref_migration_done";
|
|
if (_configDb == nil)
|
return;
|
|
|
if ([HDLConfigManager.instance lpConfigIntForKeyWithKey:migration_flag defaultValue:0]) {
|
return;
|
}
|
|
NSDictionary *defaults = [[NSUserDefaults standardUserDefaults] dictionaryRepresentation];
|
NSArray *defaults_keys = [defaults allKeys];
|
NSDictionary *values =
|
@{ @"backgroundmode_preference" : @NO,
|
@"debugenable_preference" : @NO,
|
@"start_at_boot_preference" : @YES };
|
BOOL shouldSync = FALSE;
|
|
for (NSString *userpref in values) {
|
if ([defaults_keys containsObject:userpref]) {
|
[HDLConfigManager.instance lpConfigSetBoolWithValue:[[defaults objectForKey:userpref] boolValue] key:userpref];
|
[[NSUserDefaults standardUserDefaults] removeObjectForKey:userpref];
|
shouldSync = TRUE;
|
|
} else if ( [HDLConfigManager.instance lpConfigStringForKeyWithKey:userpref] == nil) {
|
// no default value found in our linphonerc, we need to add them
|
|
[HDLConfigManager.instance lpConfigSetBoolWithValue:[[values objectForKey:userpref] boolValue] key:userpref];
|
}
|
}
|
if (shouldSync) {
|
[[NSUserDefaults standardUserDefaults] synchronize];
|
}
|
// don't get back here in the future
|
[HDLConfigManager.instance lpConfigSetBoolWithValue:YES key:migration_flag];
|
}
|
|
|
- (void)audioRouteChangeListenerCallback:(NSNotification *)notif {
|
|
// there is at least one bug when you disconnect an audio bluetooth headset
|
// since we only get notification of route having changed, we cannot tell if that is due to:
|
// -bluetooth headset disconnected or
|
// -user wanted to use earpiece
|
// the only thing we can assume is that when we lost a device, it must be a bluetooth one (strong hypothesis though)
|
if ([[notif.userInfo valueForKey:AVAudioSessionRouteChangeReasonKey] integerValue] == AVAudioSessionRouteChangeReasonOldDeviceUnavailable)
|
_bluetoothAvailable = NO;
|
|
AVAudioSessionRouteDescription *newRoute = [AVAudioSession sharedInstance].currentRoute;
|
|
if (newRoute && newRoute.outputs.count > 0) {
|
NSString *route = newRoute.outputs[0].portType;
|
|
|
HDLCallManager.instance.speakerEnabled = [route isEqualToString:AVAudioSessionPortBuiltInSpeaker];
|
if (([[HDLAudioHelper bluetoothRoutes] containsObject:route]) && !HDLCallManager.instance.speakerEnabled) {
|
_bluetoothAvailable = TRUE;
|
HDLCallManager.instance.bluetoothEnabled = TRUE;
|
} else
|
HDLCallManager.instance.bluetoothEnabled = FALSE;
|
|
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:_bluetoothAvailable], @"available", nil];
|
[NSNotificationCenter.defaultCenter postNotificationName:kLinphoneBluetoothAvailabilityUpdate
|
object:self
|
userInfo:dict];
|
}
|
}
|
|
+ (BOOL)copyFile:(NSString *)src destination:(NSString *)dst override:(BOOL)override ignore:(BOOL)ignore {
|
NSFileManager *fileManager = NSFileManager.defaultManager;
|
NSError *error = nil;
|
if ([fileManager fileExistsAtPath:src] == NO) {
|
if (!ignore)
|
|
return FALSE;
|
}
|
if ([fileManager fileExistsAtPath:dst] == YES) {
|
if (override) {
|
[fileManager removeItemAtPath:dst error:&error];
|
if (error != nil) {
|
|
return FALSE;
|
}
|
} else {
|
|
return FALSE;
|
}
|
}
|
[fileManager copyItemAtPath:src toPath:dst error:&error];
|
if (error != nil) {
|
|
return FALSE;
|
}
|
return TRUE;
|
}
|
|
+ (NSString *)oldPreferenceFile:(NSString *)file {
|
// migration
|
LinphoneFactory *factory = linphone_factory_get();
|
NSString *fullPath = [NSString stringWithUTF8String:linphone_factory_get_config_dir(factory, nil)];
|
return [fullPath stringByAppendingPathComponent:file];
|
}
|
|
+ (NSString *)preferenceFile:(NSString *)file {
|
LinphoneFactory *factory = linphone_factory_get();
|
NSString *fullPath = [NSString stringWithUTF8String:linphone_factory_get_config_dir(factory, nil)];
|
return [fullPath stringByAppendingPathComponent:file];
|
}
|
|
+ (NSString *)documentFile:(NSString *)file {
|
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
|
NSString *documentsPath = [paths objectAtIndex:0];
|
return [documentsPath stringByAppendingPathComponent:file];
|
}
|
|
|
+ (NSString *)oldDataFile:(NSString *)file {
|
// migration
|
LinphoneFactory *factory = linphone_factory_get();
|
NSString *fullPath = [NSString stringWithUTF8String:linphone_factory_get_data_dir(factory, nil)];
|
return [fullPath stringByAppendingPathComponent:file];
|
}
|
|
+ (NSString *)bundleFile:(NSString *)file {
|
return [[NSBundle mainBundle] pathForResource:[file stringByDeletingPathExtension] ofType:[file pathExtension]];
|
}
|
|
static BOOL libStarted = FALSE;
|
|
- (void)launchLinphoneCore {
|
|
if (libStarted) {
|
return;
|
}
|
|
libStarted = TRUE;
|
|
signal(SIGPIPE, SIG_IGN);
|
|
// create linphone core
|
[self createLinphoneCore];
|
|
|
|
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
|
BOOL bAudioInputAvailable = audioSession.inputAvailable;
|
NSError *err = nil;
|
|
if (![audioSession setActive:NO error:&err] && err) {
|
|
err = nil;
|
}
|
if (!bAudioInputAvailable) {
|
|
}
|
}
|
|
- (void)createLinphoneCore {
|
[self migrationAllPre];
|
if (theLinphoneCore != nil) {
|
return;
|
}
|
|
|
// Set audio assets
|
NSString *ring =
|
([HDLLinphoneManager bundleFile:@"notes_of_the_optimistic.caf"])
|
.lastPathComponent;
|
NSString *ringback =
|
([HDLLinphoneManager bundleFile:@"ringback.wav"])
|
.lastPathComponent;
|
NSString *hold =
|
([HDLLinphoneManager bundleFile:@"hold.mkv"])
|
.lastPathComponent;
|
|
[HDLConfigManager.instance lpConfigSetStringWithValue:[HDLLinphoneManager bundleFile:ring] key:@"local_ring" section:@"sound"];
|
[HDLConfigManager.instance lpConfigSetStringWithValue:[HDLLinphoneManager bundleFile:ringback] key:@"remote_ring" section:@"sound"];
|
[HDLConfigManager.instance lpConfigSetStringWithValue:[HDLLinphoneManager bundleFile:hold] key:@"hold_music" section:@"sound"];
|
|
|
LinphoneFactory *factory = linphone_factory_get();
|
LinphoneCoreCbs *cbs = linphone_factory_create_core_cbs(factory);
|
linphone_core_cbs_set_registration_state_changed(cbs,linphone_iphone_registration_state);
|
linphone_core_cbs_set_notify_presence_received_for_uri_or_tel(cbs, linphone_iphone_notify_presence_received_for_uri_or_tel);
|
linphone_core_cbs_set_authentication_requested(cbs, linphone_iphone_popup_password_request);
|
linphone_core_cbs_set_message_received(cbs, linphone_iphone_message_received);
|
linphone_core_cbs_set_message_received_unable_decrypt(cbs, linphone_iphone_message_received_unable_decrypt);
|
linphone_core_cbs_set_transfer_state_changed(cbs, linphone_iphone_transfer_state_changed);
|
linphone_core_cbs_set_is_composing_received(cbs, linphone_iphone_is_composing_received);
|
linphone_core_cbs_set_configuring_status(cbs, linphone_iphone_configuring_status_changed);
|
linphone_core_cbs_set_global_state_changed(cbs, linphone_iphone_global_state_changed);
|
linphone_core_cbs_set_notify_received(cbs, linphone_iphone_notify_received);
|
linphone_core_cbs_set_call_encryption_changed(cbs, linphone_iphone_call_encryption_changed);
|
linphone_core_cbs_set_chat_room_state_changed(cbs, linphone_iphone_chatroom_state_changed);
|
|
linphone_core_cbs_set_call_log_updated(cbs, linphone_iphone_call_log_updated);
|
linphone_core_cbs_set_user_data(cbs, (__bridge void *)(self));
|
theLinphoneCore = linphone_factory_create_core_with_config_3(factory, _configDb, NULL);
|
linphone_core_add_callbacks(theLinphoneCore, cbs);
|
|
[HDLCallManager.instance setCoreWithCore:theLinphoneCore];
|
[HDLCoreManager.instance setCoreWithCore:theLinphoneCore];
|
[HDLConfigManager.instance setDbWithDb:_configDb];
|
|
linphone_core_start(theLinphoneCore);
|
|
NSLog(@"创建成功");
|
// Let the core handle cbs
|
linphone_core_cbs_unref(cbs);
|
|
|
// Load plugins if available in the linphone SDK - otherwise these calls will do nothing
|
MSFactory *f = linphone_core_get_ms_factory(theLinphoneCore);
|
libmssilk_init(f);
|
libmsamr_init(f);
|
libmsx264_init(f);
|
libmsopenh264_init(f);
|
libmswebrtc_init(f);
|
libmscodec2_init(f);
|
|
linphone_core_reload_ms_plugins(theLinphoneCore, NULL);
|
[self migrationAllPost];
|
|
/* Use the rootca from framework, which is already set*/
|
//linphone_core_set_root_ca(theLinphoneCore, [LinphoneManager bundleFile:@"rootca.pem"].UTF8String);
|
linphone_core_set_user_certificates_path(theLinphoneCore, [HDLLinphoneManager cacheDirectory].UTF8String);
|
|
/* The core will call the linphone_iphone_configuring_status_changed callback when the remote provisioning is loaded
|
(or skipped).
|
Wait for this to finish the code configuration */
|
|
[NSNotificationCenter.defaultCenter addObserver:self
|
selector:@selector(globalStateChangedNotificationHandler:)
|
name:kLinphoneGlobalStateUpdate
|
object:nil];
|
[NSNotificationCenter.defaultCenter addObserver:self
|
selector:@selector(configuringStateChangedNotificationHandler:)
|
name:kLinphoneConfiguringStateUpdate
|
object:nil];
|
|
|
/*call iterate once immediately in order to initiate background connections with sip server or remote provisioning
|
* grab, if any */
|
// [self iterate];
|
// start scheduler
|
|
[HDLCoreManager.instance startIterateTimer];
|
}
|
|
|
|
- (void)migrationAllPre {
|
// migrate xmlrpc URL if needed
|
if ([HDLConfigManager.instance lpConfigBoolForKeyWithKey:@"migration_xmlrpc"] == NO) {
|
[HDLConfigManager.instance lpConfigSetStringWithValue:@"https://subscribe.linphone.org:444/wizard.php" key:@"xmlrpc_url" section:@"assistant"];
|
[HDLConfigManager.instance lpConfigSetStringWithValue:@"sip:rls@sip.linphone.org" key:@"rls_uri" section:@"sip"];
|
[HDLConfigManager.instance lpConfigSetBoolWithValue:YES key:@"migration_xmlrpc"];
|
}
|
[HDLConfigManager.instance lpConfigSetBoolWithValue:NO key:@"store_friends" section:@"misc"];
|
//so far, storing friends in files is not needed. may change in the future.
|
|
}
|
|
- (void)migrationAllPost {
|
[self migrationLinphoneSettings];
|
[self migrationPerAccount];
|
}
|
|
+ (NSString *)cacheDirectory {
|
LinphoneFactory *factory = linphone_factory_get();
|
|
NSString *cachePath = [NSString stringWithUTF8String:linphone_factory_get_download_dir(factory, NULL)];
|
BOOL isDir = NO;
|
NSError *error;
|
// cache directory must be created if not existing
|
if (![[NSFileManager defaultManager] fileExistsAtPath:cachePath isDirectory:&isDir] && isDir == NO) {
|
[[NSFileManager defaultManager] createDirectoryAtPath:cachePath
|
withIntermediateDirectories:NO
|
attributes:nil
|
error:&error];
|
}
|
return cachePath;
|
}
|
|
- (void)globalStateChangedNotificationHandler:(NSNotification *)notif {
|
if ((LinphoneGlobalState)[[[notif userInfo] valueForKey:@"state"] integerValue] == LinphoneGlobalOn) {
|
[self finishCoreConfiguration];
|
}
|
}
|
|
- (void)iterate {
|
linphone_core_iterate(theLinphoneCore);
|
}
|
|
- (void)configuringStateChangedNotificationHandler:(NSNotification *)notif {
|
|
|
}
|
|
|
- (void)migrationPerAccount {
|
const bctbx_list_t * proxies = linphone_core_get_proxy_config_list(theLinphoneCore);
|
|
|
NSString *appDomain = [HDLConfigManager.instance lpConfigStringForKeyWithKey:@"domain_name" section:@"app" defaultValue:@"sip.linphone.org"];
|
while (proxies) {
|
LinphoneProxyConfig *config = proxies->data;
|
// can not create group chat without conference factory
|
if (!linphone_proxy_config_get_conference_factory_uri(config)) {
|
if (strcmp(appDomain.UTF8String, linphone_proxy_config_get_domain(config)) == 0) {
|
linphone_proxy_config_set_conference_factory_uri(config, "sip:conference-factory@sip.linphone.org");
|
}
|
}
|
proxies = proxies->next;
|
}
|
|
NSString *s = [HDLConfigManager.instance lpConfigStringForKeyWithKey:@"pushnotification_preference"];
|
if (s && s.boolValue) {
|
|
[HDLConfigManager.instance lpConfigSetBoolWithValue:NO key:@"pushnotification_preference"];
|
const MSList *proxies = linphone_core_get_proxy_config_list(theLinphoneCore);
|
while (proxies) {
|
linphone_proxy_config_set_push_notification_allowed(proxies->data, true);
|
// [self configurePushTokenForProxyConfig:proxies->data];
|
proxies = proxies->next;
|
}
|
}
|
}
|
- (void)migrationLinphoneSettings {
|
/* AVPF migration */
|
|
|
if ( [HDLConfigManager.instance lpConfigBoolForKeyWithKey:@"avpf_migration_done"] == FALSE) {
|
const MSList *proxies = linphone_core_get_proxy_config_list(theLinphoneCore);
|
while (proxies) {
|
LinphoneProxyConfig *proxy = (LinphoneProxyConfig *)proxies->data;
|
const char *addr = linphone_proxy_config_get_addr(proxy);
|
// we want to enable AVPF for the proxies
|
|
if (addr &&
|
strstr(addr, [HDLConfigManager.instance lpConfigStringForKeyWithKey:@"domain_name" section:@"app" defaultValue:@"sip.linphone.org"]
|
.UTF8String) != 0) {
|
linphone_proxy_config_enable_avpf(proxy, TRUE);
|
}
|
proxies = proxies->next;
|
}
|
[HDLConfigManager.instance lpConfigSetBoolWithValue:TRUE key:@"avpf_migration_done"];
|
|
}
|
/* Quality Reporting migration */
|
if ([HDLConfigManager.instance lpConfigBoolForKeyWithKey:@"quality_report_migration_done"] == FALSE) {
|
const MSList *proxies = linphone_core_get_proxy_config_list(theLinphoneCore);
|
while (proxies) {
|
LinphoneProxyConfig *proxy = (LinphoneProxyConfig *)proxies->data;
|
const char *addr = linphone_proxy_config_get_addr(proxy);
|
// we want to enable quality reporting for the proxies that are on linphone.org
|
|
if (addr &&
|
strstr(addr, [HDLConfigManager.instance lpConfigStringForKeyWithKey: @"domain_name" section:@"app" defaultValue:@"sip.linphone.org"]
|
.UTF8String) != 0) {
|
|
linphone_proxy_config_set_quality_reporting_collector(
|
proxy, "sip:voip-metrics@sip.linphone.org;transport=tcp");
|
linphone_proxy_config_set_quality_reporting_interval(proxy, 180);
|
linphone_proxy_config_enable_quality_reporting(proxy, TRUE);
|
}
|
proxies = proxies->next;
|
}
|
[HDLConfigManager.instance lpConfigSetBoolWithValue:TRUE key:@"quality_report_migration_done"];
|
}
|
/* File transfer migration */
|
if ([HDLConfigManager.instance lpConfigBoolForKeyWithKey:@"file_transfer_migration_done"] == FALSE) {
|
const char *newURL = "https://www.linphone.org:444/lft.php";
|
|
linphone_core_set_file_transfer_server(theLinphoneCore, newURL);
|
[HDLConfigManager.instance lpConfigSetBoolWithValue:TRUE key:@"file_transfer_migration_done"];
|
}
|
|
if ([HDLConfigManager.instance lpConfigBoolForKeyWithKey:@"lime_migration_done"] == FALSE) {
|
const MSList *proxies = linphone_core_get_proxy_config_list(theLinphoneCore);
|
while (proxies) {
|
if (!strcmp(linphone_proxy_config_get_domain((LinphoneProxyConfig *)proxies->data),"sip.linphone.org")) {
|
linphone_core_set_lime_x3dh_server_url(theLinphoneCore, "https://lime.linphone.org/lime-server/lime-server.php");
|
break;
|
}
|
proxies = proxies->next;
|
}
|
[HDLConfigManager.instance lpConfigSetBoolWithValue:TRUE key:@"lime_migration_done"];
|
}
|
|
if ([HDLConfigManager.instance lpConfigBoolForKeyWithKey:@"push_notification_migration_done"] == FALSE) {
|
const MSList *proxies = linphone_core_get_proxy_config_list(theLinphoneCore);
|
bool_t pushEnabled;
|
while (proxies) {
|
const char *refkey = linphone_proxy_config_get_ref_key(proxies->data);
|
if (refkey) {
|
pushEnabled = (strcmp(refkey, "push_notification") == 0);
|
} else {
|
pushEnabled = true;
|
}
|
linphone_proxy_config_set_push_notification_allowed(proxies->data, pushEnabled);
|
proxies = proxies->next;
|
}
|
[HDLConfigManager.instance lpConfigSetBoolWithValue:TRUE key:@"push_notification_migration_done"];
|
}
|
}
|
|
- (void)finishCoreConfiguration {
|
//Force keep alive to workaround push notif on chat message
|
linphone_core_enable_keep_alive(theLinphoneCore, true);
|
|
// get default config from bundle
|
NSString *zrtpSecretsFileName = [HDLLinphoneManager dataFile:@"zrtp_secrets"];
|
NSString *chatDBFileName = [HDLLinphoneManager dataFile:kLinphoneInternalChatDBFilename];
|
NSString *device = [[NSMutableString alloc] initWithString:[NSString stringWithFormat:@"%@iOS/%@ (%@) LinphoneSDK",
|
[NSBundle.mainBundle objectForInfoDictionaryKey:@"CFBundleDisplayName"],
|
[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"],
|
[[UIDevice currentDevice] name]]];
|
|
|
linphone_core_set_user_agent(theLinphoneCore, device.UTF8String,LINPHONE_SDK_VERSION);
|
|
|
_contactSipField = [HDLConfigManager.instance lpConfigStringForKeyWithKey:@"contact_im_type_value" section:@"sip" defaultValue:@"SIP"];
|
|
|
|
linphone_core_set_zrtp_secrets_file(theLinphoneCore, [zrtpSecretsFileName UTF8String]);
|
//linphone_core_set_chat_database_path(theLinphoneCore, [chatDBFileName UTF8String]);
|
linphone_core_set_call_logs_database_path(theLinphoneCore, [chatDBFileName UTF8String]);
|
|
NSString *path = [HDLLinphoneManager bundleFile:@"nowebcamCIF.jpg"];
|
if (path) {
|
const char *imagePath = [path UTF8String];
|
linphone_core_set_static_picture(theLinphoneCore, imagePath);
|
}
|
|
/*DETECT cameras*/
|
_frontCamId = _backCamId = nil;
|
char **camlist = (char **)linphone_core_get_video_devices(theLinphoneCore);
|
if (camlist) {
|
for (char *cam = *camlist; *camlist != NULL; cam = *++camlist) {
|
if (strcmp(FRONT_CAM_NAME, cam) == 0) {
|
_frontCamId = cam;
|
// great set default cam to front
|
|
linphone_core_set_video_device(theLinphoneCore, _frontCamId);
|
}
|
if (strcmp(BACK_CAM_NAME, cam) == 0) {
|
_backCamId = cam;
|
}
|
}
|
} else {
|
|
}
|
|
// [self enableProxyPublish:([UIApplication sharedApplication].applicationState == UIApplicationStateActive)];
|
|
|
// Post event
|
NSDictionary *dict = [NSDictionary dictionaryWithObject:[NSValue valueWithPointer:theLinphoneCore] forKey:@"core"];
|
|
[NSNotificationCenter.defaultCenter postNotificationName:kLinphoneCoreUpdate
|
object:HDLLinphoneManager.instance
|
userInfo:dict];
|
}
|
|
- (void)onRegister:(LinphoneCore *)lc
|
cfg:(LinphoneProxyConfig *)cfg
|
state:(LinphoneRegistrationState)state
|
message:(const char *)cmessage {
|
|
LinphoneReason reason = linphone_proxy_config_get_error(cfg);
|
NSString *message = nil;
|
switch (reason) {
|
case LinphoneReasonBadCredentials:
|
message = NSLocalizedString(@"Bad credentials, check your account settings", nil);
|
break;
|
case LinphoneReasonNoResponse:
|
message = NSLocalizedString(@"No response received from remote", nil);
|
break;
|
case LinphoneReasonUnsupportedContent:
|
message = NSLocalizedString(@"Unsupported content", nil);
|
break;
|
case LinphoneReasonIOError:
|
message = NSLocalizedString(
|
@"Cannot reach the server: either it is an invalid address or it may be temporary down.", nil);
|
break;
|
|
case LinphoneReasonUnauthorized:
|
message = NSLocalizedString(@"Operation is unauthorized because missing credential", nil);
|
break;
|
case LinphoneReasonNoMatch:
|
message = NSLocalizedString(@"Operation could not be executed by server or remote client because it "
|
@"didn't have any context for it",
|
nil);
|
break;
|
case LinphoneReasonMovedPermanently:
|
message = NSLocalizedString(@"Resource moved permanently", nil);
|
break;
|
case LinphoneReasonGone:
|
message = NSLocalizedString(@"Resource no longer exists", nil);
|
break;
|
case LinphoneReasonTemporarilyUnavailable:
|
message = NSLocalizedString(@"Temporarily unavailable", nil);
|
break;
|
case LinphoneReasonAddressIncomplete:
|
message = NSLocalizedString(@"Address incomplete", nil);
|
break;
|
case LinphoneReasonNotImplemented:
|
message = NSLocalizedString(@"Not implemented", nil);
|
break;
|
case LinphoneReasonBadGateway:
|
message = NSLocalizedString(@"Bad gateway", nil);
|
break;
|
case LinphoneReasonServerTimeout:
|
message = NSLocalizedString(@"Server timeout", nil);
|
break;
|
case LinphoneReasonNotAcceptable:
|
case LinphoneReasonDoNotDisturb:
|
case LinphoneReasonDeclined:
|
case LinphoneReasonNotFound:
|
case LinphoneReasonNotAnswered:
|
case LinphoneReasonBusy:
|
case LinphoneReasonNone:
|
case LinphoneReasonUnknown:
|
message = NSLocalizedString(@"Unknown error", nil);
|
break;
|
}
|
|
// Post event
|
NSDictionary *dict =
|
[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:state], @"state",
|
[NSValue valueWithPointer:cfg], @"cfg", message, @"message", nil];
|
[NSNotificationCenter.defaultCenter postNotificationName:kLinphoneRegistrationUpdate object:nil userInfo:dict];
|
}
|
|
- (void)onNotifyPresenceReceivedForUriOrTel:(LinphoneCore *)lc
|
friend:(LinphoneFriend *)lf
|
uri:(const char *)uri
|
presenceModel:(const LinphonePresenceModel *)model {
|
// Post event
|
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
|
[dict setObject:[NSValue valueWithPointer:lf] forKey:@"friend"];
|
[dict setObject:[NSValue valueWithPointer:uri] forKey:@"uri"];
|
[dict setObject:[NSValue valueWithPointer:model] forKey:@"presence_model"];
|
[NSNotificationCenter.defaultCenter postNotificationName:kLinphoneNotifyPresenceReceivedForUriOrTel
|
object:self
|
userInfo:dict];
|
}
|
|
- (void)onMessageReceived:(LinphoneCore *)lc room:(LinphoneChatRoom *)room message:(LinphoneChatMessage *)msg {
|
|
}
|
|
- (void)onMessageComposeReceived:(LinphoneCore *)core forRoom:(LinphoneChatRoom *)room {
|
[NSNotificationCenter.defaultCenter postNotificationName:kLinphoneTextComposeEvent
|
object:self
|
userInfo:@{
|
@"room" : [NSValue valueWithPointer:room]
|
}];
|
}
|
|
-(void)login:(NSString*)username password:(NSString*)pwd domain:(NSString*) domain {
|
LinphoneProxyConfig *config = linphone_core_create_proxy_config(theLinphoneCore);
|
LinphoneAddress *addr = linphone_address_new(NULL);
|
LinphoneAddress *tmpAddr = linphone_address_new([NSString stringWithFormat:@"sip:%@",domain].UTF8String);
|
if (tmpAddr == nil) {
|
return;
|
}
|
|
linphone_address_set_username(addr, username.UTF8String);
|
linphone_address_set_port(addr, linphone_address_get_port(tmpAddr));
|
linphone_address_set_domain(addr, linphone_address_get_domain(tmpAddr));
|
// if (displayName && ![displayName isEqualToString:@""]) {
|
// linphone_address_set_display_name(addr, displayName.UTF8String);
|
// }
|
linphone_proxy_config_set_identity_address(config, addr);
|
// set transport
|
NSString *type = @"UDP";
|
linphone_proxy_config_set_route(
|
config,
|
[NSString stringWithFormat:@"%s;transport=%s", domain.UTF8String, type.lowercaseString.UTF8String]
|
.UTF8String);
|
linphone_proxy_config_set_server_addr(
|
config,
|
[NSString stringWithFormat:@"%s;transport=%s", domain.UTF8String, type.lowercaseString.UTF8String]
|
.UTF8String);
|
linphone_proxy_config_enable_publish(config, FALSE);
|
linphone_proxy_config_enable_register(config, TRUE);
|
|
LinphoneAuthInfo *info =
|
linphone_auth_info_new(linphone_address_get_username(addr), // username
|
NULL, // user id
|
pwd.UTF8String, // passwd
|
NULL, // ha1
|
linphone_address_get_domain(addr), // realm - assumed to be domain
|
linphone_address_get_domain(addr) // domain
|
);
|
linphone_core_add_auth_info(theLinphoneCore, info);
|
linphone_address_unref(addr);
|
linphone_address_unref(tmpAddr);
|
if (config) {
|
// [[LinphoneManager instance] configurePushTokenForProxyConfig:config];
|
if (linphone_core_add_proxy_config(theLinphoneCore, config) != -1) {
|
linphone_core_set_default_proxy_config(theLinphoneCore, config);
|
// reload address book to prepend proxy config domain to contacts' phone number
|
// todo: STOP doing that!
|
// [[LinphoneManager.instance fastAddressBook] fetchContactsInBackGroundThread];
|
|
NSLog(@"登录成功");
|
}
|
}
|
}
|
|
|
-(void)startCall:(NSString*)phoneNum {
|
LinphoneProxyConfig *cfg = linphone_core_get_default_proxy_config(theLinphoneCore);
|
const char *normvalue;
|
normvalue = linphone_proxy_config_is_phone_number(cfg, phoneNum.UTF8String)
|
? linphone_proxy_config_normalize_phone_number(cfg, phoneNum.UTF8String)
|
: phoneNum.UTF8String;
|
|
LinphoneAddress *addr = linphone_proxy_config_normalize_sip_uri(cfg, normvalue);
|
|
// numbers by default
|
if (addr && cfg) {
|
const char *username = linphone_proxy_config_get_dial_escape_plus(cfg) ? normvalue : phoneNum.UTF8String;
|
if (linphone_proxy_config_is_phone_number(cfg, username))
|
linphone_address_set_username(addr, linphone_proxy_config_normalize_phone_number(cfg, username));
|
}
|
[self call:addr];
|
if (addr)
|
linphone_address_destroy(addr);
|
}
|
|
-(void)endCall{
|
LinphoneCall * call = linphone_core_get_current_call(theLinphoneCore);
|
[HDLCallManager.instance terminateCallWithCall:call];
|
}
|
-(void)acceptCall{
|
// [HDLCallManager configAudioSessionWithAudioSession:[AVAudioSession sharedInstance]];
|
LinphoneCall * call = linphone_core_get_current_call(theLinphoneCore);
|
[HDLCallManager.instance acceptCallWithCall:call hasVideo:YES];
|
}
|
|
-(void)fetchVideo{
|
|
if (!linphone_core_video_display_enabled(theLinphoneCore))
|
return;
|
LinphoneCall *call = linphone_core_get_current_call(theLinphoneCore);
|
if (call) {
|
CallAppData *data = [HDLCallManager getAppDataWithCall:call];
|
data.videoRequested = TRUE;/* will be used later to notify user if video was not activated because of the linphone core*/
|
[HDLCallManager setAppDataWithCall:call appData:data];
|
LinphoneCallParams *call_params = linphone_core_create_call_params(theLinphoneCore,call);
|
linphone_call_params_enable_video(call_params, TRUE);
|
linphone_call_update(call, call_params);
|
linphone_call_params_unref(call_params);
|
} else {
|
|
}
|
|
}
|
|
-(void)closeCamera {
|
if (!linphone_core_video_display_enabled(theLinphoneCore))
|
return;
|
// [LinphoneManager.instance setSpeakerEnabled:FALSE];
|
|
LinphoneCall *call = linphone_core_get_current_call(theLinphoneCore);
|
if (call) {
|
LinphoneCallParams *call_params = linphone_core_create_call_params(theLinphoneCore,call);
|
linphone_call_params_enable_video(call_params, FALSE);
|
linphone_core_update_call(theLinphoneCore, call, call_params);
|
linphone_call_params_destroy(call_params);
|
} else {
|
NSLog(@"Cannot toggle video button, because no current call");
|
}
|
}
|
|
- (void)call:(const LinphoneAddress *)iaddr {
|
// First verify that network is available, abort otherwise.
|
if (!linphone_core_is_network_reachable(theLinphoneCore)) {
|
|
return;
|
}
|
|
// Then check that no GSM calls are in progress, abort otherwise.
|
CTCallCenter *callCenter = [[CTCallCenter alloc] init];
|
if ([callCenter currentCalls] != nil && floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_9_x_Max) {
|
|
return;
|
}
|
|
if (!iaddr) {
|
|
return;
|
}
|
// For OutgoingCall, show CallOutgoingView
|
[HDLCallManager.instance startCallWithAddr:iaddr isSas:FALSE];
|
}
|
|
|
- (void)onConfiguringStatusChanged:(LinphoneConfiguringState)status withMessage:(const char *)message {
|
NSDictionary *dict = [NSDictionary
|
dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:status], @"state",
|
[NSString stringWithUTF8String:message ? message : ""], @"message", nil];
|
|
// dispatch the notification asynchronously
|
dispatch_async(dispatch_get_main_queue(), ^(void) {
|
[NSNotificationCenter.defaultCenter postNotificationName:kLinphoneConfiguringStateUpdate
|
object:self
|
userInfo:dict];
|
});
|
}
|
|
|
- (void)onGlobalStateChanged:(LinphoneGlobalState)state withMessage:(const char *)message {
|
|
|
NSDictionary *dict = [NSDictionary
|
dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:state], @"state",
|
[NSString stringWithUTF8String:message ? message : ""], @"message", nil];
|
|
// dispatch the notification asynchronously
|
dispatch_async(dispatch_get_main_queue(), ^(void) {
|
if (theLinphoneCore && linphone_core_get_global_state(theLinphoneCore) != LinphoneGlobalOff)
|
[NSNotificationCenter.defaultCenter postNotificationName:kLinphoneGlobalStateUpdate object:self userInfo:dict];
|
});
|
}
|
|
- (void)onNotifyReceived:(LinphoneCore *)lc
|
event:(LinphoneEvent *)lev
|
notifyEvent:(const char *)notified_event
|
content:(const LinphoneContent *)body {
|
// Post event
|
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
|
[dict setObject:[NSValue valueWithPointer:lev] forKey:@"event"];
|
[dict setObject:[NSString stringWithUTF8String:notified_event] forKey:@"notified_event"];
|
if (body != NULL) {
|
[dict setObject:[NSValue valueWithPointer:body] forKey:@"content"];
|
}
|
[NSNotificationCenter.defaultCenter postNotificationName:kLinphoneNotifyReceived object:self userInfo:dict];
|
}
|
|
- (void)onCallEncryptionChanged:(LinphoneCore *)lc
|
call:(LinphoneCall *)call
|
on:(BOOL)on
|
token:(const char *)authentication_token {
|
// Post event
|
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
|
[dict setObject:[NSValue valueWithPointer:call] forKey:@"call"];
|
[dict setObject:[NSNumber numberWithBool:on] forKey:@"on"];
|
if (authentication_token) {
|
[dict setObject:[NSString stringWithUTF8String:authentication_token] forKey:@"token"];
|
}
|
[NSNotificationCenter.defaultCenter postNotificationName:kLinphoneCallEncryptionChanged object:self userInfo:dict];
|
}
|
|
-(void)initalLinPhonal{
|
[HDLLinphoneManager.instance launchLinphoneCore];
|
// Override point for customization after application launch.
|
// UIApplication *app = [UIApplication sharedApplication];
|
if (!account_creator) {
|
account_creator = linphone_account_creator_new(
|
[HDLLinphoneManager getLc],
|
[HDLConfigManager.instance lpConfigStringForKeyWithKey:@"xmlrpc_url" section:@"assistant" defaultValue:@""]
|
.UTF8String);
|
}
|
[self loadAssistantConfig:@"assistant_external_sip.rc"];
|
|
}
|
- (void)loadAssistantConfig:(NSString *)rcFilename {
|
linphone_core_load_config_from_xml( [HDLLinphoneManager getLc],
|
[HDLLinphoneManager bundleFile:rcFilename].UTF8String);
|
|
if (account_creator) {
|
linphone_account_creator_set_domain(account_creator, [ [HDLConfigManager.instance lpConfigStringForKeyWithKey:@"domain" section:@"assistant" defaultValue:@""] UTF8String]);
|
|
|
linphone_account_creator_set_algorithm(account_creator, [[HDLConfigManager.instance lpConfigStringForKeyWithKey:@"algorithm" section:@"assistant" defaultValue:@""] UTF8String]);
|
}
|
// linphone_core_set_preferred_video_size_by_name([HDLLinphoneManager getLc], [@"vga" UTF8String]);
|
MSVideoSize vsize;
|
MS_VIDEO_SIZE_ASSIGN(vsize, QVGA);
|
linphone_core_set_preferred_video_size([HDLLinphoneManager getLc], vsize);
|
linphone_core_set_video_preset([HDLLinphoneManager getLc], [@"custom" UTF8String]);
|
linphone_core_set_preferred_framerate([HDLLinphoneManager getLc], 5);
|
|
// LinphoneVideoPolicy policy;
|
// policy.automatically_initiate = YES;
|
// policy.automatically_accept = YES;
|
// linphone_core_set_video_policy([HDLLinphoneManager getLc], &policy);
|
// linphone_core_set_audio_payload_types([HDLLinphoneManager getLc], <#const bctbx_list_t *payload_types#>)
|
|
// PayloadType *pt;
|
// int bitrate = linphone_config_get_int(
|
// _configDb, "audio", "codec_bitrate_limit",
|
// 36); /*default value is in linphonerc or linphonerc-factory*/
|
// const MSList *audio_codecs = linphone_core_get_audio_payload_types(theLinphoneCore);
|
// const MSList *codec = audio_codecs;
|
// while (codec) {
|
// pt = codec->data;
|
// if (linphone_core_payload_type_is_vbr([HDLLinphoneManager getLc], pt)) {
|
// linphone_core_set_payload_type_bitrate([HDLLinphoneManager getLc], pt, bitrate);
|
// }
|
// codec = codec->next;
|
// }
|
}
|
|
-(void)snapShot{
|
NSString *path=[HDLLinPhoneCommon temporarySaveImagePath];
|
LinphoneCall * call = linphone_core_get_current_call(theLinphoneCore);
|
[HDLCallManager.instance snaphotWithFilePath:path call:call];
|
NSLog(@"path:%@",path);
|
UIImage *image=[UIImage imageWithContentsOfFile:path];
|
|
NSLog(@"获取到的图片:%@",image);
|
[HDLLinPhoneCommon saveImageToPhotosAlbum:image];
|
|
|
}
|
-(void)snapShotWithView:(UIView *)view{
|
UIImage *image= [HDLLinPhoneCommon captureImageFromView:view];
|
[HDLLinPhoneCommon saveImageToPhotosAlbum:image];
|
}
|
|
|
-(void)removeAllAccounts{
|
|
const bctbx_list_t *accounts = linphone_core_get_proxy_config_list(theLinphoneCore);
|
size_t count = bctbx_list_size(accounts);
|
for (size_t i = 1; i <= count; i++, accounts = accounts->next) {
|
LinphoneProxyConfig *config = (LinphoneProxyConfig *)accounts->data;
|
if (config!=NULL) {
|
//移除config
|
linphone_core_remove_proxy_config(theLinphoneCore, config);
|
const LinphoneAuthInfo *ai = linphone_proxy_config_find_auth_info(config);
|
if (ai) {
|
linphone_core_remove_auth_info(theLinphoneCore, ai);
|
}
|
|
}
|
|
}
|
|
}
|
|
-(void)clearConfigs{
|
// const bctbx_list_t *proxies=
|
// linphone_core_get_proxy_config_list(theLinphoneCore);
|
// if (proxies==NULL) {
|
// return;
|
// }
|
//// NSLog(@"list:%@",list);
|
// while (proxies) {
|
// LinphoneProxyConfig *config = proxies->data;
|
// if (config!=NULL) {
|
// const LinphoneAuthInfo *ai = linphone_proxy_config_find_auth_info(config);
|
// if (ai) {
|
// linphone_core_remove_auth_info(theLinphoneCore, ai);
|
// }
|
// //移除config
|
// linphone_core_remove_proxy_config(theLinphoneCore, config);
|
// }
|
//
|
//
|
// proxies= proxies->next;
|
// }
|
}
|
|
// C Function
|
static void linphone_iphone_registration_state(LinphoneCore *lc, LinphoneProxyConfig *cfg,
|
LinphoneRegistrationState state, const char *message) {
|
[(__bridge HDLLinphoneManager *)linphone_core_cbs_get_user_data(linphone_core_get_current_callbacks(lc)) onRegister:lc cfg:cfg state:state message:message];
|
}
|
|
static void linphone_iphone_notify_presence_received_for_uri_or_tel(LinphoneCore *lc, LinphoneFriend *lf,
|
const char *uri_or_tel,
|
const LinphonePresenceModel *presence_model) {
|
[(__bridge HDLLinphoneManager *)linphone_core_cbs_get_user_data(linphone_core_get_current_callbacks(lc)) onNotifyPresenceReceivedForUriOrTel:lc
|
friend:lf
|
uri:uri_or_tel
|
presenceModel:presence_model];
|
|
}
|
|
static void linphone_iphone_popup_password_request(LinphoneCore *lc, LinphoneAuthInfo *auth_info, LinphoneAuthMethod method) {
|
// let the wizard handle its own errors
|
printf("账号认证错误");
|
}
|
|
static void linphone_iphone_message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *message) {
|
[(__bridge HDLLinphoneManager *)linphone_core_cbs_get_user_data(linphone_core_get_current_callbacks(lc)) onMessageReceived:lc room:room message:message];
|
}
|
|
static void linphone_iphone_message_received_unable_decrypt(LinphoneCore *lc, LinphoneChatRoom *room,
|
LinphoneChatMessage *message) {
|
NSString *callId = [NSString stringWithUTF8String:linphone_chat_message_get_custom_header(message, "Call-ID")];
|
}
|
|
static void linphone_iphone_transfer_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState state) {
|
|
|
}
|
|
static void linphone_iphone_is_composing_received(LinphoneCore *lc, LinphoneChatRoom *room) {
|
[(__bridge HDLLinphoneManager *)linphone_core_cbs_get_user_data(linphone_core_get_current_callbacks(lc)) onMessageComposeReceived:lc forRoom:room];
|
}
|
|
static void linphone_iphone_configuring_status_changed(LinphoneCore *lc, LinphoneConfiguringState status,
|
const char *message) {
|
[(__bridge HDLLinphoneManager *)linphone_core_cbs_get_user_data(linphone_core_get_current_callbacks(lc)) onConfiguringStatusChanged:status withMessage:message];
|
}
|
|
static void linphone_iphone_global_state_changed(LinphoneCore *lc, LinphoneGlobalState gstate, const char *message) {
|
[(__bridge HDLLinphoneManager *)linphone_core_cbs_get_user_data(linphone_core_get_current_callbacks(lc)) onGlobalStateChanged:gstate withMessage:message];
|
}
|
|
static void linphone_iphone_notify_received(LinphoneCore *lc, LinphoneEvent *lev, const char *notified_event,
|
const LinphoneContent *body) {
|
[(__bridge HDLLinphoneManager *)linphone_core_cbs_get_user_data(linphone_core_get_current_callbacks(lc)) onNotifyReceived:lc
|
event:lev
|
notifyEvent:notified_event
|
content:body];
|
}
|
|
static void linphone_iphone_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t on,
|
const char *authentication_token) {
|
[(__bridge HDLLinphoneManager *)linphone_core_cbs_get_user_data(linphone_core_get_current_callbacks(lc)) onCallEncryptionChanged:lc
|
call:call
|
on:on
|
token:authentication_token];
|
}
|
|
void linphone_iphone_chatroom_state_changed(LinphoneCore *lc, LinphoneChatRoom *cr, LinphoneChatRoomState state) {
|
if (state == LinphoneChatRoomStateCreated) {
|
[NSNotificationCenter.defaultCenter postNotificationName:kLinphoneMessageReceived object:nil];
|
}
|
}
|
|
static void linphone_iphone_call_log_updated(LinphoneCore *lc, LinphoneCallLog *newcl) {
|
if (linphone_call_log_get_status(newcl) == LinphoneCallEarlyAborted) {
|
const char *cid = linphone_call_log_get_call_id(newcl);
|
if (cid) {
|
[HDLCallManager.instance markCallAsDeclinedWithCallId:[NSString stringWithUTF8String:cid]];
|
}
|
}
|
}
|
|
- (BOOL)enterBackgroundMode {
|
linphone_core_enter_background(theLinphoneCore);
|
|
// LinphoneProxyConfig *proxyCfg = linphone_core_get_default_proxy_config(theLinphoneCore);
|
// BOOL shouldEnterBgMode = FALSE;
|
//
|
// // disable presence
|
// [self enableProxyPublish:NO];
|
//
|
// // handle proxy config if any
|
// if (proxyCfg) {
|
// const char *refkey = proxyCfg ? linphone_proxy_config_get_ref_key(proxyCfg) : NULL;
|
// BOOL pushNotifEnabled = (refkey && strcmp(refkey, "push_notification") == 0);
|
// if ([HDLConfigManager.instance lpConfigBoolForKeyWithKey:@"backgroundmode_preference"] || pushNotifEnabled) {
|
// if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_9_x_Max) {
|
// // For registration register
|
// [self refreshRegisters];
|
// }
|
// }
|
//
|
// if ([HDLConfigManager.instance lpConfigBoolForKeyWithKey:@"voip_mode_preference"] && [HDLConfigManager.instance lpConfigBoolForKeyWithKey:@"backgroundmode_preference"] && !pushNotifEnabled) {
|
// // Keep this!! Socket VoIP is deprecated after 9.0, but sometimes it's the only way to keep the phone background and receive the call. For example, when there is only local area network.
|
// // register keepalive
|
// NSLog(@"keepalive保活");
|
// if ([[UIApplication sharedApplication]
|
// setKeepAliveTimeout:600 /*(NSTimeInterval)linphone_proxy_config_get_expires(proxyCfg)*/
|
// handler:^{
|
//// LOGW(@"keepalive handler");
|
// self->mLastKeepAliveDate = [NSDate date];
|
// if (theLinphoneCore == nil) {
|
//// LOGW(@"It seems that Linphone BG mode was deactivated, just skipping");
|
// return;
|
// }
|
//// [_iapManager check];
|
// if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_9_x_Max) {
|
// // For registration register
|
// [self refreshRegisters];
|
// }
|
// linphone_core_iterate(theLinphoneCore);
|
// }]) {
|
// NSLog(@"keepalive handler succesfully registered");
|
// } else {
|
//// LOGI(@"keepalive handler cannot be registered");
|
// }
|
// shouldEnterBgMode = TRUE;
|
// }
|
// }
|
//
|
// LinphoneCall *currentCall = linphone_core_get_current_call(theLinphoneCore);
|
// const bctbx_list_t *callList = linphone_core_get_calls(theLinphoneCore);
|
// if (!currentCall // no active call
|
// && callList // at least one call in a non active state
|
// && bctbx_list_find_custom(callList, (bctbx_compare_func)comp_call_state_paused, NULL)) {
|
// [self startCallPausedLongRunningTask];
|
// }
|
// if (callList) // If at least one call exist, enter normal bg mode
|
// shouldEnterBgMode = TRUE;
|
//
|
// // Stop the video preview
|
// if (theLinphoneCore) {
|
// linphone_core_enable_video_preview(theLinphoneCore, FALSE);
|
// [self iterate];
|
// }
|
// linphone_core_stop_dtmf_stream(theLinphoneCore);
|
//
|
//// LOGI(@"Entering [%s] bg mode", shouldEnterBgMode ? "normal" : "lite");
|
// if (!shouldEnterBgMode && floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_9_x_Max) {
|
// const char *refkey = proxyCfg ? linphone_proxy_config_get_ref_key(proxyCfg) : NULL;
|
// BOOL pushNotifEnabled = (refkey && strcmp(refkey, "push_notification") == 0);
|
// if (pushNotifEnabled) {
|
//// LOGI(@"Keeping lc core to handle push");
|
// return YES;
|
// }
|
// return NO;
|
// }
|
return YES;
|
|
}
|
|
- (void)enableProxyPublish:(BOOL)enabled {
|
if (linphone_core_get_global_state(theLinphoneCore) != LinphoneGlobalOn || !linphone_core_get_default_friend_list(theLinphoneCore)) {
|
// LOGW(@"Not changing presence configuration because linphone core not ready yet");
|
return;
|
}
|
|
if ([HDLConfigManager.instance lpConfigBoolForKeyWithKey:@"publish_presence"]) {
|
// set present to "tv", because "available" does not work yet
|
if (enabled) {
|
linphone_core_set_presence_model(theLinphoneCore, linphone_core_create_presence_model_with_activity(theLinphoneCore, LinphonePresenceActivityTV, NULL));
|
}
|
|
const MSList *proxies = linphone_core_get_proxy_config_list(theLinphoneCore);
|
while (proxies) {
|
LinphoneProxyConfig *cfg = proxies->data;
|
linphone_proxy_config_edit(cfg);
|
linphone_proxy_config_enable_publish(cfg, enabled);
|
linphone_proxy_config_done(cfg);
|
proxies = proxies->next;
|
}
|
// force registration update first, then update friend list subscription
|
[self iterate];
|
}
|
|
linphone_core_enable_friend_list_subscription(theLinphoneCore, enabled && [HDLConfigManager.instance lpConfigBoolForKeyWithKey:@"use_rls_presence"]);
|
}
|
|
- (void)refreshRegisters {
|
linphone_core_refresh_registers(theLinphoneCore); // just to make sure REGISTRATION is up to date
|
}
|
|
- (void)startCallPausedLongRunningTask {
|
pausedCallBgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
|
// LOGW(@"Call cannot be paused any more, too late");
|
[[UIApplication sharedApplication] endBackgroundTask:self->pausedCallBgTask];
|
}];
|
// LOGI(@"Long running task started, remaining [%@] because at least one call is paused",
|
// [LinphoneUtils intervalToString:[[UIApplication sharedApplication] backgroundTimeRemaining]]);
|
}
|
|
-(void)willResignActive{
|
LinphoneCall *call = linphone_core_get_current_call(theLinphoneCore);
|
|
if (!call)
|
return;
|
|
/* save call context */
|
HDLLinphoneManager *instance = HDLLinphoneManager.instance;
|
instance->currentCallContextBeforeGoingBackground.call = call;
|
instance->currentCallContextBeforeGoingBackground.cameraIsEnabled = linphone_call_camera_enabled(call);
|
|
const LinphoneCallParams *params = linphone_call_get_current_params(call);
|
if (linphone_call_params_video_enabled(params))
|
linphone_call_enable_camera(call, false);
|
}
|
|
- (void)becomeActive {
|
linphone_core_enter_foreground(theLinphoneCore);
|
|
[self checkNewVersion];
|
|
// enable presence
|
if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_9_x_Max) {
|
[self refreshRegisters];
|
}
|
if (pausedCallBgTask) {
|
[[UIApplication sharedApplication] endBackgroundTask:pausedCallBgTask];
|
pausedCallBgTask = 0;
|
}
|
if (incallBgTask) {
|
[[UIApplication sharedApplication] endBackgroundTask:incallBgTask];
|
incallBgTask = 0;
|
}
|
|
/*IOS specific*/
|
linphone_core_start_dtmf_stream(theLinphoneCore);
|
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo
|
completionHandler:^(BOOL granted){
|
}];
|
|
/*start the video preview in case we are in the main view*/
|
if (linphone_core_video_display_enabled(theLinphoneCore) && [HDLConfigManager.instance lpConfigBoolForKeyWithKey:@"preview_preference"]) {
|
linphone_core_enable_video_preview(theLinphoneCore, TRUE);
|
}
|
/*check last keepalive handler date*/
|
if (mLastKeepAliveDate != Nil) {
|
NSDate *current = [NSDate date];
|
if ([current timeIntervalSinceDate:mLastKeepAliveDate] > 700) {
|
NSString *datestr = [mLastKeepAliveDate description];
|
// LOGW(@"keepalive handler was called for the last time at %@", datestr);
|
}
|
}
|
|
[self enableProxyPublish:YES];
|
}
|
|
- (void)checkNewVersion {
|
// if (!CHECK_VERSION_UPDATE)
|
// return;
|
// if (theLinphoneCore == nil)
|
// return;
|
// NSString *curVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
|
// const char *curVersionCString = [curVersion cStringUsingEncoding:NSUTF8StringEncoding];
|
// linphone_core_check_for_update(theLinphoneCore, curVersionCString);
|
}
|
|
static int comp_call_state_paused(const LinphoneCall *call, const void *param) {
|
return linphone_call_get_state(call) != LinphoneCallPaused;
|
}
|
@end
|