Add voice message recording duration indicator and limit (#1628)

---------

Co-authored-by: ElementBot <benoitm+elementbot@element.io>
This commit is contained in:
jonnyandrew 2023-10-24 12:44:53 +01:00 committed by GitHub
parent 8c0d9cc6a0
commit f1b142f002
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 263 additions and 35 deletions

View file

@ -37,15 +37,19 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.yield
import timber.log.Timber
import java.io.File
import java.util.UUID
import javax.inject.Inject
import kotlin.time.Duration.Companion.minutes
import kotlin.time.TimeSource
@SingleIn(RoomScope::class)
@ContributesBinding(RoomScope::class)
class VoiceRecorderImpl @Inject constructor(
private val dispatchers: CoroutineDispatchers,
private val timeSource: TimeSource,
private val audioReaderFactory: AudioReader.Factory,
private val encoder: Encoder,
private val fileManager: VoiceFileManager,
@ -74,16 +78,27 @@ class VoiceRecorderImpl @Inject constructor(
val audioRecorder = audioReaderFactory.create(config, dispatchers).also { audioReader = it }
recordingJob = voiceCoroutineScope.launch {
val startedAt = timeSource.markNow()
audioRecorder.record { audio ->
yield()
val elapsedTime = startedAt.elapsedNow()
if (elapsedTime >= 30.minutes) {
Timber.w("Voice message time limit reached")
stopRecord(false)
return@record
}
when (audio) {
is Audio.Data -> {
val audioLevel = audioLevelCalculator.calculateAudioLevel(audio.buffer)
_state.emit(VoiceRecorderState.Recording(audioLevel))
_state.emit(VoiceRecorderState.Recording(elapsedTime, audioLevel))
encoder.encode(audio.buffer, audio.readSize)
}
is Audio.Error -> {
Timber.e("Voice message error: code=${audio.audioRecordErrorCode}")
_state.emit(VoiceRecorderState.Recording(0.0))
_state.emit(VoiceRecorderState.Recording(elapsedTime, 0.0))
}
}
}

View file

@ -37,9 +37,13 @@ import kotlinx.coroutines.test.runTest
import org.junit.BeforeClass
import org.junit.Test
import java.io.File
import kotlin.time.Duration.Companion.minutes
import kotlin.time.Duration.Companion.seconds
import kotlin.time.TestTimeSource
class VoiceRecorderImplTest {
private val fakeFileSystem = FakeFileSystem()
private val timeSource = TestTimeSource()
@Test
fun `it emits the initial state`() = runTest {
@ -56,9 +60,27 @@ class VoiceRecorderImplTest {
assertThat(awaitItem()).isEqualTo(VoiceRecorderState.Idle)
voiceRecorder.startRecord()
assertThat(awaitItem()).isEqualTo(VoiceRecorderState.Recording(1.0))
assertThat(awaitItem()).isEqualTo(VoiceRecorderState.Recording(0.0))
assertThat(awaitItem()).isEqualTo(VoiceRecorderState.Recording(1.0))
assertThat(awaitItem()).isEqualTo(VoiceRecorderState.Recording(0.seconds, 1.0))
timeSource += 1.seconds
assertThat(awaitItem()).isEqualTo(VoiceRecorderState.Recording(1.seconds,0.0))
timeSource += 1.seconds
assertThat(awaitItem()).isEqualTo(VoiceRecorderState.Recording(2.seconds, 1.0))
}
}
@Test
fun `when elapsed time reaches 30 minutes, it stops recording`() = runTest {
val voiceRecorder = createVoiceRecorder()
voiceRecorder.state.test {
assertThat(awaitItem()).isEqualTo(VoiceRecorderState.Idle)
voiceRecorder.startRecord()
assertThat(awaitItem()).isEqualTo(VoiceRecorderState.Recording(0.minutes, 1.0))
timeSource += 29.minutes
assertThat(awaitItem()).isEqualTo(VoiceRecorderState.Recording(29.minutes, 0.0))
timeSource += 1.minutes
assertThat(awaitItem()).isEqualTo(VoiceRecorderState.Finished(File(FILE_PATH), "audio/ogg"))
}
}
@ -94,6 +116,7 @@ class VoiceRecorderImplTest {
val fileConfig = VoiceRecorderModule.provideVoiceFileConfig()
return VoiceRecorderImpl(
dispatchers = testCoroutineDispatchers(),
timeSource = timeSource,
audioReaderFactory = FakeAudioRecorderFactory(
audio = AUDIO,
),

View file

@ -35,6 +35,7 @@ class FakeAudioReader(
while (audios.hasNext()) {
if (!isRecording) break
onAudio(audios.next())
yield()
}
while (isActive) {
// do not return from the coroutine until it is cancelled