diff --git a/Classes/AudioHelper.m b/Classes/AudioHelper.m new file mode 100644 index 000000000..2231daec4 --- /dev/null +++ b/Classes/AudioHelper.m @@ -0,0 +1,43 @@ +// +// AudioHelper.m +// linphone +// +// Created by REIS Benjamin on 01/03/2017. +// +// + +#import "AudioHelper.h" +#import +#import + +@implementation AudioHelper + ++ (NSArray *)bluetoothRoutes { + return @[ AVAudioSessionPortBluetoothA2DP, AVAudioSessionPortBluetoothLE, AVAudioSessionPortBluetoothHFP ]; +} + ++ (AVAudioSessionPortDescription *)bluetoothAudioDevice { + return [AudioHelper audioDeviceFromTypes:[AudioHelper bluetoothRoutes]]; +} + ++ (AVAudioSessionPortDescription *)builtinAudioDevice { + NSArray *builtinRoutes = @[ AVAudioSessionPortBuiltInMic ]; + return [AudioHelper audioDeviceFromTypes:builtinRoutes]; +} + ++ (AVAudioSessionPortDescription *)speakerAudioDevice { + NSArray *builtinRoutes = @[ AVAudioSessionPortBuiltInSpeaker ]; + return [AudioHelper audioDeviceFromTypes:builtinRoutes]; +} + ++ (AVAudioSessionPortDescription *)audioDeviceFromTypes:(NSArray *)types { + NSArray *routes = [[AVAudioSession sharedInstance] availableInputs]; + for (AVAudioSessionPortDescription *route in routes) { + if ([types containsObject:route.portType]) { + return route; + } + } + return nil; +} + +@end diff --git a/Classes/CallView.m b/Classes/CallView.m index b936de75b..2a367b150 100644 --- a/Classes/CallView.m +++ b/Classes/CallView.m @@ -17,6 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#import #import #import #import diff --git a/Classes/LinphoneManager.m b/Classes/LinphoneManager.m index 66f7916c8..f7edcf4fd 100644 --- a/Classes/LinphoneManager.m +++ b/Classes/LinphoneManager.m @@ -31,8 +31,9 @@ #import #import -#import "LinphoneManager.h" #import "LinphoneCoreSettingsStore.h" +#import "LinphoneManager.h" +#import "Utils/AudioHelper.h" #import "Utils/FileTransferDelegate.h" #include "linphone/linphonecore_utils.h" @@ -2517,13 +2518,12 @@ static int comp_call_state_paused(const LinphoneCall *call, const void *param) { return true; bool allow = true; - CFStringRef lNewRoute = CFSTR("Unknown"); - UInt32 lNewRouteSize = sizeof(lNewRoute); - OSStatus lStatus = AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &lNewRouteSize, &lNewRoute); - if (!lStatus && lNewRouteSize > 0) { - NSString *route = (__bridge NSString *)lNewRoute; - allow = ![route containsSubstring:@"Heads"] && ![route isEqualToString:@"Lineout"]; - CFRelease(lNewRoute); + AVAudioSessionRouteDescription *newRoute = [AVAudioSession sharedInstance].currentRoute; + if (newRoute) { + NSString *route = newRoute.outputs[0].portType; + allow = !([route isEqualToString:AVAudioSessionPortLineOut] || + [route isEqualToString:AVAudioSessionPortHeadphones] || + [[AudioHelper bluetoothRoutes] containsObject:route]); } return allow; } @@ -2541,17 +2541,14 @@ static int comp_call_state_paused(const LinphoneCall *call, const void *param) { AVAudioSessionRouteChangeReasonOldDeviceUnavailable) { _bluetoothAvailable = NO; } + AVAudioSessionRouteDescription *newRoute = [AVAudioSession sharedInstance].currentRoute; - CFStringRef newRoute = CFSTR("Unknown"); - UInt32 newRouteSize = sizeof(newRoute); - - OSStatus status = AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &newRouteSize, &newRoute); - if (!status && newRouteSize > 0) { - NSString *route = (__bridge NSString *)newRoute; + if (newRoute) { + NSString *route = newRoute.outputs[0].portType; LOGI(@"Current audio route is [%s]", [route UTF8String]); - _speakerEnabled = [route isEqualToString:@"Speaker"] || [route isEqualToString:@"SpeakerAndMicrophone"]; - if ([route isEqualToString:@"HeadsetBT"] && !_speakerEnabled) { + _speakerEnabled = [route isEqualToString:AVAudioSessionPortBuiltInSpeaker]; + if (([[AudioHelper bluetoothRoutes] containsObject:route]) && !_speakerEnabled) { _bluetoothAvailable = TRUE; _bluetoothEnabled = TRUE; } else { @@ -2562,39 +2559,26 @@ static int comp_call_state_paused(const LinphoneCall *call, const void *param) { [NSNotificationCenter.defaultCenter postNotificationName:kLinphoneBluetoothAvailabilityUpdate object:self userInfo:dict]; - CFRelease(newRoute); } } - (void)setSpeakerEnabled:(BOOL)enable { - OSStatus ret; _speakerEnabled = enable; UInt32 override = kAudioSessionUnspecifiedError; - - if (!enable && _bluetoothAvailable) { - UInt32 bluetoothInputOverride = _bluetoothEnabled; - ret = AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryEnableBluetoothInput, - sizeof(bluetoothInputOverride), &bluetoothInputOverride); - // if setting bluetooth failed, it must be because the device is not available - // anymore (disconnected), so deactivate bluetooth. - if (ret != kAudioSessionNoError) { - _bluetoothAvailable = _bluetoothEnabled = FALSE; - } - } + NSError *err; if (override != kAudioSessionNoError) { if (enable && [self allowSpeaker]) { - override = kAudioSessionOverrideAudioRoute_Speaker; - ret = AudioSessionSetProperty(kAudioSessionProperty_OverrideAudioRoute, sizeof(override), &override); + [[AVAudioSession sharedInstance] overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:&err]; _bluetoothEnabled = FALSE; } else { - override = kAudioSessionOverrideAudioRoute_None; - ret = AudioSessionSetProperty(kAudioSessionProperty_OverrideAudioRoute, sizeof(override), &override); + AVAudioSessionPortDescription *builtinPort = [AudioHelper builtinAudioDevice]; + [[AVAudioSession sharedInstance] setPreferredInput:builtinPort error:&err]; } } - if (ret != kAudioSessionNoError) { - LOGE(@"Failed to change audio route: err %d", ret); + if (err) { + LOGE(@"Failed to change audio route: err %d", err.localizedDescription); } } @@ -2602,8 +2586,21 @@ static int comp_call_state_paused(const LinphoneCall *call, const void *param) { if (_bluetoothAvailable) { // The change of route will be done in setSpeakerEnabled _bluetoothEnabled = enable; - [self setSpeakerEnabled:!_bluetoothEnabled && _speakerEnabled]; + if (_bluetoothEnabled) { + NSError *err; + AVAudioSessionPortDescription *_bluetoothPort = [AudioHelper bluetoothAudioDevice]; + [[AVAudioSession sharedInstance] setPreferredInput:_bluetoothPort error:&err]; + // if setting bluetooth failed, it must be because the device is not available + // anymore (disconnected), so deactivate bluetooth. + if (err) { + _bluetoothAvailable = _bluetoothEnabled = FALSE; + } else { + _speakerEnabled = FALSE; + return; + } + } } + [self setSpeakerEnabled:_speakerEnabled]; } #pragma mark - Call Functions diff --git a/Classes/LinphoneUI/UIBluetoothButton.m b/Classes/LinphoneUI/UIBluetoothButton.m index 002d02624..52ab9259b 100644 --- a/Classes/LinphoneUI/UIBluetoothButton.m +++ b/Classes/LinphoneUI/UIBluetoothButton.m @@ -18,8 +18,10 @@ */ #import "UIBluetoothButton.h" -#import +#import "../Utils/AudioHelper.h" #import "Utils.h" +#import +#import #include "linphone/linphonecore.h" @@ -29,29 +31,13 @@ LOGE(@"UIBluetoothButton error for %s: ret=%ld", method, au) - (void)onOn { - // redirect audio to bluetooth - - UInt32 size = sizeof(CFStringRef); - CFStringRef route = CFSTR("HeadsetBT"); - OSStatus result = AudioSessionSetProperty(kAudioSessionProperty_AudioRoute, size, &route); - check_auresult(result, "set kAudioSessionProperty_AudioRoute HeadsetBT"); - - int allowBluetoothInput = 1; - result = AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryEnableBluetoothInput, - sizeof(allowBluetoothInput), &allowBluetoothInput); - check_auresult(result, "set kAudioSessionProperty_OverrideCategoryEnableBluetoothInput 1"); + AVAudioSessionPortDescription *_bluetoothPort = [AudioHelper bluetoothAudioDevice]; + [[AVAudioSession sharedInstance] setPreferredInput:_bluetoothPort error:nil]; } - (void)onOff { - // redirect audio to bluetooth - int allowBluetoothInput = 0; - OSStatus result = AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryEnableBluetoothInput, - sizeof(allowBluetoothInput), &allowBluetoothInput); - check_auresult(result, "set kAudioSessionProperty_OverrideCategoryEnableBluetoothInput 0"); - UInt32 size = sizeof(CFStringRef); - CFStringRef route = CFSTR("ReceiverAndMicrophone"); - result = AudioSessionSetProperty(kAudioSessionProperty_AudioRoute, size, &route); - check_auresult(result, "set kAudioSessionProperty_AudioRoute ReceiverAndMicrophone"); + AVAudioSessionPortDescription *builtinPort = [AudioHelper builtinAudioDevice]; + [[AVAudioSession sharedInstance] setPreferredInput:builtinPort error:nil]; } - (bool)onUpdate { diff --git a/Classes/ProviderDelegate.m b/Classes/ProviderDelegate.m index 9f02e5d17..6bd90c350 100644 --- a/Classes/ProviderDelegate.m +++ b/Classes/ProviderDelegate.m @@ -50,7 +50,9 @@ } - (void)configAudioSession:(AVAudioSession *)audioSession { - [audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:nil]; + [audioSession setCategory:AVAudioSessionCategoryPlayAndRecord + withOptions:AVAudioSessionCategoryOptionAllowBluetooth + error:nil]; [audioSession setMode:AVAudioSessionModeVoiceChat error:nil]; double sampleRate = 44100.0; [audioSession setPreferredSampleRate:sampleRate error:nil]; diff --git a/Classes/Utils/AudioHelper.h b/Classes/Utils/AudioHelper.h new file mode 100644 index 000000000..d770d3b50 --- /dev/null +++ b/Classes/Utils/AudioHelper.h @@ -0,0 +1,21 @@ +// +// AudioHelper.h +// linphone +// +// Created by REIS Benjamin on 01/03/2017. +// +// + +#ifndef AudioHelper_h +#define AudioHelper_h + +@interface AudioHelper : NSObject + ++ (NSArray *)bluetoothRoutes; ++ (AVAudioSessionPortDescription *)bluetoothAudioDevice; ++ (AVAudioSessionPortDescription *)builtinAudioDevice; ++ (AVAudioSessionPortDescription *)speakerAudioDevice; ++ (AVAudioSessionPortDescription *)audioDeviceFromTypes:(NSArray *)types; +@end + +#endif /* AudioHelper_h */ diff --git a/linphone.xcodeproj/project.pbxproj b/linphone.xcodeproj/project.pbxproj index cb8362337..9606e5efa 100755 --- a/linphone.xcodeproj/project.pbxproj +++ b/linphone.xcodeproj/project.pbxproj @@ -669,6 +669,7 @@ 63FD3F121CA17FA400E9AECC /* libmbedx509.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 63FD3F081CA17F9100E9AECC /* libmbedx509.a */; }; 70E542F313E147E3002BA2C0 /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 70E542F213E147E3002BA2C0 /* OpenGLES.framework */; }; 70E542F513E147EB002BA2C0 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 70E542F413E147EB002BA2C0 /* QuartzCore.framework */; }; + 8C1B67061E671826001EA2FE /* AudioHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C1B67051E671826001EA2FE /* AudioHelper.m */; }; 8C2595DD1DEDC92D007A6424 /* ProviderDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C2595DC1DEDC92D007A6424 /* ProviderDelegate.m */; }; 8C2595DF1DEDCC8E007A6424 /* CallKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8C2595DE1DEDCC8E007A6424 /* CallKit.framework */; }; 8C2595E11DEDDC67007A6424 /* callkit_logo.png in Resources */ = {isa = PBXBuildFile; fileRef = 8C2595E01DEDDC67007A6424 /* callkit_logo.png */; }; @@ -1591,6 +1592,8 @@ 7066FC0B13E830E400EFC6DC /* libvpx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libvpx.a; path = "liblinphone-sdk/apple-darwin/lib/libvpx.a"; sourceTree = ""; }; 70E542F213E147E3002BA2C0 /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; }; 70E542F413E147EB002BA2C0 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; + 8C1B67051E671826001EA2FE /* AudioHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AudioHelper.m; sourceTree = ""; }; + 8C1B67081E6718BC001EA2FE /* AudioHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = AudioHelper.h; path = Utils/AudioHelper.h; sourceTree = ""; }; 8C1C42E61E43408E00FE9A91 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/AboutView.strings; sourceTree = ""; }; 8C1C42E71E43408F00FE9A91 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/AssistantLinkView.strings; sourceTree = ""; }; 8C1C42E81E43409000FE9A91 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/AssistantView.strings; sourceTree = ""; }; @@ -2973,6 +2976,8 @@ 63D11C541C3D503A00E8FCEE /* Log.h */, 63423C081C4501D000D9A050 /* Contact.h */, 63423C091C4501D000D9A050 /* Contact.m */, + 8C1B67081E6718BC001EA2FE /* AudioHelper.h */, + 8C1B67051E671826001EA2FE /* AudioHelper.m */, ); name = Utils; sourceTree = ""; @@ -3923,6 +3928,7 @@ D3ED3EA71587334E006C0DE4 /* HistoryListTableView.m in Sources */, D3ED3EB81587392C006C0DE4 /* HistoryListView.m in Sources */, 24A345A61D95798A00881A5C /* UIShopTableCell.m in Sources */, + 8C1B67061E671826001EA2FE /* AudioHelper.m in Sources */, D35497FE15875372000081D8 /* ContactsListView.m in Sources */, 635173F91BA082A40095EB0A /* UIChatBubblePhotoCell.m in Sources */, D3549816158761D0000081D8 /* ContactsListTableView.m in Sources */,