diff --git a/libraries/voicerecorder/impl/src/main/kotlin/io/element/android/libraries/voicerecorder/impl/DefaultVoiceRecorder.kt b/libraries/voicerecorder/impl/src/main/kotlin/io/element/android/libraries/voicerecorder/impl/DefaultVoiceRecorder.kt index 5e4c9ae132..4823c67c6a 100644 --- a/libraries/voicerecorder/impl/src/main/kotlin/io/element/android/libraries/voicerecorder/impl/DefaultVoiceRecorder.kt +++ b/libraries/voicerecorder/impl/src/main/kotlin/io/element/android/libraries/voicerecorder/impl/DefaultVoiceRecorder.kt @@ -71,14 +71,17 @@ class DefaultVoiceRecorder( override val state: StateFlow = _state @RequiresPermission(Manifest.permission.RECORD_AUDIO) - override suspend fun startRecord() { + override suspend fun startRecord() = lock.withLock { + if (recordingJob != null) { + Timber.w("Voice recorder is already recording, ignoring this start") + return@withLock + } + Timber.i("Voice recorder started recording") outputFile = fileManager.createFile() .also(encoder::init) - lock.withLock { - levels.clear() - } + levels.clear() val audioRecorder = audioReaderFactory.create(config, dispatchers).also { audioReader = it } diff --git a/libraries/voicerecorder/impl/src/test/kotlin/io/element/android/libraries/voicerecorder/impl/DefaultVoiceRecorderTest.kt b/libraries/voicerecorder/impl/src/test/kotlin/io/element/android/libraries/voicerecorder/impl/DefaultVoiceRecorderTest.kt index e3ff6f9198..158b9ba481 100644 --- a/libraries/voicerecorder/impl/src/test/kotlin/io/element/android/libraries/voicerecorder/impl/DefaultVoiceRecorderTest.kt +++ b/libraries/voicerecorder/impl/src/test/kotlin/io/element/android/libraries/voicerecorder/impl/DefaultVoiceRecorderTest.kt @@ -39,6 +39,7 @@ import kotlin.time.TestTimeSource class DefaultVoiceRecorderTest { private val fakeFileSystem = FakeFileSystem() private val timeSource = TestTimeSource() + private val audioReaderFactory = FakeAudioReaderFactory(audio = AUDIO) @Test fun `it emits the initial state`() = runTest { @@ -109,6 +110,32 @@ class DefaultVoiceRecorderTest { } } + @Test + fun `when startRecord is called twice, the second call is ignored`() = runTest { + val voiceRecorder = createDefaultVoiceRecorder() + voiceRecorder.state.test { + assertThat(awaitItem()).isEqualTo(VoiceRecorderState.Idle) + + voiceRecorder.startRecord() + voiceRecorder.startRecord() + assertThat(audioReaderFactory.createdCount).isEqualTo(1) + + skipItems(1) + timeSource += 5.seconds + skipItems(2) + voiceRecorder.stopRecord() + assertThat(awaitItem()).isEqualTo( + VoiceRecorderState.Finished( + file = File(FILE_PATH), + mimeType = MimeTypes.Ogg, + waveform = List(100) { 1f }, + duration = 5.seconds, + ) + ) + expectNoEvents() + } + } + @Test fun `when cancelled, it deletes the file`() = runTest { val voiceRecorder = createDefaultVoiceRecorder() @@ -128,9 +155,7 @@ class DefaultVoiceRecorderTest { return DefaultVoiceRecorder( dispatchers = testCoroutineDispatchers(), timeSource = timeSource, - audioReaderFactory = FakeAudioReaderFactory( - audio = AUDIO, - ), + audioReaderFactory = audioReaderFactory, encoder = FakeEncoder(fakeFileSystem), config = AudioConfig( format = audioFormat, diff --git a/libraries/voicerecorder/impl/src/test/kotlin/io/element/android/libraries/voicerecorder/test/FakeAudioReaderFactory.kt b/libraries/voicerecorder/impl/src/test/kotlin/io/element/android/libraries/voicerecorder/test/FakeAudioReaderFactory.kt index d4bd241aaa..d3e434538e 100644 --- a/libraries/voicerecorder/impl/src/test/kotlin/io/element/android/libraries/voicerecorder/test/FakeAudioReaderFactory.kt +++ b/libraries/voicerecorder/impl/src/test/kotlin/io/element/android/libraries/voicerecorder/test/FakeAudioReaderFactory.kt @@ -16,7 +16,11 @@ import io.element.android.libraries.voicerecorder.impl.audio.AudioReader class FakeAudioReaderFactory( private val audio: List