Android: Use OpenSL ES for audio on TVs, add audio API and MMAP settings

An Android 11 TV played nothing over a Bluetooth headset since the switch
to Oboe, while its speakers worked. Testing on it showed AAudio with MMAP
is silent there and AAudio without MMAP works, as does OpenSL ES (also
when the headset is connected mid-game), whatever the stream usage. MMAP
should never be used for a Bluetooth route, so it's a firmware bug.

Audio settings get an Audio API choice and a Low-latency audio (MMAP)
checkbox, with hints, so other devices with the same kind of bug can be
worked around. The API defaults to OpenSL ES on TVs and before Android
8.1, where the choice isn't offered, and AAudio elsewhere. Changing them
reopens the streams right away. System Information shows the output
stream that got opened (API, MMAP or not, rate, buffers, device) and any
audio error.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Henrik RydgårdandClaude Opus 5.5 committed 2026-10-24 23:58:42 +02:00
1 parent b438655479
commit a5c90b61df
8 files changed
+129 -12

No files matched your search

+16
View File
@@ -879,9 +879,25 @@ bool DefaultAudioMixWithOthers() {
#endif
}
static int DefaultAndroidAudioApi() {
// AAudio isn't stable before Android 8.1 (API 27), Oboe's own cutoff.
if (System_GetPropertyInt(SYSPROP_SYSTEMVERSION) < 27) {
return (int)AndroidAudioApi::OPENSLES;
}
// An Android 11 TV played nothing over Bluetooth when AAudio used MMAP, which should never
// be used for a Bluetooth route. OpenSL ES worked, also when the headset was connected mid-game.
// Latency on a TV is mostly the TV's own anyway.
if (System_GetPropertyInt(SYSPROP_DEVICE_TYPE) == DEVICE_TYPE_TV) {
return (int)AndroidAudioApi::OPENSLES;
}
return (int)AndroidAudioApi::AAUDIO;
}
static constexpr ConfigSetting soundSettings[] = {
ConfigSetting("Enable", SETTING(g_Config, bEnableSound), true, CfgFlag::PER_GAME),
ConfigSetting("ExtraAudioBuffering", SETTING(g_Config, bExtraAudioBuffering), false, CfgFlag::DEFAULT),
ConfigSetting("AndroidAudioBackend", SETTING(g_Config, iAndroidAudioApi), &DefaultAndroidAudioApi, CfgFlag::DEFAULT),
ConfigSetting("AndroidAudioMMap", SETTING(g_Config, bAndroidAudioMMap), true, CfgFlag::DEFAULT),
ConfigSetting("AudioBufferSize", SETTING(g_Config, iSDLAudioBufferSize), 256, CfgFlag::DEFAULT),
ConfigSetting("FillAudioGaps", SETTING(g_Config, bFillAudioGaps), true, CfgFlag::DEFAULT),