Keep mixer shutdown inside the guarded cleanup path

This commit is contained in:
evgeny committed 2026-10-29 13:34:24 +01:00
1 parent 304b48a289
commit 16c7d817cc
2 files changed
+10 -8

No files matched your search

@@ -1,7 +1,9 @@
package com.utun.chat.data
/** Один AudioTrack для всех трансляций. Mixer только копирует и смешивает готовый PCM.
* Input закрывается после исключения из списка; его короткий lock защищает consumer от release. */
* Input закрывается после исключения из списка; его короткий lock защищает consumer от release.
* Выход принадлежит worker до успешного close; новые inputs ждут cleanup, не открывая второй AudioTrack.
*/
internal object StreamAudioMixer {
data class OutputState(val played: Long = 0, val leadUs: Long = 0)
@Volatile var output = OutputState()
@@ -58,11 +60,8 @@ internal object StreamAudioMixer {
LogManager.addLog("INFO", "stream", "mixer started: ready PCM only, blockFrames=${mix.frames}")
while (true) {
val current = synchronized(lock) {
if (inputs.isEmpty()) {
return
}
snapshot
}
if (inputs.isEmpty()) null else snapshot
} ?: break
device.step(System.nanoTime(), hold = false, pull = {
mix.clear()
var active = false
@@ -186,8 +185,10 @@ internal class StreamMixedPlayback(val id: Long, pts: Long, private val audioEna
true
} catch (e: Exception) {
outputFailure = e.message ?: "Audio mixing failed"
wake()
LogManager.addLog("ERROR", "stream", "mixer input failed id=$id: ${e.message}")
try { wake() } catch (notification: Exception) {
LogManager.addLog("ERROR", "stream", "mixer failure notification failed id=$id: $notification")
}
false
}
}
@@ -158,7 +158,8 @@ internal class StreamVideoPlayback(
}
}
} catch (e: Exception) {
if (running) {
val report = running; running = false
if (report) {
failure = e
LogManager.addLog("ERROR", "video", "viewer video worker failed id=$id generation=$activeGeneration: ${e.message}")
wake()