|
|
|
|
@ -9,6 +9,7 @@ import android.media.AudioRecord
|
|
|
|
|
import android.media.AudioTimestamp |
|
|
|
|
import android.media.AudioTrack |
|
|
|
|
import android.media.MediaRecorder |
|
|
|
|
import android.os.Build |
|
|
|
|
import android.os.Handler |
|
|
|
|
import android.os.Looper |
|
|
|
|
import android.os.SystemClock |
|
|
|
|
@ -175,6 +176,14 @@ class CallAudioEngine {
|
|
|
|
|
return@runWorker |
|
|
|
|
} |
|
|
|
|
applyTrackOutputDevice(router.currentOutputDevice) |
|
|
|
|
// Ёмкость устройства не должна становиться постоянной задержкой звонка. |
|
|
|
|
// Два блока оставляют запас на пробуждение playback-потока каждые 20 мс. |
|
|
|
|
val startFrames = FRAME_SAMPLES * 2 |
|
|
|
|
val actualStart = if (Build.VERSION.SDK_INT >= 31) track.setStartThresholdInFrames(startFrames) |
|
|
|
|
else track.setBufferSizeInFrames(startFrames) |
|
|
|
|
LogManager.addLog(if (actualStart > 0) "INFO" else "WARN", "CallAudio", |
|
|
|
|
"playback buffering id=$id requestedStart=$startFrames actualStart=$actualStart " + |
|
|
|
|
"bufferFrames=${track.bufferSizeInFrames} capacityFrames=${track.bufferCapacityInFrames}") |
|
|
|
|
val trackCreateMs = SystemClock.elapsedRealtime() - createdAt |
|
|
|
|
val playedAt = SystemClock.elapsedRealtime() |
|
|
|
|
track.play() |
|
|
|
|
@ -431,6 +440,7 @@ class CallAudioEngine {
|
|
|
|
|
val head = CallPlaybackHead() |
|
|
|
|
var clockFailed = false |
|
|
|
|
var logAtUs = 0L |
|
|
|
|
var lastUnderruns = 0 |
|
|
|
|
while (active) { |
|
|
|
|
val track = audioTrack ?: return |
|
|
|
|
val n = NativeLib.callAudioPull(callId, buf) |
|
|
|
|
@ -474,9 +484,14 @@ class CallAudioEngine {
|
|
|
|
|
} |
|
|
|
|
if (nowUs - logAtUs >= 1_000_000 && NativeLib.callAudioClock(callId, nowUs, snapshot)) { |
|
|
|
|
logAtUs = nowUs |
|
|
|
|
LogManager.addLog("DEBUG", "CallAudio", |
|
|
|
|
val underruns = track.underrunCount |
|
|
|
|
val threshold = if (Build.VERSION.SDK_INT >= 31) track.startThresholdInFrames else track.bufferSizeInFrames |
|
|
|
|
val queuedUs = (snapshot[3] - snapshot[2]).coerceAtLeast(0) * 1_000_000 / SAMPLE_RATE |
|
|
|
|
LogManager.addLog(if (underruns > lastUnderruns) "WARN" else "DEBUG", "CallAudio", |
|
|
|
|
"clock epoch=${snapshot[0]} source=${snapshot[1]} played=${snapshot[2]} written=${snapshot[3]} " + |
|
|
|
|
"ptsUs=${snapshot[4]} valid=${snapshot[5]} measured=${snapshot[6]} heldUs=${snapshot[7]}") |
|
|
|
|
"ptsUs=${snapshot[4]} valid=${snapshot[5]} measured=${snapshot[6]} heldUs=${snapshot[7]} " + |
|
|
|
|
"queuedUs=$queuedUs bufferFrames=${track.bufferSizeInFrames} startFrames=$threshold underruns=$underruns") |
|
|
|
|
lastUnderruns = underruns |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|