From 2503d34724bdde6a9658d4e6ec7cf5c065045d94 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Wed, 1 Apr 2026 20:38:27 -0400 Subject: [PATCH] aaudio: Respect SDL_HINT_AUDIO_DEVICE_STREAM_ROLE hint. Fixes #15299. (cherry picked from commit 4d17b99d0a1c33c5257063b098f883c669ade40b) --- include/SDL3/SDL_hints.h | 5 +++++ src/audio/aaudio/SDL_aaudio.c | 24 ++++++++++++++++++++++++ src/audio/aaudio/SDL_aaudiofuncs.h | 2 +- 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/include/SDL3/SDL_hints.h b/include/SDL3/SDL_hints.h index 76efb9164e..44454f5909 100644 --- a/include/SDL3/SDL_hints.h +++ b/include/SDL3/SDL_hints.h @@ -402,6 +402,11 @@ extern "C" { * - "Movie" - Music or sound with dialog * - "Media" - Music or sound without dialog * + * Android's AAudio target supports this hint as of SDL 3.4.4. Android does + * not support the exact same options as WASAPI, but for portability, will + * attempt to map these same strings to the `aaudio_usage_t` constants. For + * example, "Movie" and "Media" will both map to `AAUDIO_USAGE_MEDIA`, etc. + * * If your application applies its own echo cancellation, gain control, and * noise reduction it should also set SDL_HINT_AUDIO_DEVICE_RAW_STREAM. * diff --git a/src/audio/aaudio/SDL_aaudio.c b/src/audio/aaudio/SDL_aaudio.c index bc0e7a285d..ea5e1c09a5 100644 --- a/src/audio/aaudio/SDL_aaudio.c +++ b/src/audio/aaudio/SDL_aaudio.c @@ -285,6 +285,28 @@ static void AAUDIO_CloseDevice(SDL_AudioDevice *device) } } +static void SetOptionalStreamUsage(AAudioStreamBuilder *builder) +{ + if (ctx.AAudioStreamBuilder_setUsage) { // optional API: requires Android 28 + const char *hint = SDL_GetHint(SDL_HINT_AUDIO_DEVICE_STREAM_ROLE); + if (hint) { + aaudio_usage_t usage = AAUDIO_USAGE_MEDIA; // covers most things, and is the system default. + if ((SDL_strcasecmp(hint, "Communications") == 0) || (SDL_strcasecmp(hint, "GameChat") == 0)) { + usage = AAUDIO_USAGE_VOICE_COMMUNICATION; + } else if (SDL_strcasecmp(hint, "Game") == 0) { + usage = AAUDIO_USAGE_GAME; + } + ctx.AAudioStreamBuilder_setUsage(builder, usage); + + // !!! FIXME: I _think_ this is okay with the current set of usages we support, but the docs + // !!! FIXME: say you need to dip down into Java to call android.app.Activity.setVolumeControlStream(usage) + // !!! FIXME: so the physical volume buttons control this stream, but that might be more for special cases + // !!! FIXME: like notification sounds, etc, and it's possible you _don't_ want to override this for those + // !!! FIXME: special cases, too! We'll revisit if there are bug reports. + } + } +} + static bool BuildAAudioStream(SDL_AudioDevice *device) { struct SDL_PrivateAudioData *hidden = device->hidden; @@ -343,6 +365,8 @@ static bool BuildAAudioStream(SDL_AudioDevice *device) SDL_Log("Low latency audio disabled"); } + SetOptionalStreamUsage(builder); + if (recording && ctx.AAudioStreamBuilder_setInputPreset) { // optional API: requires Android 28 // try to use a microphone that is for recording external audio. Otherwise Android might choose the mic used for talking // on the telephone when held to the user's ear, which is often not useful at any distance from the device. diff --git a/src/audio/aaudio/SDL_aaudiofuncs.h b/src/audio/aaudio/SDL_aaudiofuncs.h index 2cea7f68e1..6568c12b0f 100644 --- a/src/audio/aaudio/SDL_aaudiofuncs.h +++ b/src/audio/aaudio/SDL_aaudiofuncs.h @@ -37,7 +37,7 @@ SDL_PROC_UNUSED(void, AAudioStreamBuilder_setSharingMode, (AAudioStreamBuilder * SDL_PROC(void, AAudioStreamBuilder_setDirection, (AAudioStreamBuilder * builder, aaudio_direction_t direction)) SDL_PROC(void, AAudioStreamBuilder_setBufferCapacityInFrames, (AAudioStreamBuilder * builder, int32_t numFrames)) SDL_PROC(void, AAudioStreamBuilder_setPerformanceMode, (AAudioStreamBuilder * builder, aaudio_performance_mode_t mode)) -SDL_PROC_UNUSED(void, AAudioStreamBuilder_setUsage, (AAudioStreamBuilder * builder, aaudio_usage_t usage)) // API 28 +SDL_PROC_OPTIONAL(void, AAudioStreamBuilder_setUsage, (AAudioStreamBuilder * builder, aaudio_usage_t usage)) // API 28 SDL_PROC_UNUSED(void, AAudioStreamBuilder_setContentType, (AAudioStreamBuilder * builder, aaudio_content_type_t contentType)) // API 28 SDL_PROC_OPTIONAL(void, AAudioStreamBuilder_setInputPreset, (AAudioStreamBuilder * builder, aaudio_input_preset_t inputPreset)) // API 28 SDL_PROC_UNUSED(void, AAudioStreamBuilder_setAllowedCapturePolicy, (AAudioStreamBuilder * builder, aaudio_allowed_capture_policy_t capturePolicy)) // API 29