如何在iOS中找到蓝牙音频设备

8dtrkrch  于 2023-05-08  发布在  iOS
关注(0)|答案(2)|浏览(189)

好吧,我正在做一个有趣的项目,有一个障碍,我需要为我的iOS应用程序启用蓝牙音频支持。
我遇到的障碍是,我甚至不能开始获得连接的蓝牙音频设备的列表。尽管我的iPhone 5S可以识别我的耳机(确切地说,是一个3 - 4岁的LG HBM-230),并通过它播放音频来打电话,但当我查询这两个配件时,外部配件和CoreBluetooth都没有给我任何有用的东西。
我的代码基于我为CoreBluetoothExternal Accessory框架找到的问题和答案。
当我的代码只是尝试“scanForPeripheralsWithServices:nil”为 * 任何 * 蓝牙设备,其中设置->蓝牙说是可见的和连接,下面的代码只是没有来一个单一的打击以外的“CBCentralManagerStatePoweredOn”消息在控制台。
而我的代码中的这一行(带有有效的EAAccessoryManager示例)

NSArray * connectedDevices = [self.eAAccessoryManager connectedAccessories];

也返回一个nil数组。
我能做错什么?
B.T.W.,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
nwsw7zdq

nwsw7zdq1#

首先,您需要配置应用程序的音频会话,以允许支持音频的蓝牙连接。例如,您可以在应用程序委托-(BOOL)application:(UIApplication *)application 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];

从iOS7开始,你可以像这样获得所有输入

// 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蓝牙的摩托罗拉恐龙检查过了,它很好用)
由于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);
}

任何低于6.0的iOS版本都需要'now deprecated' AudioSessionServices类。这个类是一个C API,它允许你添加属性监听器,而不是通知。
我将在这张纸条上结束-你不总是从系统中得到你想要的。需要观察中断处理通知和大量的错误检查。我认为这是一个非常好的问题,我希望这能让你明白你想要实现什么。

njthzxwz

njthzxwz2#

Swift版本

do {
        try AVAudioSession.sharedInstance().setCategory(.playAndRecord, options: .allowBluetooth)
        try AVAudioSession.sharedInstance().setActive(true)
    } catch {}
let availableInputs = AVAudioSession.sharedInstance().availableInputs

相关问题