Фикс подсчёта потерь: повторы/инверсии seq говорящего и паузы не считаются потерями
This commit is contained in:
@@ -331,10 +331,15 @@ class OpusEngine(
|
|||||||
private fun updateRxStats(seq: Int) {
|
private fun updateRxStats(seq: Int) {
|
||||||
val now = System.currentTimeMillis()
|
val now = System.currentTimeMillis()
|
||||||
if (lastSeq >= 0) {
|
if (lastSeq >= 0) {
|
||||||
val gap = ((seq - lastSeq - 1) and 0xFFFF).toLong()
|
|
||||||
if (gap > 0) lossCount += gap
|
|
||||||
pktCount++
|
|
||||||
val dt = now - lastPktTime
|
val dt = now - lastPktTime
|
||||||
|
// seq — счётчик ГОВОРЯЩЕГО: при повторах кадров он может
|
||||||
|
// повторяться или идти назад — это не потери. Пауза > 200 мс
|
||||||
|
// между пакетами — смена реплики/говорящего, тоже не потери.
|
||||||
|
if (dt <= 200) {
|
||||||
|
val gap = (seq - lastSeq - 1).toLong()
|
||||||
|
if (gap in 1..50000) lossCount += gap
|
||||||
|
}
|
||||||
|
pktCount++
|
||||||
val j = abs(dt - 20).toDouble()
|
val j = abs(dt - 20).toDouble()
|
||||||
if (j < 100) {
|
if (j < 100) {
|
||||||
jitterAccum += j
|
jitterAccum += j
|
||||||
@@ -350,6 +355,7 @@ class OpusEngine(
|
|||||||
if (now - lastEvalTime < 5000 || pktCount < 30) return
|
if (now - lastEvalTime < 5000 || pktCount < 30) return
|
||||||
val lossPct = lossCount * 100.0 / pktCount
|
val lossPct = lossCount * 100.0 / pktCount
|
||||||
val jitterMs = if (jitterN > 0) jitterAccum / jitterN else 0.0
|
val jitterMs = if (jitterN > 0) jitterAccum / jitterN else 0.0
|
||||||
|
Log.d(TAG, "stats window: pkt=$pktCount loss=$lossCount pct=$lossPct j=$jitterMs lastSeq=$lastSeq")
|
||||||
if (lossPct > 3.0 || jitterMs > 60.0) {
|
if (lossPct > 3.0 || jitterMs > 60.0) {
|
||||||
if (autoKbps > AUTO_BITRATE_MIN) {
|
if (autoKbps > AUTO_BITRATE_MIN) {
|
||||||
autoKbps -= AUTO_BITRATE_STEP
|
autoKbps -= AUTO_BITRATE_STEP
|
||||||
|
|||||||
@@ -541,7 +541,7 @@ class ReflectorClient(
|
|||||||
if (data.size < 6) return
|
if (data.size < 6) return
|
||||||
val r = BinReader(data)
|
val r = BinReader(data)
|
||||||
val type = r.u16()
|
val type = r.u16()
|
||||||
r.u16() // client id
|
val cid = r.u16() // client id
|
||||||
val seq = r.u16()
|
val seq = r.u16()
|
||||||
val payload = data.copyOfRange(6, data.size)
|
val payload = data.copyOfRange(6, data.size)
|
||||||
when (type) {
|
when (type) {
|
||||||
@@ -549,7 +549,7 @@ class ReflectorClient(
|
|||||||
ReflectorProtocol.MSG_UDP_AUDIO -> {
|
ReflectorProtocol.MSG_UDP_AUDIO -> {
|
||||||
val audio = MsgParser.udpAudio(payload)
|
val audio = MsgParser.udpAudio(payload)
|
||||||
if (audio != null && audio.isNotEmpty()) {
|
if (audio != null && audio.isNotEmpty()) {
|
||||||
Log.d(TAG, "UDP RX audio seq=$seq len=${audio.size}")
|
Log.d(TAG, "UDP RX audio seq=$seq cid=$cid len=${audio.size}")
|
||||||
callbacks.onAudioPacket(audio, seq)
|
callbacks.onAudioPacket(audio, seq)
|
||||||
} else {
|
} else {
|
||||||
Log.w(TAG, "UDP RX audio empty/null len=${payload.size}")
|
Log.w(TAG, "UDP RX audio empty/null len=${payload.size}")
|
||||||
|
|||||||
Reference in New Issue
Block a user