|
|
|
|
@ -59,6 +59,8 @@ class StreamPlayerEngine(private val group: Long, private val source: Long, priv
|
|
|
|
|
var lastHead = -1L |
|
|
|
|
var headChangedNs = 0L |
|
|
|
|
var endDrainUntil = 0L |
|
|
|
|
var headEpoch = 0L |
|
|
|
|
var previousRawHead = 0L |
|
|
|
|
|
|
|
|
|
fun resetVideo() { |
|
|
|
|
try { decoder?.stop() } |
|
|
|
|
@ -75,15 +77,28 @@ class StreamPlayerEngine(private val group: Long, private val source: Long, priv
|
|
|
|
|
catch (e: Exception) { LogManager.addLog("WARN", "stream", "audio release id=$id: ${e.message}") } |
|
|
|
|
track = null |
|
|
|
|
if (opus != 0L) NativeLib.streamOpusClose(opus) |
|
|
|
|
opus = 0; audioBase = -1; written = 0; lastHead = -1; audios.clear() |
|
|
|
|
opus = 0; audioBase = -1; written = 0; lastHead = -1; headEpoch = 0; previousRawHead = 0; audios.clear() |
|
|
|
|
} |
|
|
|
|
// PlaybackHeadPosition — unsigned 32 bit: при 48kHz оборачивается примерно через 25 часов. |
|
|
|
|
fun playedFrames(t: AudioTrack): Long { |
|
|
|
|
val raw = t.playbackHeadPosition.toLong() and 0xffffffffL |
|
|
|
|
if (raw < previousRawHead) headEpoch += 0x100000000L |
|
|
|
|
previousRawHead = raw |
|
|
|
|
return headEpoch + raw |
|
|
|
|
} |
|
|
|
|
fun currentPts(now: Long): Long { |
|
|
|
|
val t = track |
|
|
|
|
if (t != null && audioBase >= 0) { |
|
|
|
|
val head = playedFrames(t) |
|
|
|
|
val played = if (t.getTimestamp(audioTimestamp)) { |
|
|
|
|
(audioTimestamp.framePosition + (now - audioTimestamp.nanoTime).coerceAtLeast(0) * 48000 / 1_000_000_000) |
|
|
|
|
var position = audioTimestamp.framePosition |
|
|
|
|
if (position <= 0xffffffffL) { |
|
|
|
|
position += headEpoch |
|
|
|
|
if (position - head > 0x80000000L) position -= 0x100000000L |
|
|
|
|
if (head - position > 0x80000000L) position += 0x100000000L |
|
|
|
|
} |
|
|
|
|
position + (now - audioTimestamp.nanoTime).coerceAtLeast(0) * 48000 / 1_000_000_000 |
|
|
|
|
} 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 |
|
|
|
|
} |
|
|
|
|
@ -168,7 +183,7 @@ class StreamPlayerEngine(private val group: Long, private val source: Long, priv
|
|
|
|
|
} |
|
|
|
|
val t = track |
|
|
|
|
if (t != null && audios.isNotEmpty()) { |
|
|
|
|
val head = t.playbackHeadPosition.toLong() and 0xffffffffL |
|
|
|
|
val head = playedFrames(t) |
|
|
|
|
if (written - head < 3840) { |
|
|
|
|
val f = audios.removeFirst() |
|
|
|
|
val missing = ((f.pts - audioBase - written * 1_000_000 / 48000).toDouble() / 20000).roundToInt() |
|
|
|
|
|