Keep video clock moving through audio underruns and drain final playback

This commit is contained in:
evgeny committed 2026-10-12 02:30:36 +02:00
1 parent e09ee919a5
commit 1209d8e4b7
2 files changed
+17 -8

No files matched your search

@@ -56,6 +56,9 @@ class StreamPlayerEngine(private val group: Long, private val source: Long) {
var report = 0L
var decoded = 0L
var discarded = 0L
var lastHead = -1L
var headChangedNs = 0L
var endDrainUntil = 0L
fun resetVideo() {
try { decoder?.stop(); decoder?.release() }
@@ -66,15 +69,18 @@ class StreamPlayerEngine(private val group: Long, private val source: Long) {
fun resetAudio() {
track?.pause(); track?.flush(); track?.release(); track = null
if (opus != 0L) NativeLib.streamOpusClose(opus)
opus = 0; audioBase = -1; written = 0; audios.clear()
opus = 0; audioBase = -1; written = 0; lastHead = -1; audios.clear()
}
fun currentPts(now: Long): Long {
val t = track
if (t != null && audioBase >= 0) {
val played = if (t.getTimestamp(audioTimestamp)) {
(audioTimestamp.framePosition + (now - audioTimestamp.nanoTime).coerceAtLeast(0) * 48000 / 1_000_000_000)
.coerceAtMost(written)
} else t.playbackHeadPosition.toLong() and 0xffffffffL
} else {
val head = t.playbackHeadPosition.toLong() and 0xffffffffL
if (head != lastHead) { lastHead = head; headChangedNs = now }
head + if (head >= written) (now - headChangedNs) * 48000 / 1_000_000_000 else 0
}
return audioBase + played * 1_000_000 / 48000
}
return if (videoBase >= 0) videoBase + (now - videoStartNs) / 1000 else 0
@@ -198,7 +204,10 @@ class StreamPlayerEngine(private val group: Long, private val source: Long) {
}
}
}
if (ended && videos.isEmpty() && audios.isEmpty()) { mutableStatus.value = R.string.stream_ended; break }
if (ended && videos.isEmpty() && audios.isEmpty()) {
if (endDrainUntil == 0L) endDrainUntil = now + 250_000_000
if (now >= endDrainUntil) { mutableStatus.value = R.string.stream_ended; break }
}
if (now - report >= 1_000_000_000) {
report = now
LogManager.addLog("DEBUG", "stream", "viewer id=$id decoded=$decoded discarded=$discarded videoQ=${videos.size}/$videoBytes " +
@@ -214,7 +223,7 @@ class StreamPlayerEngine(private val group: Long, private val source: Long) {
try { track?.stop(); track?.release() } catch (e: Exception) { LogManager.addLog("WARN", "stream", "audio release id=$id: ${e.message}") }
if (opus != 0L) NativeLib.streamOpusClose(opus)
val deadline = System.nanoTime() + 500_000_000
while (NativeLib.isReady() && System.nanoTime() < deadline) {
while (!ended && NativeLib.isReady() && System.nanoTime() < deadline) {
val event = NativeLib.streamPull(id)
if (event != null && event[0].toInt() in 5..6) break
Thread.sleep(5)