From f1c2b38c51e0fd829a67f7ca3b70cd6a6cf6b869 Mon Sep 17 00:00:00 2001 From: Narasimha-sc <166327228+Narasimha-sc@users.noreply.github.com> Date: Wed, 29 Apr 2026 07:54:30 +0000 Subject: [PATCH] android, desktop: don't probe duration synchronously when stopping recorder AudioPlayer.start() synchronously invokes RecorderInterface.stopRecording. RecorderNative.stop() ran runBlocking { progressJob.cancelAndJoin() }, which waits for the progress coroutine's invokeOnCompletion handler - and that handler calls realDuration(path). On Desktop realDuration goes through AudioPlayer.duration which constructs a fresh AudioPlayerComponent and runs media().startPaused() on the recording file VLC just released; that probe is slow and on Waydroid sometimes never returns. A second realDuration call for stop()'s return value duplicated the I/O. Skip the runBlocking await and return wall-clock elapsed from progress() instead of probing the file. The progressJob's invokeOnCompletion still fires (now async on Default), so the recState transition still happens via the existing listener path - just no longer blocking the caller. durationMs reported to RecordingState.Finished by stopRecordingAndAddAudio is now wall-clock elapsed rather than container-probed - tens of ms looser, well below any user-visible threshold for a voice message. --- .../chat/simplex/common/platform/RecAndPlay.android.kt | 7 ++----- .../chat/simplex/common/platform/RecAndPlay.desktop.kt | 4 ++-- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/platform/RecAndPlay.android.kt b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/platform/RecAndPlay.android.kt index e5dda23f0f..d2b3e19164 100644 --- a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/platform/RecAndPlay.android.kt +++ b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/platform/RecAndPlay.android.kt @@ -78,15 +78,12 @@ actual class RecorderNative: RecorderInterface { runCatching { recorder?.release() } - // Await coroutine finishes in order to send real duration to it's listener - runBlocking { - progressJob?.cancelAndJoin() - } + progressJob?.cancel() progressJob = null filePath = null recorder = null keepScreenOn(false) - return (realDuration(path) ?: 0).also { recStartedAt = null } + return (progress() ?: 0).also { recStartedAt = null } } private fun progress(): Int? = recStartedAt?.let { (System.currentTimeMillis() - it).toInt() } diff --git a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/RecAndPlay.desktop.kt b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/RecAndPlay.desktop.kt index 59d71a83f1..f5cb714997 100644 --- a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/RecAndPlay.desktop.kt +++ b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/RecAndPlay.desktop.kt @@ -70,11 +70,11 @@ actual class RecorderNative: RecorderInterface { RecorderInterface.stopRecording = null runCatching { player?.controls()?.stop() } runCatching { player?.release() } - runBlocking { progressJob?.cancelAndJoin() } + progressJob?.cancel() progressJob = null filePath = null player = null - return (realDuration(path) ?: 0).also { recStartedAt = null } + return (progress() ?: 0).also { recStartedAt = null } } private fun progress(): Int? = recStartedAt?.let { (System.currentTimeMillis() - it).toInt() }