How to output app audio to bluetooth speakers?


#1

I just bought some cool new wireless speakers, and connected them to my iPhone via bluetooth. I then restarted my app, but was disappointed to find that it is still playing sound through the iPhone speakers, while other apps such as Spotify immediately switched to the new speaker. Is there some method in JUCE that can allow me to detect that some wireless audio device is available?


#2

Did you try to get a changeMessage from the AudioDeviceManager?
It should send a void ChangeListener::changeListenerCallback (ChangeBroadcaster* source), if I understand it correctly.
But maybe that feature is yet to come, I haven’t tested it…


#3

I’ve never heard of the change listener but I will check it out. Thanks. It sounds very useful and might solve another problem that I’ve had: if I start my app with headphones, then remove the headphones, my app keeps trying to send audio to the headphone jack so the app goes silent. My temporary solution had been to restart the audio device every time playback is started.


#4

Yes, that’s where I use the changeCallback as well:

void AuditionComponent::changeListenerCallback (ChangeBroadcaster* sender)
{
    if (sender == &devMan) {
        devMan.removeAudioCallback (player);
        devMan.addAudioCallback (player);
    }
}

devMan.addChangeListener (this);

This solves the condition, when the headphones are removed or added. The addAudioCallback picks the new default device for me. I am curious, if that works for BT devices as well…


#5

I’ve just tried this, and run into a complication. My class was a subclass of AudioAppComponent and therefore I use the parent class’ functions setAudioChannels() and shutdownAudio() which in turn call the removeAudioCallback() and addAudioCallback() functions. The player is a private member, so I cannot access it from my class and add/remove that audio callback directly. So, naturally, I tried running shutdownAudio and setAudioChannels from within the changeListenerCallback, and this caused the app to freeze because the callback kept triggering itself recursively.

Interestingly enough however, the headphone issue seems to have disappeared entirely. I wonder if perhaps the JUCE team fixed it in a recent update. No luck yet on fixing the bluetooth issue tho


#6

Or perhaps the headphone issue only seems to have disappeared because I’m using an iPhone today, instead of my MacBook.


#7

Found the cause of the problem. It was because I had made a poor habit of always having my input channels initialised regardless of whether or not they were currently required. Since my bluetooth speaker has no inputs, it was only logical that the framework or OS or whoever would choose to default to the internal sound system rather than bluetooth


#8

Thanks for sharing the results. That explains some happenings I observed too.

Even though I think, it should be possible to keep using the internal microphone and output to the BT speakers. But I guess that requires then manual handling of the events…


#9

Yeah it would be good if you could continue to use the internal microphone, but it seems that on iOS, the operating system is treating the sound devices like a black box. I don’t see any way of distinguishing between internal and external sound devices. I’ve been looking into the underlying iOS code and it seems as though the OS just makes all the decisions for us. We tell it how many input and output channels we want, then it just gives us whatever it wants to give us.