Neues Native-Modul fuer die Streaming-STT-Pipeline:
PcmStreamRecorder.start() — oeffnet AudioRecord 16 kHz mono PCM,
VOICE_COMMUNICATION-Source mit AEC/NS,
PARTIAL_WAKE_LOCK gegen Doze
PcmStreamRecorder.stop() — sauber schliessen
Event "PcmStreamChunk" — {pcm: base64-s16le, seq, ts} alle 200ms
Event "PcmStreamError" — bei Capture-Crash
200ms-Chunks: gross genug fuer geringen RVS-Overhead, klein genug fuer
granulares Endpointing in der Whisper-Bridge.
Mic-Ownership: darf NICHT parallel zu OpenWakeWord laufen — beide
wollen AudioRecord. Coordination liegt bei audio.ts (stop OWW vor
start, start OWW nach stop), genau wie's bisher mit react-native-
audio-recorder-player gemacht wurde.
Stefan-Anforderung: GPS soll auch im Hintergrund liefern (Auto-Szenarien,
Handy-Tasche), aber NUR fuer Power-User die das bewusst aktivieren.
Mama-Tauglichkeit bleibt erhalten — Default AUS, keine Surprise-Permission.
Aenderungen:
AndroidManifest:
- ACCESS_BACKGROUND_LOCATION Permission
- FOREGROUND_SERVICE_LOCATION Permission
- AriaPlaybackService foregroundServiceType erweitert um |location
(vorher: mediaPlayback|microphone)
backgroundAudio.ts:
- Neuer Slot 'location' zwischen 'wake' und 'background' in der
Prioritaeten-Liste. Notification zeigt entsprechend.
gpsTracking.ts:
- isBackgroundGpsEnabled() / setBackgroundGpsEnabled() AsyncStorage-Helper
- ensureBackgroundLocationPermission() pruefte ACCESS_BACKGROUND_LOCATION
und oeffnet Android-Settings wenn fehlend (auf Android 10+ kann das
NICHT ueber den normalen Permission-Dialog angefordert werden)
- start(): wenn BG-GPS enabled, acquireBackgroundAudio('location') →
Foreground-Service hochziehen mit type=location
- stop(): releaseBackgroundAudio('location')
SettingsScreen.tsx:
- Neuer Toggle "GPS auch im Hintergrund" direkt unter dem
GPS-Tracking-Toggle, rot (#FF3B30) statt orange weil's eine stark
privacy-relevante Einstellung ist
- Erklaerungs-Text zu Android-Settings + Akku-Verbrauch
- Beim Aktivieren: Permission-Check, ggf. Android-Settings oeffnen
- Wenn Tracking bereits laeuft: neustart damit location-Slot greift
APK neu bauen erforderlich.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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) <noreply@anthropic.com>
Stefan-Ergaenzung: nach Wake-Word muss Aufnahme, Senden und ARIA-
Antwort + TTS auch im Hintergrund klappen, und danach soll das ganze
wieder von vorne als Konversations-Schleife laufen.
Vorher hielt nur OpenWakeWordModule einen WakeLock (commit 408d20a).
Sobald Wake-Word erkannt wurde, ruft die JS-Seite OpenWakeWord.stop()
fuer das Mic-Handover an audioService.startRecording() — und der
WakeLock wurde released. Mid-Aufnahme konnte die CPU dann in Doze
gehen, Audio-Chunks erreichten die JS-Bridge nicht zuverlaessig.
Fix: AriaPlaybackService haelt selbst einen PARTIAL_WAKE_LOCK,
solange der Foreground-Service aktiv ist. acquireBackgroundAudio()
in der JS-Seite haelt den Service ueber alle Pipeline-Schritte
(wake → rec → tts → wake) durchgehend — damit ist der WakeLock
ueber die ganze Konversations-Schleife durchgehend aktiv.
Doppelter Schutz (WakeLock auch im OpenWakeWordModule) bleibt drin
als defense in depth — beide haben setReferenceCounted(false), also
keine doppel-buchhaltung, einfach robuster gegen einzeln-failende
acquires.
APK neu bauen erforderlich (native Kotlin-Aenderung).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Stefan-Bug-Report: Wake-Word wird im Hintergrund erkannt (Spotify
pausiert sofort), aber der Gong + Aufnahme-Start kommen erst wenn die
App in den Vordergrund geholt wird. Akku-Optimierung war bereits
deaktiviert ("Hintergrund aktiv").
Ursache: Foreground-Service haelt den App-Prozess am Leben + erlaubt
mic-Zugriff via foregroundServiceType=microphone. Aber: ohne expliziten
WakeLock kann die CPU im Doze-Mode (Display aus / Telefon idle) die
Auslieferung von DeviceEvents an die React-Native-JS-Bridge pausieren.
Folge: Native erkennt Wake-Word, ruft emit("WakeWordDetected"), aber
das Event queued sich nur — der JS-Listener (onWakeDetected → start-
Recording + playWakeReadySound) feuert erst beim naechsten JS-Tick,
und der kommt erst beim App-Resume.
Fix:
- AndroidManifest: WAKE_LOCK Permission hinzu (kein User-Prompt noetig,
ist eine "normal" Permission).
- OpenWakeWordModule.kt: PowerManager.PARTIAL_WAKE_LOCK in start()
acquired (8h Cap als Sicherheit), in stop() + dispose() released.
Lock-Tag "AriaCockpit:WakeWordRecord" damit der in adb shell dumpsys
power sichtbar ist.
Wirkung: solange Wake-Word "armed" ist, bleibt die CPU wach und die
JS-Bridge verarbeitet die Detection-Events live — Gong, Mic-Start,
ARIA-Antwort kommen ohne Foreground-Resume durch.
APK muss neu gebaut werden (native Kotlin-Aenderung).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Stefan-Bug-Report: wenn ich in der App auf den Mund-halten-Button
klicke waehrend ARIA redet, stoppt sie nicht.
Ursache: stopInternal() rief nur AudioTrack.stop() + release(). Das
stoppt zwar den Track, aber der bereits in den Hardware-Buffer
geschriebene PCM-Audio (200-500ms je nach Geraet) spielt noch
hoerbar weiter. Fuer den User klang das so als wuerde der Button
nichts tun.
Fix in 2 Zeilen: AudioTrack.pause() + AudioTrack.flush() vor stop().
flush() verwirft den Hardware-Buffer-Inhalt, dadurch ist die
Wiedergabe wirklich sofort still. pause() davor weil flush() laut
Android-Docs nur in non-playing state safe ist.
Native module ist kompiliert in app/build/tmp/kotlin-classes — APK
muss neu gebaut werden damit der Fix greift.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Symptom: App bekommt im minimierten oder display-gesperrten Zustand
nicht mit ob ein Anruf angefangen oder beendet wurde — TTS spricht
weiter waehrend Telefon klingelt, oder bleibt stumm nach Auflegen.
Zwei Ursachen:
1) Kotlin: TelephonyCallback war auf reactApplicationContext.mainExecutor
registriert. Wenn die Activity pausiert ist (display aus, App im
Hintergrund), wird der mainExecutor verzoegert oder gar nicht
abgearbeitet — Call-State-Events kommen nicht durch.
Fix: eigener Executors.newSingleThreadExecutor() — laeuft unabhaengig
vom UI-Thread solange der App-Prozess lebt (Foreground-Service
garantiert das).
2) TS: TelephonyManager-Listener kann nach laengerer Hintergrund-Zeit
verloren gehen (React-Bridge-Context recreated nach Resume).
Fix: neue refresh()-Methode in phoneCallService, AppState-Resume
ruft sie auf — wenn telephonyAttached=false ist, wird der Native-
Listener neu attached.
Plus: Status-Property telephonyAttached macht in Logs sichtbar ob
Pfad 1 (TelephonyManager) wirklich greift. Pfad 2 (AudioFocus fuer
VoIP) war nie betroffen, der laeuft komplett im Native-Code.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>