cómo encontrar dispositivos de audio Bluetooth en iOS

De acuerdo, estoy trabajando en un proyecto divertido que tiene un obstáculo en el que necesito habilitar el soporte de audio Bluetooth para mi aplicación de iOS.

El obstáculo en el que estoy es que simplemente no puedo comenzar a obtener una lista de dispositivos de audio Bluetooth conectados. A pesar de que mi iPhone 5S reconoce mi auricular (un ~ 3 – 4 años LG HBM-230 , para ser precisos) y reproduce audio a través de él para llamadas telefónicas, AMBOS Accesorios Externos y CoreBluetooth no me dan nada útil cuando consulto ambos.

Estoy basando mi propio código en las preguntas y respuestas que encontré para los frameworks CoreBluetooth y External Accessory .

Cuando mi código simplemente intenta ” scanForPeripheralsWithServices:nil para scanForPeripheralsWithServices:nil ” para cualquier dispositivo con Bluetooth que los ajustes-> Bluetooth dicen que son visibles y están conectados, el código siguiente simplemente NO tiene un solo CBCentralManagerStatePoweredOn más allá del mensaje ” CBCentralManagerStatePoweredOn ” en la consola.

Y esta línea en mi código (con una instancia válida de EAAccessoryManager)

 NSArray * connectedDevices = [self.eAAccessoryManager connectedAccessories]; 

también regresa con una matriz nil.

¿Qué podría estar haciendo mal?

Por cierto, he hecho este código disponible como un proyecto de 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 

Primero, deberá configurar la sesión de audio de su aplicación para permitir conexiones Bluetooth que admitan audio. Puede hacerlo en, por ejemplo, la aplicación delega: aplicación (BOOL): aplicación (UIApplication *) didFinishLaunchingWithOptions: (NSDictionary *) método launchOptions. Asegúrese de vincular el Marco de AVFoundation e importar en los encabezados que lo usarán.

 #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; } 

Cada aplicación tiene una sesión de audio singleton que puede configurar. La categoría y el modo de sesiones (en este ejemplo, no configuré el modo para que vuelva al modo predeterminado) declaro las intenciones de las aplicaciones sobre cómo desea que se maneje el enrutamiento de audio. Sigue una regla importante de último en victorias . Esto significa que si el usuario conecta un auricular o en este caso un dispositivo bluetooth que es un periférico manos libres (HFP), el sistema enrutará automáticamente el audio al auricular o al dispositivo bluetooth. Las acciones físicas de los usuarios se utilizan para determinar el enrutamiento de audio. Sin embargo, si desea darle al usuario una lista de rutas disponibles, Apple recomienda usar la clase MPVolumeView.

Un ejemplo para agregar MPVolumeView podría incluirse en el método viewDidLoad de subclases UIViewController.

 #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]; 

A partir de iOS 7 puedes obtener todas las entradas como esta

 // 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); } 

El portType en el que estaría interesado es "BluetoothHFP". La propiedad portName es típicamente el fabricante / modelo que es lo que mostrarías al usuario. (Lo he comprobado con un dinosaurio Motorola que no es de LE y funciona)

Debido a la última regla de ganancias , deberá observar estas dos notificaciones (iOS 7 incluido). Uno para manejar interrupciones (como llamadas telefónicas o una alarma) y el segundo para recibir notificaciones de cambios de ruta. Las notificaciones de cambio de ruta son las relacionadas con esta pregunta.

 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(myInterruptionSelector:) name:AVAudioSessionInterruptionNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(myRouteChangeSelector:) name:AVAudioSessionRouteChangeNotification object:nil]; 

Para iOS 6.x, puede leer la propiedad currentRoute de AVAudioSession dentro del selector myRouteChange: para obtener la nueva ruta, ya que se llamará cuando se conecte un auricular o un dispositivo bluetooth.

 - (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); } 

Cualquier versión de iOS <6.0 necesitará la clase AudioSessionServices ' ahora en desuso '. Esta clase es una API que, en lugar de notificaciones, le permite agregar detectores de propiedad.

Terminaré con esta nota: NO SIEMPRE OBTENDRAS LO QUE QUIERES del sistema. Hay notificaciones de interrupción que se deben observar y se necesita mucha comprobación de errores. Creo que esta es una muy buena pregunta y espero que arroje algo de luz sobre qué es lo que estás tratando de lograr.

Intereting Posts