好吧,我正在开发一个有趣的项目,我需要为我的iOS应用程序启用蓝牙音频支持.
我遇到的障碍是我甚至无法开始获得连接的蓝牙音频设备列表.即使我的iPhone 5S识别我的耳机(准确地说是一个~3 - 4岁的LG HBM-230)并通过它播放音频进行电话呼叫,但当我查询两者时,BOTH External Accessory和CoreBluetooth都没有给我任何帮助.
我将我自己的代码基于我发现的CoreBluetooth和External Accessory框架的问题和答案.
当我的代码只是试图" scanForPeripheralsWithServices:nil
" 设置 - >蓝牙说的任何蓝牙设备可见并连接时,下面的代码只是CBCentralManagerStatePoweredOn
在控制台中的" "消息之外不会出现一次命中.
我的代码中的这一行(带有有效的EAAccessoryManager实例)
NSArray * connectedDevices = [self.eAAccessoryManager connectedAccessories];
还带有一个nil数组.
我能做错什么?
顺便说一下,我已将此代码作为GitHub项目提供.
@implementation BluetoothManager + (BluetoothManager *)sharedInstance { static dispatch_once_t pred = 0; __strong static id _bluetoothMGR = nil; dispatch_once(&pred, ^{ _bluetoothMGR = [[BluetoothManager alloc] init]; }); return _bluetoothMGR; } - (id)init { self = [super init]; if(self) { dispatch_queue_t centralQueue = dispatch_queue_create("com.yo.mycentral", DISPATCH_QUEUE_SERIAL); // whether we try this on a queue of "nil" (the main queue) or this separate thread, still not getting results self.cbManager = [[CBCentralManager alloc] initWithDelegate:self queue:centralQueue options:nil]; } return self; } // this would hit.... if I instantiated this in a storyboard of XIB file - (void)awakeFromNib { if(!self.cbManager) self.cbManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:nil]; } - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI { NSLog(@"hey I found %@",[advertisementData description]); } - (void)centralManager:(CBCentralManager *)central didRetrieveConnectedPeripherals:(NSArray *)peripherals { NSLog( @"I retrieved CONNECTED peripherals"); } -(void)centralManager:(CBCentralManager *)central didRetrievePeripherals:(NSArray *)peripherals{ NSLog(@"This is it!"); } - (void)centralManagerDidUpdateState:(CBCentralManager *)central{ NSString *messtoshow; switch (central.state) { case CBCentralManagerStateUnknown: { messtoshow=@"State unknown, update imminent."; break; } case CBCentralManagerStateResetting: { messtoshow=@"The connection with the system service was momentarily lost, update imminent."; break; } case CBCentralManagerStateUnsupported: { messtoshow=@"The platform doesn't support Bluetooth Low Energy"; break; } case CBCentralManagerStateUnauthorized: { messtoshow=@"The app is not authorized to use Bluetooth Low Energy"; break; } case CBCentralManagerStatePoweredOff: { messtoshow=@"Bluetooth is currently powered off."; break; } case CBCentralManagerStatePoweredOn: { messtoshow=@"Bluetooth is currently powered on and available to use."; NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], CBCentralManagerScanOptionAllowDuplicatesKey, nil]; [_cbManager scanForPeripheralsWithServices:nil options:options]; break; } } NSLog(@"%@", messtoshow); } @end
Bamsworld.. 32
首先,您需要配置应用程序音频会话以允许支持音频的蓝牙连接.您可以在例如应用程序委托 - (BOOL)应用程序:(UIApplication*)应用程序didFinishLaunchingWithOptions:(NSDictionary*)launchOptions方法中执行此操作.确保链接AVFoundation Framework并导入将使用它的标头.
#import// place in .h [self prepareAudioSession];// called from application didFinishLaunchingWithOptions - (BOOL)prepareAudioSession { // deactivate session BOOL success = [[AVAudioSession sharedInstance] setActive:NO error: nil]; if (!success) { NSLog(@"deactivationError"); } // set audio session category AVAudioSessionCategoryPlayAndRecord options AVAudioSessionCategoryOptionAllowBluetooth success = [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionAllowBluetooth error:nil]; if (!success) { NSLog(@"setCategoryError"); } // activate audio session success = [[AVAudioSession sharedInstance] setActive:YES error: nil]; if (!success) { NSLog(@"activationError"); } return success; }
每个应用程序都有一个可以配置的音频会话单例.会话类别和模式(在此示例中,我没有设置模式以使其恢复为默认模式)声明您的应用程序意图,了解您希望如何处理音频路由.它遵循胜利的最后一个重要规则.这意味着如果用户插入耳机或在这种情况下是免提外围设备(HFP)的蓝牙设备,则系统将自动将音频路由到耳机或蓝牙设备.用户物理动作用于确定音频路由.但是,如果您希望向用户提供Apple推荐使用MPVolumeView类的可用路由列表.
添加MPVolumeView的示例可以放在UIViewController子类viewDidLoad方法中.
#import// place in .h // prefered way using MPVolumeView for user selecting audio routes self.view.backgroundColor = [UIColor clearColor]; CGRect frameForMPVV = CGRectMake(50.0, 50.0, 100.0, 100.0); MPVolumeView *routeView = [[MPVolumeView alloc] initWithFrame:frameForMPVV]; [routeView setShowsVolumeSlider:NO]; [routeView setShowsRouteButton:YES]; [self.view addSubview: routeView];
从iOS 7开始,您可以获得所有这样的输入
// portDesc.portType could be for example - BluetoothHFP, MicrophoneBuiltIn, MicrophoneWired NSArray *availInputs = [[AVAudioSession sharedInstance] availableInputs]; int count = [availInputs count]; for (int k = 0; k < count; k++) { AVAudioSessionPortDescription *portDesc = [availInputs objectAtIndex:k]; NSLog(@"input%i port type %@", k+1, portDesc.portType); NSLog(@"input%i port name %@", k+1, portDesc.portName); }
您感兴趣的portType是"BluetoothHFP".portName属性通常是您要向用户显示的制造商/型号.(我用非LE蓝牙摩托罗拉恐龙检查了这个并且它有效)
由于最后的胜利规则,您需要观察这两个通知(包括iOS 7).一个用于处理中断(例如电话或警报),第二个用于通知路由更改.路线更改通知是与此问题相关的通知.
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(myInterruptionSelector:) name:AVAudioSessionInterruptionNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(myRouteChangeSelector:) name:AVAudioSessionRouteChangeNotification object:nil];
对于iOS 6.x,您可以在myRouteChange:选择器中读取AVAudioSession的currentRoute属性以获取新路由,因为这将在连接耳机或蓝牙设备时被调用.
- (void)myRouteChangeSelector:(NSNotification*)notification { AVAudioSessionRouteDescription *currentRoute = [[AVAudioSession sharedInstance] currentRoute]; NSArray *inputsForRoute = currentRoute.inputs; NSArray *outputsForRoute = currentRoute.outputs; AVAudioSessionPortDescription *outPortDesc = [outputsForRoute objectAtIndex:0]; NSLog(@"current outport type %@", outPortDesc.portType); AVAudioSessionPortDescription *inPortDesc = [inputsForRoute objectAtIndex:0]; NSLog(@"current inPort type %@", inPortDesc.portType); }
任何iOS版本<6.0你都需要' 现已弃用的 'AudioSessionServices类.这个类是一个C api而不是通知它允许你添加属性监听器.
我将在这个笔记上完成 - 你总是不知道你想从系统中得到什么.需要观察中断处理通知并进行大量错误检查.我认为这是一个非常好的问题,我希望这能说明你正在努力实现的目标.
首先,您需要配置应用程序音频会话以允许支持音频的蓝牙连接.您可以在例如应用程序委托 - (BOOL)应用程序:(UIApplication*)应用程序didFinishLaunchingWithOptions:(NSDictionary*)launchOptions方法中执行此操作.确保链接AVFoundation Framework并导入将使用它的标头.
#import <AVFoundation/AVFoundation.h>// place in .h [self prepareAudioSession];// called from application didFinishLaunchingWithOptions - (BOOL)prepareAudioSession { // deactivate session BOOL success = [[AVAudioSession sharedInstance] setActive:NO error: nil]; if (!success) { NSLog(@"deactivationError"); } // set audio session category AVAudioSessionCategoryPlayAndRecord options AVAudioSessionCategoryOptionAllowBluetooth success = [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionAllowBluetooth error:nil]; if (!success) { NSLog(@"setCategoryError"); } // activate audio session success = [[AVAudioSession sharedInstance] setActive:YES error: nil]; if (!success) { NSLog(@"activationError"); } return success; }
每个应用程序都有一个可以配置的音频会话单例.会话类别和模式(在此示例中,我没有设置模式以使其恢复为默认模式)声明您的应用程序意图,了解您希望如何处理音频路由.它遵循胜利的最后一个重要规则.这意味着如果用户插入耳机或在这种情况下是免提外围设备(HFP)的蓝牙设备,则系统将自动将音频路由到耳机或蓝牙设备.用户物理动作用于确定音频路由.但是,如果您希望向用户提供Apple推荐使用MPVolumeView类的可用路由列表.
添加MPVolumeView的示例可以放在UIViewController子类viewDidLoad方法中.
#import <MediaPlayer/MediaPlayer.h> // place in .h // prefered way using MPVolumeView for user selecting audio routes self.view.backgroundColor = [UIColor clearColor]; CGRect frameForMPVV = CGRectMake(50.0, 50.0, 100.0, 100.0); MPVolumeView *routeView = [[MPVolumeView alloc] initWithFrame:frameForMPVV]; [routeView setShowsVolumeSlider:NO]; [routeView setShowsRouteButton:YES]; [self.view addSubview: routeView];
从iOS 7开始,您可以获得所有这样的输入
// portDesc.portType could be for example - BluetoothHFP, MicrophoneBuiltIn, MicrophoneWired NSArray *availInputs = [[AVAudioSession sharedInstance] availableInputs]; int count = [availInputs count]; for (int k = 0; k < count; k++) { AVAudioSessionPortDescription *portDesc = [availInputs objectAtIndex:k]; NSLog(@"input%i port type %@", k+1, portDesc.portType); NSLog(@"input%i port name %@", k+1, portDesc.portName); }
您感兴趣的portType是"BluetoothHFP".portName属性通常是您要向用户显示的制造商/型号.(我用非LE蓝牙摩托罗拉恐龙检查了这个并且它有效)
由于最后的胜利规则,您需要观察这两个通知(包括iOS 7).一个用于处理中断(例如电话或警报),第二个用于通知路由更改.路线更改通知是与此问题相关的通知.
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(myInterruptionSelector:) name:AVAudioSessionInterruptionNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(myRouteChangeSelector:) name:AVAudioSessionRouteChangeNotification object:nil];
对于iOS 6.x,您可以在myRouteChange:选择器中读取AVAudioSession的currentRoute属性以获取新路由,因为这将在连接耳机或蓝牙设备时被调用.
- (void)myRouteChangeSelector:(NSNotification*)notification { AVAudioSessionRouteDescription *currentRoute = [[AVAudioSession sharedInstance] currentRoute]; NSArray *inputsForRoute = currentRoute.inputs; NSArray *outputsForRoute = currentRoute.outputs; AVAudioSessionPortDescription *outPortDesc = [outputsForRoute objectAtIndex:0]; NSLog(@"current outport type %@", outPortDesc.portType); AVAudioSessionPortDescription *inPortDesc = [inputsForRoute objectAtIndex:0]; NSLog(@"current inPort type %@", inPortDesc.portType); }
任何iOS版本<6.0你都需要' 现已弃用的 'AudioSessionServices类.这个类是一个C api而不是通知它允许你添加属性监听器.
我将在这个笔记上完成 - 你总是不知道你想从系统中得到什么.需要观察中断处理通知并进行大量错误检查.我认为这是一个非常好的问题,我希望这能说明你正在努力实现的目标.