SDL icon indicating copy to clipboard operation
SDL copied to clipboard

[MacOS] SDL2 does not support bluetooth headsets when the microphone is active

Open OIRNOIR opened this issue 2 years ago • 4 comments

When using a bluetooth headphone device, the audio stops when the microphone is activated due to the headphones switching to a lower bitrate for bidirectional communications because bluetooth

OIRNOIR avatar Sep 03 '23 03:09 OIRNOIR

When a headset is connected where the mic is not in use, the bluetooth connection has a high bitrate because data is only going in one direction (from the computer to the audio device). However, when the device is being used as both an input and an output device, the connection is switched to a far lower bitrate to allow for bidirectional transmission (smh bluetooth)

OIRNOIR avatar Sep 03 '23 03:09 OIRNOIR

I'll verify this, but I think this got fixed by the audio subsystem rewrite.

icculus avatar Oct 06 '24 17:10 icculus

I don't use MacOS anymore so I can't verify this anymore. Thank you!

OIRNOIR avatar Oct 06 '24 18:10 OIRNOIR

Hi, I'm seeing the same issue; I created a simple test program with the preview-3.1.3 tag and it still happens. I'm using SDL_OpenAudioDeviceStream() which I assume is part of the audio subsystem rewrite?

darbyjohnston avatar Oct 08 '24 19:10 darbyjohnston

(Info dump incoming. You can skip this, this is for my own record here.)

Okay, so this drops to a lower quality when the microphone is in use at the system level, and is to be expected.

BUT: the output we're generating is significantly worse than I get from, say, Netflix playing a movie in a browser tab or Quicktime Player running some media. When this happens for those programs, it sounds less "rich" but otherwise sounds correct. Ours gets all crackly but isn't otherwise wrong (not corrupted, not sped up, etc), but the crackly sound is relentlessly awful, so that's a bug.

My test case is to start something playing (like test/loopwave), and then also start test/testaudiorecording, which opens the microphone by default and we don't have to touch it again, other than it existing. You can hear loopwave lose its mind, while other things don't.

Closing test/testaudiorecording will cause a brief dropout of audio in loopwave and then it comes back to sounding normal.

Other apps also get this dropout--unavoidable--and their audio sounds less "thin".

The thinness is a sample rate thing. Running system_profiler SPAudioDataType finds this for my bluetooth headphones...

          Default Output Device: Yes
          Default System Output Device: Yes
          Manufacturer: Apple Inc.
          Output Channels: 2
          Current SampleRate: 44100
          Transport: Bluetooth
          Output Source: Default

...and when the microphone is recording...

          Default Output Device: Yes
          Default System Output Device: Yes
          Manufacturer: Apple Inc.
          Output Channels: 1
          Current SampleRate: 16000
          Transport: Bluetooth
          Output Source: Default

...it drops from stereo, 44.1k sample rate, to mono, 16k sample rate.

My guess is Firefox and Quicktime Player aren't using an AudioQueue, but probably some complex AudioUnit stuff. However, I could detect the bluetooth profile change:

static void aqpropchanged(void *inUserData, AudioQueueRef inAQ, AudioQueuePropertyID inID)
{
    SDL_Log("AudioQueue property changed! '%c%c%c%c'", (char) ((inID >> 24) & 0xFF), (char) ((inID >> 16) & 0xFF), (char) ((inID >> 8) & 0xFF), (char) (inID & 0xFF));
}

and

AudioQueueAddPropertyListener(device->hidden->audioQueue, kAudioQueueProperty_StreamDescription, aqpropchanged, NULL);
AudioQueueAddPropertyListener(device->hidden->audioQueue, kAudioQueueDeviceProperty_SampleRate, aqpropchanged, NULL);
AudioQueueAddPropertyListener(device->hidden->audioQueue, kAudioQueueDeviceProperty_NumberChannels, aqpropchanged, NULL);

When the profile changes, the kAudioQueueProperty_StreamDescription does not change, but kAudioQueueDeviceProperty_SampleRate and kAudioQueueDeviceProperty_NumberChannels do. Might be a macOS bug that it fails to convert ongoing audio data to the new format correctly, or screws up the buffering, I don't know. A lot of this is unexplored territory on Google, afaict.

It's possible we can check for these property changes and adjust our own SDL_AudioStream's format and this might magically fix things? I'm going to experiment.

icculus avatar Jan 20 '25 21:01 icculus

Interesting: audio is bad if recording when loopwave is started, too, so it's not that the format changed on us.

icculus avatar Jan 20 '25 22:01 icculus

This is just as stupid as using more AudioQueueBuffers. I changed it from 2 to 4 and it works just fine without looking for device property changes.

I'm going to do some testing for latency, and if it's the number of buffers vs the buffer size, and we'll probably be done with this, then.

icculus avatar Jan 20 '25 22:01 icculus