[英]iOS Audio Streaming only works for **SOME** bluetooth devices?
[英]how to find Bluetooth audio devices in iOS
好的,我正在开发一个有趣的项目,该项目有一个障碍,我需要为我的 iOS 应用程序启用蓝牙音频支持。
我遇到的障碍是我什至无法开始获取已连接蓝牙音频设备的列表。 虽然我的iPhone 5S认识我的耳机(A〜3 - 4岁的LG HBM-230 ,要准确),并通过它来进行电话呼叫播放音频,既有外部附件和CoreBluetooth是给我什么有用的,当我查询两者。
我将自己的代码基于为CoreBluetooth和外部附件框架找到的问题和答案。
当我的代码只是尝试“ 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
首先,您需要配置应用程序音频会话以允许支持音频的蓝牙连接。 例如,您可以在您的应用程序委托中执行此操作 - (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 蓝牙摩托罗拉恐龙检查过这个,它可以工作)
由于获胜规则的最后一个,您需要观察这两个通知(包括 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);
}
任何低于 6.0 的 iOS 版本都需要“现已弃用”的 AudioSessionServices 类。 此类是一个 C api,它允许您添加属性侦听器而不是通知。
我会在这个笔记上结束 - 你并不总是从系统中得到你想要的。 有中断处理通知需要观察并需要进行大量错误检查。 我认为这是一个非常好的问题,我希望这对您正在努力实现的目标有所了解。
迅捷版
do {
try AVAudioSession.sharedInstance().setCategory(.playAndRecord, options: .allowBluetooth)
try AVAudioSession.sharedInstance().setActive(true)
} catch {}
let availableInputs = AVAudioSession.sharedInstance().availableInputs
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.