diff --git a/android/android/app/src/main/java/com/ariacockpit/PcmStreamPlayerModule.kt b/android/android/app/src/main/java/com/ariacockpit/PcmStreamPlayerModule.kt index 92f3947..e970a43 100644 --- a/android/android/app/src/main/java/com/ariacockpit/PcmStreamPlayerModule.kt +++ b/android/android/app/src/main/java/com/ariacockpit/PcmStreamPlayerModule.kt @@ -92,12 +92,7 @@ class PcmStreamPlayerModule(reactContext: ReactApplicationContext) : ReactContex val newTrack = AudioTrack.Builder() .setAudioAttributes( AudioAttributes.Builder() - // USAGE_MEDIA statt USAGE_ASSISTANT — auf OnePlus A12 stallt - // AudioTrack mit USAGE_ASSISTANT wenn play() nach komplettem - // Buffer-Fuellen called wird (pos bleibt 0). USAGE_MEDIA ist - // robust. AudioFocus wird eh separat ueber AudioFocusModule - // gehandhabt, nicht ueber dieses USAGE-Tag. - .setUsage(AudioAttributes.USAGE_MEDIA) + .setUsage(AudioAttributes.USAGE_ASSISTANT) .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH) .build(), ) @@ -164,11 +159,12 @@ class PcmStreamPlayerModule(reactContext: ReactApplicationContext) : ReactContex val data = queue.poll(50, java.util.concurrent.TimeUnit.MILLISECONDS) if (data == null) { if (endRequested) { - // Bei kurzem Text NICHT hier play() callen — erst nach - // Trailing-Silence + Padding (siehe Block nach mainLoop), - // damit AudioTrack mit komplett gefuelltem Buffer startet. - // OnePlus A12: AudioTrack startet nicht zuverlaessig wenn - // play() bei dünnem Buffer gerufen wird. + // Falls play() noch gar nicht lief (Stream ohne data + // ueberhaupt — sehr seltene Edge-Case): jetzt anstossen + // damit das finally{}-Wait nicht endlos blockt. + if (!playbackStarted) { + try { t.play(); playbackStarted = true } catch (_: Exception) {} + } break@mainLoop } // Underrun-Schutz: Stille reinfuettern wenn der AudioTrack- @@ -199,12 +195,16 @@ class PcmStreamPlayerModule(reactContext: ReactApplicationContext) : ReactContex } idleMs = 0L - // Pre-Roll Check: play() erst wenn genug gepuffert - if (!playbackStarted && bytesBuffered + data.size >= prerollBytes) { + // play() beim ALLERERSTEN data-chunk aufrufen — egal wie wenig + // Daten da sind. Sonst stallt AudioTrack auf OnePlus A12 wenn + // play() erst gerufen wird nachdem der Buffer komplett gefuellt + // ist. Pre-Roll als "Vorrat aufbauen" passiert dann waehrend + // der Track schon spielt — Underrun-Schutz fuettert ggf. Stille. + if (!playbackStarted) { try { t.play() playbackStarted = true - Log.i(TAG, "Playback gestartet nach Pre-Roll ${bytesBuffered + data.size} Bytes") + Log.i(TAG, "Playback gestartet beim 1. Chunk (${bytesBuffered}B leading + ${data.size}B data)") } catch (e: Exception) { Log.w(TAG, "play() failed: ${e.message}") } @@ -231,31 +231,6 @@ class PcmStreamPlayerModule(reactContext: ReactApplicationContext) : ReactContex } bytesBuffered += silence.size } - // Bei kurzem Text (play() noch nicht gestartet): Buffer auf min. - // 3s padden + DANN play(). Auf OnePlus A12 startet AudioTrack - // bei < 3s Buffer-Inhalt nicht — pos bleibt auf 0 stehen. - // (2s war zu wenig, 8 Worte ~2.5s gingen, 3 Worte ~1s nicht.) - if (!playbackStarted && !writerShouldStop) { - val minStartBytes = bytesPerSecond * 3 - if (bytesBuffered < minStartBytes) { - val padBytes = (minStartBytes - bytesBuffered.toInt()) and 0x7FFFFFFE - val pad = ByteArray(padBytes) - var padOff = 0 - while (padOff < pad.size && !writerShouldStop) { - val w = t.write(pad, padOff, pad.size - padOff) - if (w <= 0) break - padOff += w - } - bytesBuffered += pad.size - } - try { - t.play() - playbackStarted = true - Log.i(TAG, "Playback gestartet (kurzer Text, ${bytesBuffered}B komplett gepuffert)") - } catch (e: Exception) { - Log.w(TAG, "play() short-text failed: ${e.message}") - } - } } catch (e: Exception) { Log.w(TAG, "Writer-Thread Fehler: ${e.message}") } finally {