Change AudioSession API and better management of Bluetooth

This commit is contained in:
Benjamin Reis 2017-03-02 14:09:56 +01:00
parent 8689179d87
commit 214611dce3
7 changed files with 114 additions and 58 deletions

43
Classes/AudioHelper.m Normal file
View file

@ -0,0 +1,43 @@
//
// AudioHelper.m
// linphone
//
// Created by REIS Benjamin on 01/03/2017.
//
//
#import "AudioHelper.h"
#import <AVFoundation/AVAudioSession.h>
#import <Foundation/Foundation.h>
@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

View file

@ -17,6 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#import <AVFoundation/AVAudioSession.h>
#import <AddressBook/AddressBook.h>
#import <AudioToolbox/AudioToolbox.h>
#import <OpenGLES/EAGL.h>

View file

@ -31,8 +31,9 @@
#import <SystemConfiguration/CaptiveNetwork.h>
#import <SystemConfiguration/SystemConfiguration.h>
#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

View file

@ -18,8 +18,10 @@
*/
#import "UIBluetoothButton.h"
#import <AudioToolbox/AudioToolbox.h>
#import "../Utils/AudioHelper.h"
#import "Utils.h"
#import <AVFoundation/AVAudioSession.h>
#import <AudioToolbox/AudioToolbox.h>
#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 {

View file

@ -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];

View file

@ -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 */

View file

@ -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 = "<group>"; };
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 = "<group>"; };
8C1B67081E6718BC001EA2FE /* AudioHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = AudioHelper.h; path = Utils/AudioHelper.h; sourceTree = "<group>"; };
8C1C42E61E43408E00FE9A91 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/AboutView.strings; sourceTree = "<group>"; };
8C1C42E71E43408F00FE9A91 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/AssistantLinkView.strings; sourceTree = "<group>"; };
8C1C42E81E43409000FE9A91 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/AssistantView.strings; sourceTree = "<group>"; };
@ -2973,6 +2976,8 @@
63D11C541C3D503A00E8FCEE /* Log.h */,
63423C081C4501D000D9A050 /* Contact.h */,
63423C091C4501D000D9A050 /* Contact.m */,
8C1B67081E6718BC001EA2FE /* AudioHelper.h */,
8C1B67051E671826001EA2FE /* AudioHelper.m */,
);
name = Utils;
sourceTree = "<group>";
@ -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 */,