0

I'm working on a voice calling app for iOS in Swift and I need to enable auto detection and auto connection of wireless(bluetooth) headsets/earpeaces.

I'm using AVAudioSession RouteChangeReason but it's not detecting when airpods or some other wireless headset is connected via bluetooth. After connecting the device I can even see it in Bluetooth settings that it's connected, but the device is not listed in MPVolumeView as you can see in the screenshoot.

I've been looking for an answer on how to work this out all over the internet and even though there are a lot of similar questions here on StackOverFlow none of them is specifically related to my case so please give me a light on how to solve this.

marcoswmv
  • 21
  • 7
  • You likely have an AVAudioSession running that forbids the device. Have you activated an AVAudioSession? What options did you pass? (It's not quite clear what you mean here by "auto detection and auto connection." Most things in that space are impossible for non-MFi devices, and somewhat limited even for MFi devices.) – Rob Napier Dec 03 '20 at 20:05
  • @RobNapier Yes, I did. With options `[.allowBluetooth, .allowBluetoothA2DP, .allowAirPlay]`. I mean't to say that I need the bluetooth headsets to connect to my app when I connect them to the iPhone. – marcoswmv Dec 03 '20 at 20:14
  • What category are you using? Those options are somewhat contradictory and can't apply to all categories. The "allow" in the setting names is misleading. You may think you're making things more flexible, but that's not how AVAudioSession works. If you pass options that don't make sense, you can exclude input sources you meant to allow. (Did I really mess up my app by making this mistake? Yes I did.) – Rob Napier Dec 03 '20 at 20:48
  • @RobNapier i’m using playAndRecord – marcoswmv Dec 03 '20 at 23:14

2 Answers2

2

I just read the code and finally found what was wrong with it. The problem was that I was setting the category more than once so for some reason this was causing wireless headset/earpeace to not connect directly to the app.

marcoswmv
  • 21
  • 7
  • I've been trying to get WebRTC to work nicely with bluetooth headsets in my app and this was the thing that fixed it for me too - removing all my code that set the category. I'd be very interested to know _why_ setting the category then seems to break all further attempts at enabling bluetooth headsets. But for now, thanks! – Mete Jul 26 '21 at 09:43
1

.allowBluetoothA2DP is not valid for playAndRecord. You can't record over A2DP. Remove that one. Note that when you do this, if the user is listening to music, the quality is going to drop dramatically (it's possible that AirPods have a proprietary work around for that; I haven't played with them in this mode). In order to record over Bluetooth you have to use HFP, which provides basically "telephone" quality audio.

Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • Thanks. But that isn't related to my problem which is airpods not connecting to the app even thought they are connected to the iPhone via Bluetooth. – marcoswmv Dec 04 '20 at 15:07
  • Have you tried removing the option? The "current route" is part of your audio session, not the phone. The fact that the device is connected over bluetooth does not mean it is valid for your audio session, and so will not be selected. Just being connected does not make a device a valid route or the current route (you can have many bluetooth audio devices connected at the same time). If you deactivate the audio route, I expect the AirPods will show up again, if I understand what you've done here. – Rob Napier Dec 04 '20 at 15:33
  • Yes, I tried and no success. I understand but even if it won't automatically connect it should at least be available or listed on currentRoute.outputs, shouldn't it? – marcoswmv Dec 04 '20 at 16:01
  • Not if it's not a valid route for the current audio session. I'm not quite clear why "динамик" is showing up separately from "iPhone." That's just the built-in speaker, right? (But only getting the built-in speaker as a route is exactly the behavior you'll see when your options are not valid. I would also remove `.allowAirPlay` and *only* pass `.allowBluetooth` (which really means HFP, not Bluetooth). If that works, build up from there. I haven't played with AirPlay, but this is exactly the symptom I saw in my app when passing both `.allowBluetooth` and `.allowBluetoothA2DP`. – Rob Napier Dec 04 '20 at 16:15
  • Yes, динамик means speaker. And passing only .allowBluetooth didn't work. I'd like also to ask if I should set some AVAudioSession mode? – marcoswmv Dec 04 '20 at 16:37
  • No, `default` should be a fine mode. For example, I would expect this to detect bluetooth devices including AirPods: `try! audioSession.setCategory(.playAndRecord, mode: .default, options: [.allowBluetooth]); try! audioSession.setActive(true)`. If you kill your app, are you currently able to hear music through your AirPods? Do you lose them when you activate your audio session? – Rob Napier Dec 04 '20 at 16:55
  • (Generally for this kind of work, I highly recommend building a tiny test app that just does this one thing, to make sure you have no other weird things going on in your app, like some other piece of code manipulating the AVAudioSession. And then simplifying further and further back. For example, starting with just `.play` rather than `.playAndRecord` and building up until you find what thing you've misunderstood, because there's always something about AVAudioSession that we all misunderstand :D) When you have a very, very simple program, it'll be easier to show everything here. – Rob Napier Dec 04 '20 at 16:57
  • When you have that, it'll also be helpful if you write up precisely what your test case is. What you mean by "connected" and showing how you know it's connected (there are several ways that Bluetooth connects: Classic/Audio, BLE, MFi/iAP2, and they mean really different things even though they're all "Bluetooth") Comparing your app to VoiceMemo is also very helpful. Does VoiceMemo see it, but you don't? – Rob Napier Dec 04 '20 at 17:00
  • 2
    Well, I'm also using WebRTC. It's actually rtcAudioSession that I'm setting using AVAudioSession. But thanks for the advise, I actually was already thinking about doing something like that. – marcoswmv Dec 04 '20 at 17:23