From a789da00ad328495f7d6612253d22af3ae7c44b2 Mon Sep 17 00:00:00 2001 From: daniel martinez lozano <161240228+Zum0DePapaya@users.noreply.github.com> Date: Mon, 10 Aug 2026 17:31:53 +0200 Subject: [PATCH] Declare AAudioStreamBuilder_setUsage weak so the module loads on API 26/27 The module is built at API 26 and blanks __INTRODUCED_IN so the API 28 entry point compiles. That also strips the availability annotation that would have made the reference weak, leaving a strong undefined symbol. The NDK links with -z now (the module carries DF_BIND_NOW and DF_1_NOW), so the dynamic linker resolves every undefined symbol at dlopen() time, before any module code runs. The android_get_device_api_level() >= 28 guard therefore never gets the chance to protect anything: on an API 26/27 device libaaudio.so has no such symbol, dlopen fails, and since the daemon runs with --fail=false it comes up with no sink at all. Redeclaring the function weak lets the linker leave the address NULL instead of failing the load, which is what makes the guard meaningful. Verified with llvm-readelf: the symbol goes from GLOBAL UND to WEAK UND, exports and 16 KB segment alignment are unchanged. Co-Authored-By: Claude Opus 5 --- pulseaudio-module/module-aaudio-sink.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/pulseaudio-module/module-aaudio-sink.c b/pulseaudio-module/module-aaudio-sink.c index 2cb417d..950c953 100755 --- a/pulseaudio-module/module-aaudio-sink.c +++ b/pulseaudio-module/module-aaudio-sink.c @@ -32,6 +32,19 @@ #undef __INTRODUCED_IN #define __INTRODUCED_IN(api_level) #include + +/* AAudioStreamBuilder_setUsage was introduced in API 28, but blanking __INTRODUCED_IN + above also strips the availability annotation that would otherwise have made the + reference weak, so it ends up a *strong* undefined symbol. The NDK links this module + with -z now, so the dynamic linker resolves every undefined symbol at dlopen() time -- + before any code in this file, including the API level check below, gets a chance to + run. On an API 26/27 device libaaudio.so does not export it, so the module fails to + load outright; because the daemon runs with --fail=false that surfaces as "no audio" + rather than an error. Redeclaring it weak lets the linker leave the address NULL + instead of failing the load, so the guard below can do its job. */ +extern __attribute__((weak)) void AAudioStreamBuilder_setUsage(AAudioStreamBuilder *builder, + aaudio_usage_t usage); + #include #define LOG_TAG "GN-PulseAudioSink" @@ -166,7 +179,7 @@ static int pa_create_aaudio_stream(struct userdata *u) { } if (u->low_latency) { - if (android_get_device_api_level() >= 28) { + if (AAudioStreamBuilder_setUsage && android_get_device_api_level() >= 28) { AAudioStreamBuilder_setUsage(u->builder, AAUDIO_USAGE_GAME); } AAudioStreamBuilder_setSharingMode(u->builder, AAUDIO_SHARING_MODE_SHARED);