From 9818dc1867eda2052865ac68dfcc9e8c1ae9204e Mon Sep 17 00:00:00 2001 From: duffyduck Date: Sat, 30 May 2026 20:09:55 +0200 Subject: [PATCH] =?UTF-8?q?fix(app):=20Spotify=20resumed=20wieder=20nach?= =?UTF-8?q?=20TTS=20=E2=80=94=20nudgeMediaResume=20mit=20TRANSIENT?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stefan-Bug-Report: ARIA liest Nachricht vor, Spotify pausiert korrekt, ARIA spricht durch — aber Spotify spielt danach NICHT automatisch weiter. Sollte mit GAIN_TRANSIENT auto-resumen, tut es aber bei manchen Spotify-Versionen/Geraeten nicht zuverlaessig. Hintergrund: alte kickReleaseMedia() mit AUDIOFOCUS_GAIN (permanent) war zu aggressiv (Spotify interpretierte als "user stoppte" = Auto-Resume kaputt). Wurde entfernt. Jetzt ist das Pendel andersrum zu weit: ohne Nudge keine Resume. Sanfter Mittelweg: nudgeMediaResume() mit GAIN_TRANSIENT statt GAIN-permanent. 100ms hold, abandon. Spotify bekommt Focus-Wechsel- Hint ohne "user stopped"-Effekt. audio.ts: nach AudioFocus.release() 50ms warten, dann nudgeMediaResume. AudioFocusModule.kt: neue Methode + alte kickReleaseMedia bleibt mit ⚠️-Markierung fuer andere Use-Cases. APK neu bauen erforderlich. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../java/com/ariacockpit/AudioFocusModule.kt | 56 +++++++++++++++++++ android/src/services/audio.ts | 8 +++ 2 files changed, 64 insertions(+) diff --git a/android/android/app/src/main/java/com/ariacockpit/AudioFocusModule.kt b/android/android/app/src/main/java/com/ariacockpit/AudioFocusModule.kt index 3b4b7af..103fce2 100644 --- a/android/android/app/src/main/java/com/ariacockpit/AudioFocusModule.kt +++ b/android/android/app/src/main/java/com/ariacockpit/AudioFocusModule.kt @@ -131,6 +131,58 @@ class AudioFocusModule(reactContext: ReactApplicationContext) : ReactContextBase promise.resolve(true) } + /** Sanfter Spotify-Resume-Nudge: kurz USAGE_MEDIA mit TRANSIENT + * requesten und sofort abandonen. Spotify bekommt das als + * Focus-Frei-Signal und resumed automatisch — aber weil TRANSIENT + * (nicht GAIN permanent), interpretiert Spotify das NICHT als + * "user stopped" was Auto-Resume verhindert haette. + * + * Hintergrund: ARIA spricht TTS via USAGE_ASSISTANT GAIN_TRANSIENT, + * Spotify pausiert. ARIA released. Spotify SOLLTE nach + * TRANSIENT-Loss + Abandon automatisch resumen, tut es aber bei + * manchen Versionen / Geraeten nicht zuverlaessig. Dieser Nudge + * triggert den Focus-Stack-Refresh ohne den Spotify-Auto-Stop-Bug + * der alten kickReleaseMedia mit GAIN permanent. + */ + @ReactMethod + fun nudgeMediaResume(promise: Promise) { + val am = audioManager() + if (am == null) { + promise.resolve(false) + return + } + Thread { + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val attrs = AudioAttributes.Builder() + .setUsage(AudioAttributes.USAGE_MEDIA) + .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) + .build() + val nudgeListener = AudioManager.OnAudioFocusChangeListener { /* ignorieren */ } + val nudgeReq = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT) + .setAudioAttributes(attrs) + .setOnAudioFocusChangeListener(nudgeListener) + .build() + am.requestAudioFocus(nudgeReq) + Thread.sleep(100) + am.abandonAudioFocusRequest(nudgeReq) + } else { + val nudgeListener = AudioManager.OnAudioFocusChangeListener { /* ignorieren */ } + @Suppress("DEPRECATION") + am.requestAudioFocus(nudgeListener, AudioManager.STREAM_MUSIC, + AudioManager.AUDIOFOCUS_GAIN_TRANSIENT) + Thread.sleep(100) + @Suppress("DEPRECATION") + am.abandonAudioFocus(nudgeListener) + } + Log.i(TAG, "nudgeMediaResume: USAGE_MEDIA TRANSIENT request+abandon (Spotify-Resume-Trigger)") + } catch (e: Exception) { + Log.w(TAG, "nudgeMediaResume failed: ${e.message}") + } + }.start() + promise.resolve(true) + } + /** Den USAGE_MEDIA-Focus-Stack im System aufmischen, damit Spotify/YouTube * resumen wenn ein anderer Player (z.B. react-native-sound) seinen Focus * nicht ordnungsgemaess released hat. Strategie: kurz selbst USAGE_MEDIA @@ -140,6 +192,10 @@ class AudioFocusModule(reactContext: ReactApplicationContext) : ReactContextBase * * Workaround fuer das react-native-sound-Bug: Sound.stop()/release() * laesst den AudioFocusRequest haengen. + * + * ⚠️ ACHTUNG: nutzt AUDIOFOCUS_GAIN (permanent), Spotify kann das als + * "user-action stopp" interpretieren und Auto-Resume verhindern. + * Fuer Spotify-Resume nach TTS lieber nudgeMediaResume() nehmen (sanfter). */ @ReactMethod fun kickReleaseMedia(promise: Promise) { diff --git a/android/src/services/audio.ts b/android/src/services/audio.ts index faa6693..db4f32c 100644 --- a/android/src/services/audio.ts +++ b/android/src/services/audio.ts @@ -40,6 +40,7 @@ const { AudioFocus, PcmStreamPlayer } = NativeModules as { AudioFocus?: { requestDuck: () => Promise; requestExclusive: () => Promise; + nudgeMediaResume: () => Promise; release: () => Promise; kickReleaseMedia: () => Promise; getMode?: () => Promise; @@ -332,6 +333,13 @@ class AudioService { } console.log('[Audio] AudioFocus jetzt released'); AudioFocus?.release().catch(() => {}); + // Spotify-Resume-Trigger: nach Abandon den USAGE_MEDIA-Focus-Stack + // mit kurzem TRANSIENT-Nudge aufmischen. Spotify resumed sonst bei + // manchen Versionen / Geraeten nicht zuverlaessig nach Auto-Loss. + // 50ms Delay damit das Abandon erst durch ist. + setTimeout(() => { + AudioFocus?.nudgeMediaResume().catch(() => {}); + }, 50); }, this.FOCUS_RELEASE_DELAY_MS); }