Validate Android voice streams and keep playback cancellation off UI waits
This commit is contained in:
1 parent
dd8041b30f
commit
c863b80917
2 files changed
+50
-30
No files matched your search
+26
-17
@@ -196,24 +196,27 @@ class AudioRecorderManager {
|
||||
fun playFromPosition(filePath: String, startMs: Int, onProgress: ((Float, Int) -> Unit)? = null, onComplete: () -> Unit = {}) {
|
||||
stopPlayback()
|
||||
playing = true
|
||||
val myGen = playGeneration
|
||||
|
||||
playThread = Thread {
|
||||
val myGen = playGeneration
|
||||
var handle = 0L
|
||||
var track: AudioTrack? = null
|
||||
try {
|
||||
val info = IntArray(3)
|
||||
val handle = NativeLib.voiceDecodeOpen(filePath, info)
|
||||
handle = NativeLib.voiceDecodeOpen(filePath, info)
|
||||
if (handle == 0L) {
|
||||
LogManager.addLog("ERROR", "AudioPlayer", "decode open failed: $filePath")
|
||||
playing = false; onComplete(); return@Thread
|
||||
return@Thread
|
||||
}
|
||||
val sampleRate = info[0]; val channels = info[1]; val totalSamples = info[2]
|
||||
|
||||
/* skip to startMs by decoding and discarding frames */
|
||||
val frameSamples = FRAME_SAMPLES * channels
|
||||
val frameSamples = sampleRate / 50 * channels
|
||||
val skipFrames = startMs / FRAME_MS
|
||||
val skipBuf = ShortArray(frameSamples)
|
||||
var skippedSamples = 0L
|
||||
for (f in 0 until skipFrames) {
|
||||
if (myGen != playGeneration) return@Thread
|
||||
val dec = NativeLib.voiceDecodeRead(handle, skipBuf)
|
||||
if (dec <= 0) break
|
||||
skippedSamples += dec
|
||||
@@ -223,43 +226,49 @@ class AudioRecorderManager {
|
||||
if (channels == 2) AudioFormat.CHANNEL_OUT_STEREO else AudioFormat.CHANNEL_OUT_MONO,
|
||||
AudioFormat.ENCODING_PCM_16BIT)
|
||||
|
||||
val track = AudioTrack(AudioManager.STREAM_MUSIC, sampleRate,
|
||||
val output = AudioTrack(AudioManager.STREAM_MUSIC, sampleRate,
|
||||
if (channels == 2) AudioFormat.CHANNEL_OUT_STEREO else AudioFormat.CHANNEL_OUT_MONO,
|
||||
AudioFormat.ENCODING_PCM_16BIT, bufSize, AudioTrack.MODE_STREAM)
|
||||
track.play()
|
||||
track = output
|
||||
output.play()
|
||||
|
||||
val pcm = ShortArray(frameSamples)
|
||||
var readTotal = 0L
|
||||
var read: Int
|
||||
while (playing) {
|
||||
while (playing && myGen == playGeneration) {
|
||||
read = NativeLib.voiceDecodeRead(handle, pcm)
|
||||
if (read <= 0) break
|
||||
track.write(pcm, 0, read)
|
||||
if (myGen != playGeneration) break
|
||||
output.write(pcm, 0, read)
|
||||
readTotal += read
|
||||
val total = (skippedSamples + readTotal).toFloat() / (totalSamples * channels).coerceAtLeast(1).toFloat()
|
||||
val total = (skippedSamples + readTotal).toFloat() / totalSamples.coerceAtLeast(1).toFloat()
|
||||
val eMs = startMs + (readTotal * FRAME_MS / frameSamples).toInt()
|
||||
onProgress?.invoke(total, eMs)
|
||||
}
|
||||
val drainMs = (bufSize * 1000L) / (sampleRate.toLong() * channels * 2) + 100
|
||||
try { Thread.sleep(drainMs) } catch (_: InterruptedException) {}
|
||||
track.stop(); track.release()
|
||||
NativeLib.voiceDecodeClose(handle)
|
||||
if (myGen == playGeneration) Thread.sleep(drainMs)
|
||||
} catch (_: InterruptedException) {
|
||||
LogManager.addLog("DEBUG", "AudioPlayer", "playback cancelled")
|
||||
} catch (e: Exception) {
|
||||
LogManager.addLog("ERROR", "AudioPlayer", "play error: ${e.message}")
|
||||
}
|
||||
if (playGeneration == myGen) {
|
||||
playing = false; onComplete()
|
||||
} finally {
|
||||
track?.apply {
|
||||
try { stop() } catch (e: Exception) { LogManager.addLog("WARN", "AudioPlayer", "stop failed: ${e.message}") }
|
||||
release()
|
||||
}
|
||||
if (handle != 0L) NativeLib.voiceDecodeClose(handle)
|
||||
if (playGeneration == myGen) { playing = false; onComplete() }
|
||||
}
|
||||
}.apply { start() }
|
||||
}
|
||||
|
||||
fun pausePlayback() {
|
||||
playGeneration++; playing = false
|
||||
playThread?.join(500); playThread = null
|
||||
playThread?.interrupt(); playThread = null
|
||||
}
|
||||
|
||||
fun stopPlayback() {
|
||||
playGeneration++; playing = false
|
||||
playThread?.join(500); playThread = null
|
||||
playThread?.interrupt(); playThread = null
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user