簡體   English   中英

如何在 iOS 中查找藍牙音頻設備

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM