Browse Source

Invalidate output measurements across concurrent Android route changes

master
evgeny 5 days ago
parent
commit
1a97219c43
  1. 16
      tools/chatgui-android/app/src/main/java/com/utun/chat/data/CallAudioEngine.kt

16
tools/chatgui-android/app/src/main/java/com/utun/chat/data/CallAudioEngine.kt

@ -625,10 +625,11 @@ class CallAudioEngine {
playFramesPlayed = played playFramesPlayed = played
operationNs = System.nanoTime() operationNs = System.nanoTime()
val device = trace.device val device = trace.device
val anchor = playbackClock.update(playFramesWritten, played, nowUs, routeGeneration, val generation = routeGeneration
device.generation, device.stampFrame, device.stampNs / 1000) val anchor = playbackClock.update(playFramesWritten, played, nowUs, generation,
device.generation, device.stampFrame, device.stampNs / 1000).takeIf { generation == routeGeneration }
outputUs = if (anchor?.measured == true) (anchor.atUs - nowUs).coerceAtLeast(0) else -1 outputUs = if (anchor?.measured == true) (anchor.atUs - nowUs).coerceAtLeast(0) else -1
outputSample = OutputSample(nowUs, routeGeneration, CallOutputLatency( outputSample = OutputSample(nowUs, generation, CallOutputLatency(
((playFramesWritten - played) * 1000 / SAMPLE_RATE).toInt(), ((playFramesWritten - played) * 1000 / SAMPLE_RATE).toInt(),
if (outputUs >= 0) (outputUs / 1000).toInt() else -1)) if (outputUs >= 0) (outputUs / 1000).toInt() else -1))
if (anchor != null) NativeLib.callAudioProgress(callId, epoch, anchor.position, anchor.atUs, nowUs, anchor.measured) if (anchor != null) NativeLib.callAudioProgress(callId, epoch, anchor.position, anchor.atUs, nowUs, anchor.measured)
@ -636,12 +637,13 @@ class CallAudioEngine {
val mode = if (anchor == null) "unavailable" else if (anchor.measured) "timestamp" else "head-estimate" val mode = if (anchor == null) "unavailable" else if (anchor.measured) "timestamp" else "head-estimate"
if (mode != clockMode) { if (mode != clockMode) {
LogManager.addLog(if (mode == "unavailable") "WARN" else "INFO", "CallAudio", LogManager.addLog(if (mode == "unavailable") "WARN" else "INFO", "CallAudio",
"playback clock id=$callId mode=$mode routeGeneration=$routeGeneration outputUs=$outputUs") "playback clock id=$callId mode=$mode routeGeneration=$generation outputUs=$outputUs")
clockMode = mode clockMode = mode
} }
} else if (!clockFailed) { } else if (!clockFailed) {
clockFailed = true clockFailed = true
playFramesPlayed = -1 playFramesPlayed = -1
outputUs = -1; outputSample = null
// Отрицательная позиция немедленно инвалидирует снимок в native. // Отрицательная позиция немедленно инвалидирует снимок в native.
NativeLib.callAudioProgress(callId, epoch, -1, nowUs, nowUs, false) NativeLib.callAudioProgress(callId, epoch, -1, nowUs, nowUs, false)
LogManager.addLog("ERROR", "CallAudio", LogManager.addLog("ERROR", "CallAudio",
@ -711,11 +713,13 @@ class CallAudioEngine {
} else { } else {
playbackBuffer?.applied(now, change, actual, capacity) playbackBuffer?.applied(now, change, actual, capacity)
} }
val level = if (actual == requested && (change == null || change.underruns == 0)) "INFO" else "WARN" val performance = track.performanceMode
val level = if (actual == requested && (change == null || change.underruns == 0) &&
performance == AudioTrack.PERFORMANCE_MODE_LOW_LATENCY) "INFO" else "WARN"
LogManager.addLog(level, "CallAudio", LogManager.addLog(level, "CallAudio",
"playback buffering id=$callId reason=$reason requestedFrames=$requested actualFrames=$actual " + "playback buffering id=$callId reason=$reason requestedFrames=$requested actualFrames=$actual " +
"previousFrames=$previous startFrames=$start capacityFrames=$capacity underruns=${change?.underruns ?: 0} " + "previousFrames=$previous startFrames=$start capacityFrames=$capacity underruns=${change?.underruns ?: 0} " +
"performanceRequested=${AudioTrack.PERFORMANCE_MODE_LOW_LATENCY} performanceActual=${track.performanceMode} pacing=device") "performanceRequested=${AudioTrack.PERFORMANCE_MODE_LOW_LATENCY} performanceActual=$performance pacing=device")
if (playReady && (previous != actual || reason == "route")) { if (playReady && (previous != actual || reason == "route")) {
// Очередь сначала принимает новый размер; устаревшая задача не затронет следующий звонок. // Очередь сначала принимает новый размер; устаревшая задача не затронет следующий звонок.
mainHandler.post { mainHandler.post {

Loading…
Cancel
Save