/** * Background-Audio: ARIAs TTS, Mic-Aufnahme und Wake-Word-Lauschen sollen * auch bei minimierter App weiterlaufen. Wir starten dafuer einen Foreground- * Service mit foregroundServiceType=mediaPlayback|microphone, der eine * persistente Notification zeigt waehrend irgendein Audio-Slot aktiv ist. * * Mehrere Komponenten koennen den Service unabhaengig "halten": * - 'tts' : ARIA spricht * - 'rec' : Aufnahme laeuft * - 'wake' : Wake-Word lauscht passiv (Ohr aktiv) * * Solange mindestens ein Slot aktiv ist, laeuft der Service. Wenn alle * Slots leer sind, wird er gestoppt. Der Notification-Text passt sich an * den hoechstprioren Slot an (tts > rec > wake). */ import { NativeModules } from 'react-native'; interface BackgroundAudioNative { start(reason: string): Promise; stop(): Promise; } const { BackgroundAudio } = NativeModules as { BackgroundAudio?: BackgroundAudioNative }; type Slot = 'tts' | 'rec' | 'wake'; const slots = new Set(); // Prioritaet fuer den Notification-Text — hoechste zuerst. const PRIORITY: Slot[] = ['tts', 'rec', 'wake']; function topReason(): string { for (const s of PRIORITY) { if (slots.has(s)) return s; } return ''; } async function applyState(): Promise { if (!BackgroundAudio) return; if (slots.size === 0) { try { await BackgroundAudio.stop(); } catch {} console.log('[BackgroundAudio] Service gestoppt (keine Slots)'); return; } const reason = topReason(); try { await BackgroundAudio.start(reason); console.log('[BackgroundAudio] Service aktiv (slot=%s, slots=%s)', reason, [...slots].join('+')); } catch (err: any) { console.warn('[BackgroundAudio] start fehlgeschlagen:', err?.message || err); } } export async function acquireBackgroundAudio(slot: Slot): Promise { if (slots.has(slot)) return; slots.add(slot); await applyState(); } export async function releaseBackgroundAudio(slot: Slot): Promise { if (!slots.has(slot)) return; slots.delete(slot); await applyState(); } export function backgroundAudioActive(): boolean { return slots.size > 0; } // --- Legacy API (nur tts-Slot) — fuer Aufruf-Sites die noch nichts vom Slot- // system wissen. Mappt auf den 'tts'-Slot. --- export const startBackgroundAudio = () => acquireBackgroundAudio('tts'); export const stopBackgroundAudio = () => releaseBackgroundAudio('tts');