|
|
|
|
@ -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) |
|
|
|
|
|