如何在 iOS 中找到蓝牙音频设备
Posted
技术标签:
【中文标题】如何在 iOS 中找到蓝牙音频设备【英文标题】:how to find Bluetooth audio devices in iOS 【发布时间】:2014-01-03 04:25:10 【问题描述】:好的,我正在做一个有趣的项目,但我需要为我的 ios 应用启用蓝牙音频支持。
我遇到的障碍是我什至无法开始获取已连接蓝牙音频设备的列表。尽管我的 iPhone 5S 可以识别我的听筒(准确地说是 3 - 4 岁 LG HBM-230)并通过它播放音频以进行通话,BOTH当我同时查询时,CoreBluetooth 并没有给我任何有用的信息。
我的代码基于我为CoreBluetooth 和External Accessory 框架找到的问题和答案。
当我的代码只是尝试“scanForPeripheralsWithServices:nil
”为设置->蓝牙说是可见和连接的 任何蓝牙设备时,下面的代码根本不会出现超出控制台中的“CBCentralManagerStatePoweredOn
”消息。
我的代码中的这一行(带有有效的 EAAccessoryManager 实例)
NSArray * connectedDevices = [self.eAAccessoryManager connectedAccessories];
还返回一个 nil 数组。
我做错了什么?
顺便说一句,I've made this code available as a GitHub project.
@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
【问题讨论】:
你的设备支持 BLE 吗? 核心蓝牙只支持低功耗设备 感谢@UndercoverDeveloper 和 Bamsworld,我确实在各个地方读到过有关 CB 仅适用于 BLE 设备的信息。我仍然想知道 iOS 如何在 Settings -> Bluetooth 中识别和列出设备,但我也无法从 ExternalAccessory 框架中获得任何爱。是否有一些其他可能的方式从我的可能非标准设备获取设备信息? 有最新的 iBeacon API,但我认为它也仅适用于 BLE:/ CoreBluetooth.framework 在这里无关紧要。它仅适用于 BLE(而不是“经典”蓝牙)。 BLE 不支持音频。 【参考方案1】:首先,您需要配置应用程序的音频会话以允许支持音频的蓝牙连接。例如,您可以在您的应用程序委托中执行此操作 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 方法。确保链接 AVFoundation 框架并导入将使用它的标头。
#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);
您感兴趣的端口类型是“BluetoothHFP”。 portName 属性通常是您要向用户显示的制造商/型号。 (我用非 LE 蓝牙摩托罗拉恐龙检查过这个,它可以工作)
由于 last in wins 规则,您需要注意这两个通知(包括 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 版本 现已弃用”AudioSessionServices 类。此类是一个 C api,它允许您添加属性侦听器,而不是通知。
我将结束这篇笔记 - 你并不总是从系统中得到你想要的东西。有需要观察的中断处理通知和大量的错误检查。我认为这是一个非常好的问题,我希望这能阐明您正在努力实现的目标。
【讨论】:
我给你+1!我尝试了你问题的前半部分,我可以看到“input3 port type BluetoothHFP input3 port name LG HBM-230
”。我现在需要看看如何(以及是否可行)将 MPVolumeView
集成到我自己的应用程序中。然后我会接受。另外,我想知道我能为 pre-iOS 7 做些什么来代替“availableInputs
”。再次感谢!
很高兴您能看到您的 BT 外围设备。至于早期的 iOS 版本,请阅读我的编辑。它并不适合每个实现,但考虑到系统在解析音频路由时面临的潜在复杂性,我们开发人员得到的选择可能是相当有限的。感谢您的 +1 @MichaelDautermann
您好,我如何为 Objective c OS X 做到这一点?【参考方案2】:
斯威夫特版本
do
try AVAudioSession.sharedInstance().setCategory(.playAndRecord, options: .allowBluetooth)
try AVAudioSession.sharedInstance().setActive(true)
catch
let availableInputs = AVAudioSession.sharedInstance().availableInputs
【讨论】:
以上是关于如何在 iOS 中找到蓝牙音频设备的主要内容,如果未能解决你的问题,请参考以下文章