Closed sabby closed 2 years ago
This is a good question... miniaudio certainly only supports default devices on iOS, simply because I don't actually know how to enumerate them properly (happy to look into this if anyone out there has some advice on this). However, since other applications route to your bluetooth headphones by default I would expect miniaudio to exhibit the same behaviour. I'm suspecting you're correct regarding overrideOutputAudioPort
. This was motivated by this bug report, but the thing is I'm worried that if I remove that I'll end up reintroducing that bug. I don't have bluetooth speakers to test with, but if I was to play around with that AVAudioSessionCategoryOptionAllowBluetoothA2DP
option would you be up for testing that out for me?
Yes. We have a device in-house that we were able to reproduce this on, so we can review any proposed changes as well.
OK, experimental fix is in the dev branch. Here's the commit: f560f4793d4910df757aa0761ff4a454f2f5119e
I've added support for explicitly disabling this feature, but at the moment it's the default. Do you think it makes sense to leave this enabled by default, or should I swap it around?
I won't have access to the bluetooth device until Monday (PST). I'll test it at that time.
I think as wireless headphones continue to become standard (especially on iOS), this will probably be the desired behavior for playback devices. As it isn't supported with full duplex or recording, it will be turned off by default for those use cases.
I've tested this against the bluetooth headset (we have a Beats3 Solo) and there is no change in behavior.
I might try poking around with the source enumeration and changes if I have some time.
Darn, that's annoying. I don't actually know what else to do to fix this one... Do you think perhaps trying the AVAudioSessionCategoryOptionAllowBluetooth option as well?
I think it is related to the AVAudioSessionCategoryOptionDefaultToSpeaker
setting as it is similar to the behavior for regular headphones. I do want to double check what happens when I comment this setting out, but unfortunately I don't have access to the device again until tomorrow.
It seems like issue #102 would be better to resolve first as it may lead us closer to figuring this one out.
As on the regular headphones, sound does play through the Bluetooth headphones (left-only) when I have that 'AVAudioSessionCategoryOptionDefaultToSpeaker' section commented out.
Just moving this comment over here as it seems to be the root cause of this issue, which implies the fix is to use AVAudioSessionCategoryMultiRoute
and handle route changes
I took a deeper look at the Audio Session Categories and played around with some things. I'm not entirely sure how these will affect the rest of the library, but when I used AVAudioSessionCategoryPlayback the sound came through the speakers without headphones plugged in and headphones with them plugged in (both Bluetooth and regular, but still left-only). After that I tried AVAudioSessionCategoryMultiRoute and successfully got the audio coming out of the speaker, regular headphones on the iPad, but not the bluetooth headphones. (I would assume that there is a default routing issue here.)
As our app requires playback only, I will (for now) be using the AVAudioSessionCategoryPlayback
category and calling it a day.
If you do happen to implement the route change and need some testing on it, I do have access to a few iOS devices and various audio devices that I can test on.
Thanks for the info on this. I'm probably going to make all of this configurable through the ma_device_config
object. I'll definitely be adding support for automatic stream routing, but I've just not had a chance to properly sit down and get it done. Hopefully soon.
OK, I've added support for configuring the session category via the ma_context_config
object. This should hopefully be a cleaner solution than having a custom version of miniaudio lying around. Largely untested so far.
One thing with this is that I removed that AVAudioSessionCategoryOptionAllowBluetoothA2DP flag, so if you want to use that you'll need to explicitly specify it in the ma_context_config.coreaudio.sessionCategoryOptions
property.
Haven't yet got to the automatic stream routing stuff.
I've added some early work on improving automatic stream routing for iOS: https://github.com/dr-soft/miniaudio/commit/a59682b97abc924a165d04b777e3b5bd522c4da9. This is completely untested (I don't have access to real hardware at the moment).
I've gone ahead and pushed these changes to the master branch and bumped the version. I'm going to go ahead and close this one, but feel free to reopen if it's not working for you.
Going to be probably a week or two before I can get to this, but I will review and post when I am able to.
Hello @mackron!
It's still not working with Bluetooth headphones.
I tried to set session category options to
AVAudioSessionCategoryOptionDefaultToSpeaker | AVAudioSessionCategoryOptionAllowBluetoothA2DP
and it seems to be working well.
P.S.
If I add AVAudioSessionCategoryOptionAllowBluetooth
option, it created only one playback channel instead of the requested two.
I'll update with what I'm experiencing since this issue is resurfacing. I was looking to get a compact working example to show the issues that I'm having, but only managed to get to the update last month and have not had the time.
I initialize the coreaudio.sessionCategory=ma_ios_session_category_playback
before calling ma_context_init
. At this point, regardless of what sound output is default on the device (headphones/bluetooth/speaker), it works and I get the appropriate number of channels of output. However. if I unplug/replug the headphones or similarly un/reattach the bluetooth, I only get one channel at that point.
It seems like either there is an issue where the channels is not set correctly in the initialization while using the default device or in the handle_route_change
. I wasn't quite able to track the changes to see why I was only getting a single audio channel, but I did notice that you weren't settng the number of channels during initialization like you were during a route change. Thus, my hack to remedy the issue was to simply comment out the lines where the channels were being set in the handle_route_change
miniaudio.h:24381
if (m_pDevice->type == ma_device_type_capture || m_pDevice->type == ma_device_type_duplex) {
//m_pDevice->capture.channels = (ma_uint32)pSession.inputNumberOfChannels;
ma_device__post_init_setup(m_pDevice, ma_device_type_capture);
}
if (m_pDevice->type == ma_device_type_playback || m_pDevice->type == ma_device_type_duplex) {
//m_pDevice->playback.channels = (ma_uint32)pSession.outputNumberOfChannels;
ma_device__post_init_setup(m_pDevice, ma_device_type_playback);
It seemed to work for my purposes, but I'm only using playback and can't speak to any additional; possible side effects from this.
I've gone ahead and pushed a potential fix for the routing issue to the dev branch. You able to give that a go? Commit: https://github.com/mackron/miniaudio/commit/5a8c88d129d0db6a7cff9482d59b696534a2b534
@BlackMATov You can instead do something like this so that you don't need to modify miniaudio directly:
ma_context_config.coreaudio.sessionCategoryOptions = ma_ios_session_category_option_default_to_speaker | ma_ios_session_category_option_allow_bluetooth_a2dp;
You can instead do something like this so that you don't need to modify miniaudio directly:
I have started using ma_context_config, and all is good now. Thank you!
I was able to get back to this to test this change out. It doesn't work. It actually stops sound from playing/finishing after a route change.
Let me know if there is any sort of debugging that would help sort this. I do have some time available to assist on this.
So it played audio (albeit with an incorrect channel count) before my last change, but then stopped working after my change? Strange. All I did was changed channelCount
to internalChannelCount
, which I still believe is correct. Unfortunately I don't have real hardware to test on (neither an iPhone/iPad nor a bluetooth headset) so it's hard for me to diagnose this one. In that code you posted earlier, if you put a breakpoint on the ma_device__post_init_setup()
line, what is the value of pSession.input/outputNumberOfChannels
?
So when I plug in/attach headphones (either Bluetooth or regular) I see these values:
pSession.inputNumberOfChannels: 1
pSession.outputNumberOfChannels: 2
Without headphones (just speaker) I see
pSession.inputNumberOfChannels: 1
pSession.outputNumberOfChannels: 1
The playback.internalChannels
value at the begining of the route change is similarly 1 for speakers and 2 for headphones before the assignment happens depending on what is attached when miniaudio is initialized.
Also, regardless of which device is attached initially, once I unplug it doesn't work, but it does when I plug it back in. Going from 2->1 channels causes the audio to speed up. Going from 1->2 creates a low pitched buzzing noise.
Sorry for the delay on this. Can you post your device initialization code, including the config? I need to see how you're setting the channel count. Also, are you able to run with #define MA_DEBUG_OUTPUT
just above your miniaudio implementation and post the output after doing the device switches? You should see some messages about the route change happening. I need to see the order of operations and the channel counts at each stage.
Initialization code is
ma_context_config cfg = ma_context_config_init();
cfg.logCallback = log_callback;
cfg.coreaudio.sessionCategory = ma_ios_session_category_playback;
ma_context_init(nullptr, 0, &cfg, &maCtx);
ma_device_config deviceConfig;
deviceConfig = ma_device_config_init(ma_device_type_playback);
deviceConfig.pUserData = nullptr;
deviceConfig.playback.format = ma_format_f32;
deviceConfig.playback.channels = 2;
deviceConfig.sampleRate = 44100;
deviceConfig.dataCallback = data_callback;
pDevice = new ma_device;
if (ma_device_init(&maCtx, &deviceConfig, _mxr.pDevice) != MA_SUCCESS) {
delete pDevice;
pDevice = nullptr;
}
return pDevice;
So I'm not seeing much in terms of the debugging, but here is the unique log statements around plug/unplug:
Attempting to initialize CoreAudio backend...
[miniaudio] Endian: LE
[miniaudio] SSE2: NO
[miniaudio] AVX2: NO
[miniaudio] AVX512F: NO
[miniaudio] NEON: NO
INFO: Output Callback: busNumber=0, frameCount=1024, mNumberBuffers=1
frameCount=1024, mNumberChannels=1, mDataByteSize=4096
[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonNewDeviceAvailable
INFO: Output Callback: busNumber=0, frameCount=1024, mNumberBuffers=1
...
INFO: Output Callback: busNumber=0, frameCount=1024, mNumberBuffers=1
[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonOldDeviceUnavailable
INFO: Output Callback: busNumber=0, frameCount=1024, mNumberBuffers=1
frameCount=1024, mNumberChannels=1, mDataByteSize=4096
Let me know if you need anything else.
Thanks for posting that. I should have clarified in my previous message - could you run that from the dev branch? I had an extra printf()
in there to print the input and output channel counts at the time of the route change. Sorry about that. I've taken the time to explicitly restart the device as well in the route change handler. No idea if this'll fix anything (probably not).
Also, after the route change, could you post a few of the INFO: Output Callback
logs immediately after? I'm wondering if that mNumberChannels=1
part is inconsistent with the channel count reported by the route change handler and is therefore causing it to break.
Also, you were saying that playback stops working completely when unplugging the device - is the data callback getting fired in this case?
Ok. I got the latest from dev. Here is the applicable log statements going from a state of unplugged to plugged to unplugged:
[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonNewDeviceAvailable
[Core Audio] Changing Route. inputNumberChannels=1; outputNumberOfChannels=2
[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonOldDeviceUnavailable
[Core Audio] Changing Route. inputNumberChannels=1; outputNumberOfChannels=1
I put a printf in my data_callback function to see exactly what is happening there. If I have headphones plugged in to start and then unplug, the audio continues but at a higher frequency and the data callback continues to be called. If I have no headphones plugged to start and then plug them in, the data_callback stops firing, though the audio buzzes as it continues to loop over what is in the buffer and I continue to see the Output Callback in the logger.
OK, I have no idea what's going on. I don't have the necessary hardware to test this so it's going to have to be left to the community to diagnose and debug. I'm not willing to invest money on hardware, nor time going back and forth using trial and error. If anybody in the community sees this issue and wants to submit a pull request I'm happy to consider it.
Sorry to resurrect this, but we've been very happily using MiniAudio for our project, but alas no one in the team thought to test with bluetooth headphones until we went into closed beta whereupon we've suddenly been bombarded with users complaining about headphone issues, triggering a minor crisis. Of course, I fully understand the sentiments above, if you haven't got the hardware, really not a lot to be done, but I thought I'd report in for the record.
I've now tested it myself, and I'm seeing the symptoms reported most recently above, that is to say it is fine starting with headphones or speaker, but when we change:
speaker -> headphones = buzzing, like the buffer's stuck headphones -> speaker = glitchy, like it's playing each sample with a delay between
After a bit of trial and error, it seems that ma_ios_session_category_playback
with no options seems to work just as well / badly as anything else, so that's what we're using.
I've started digging into the route switching stuff for any clues as to what's happening since it seemed likely that it'd be something to with properties changing when switching devices, and after a few hours of increasingly desperate printf-ing I just commented this out altogether:
if (m_pDevice->type == ma_device_type_playback || m_pDevice->type == ma_device_type_duplex) {
//m_pDevice->playback.internalChannels = (ma_uint32)pSession.outputNumberOfChannels;
//m_pDevice->playback.internalSampleRate = (ma_uint32)pSession.sampleRate;
//ma_device__post_init_setup(m_pDevice, ma_device_type_playback);
}
...and actually found that in my particular test case (iPhone with AirPods, sample rate remains at 48000, channels 1->2) that actually makes everything work fine. The headphones are even in stereo, goodness only knows why.
Of course, I wouldn't rely on this as a "fix", but I wonder if it might ring any bells as to what we're dealing with here? Given that I haven't removed the ma_device_stop
and ma_device_start
calls in handle_route_change
I can only assume that something is happening in ma_device__post_init_setup
.
I'll start chopping my way through tomorrow that, but if anything springs to mind etc. etc.
I'm happy enough to temporarily comment out that ma_device__post_init_setup()
call just to get you going and to get it at least somewhat working, but like you said, that doesn't feel like the right final solution to me. That function is where the data converter is initialized which is used to convert the data the caller specified in the device config to the device's internal native format as specified by the backend (and vice versa for capture).
When you can hear sound coming from your stereo speaker, I wonder if it's still taking a mono stream as input, but Core Audio under the hood is just converting it to stereo. As in, I wonder if Core Audio saw that we first initialized the internal device as a mono device, but is now trying to be helpful by not changing any data buffer requirements so that the caller doesn't need to deal with a teardown/reinit? Just a random thought, could be wrong about that.
I've also had a user on Discord play around with this. Maybe this comment might help you?
Right this is weird. iOS reports the route change and miniaudio sees that there are 5 channels so says it's now getting 5 channels, but the AudioUnitRender function for the existing AudioUnit only wants a buffer with one channel and a capacity for one channel worth of data, but the next time you stop and start it then it wants a buffer with 5 channels worth of data. Is there an internal way to tear everything down and start again, or at least just the audiounits?
My response to that was that I don't have any existing infrastructure for tearing down and reinitializing the device in iOS.
Another question on this - in that same section of code, if you comment out the device stop/start functions, does that also cause things to continue to work?
Edit: I've pushed an update to the dev branch for you to try. It comments out that section you mentioned, but it also comments out the stop/restart parts as well. Probably worth giving that a quick test.
Yeah, I'm pretty sure (fuzzy - it was late!) I tried removing the stop / start and it resulted in no audio at all when the route changed.
Definitely the impression I'm getting is that CoreAudio is doing some ✨magic✨ and that somehow it isn't playing nice with you reconfiguring things yourself, eg. particular type of glitchiness I'm hearing when going from headphones to speaker kinda sounds to me that it's missing every other sample, which makes me think that its still expecting stereo data but not getting it (or something).
Anyway thanks so much for for the insights, feels like I'm on the right path and unless anything else blows up at work I'm going to spending today on this and as a first step will simply hack away at ma_device__post_init_setup
until I get a clearer understanding of what's going on.
OK, if upon testing my change, if you don't hear any audio I'll change it to only comment out the section you mentioned and leave the stop / restart in there. That seems really strange, though.
Yep, will check that change again properly to check, but I'm pretty sure that's what happened. I'll update after todays experiments!
Right! I had a couple more hours to try and investigate this. Firstly, you were absolutely right, you can remove the ma_device_stop
and ma_device_start
when ma_device__post_init_setup
is disabled and everything continues to function as expected.
Given that we know that only the channel count is changing when connecting my headphones, I tested removing just that and leaving the ma_device__post_init_setup
call in place:
if (m_pDevice->type == ma_device_type_playback || m_pDevice->type == ma_device_type_duplex) {
//m_pDevice->playback.internalChannels = (ma_uint32)pSession.outputNumberOfChannels;
m_pDevice->playback.internalSampleRate = (ma_uint32)pSession.sampleRate;
ma_device__post_init_setup(m_pDevice, ma_device_type_playback);
}
...and sure enough everything works as expected. So, yes, it does seem that it could be because it's converting for the new settings, but the AudioUnit still wants to consume data in the original format. I have no knowledge of CoreAudio so I hesitate to suggest this, but I did notice that in ma_device_init_internal__coreaudio
it uses AVAudioSession's properties to configure a AudioStreamBasicDescription
for the AudioUnit:
status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioUnitProperty_StreamFormat, formatScope, formatElement, &bestFormat, sizeof(bestFormat));
But since this this only appears to be called once, wouldn't that mean that the AudioUnit will not know to expect anything different from ma_on_output__coreaudio
callback, even though miniaudio has accounted for changes in the channel count or sample rate?
For what it's worth we don't use stereo effects for anything critical to our functionality, so with the "fix" from last night, I suspect this will no longer be a showstopper if QA on more devices goes ok. But I'd still like to get to the bottom of this!
Thanks a lot for testing that for me. Thinking about this a bit more, it doesn't really matter if Core Audio wants to keep the same data format that we originally requested because miniaudio actually has the same behaviour - the public-facing format is always whatever the user originally received when the device was first initialized, even after a route change. I'm pretty sure what we have now is a valid solution for iOS.
I'm going to release the change I made earlier in the next version which should hopefully be fairly soon - just waiting on confirmation for another bug fix (unrelated to this one) and then I'll get it out.
That's great, I'm glad we've sussed this out and your logic makes perfect sense. I've had the fix as I initially did it running in our project for a a week or so now and it seems to be behaving itself.
I'm going to go ahead and close this one again. We can reopen this if something comes up later on. Thanks for taking the time to test all that stuff.
Thanks for the help! We're in the process shipping a product using our version and so far it's proving pretty rock solid with testers. Once we're sure everything is good, I'll probably submit a pull request with callbacks for routing changes, since it's useful for mobile devices at the very least.
Hey folks,
First I'll say a huge thanks to you @mackron, this library is wonderful.
I stumbled onto this issue after noticing that the default playback configuration wasn't playing through a connected bluetooth device as expected, rather playing through the iOS device speakers. Specifically, the initialization code I was working with was the following:
ma_device_config deviceConfig;
ma_device* device = new ma_device();
deviceConfig = ma_device_config_init(ma_device_type_playback);
deviceConfig.playback.pDeviceID = NULL;
deviceConfig.playback.format = ma_format_f32;
deviceConfig.playback.channels = 2;
deviceConfig.sampleRate = 44100;
deviceConfig.dataCallback = data_callback;
deviceConfig.pUserData = deviceData.get();
result = ma_device_init(NULL, &deviceConfig, device);
if (result != MA_SUCCESS) {
deviceData.reset();
delete device;
return;
}
This is the code that led to the issue above: playing through the device speakers even when a bluetooth device was connected. After reading through the discussion here, I've updated my code as follows:
ma_context* context = new ma_context();
ma_context_config contextConfig = ma_context_config_init();
ma_device_config deviceConfig;
ma_device* device = new ma_device();
contextConfig.coreaudio.sessionCategory = ma_ios_session_category_playback;
// contextConfig.coreaudio.sessionCategoryOptions = ma_ios_session_category_option_default_to_speaker | ma_ios_session_category_option_allow_bluetooth | ma_ios_session_category_option_allow_bluetooth_a2dp;
if (MA_SUCCESS != ma_context_init(nullptr, 0, &contextConfig, context)) {
deviceData.reset();
delete context;
delete device;
return;
}
deviceConfig = ma_device_config_init(ma_device_type_playback);
deviceConfig.playback.pDeviceID = NULL;
deviceConfig.playback.format = ma_format_f32;
deviceConfig.playback.channels = 2;
deviceConfig.sampleRate = 44100;
deviceConfig.dataCallback = data_callback;
deviceConfig.pUserData = deviceData.get();
result = ma_device_init(context, &deviceConfig, device);
if (result != MA_SUCCESS) {
deviceData.reset();
delete context;
delete device;
return;
}
With this code, I'm finding the expected behavior: my app will pick the expected default device (bluetooth if connected, else play through device speaker). My app also handles route changes well; if I connect to bluetooth, play sound, then turn off the bluetooth device, my app will correctly re-route and start playing through its own speakers. If I then turn the bluetooth device back on, reconnect, my app updates and starts outputting to bluetooth. This all works great.
The reason I'm chiming in here then is twofold: first, is my above fix correct? And second, notice that in my working code, I've commented out the assignment to sessionCategoryOptions
. If I uncomment that line, audio output just doesn't work at all (and I've tried various assignments to that option). I only stumbled onto this fix from @jskuse's comment above, and I'm happy to report it works when commented out, but that seems odd.
I'd appreciate any new insights if you have them. Otherwise I'll just leave this here in case it's helpful to anybody else finding this issue.
Thanks
To be honest with you, I'm not entirely sure what each of those options do. They're options that are available in Core Audio and I just expose them via miniaudio's config system in case it ends up being useful. Those options were implemented in response to this bug report from memory.
Indeed, my preferred default behaviour would be what you're expecting (your second code snippet) - it should automatically "Just Work" with whatever your default device is. I looked at the logic for when the ma_ios_session_category_default
option is used (this is the default when you don't specify any option as in your first example) and it's a bit strange. I've pushed a change to the dev branch - does that fix your first example to work as expected?
We're still using our version of miniaudio with my first stab at implementation of the routing behaviour, but I can confirm it's been behaving itself on the app store with pretty heavy usage for about 6 months now.
To address your direct question, I've just had a search through the code and and it doesn't look like we set sessionCategoryOptions
(and thus AVAudioSessionCategoryOptions
) to anything. Which (you'd think) means that it'd be set to 0
when assigned in miniaudio's call to [pAudioSession setCategory: withOptions:]
, which isn't in the enumeration, but seems harmless enough.
Thanks @mackron @jskuse.
I briefly looked at the code change you pushed, that change makes sense to me, but I've updated from v0.11.9 locally to the latest on dev and it seems that the change reverts to a behavior with no audio output at all. This is similar to what I was experiencing when I uncomment the // contextConfig.coreaudio.sessionCategoryOptions = ma_ios_session_category_option_default_to_speaker | ma_ios_session_category_option_allow_bluetooth | ma_ios_session_category_option_allow_bluetooth_a2dp;
line in my second snippet above.
@nick-thompson Darn, that's annoying! So the ma_ios_session_category_default
option will default to the AVAudioSessionCategoryPlayAndRecord
, and then fall back to AVAudioSessionCategoryPlayback
if that fails. I wonder if that's the issue? With your first code snippet, where you initialize the device without an explicit context, I wonder if it should default to ma_ios_session_category_playback
if a playback device is requested, ma_ios_session_category_record
for a capture device and ma_ios_session_category_play_and_record
for duplex? I've pushed this change to the dev branch as an experiment - are you able to give that a try when you get the chance? In that change, I've also reverted that other change I made earlier because I feel like that's a regression.
The annoying thing with this whole thing is that it's a global setting on the Core Audio side which doesn't map very well at all with miniaudio's "device" abstraction where you can have multiple of them. That's why I've made it an option at the context level. It just doesn't work well in the case where you aren't using an explicit context, but I really do want that to scenario to work properly. I'm not quite sure how to handle it to be honest. Out of curiosity, have you tried ma_ios_session_category_none
? In this case it doesn't even attempt to set the session category at all. I'm also questioning if that should be the default?
I think I have a related issue, and maybe it warrants a separate thread. Let me know.
My issue is that I only get ~1s of sound on iOS 16 when I start my game with my AirPods Pro already connected, then it fizzles out and everything becomes silent. If take my AirPods Pro out (and put them back in), essentially forcing a route change, then the sound starts working again. The same code works just fine when running on my Mac M1 running MacOS Monterey.
I've tried the dev
branch version of the library and the issue remains.
Initialization says:
INFO: [Core Audio]
INFO: Default Playback Device (Playback)
INFO: Format: 32-bit IEEE Floating Point -> 32-bit IEEE Floating Point
INFO: Channels: 2 -> 2
INFO: Sample Rate: 48000 -> 48000
INFO: Buffer Size: 512*3 (1536)
INFO: Conversion:
INFO: Pre Format Conversion: NO
INFO: Post Format Conversion: NO
INFO: Channel Routing: NO
INFO: Resampling: NO
INFO: Passthrough: YES
INFO: Channel Map In: {CHANNEL_FRONT_LEFT CHANNEL_FRONT_RIGHT}
INFO: Channel Map Out: {CHANNEL_FRONT_LEFT CHANNEL_FRONT_RIGHT}
Then taking the AirPods Pro out and putting them back in results in:
INFO: [Core Audio] Route Changed: AVAudioSessionRouteChangeReasonOldDeviceUnavailable
DEBUG: [Core Audio] Changing Route. inputNumberChannels=0; outputNumberOfChannels=2
INFO: [Core Audio] Route Changed: AVAudioSessionRouteChangeReasonNewDeviceAvailable
DEBUG: [Core Audio] Changing Route. inputNumberChannels=0; outputNumberOfChannels=2
After this, the sound works as expected.
Currently I'm using the ma_engine
API but inititalizing my own ma_context
so that I can set the iOS session category to ma_ios_session_category_ambient
. I've also tried ma_ios_session_category_playback
but it results in the same behavior.
I don't see any errors during intialization or when the sound "disappears" either. Perhaps there's a way to query the device state to debug the situation?
Also, by the way, thank you for an awesome library!
It appears that on iOS, a pair of Bluetooth headphones will be ignored while the library continues to play audio through the speaker.
This seems like it might be related to the overrideOutputAudioPort call in miniaudio.h:20411. However, it also seems like this might require a categoryOption of AVAudioSessionCategoryOptionAllowBluetoothA2DP.
Do you have any insight into this? In reading through the code it seemed to me like you are generally just dealing with a default audio device and not adjusting routing. The asynchronous nature of much of this framework (AVAudioSession) doesn't seem to match well with the device enumeration in many of the other back ends.