Audio: reduce RX startup clipping
This commit is contained in:
@@ -31,6 +31,7 @@ class OpusEngine(
|
||||
const val CHANNELS = 1
|
||||
const val FRAME_SIZE = 160 // 20 мс в 8 кГц
|
||||
const val BIT_RATE = 20000
|
||||
private const val GATE_MIN_WAIT_MS = 100L
|
||||
// Авто-адаптация битрейта TX (0 = авто включено в настройках)
|
||||
const val AUTO_BITRATE_MIN = 8
|
||||
const val AUTO_BITRATE_MAX = 24
|
||||
@@ -384,56 +385,26 @@ class OpusEngine(
|
||||
onRxStats?.invoke(lossPct, jitterMs)
|
||||
}
|
||||
|
||||
/** Джиттер-гейт открыт: накопили кадры или вышло 300 мс с первого пакета. */
|
||||
/** Джиттер-гейт открыт: накопили кадры или вышел короткий таймаут. */
|
||||
private fun gateOpen(): Boolean {
|
||||
if (playStarted) return true
|
||||
if (rxQueue.size >= jitterFrames) return true
|
||||
return gateStart != 0L && System.currentTimeMillis() - gateStart >= 300
|
||||
val waitMs = maxOf(GATE_MIN_WAIT_MS, jitterFrames * 20L)
|
||||
return gateStart != 0L && System.currentTimeMillis() - gateStart >= waitMs
|
||||
}
|
||||
|
||||
fun onAudioFlush() {
|
||||
try {
|
||||
// MediaCodec.flush() возвращает входные буферы, но уже выданные индексы
|
||||
// остаются у нас в freeInputs и дублируются колбэками «повторной выдачи» —
|
||||
// queueInputBuffer падает (index not owned by client) и кадры теряются.
|
||||
// Надёжнее пересоздать декодер: колбэки старого отсекаются проверкой
|
||||
// codec !== decoder.
|
||||
player?.flush()
|
||||
rxQueue.clear()
|
||||
receivedAny = false
|
||||
playStarted = false
|
||||
gateStart = 0L
|
||||
onLevel(SRC_SPEAKER, 0f)
|
||||
restartDecoder()
|
||||
} catch (_: Exception) {
|
||||
}
|
||||
}
|
||||
|
||||
/** Пересоздать только декодер (плеер и джиттер-буфер сохраняем). */
|
||||
private fun restartDecoder() {
|
||||
val dec = decoder
|
||||
decoder = null
|
||||
if (dec != null) {
|
||||
try {
|
||||
dec.stop()
|
||||
} catch (_: Exception) {
|
||||
}
|
||||
try {
|
||||
dec.release()
|
||||
} catch (_: Exception) {
|
||||
}
|
||||
}
|
||||
val format = MediaFormat()
|
||||
format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_AUDIO_OPUS)
|
||||
format.setInteger(MediaFormat.KEY_SAMPLE_RATE, OUT_SAMPLE_RATE)
|
||||
format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, CHANNELS)
|
||||
if (startDecoderCodec(format)) {
|
||||
concealLogs = 0
|
||||
dbgOut = 0
|
||||
ptsCounter = 20_000L
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Один кадр тишины (20 мс) для скрытия потерь вместо паузы в звуке.
|
||||
* Сгенерирован opuslib: 8 кГц, моно, 20 кбит/с, нули PCM.
|
||||
@@ -664,4 +635,4 @@ class OpusEngine(
|
||||
val norm = (db + 60.0) / 48.0
|
||||
return norm.toFloat().coerceIn(0f, 1f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user