FIx height and concurrent exception

- Fix live waveform hight
- Fix concurrent modification exception when sharing levels
- Tidy up width of live waveform
This commit is contained in:
David Langley
2023-10-27 08:41:08 +01:00
parent 510b1f63b9
commit d20ae3f6b9
3 changed files with 34 additions and 20 deletions

View File

@@ -44,6 +44,7 @@ import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.theme.ElementTheme
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toPersistentList
import java.lang.Float.min
private const val DEFAULT_GRAPHICS_LAYER_ALPHA: Float = 0.99F
private val waveFormHeight = 26.dp
@@ -57,7 +58,7 @@ fun LiveWaveformView(
) {
var canvasSize by remember { mutableStateOf(DpSize(0.dp, 0.dp)) }
val canvasWidth by remember(levels, lineWidth, linePadding) {
val waveformWidth by remember(levels, lineWidth, linePadding) {
derivedStateOf {
levels.size * (lineWidth.value + linePadding.value)
}
@@ -72,11 +73,11 @@ fun LiveWaveformView(
) {
Canvas(
modifier = Modifier
.width(Dp(canvasWidth))
.width(canvasSize.width)
.graphicsLayer(alpha = DEFAULT_GRAPHICS_LAYER_ALPHA)
.then(modifier)
) {
canvasSize = DpSize(Dp(canvasWidth), size.height.toDp())
canvasSize = DpSize(Dp(min(waveformWidth, width.toFloat())), size.height.toDp())
val countThatFitsWidth = (width.toFloat() / (lineWidth.toPx() + linePadding.toPx())).toInt()
drawWaveform(
waveformData = levels.takeLast(countThatFitsWidth).toPersistentList(),

View File

@@ -73,7 +73,7 @@ internal fun VoiceMessageRecording(
LiveWaveformView(
modifier = Modifier
.height(34.dp)
.height(26.dp)
.weight(1f),
levels = levels
)

View File

@@ -23,6 +23,7 @@ import io.element.android.libraries.core.coroutine.CoroutineDispatchers
import io.element.android.libraries.core.coroutine.childScope
import io.element.android.libraries.di.RoomScope
import io.element.android.libraries.di.SingleIn
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
import io.element.android.libraries.voicerecorder.api.VoiceRecorder
import io.element.android.libraries.voicerecorder.api.VoiceRecorderState
import io.element.android.libraries.voicerecorder.impl.audio.Audio
@@ -38,6 +39,8 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.yield
import timber.log.Timber
import java.io.File
@@ -67,6 +70,7 @@ class VoiceRecorderImpl @Inject constructor(
private var audioReader: AudioReader? = null
private var recordingJob: Job? = null
private val levels: MutableList<Float> = mutableListOf()
private val lock = Mutex()
private val _state = MutableStateFlow<VoiceRecorderState>(VoiceRecorderState.Idle)
override val state: StateFlow<VoiceRecorderState> = _state
@@ -76,7 +80,10 @@ class VoiceRecorderImpl @Inject constructor(
Timber.i("Voice recorder started recording")
outputFile = fileManager.createFile()
.also(encoder::init)
levels.clear()
lock.withLock {
levels.clear()
}
val audioRecorder = audioReaderFactory.create(config, dispatchers).also { audioReader = it }
@@ -96,8 +103,11 @@ class VoiceRecorderImpl @Inject constructor(
when (audio) {
is Audio.Data -> {
val audioLevel = audioLevelCalculator.calculateAudioLevel(audio.buffer)
levels.add(audioLevel)
_state.emit(VoiceRecorderState.Recording(elapsedTime, levels))
lock.withLock{
levels.add(audioLevel)
_state.emit(VoiceRecorderState.Recording(elapsedTime, levels.toList()))
}
encoder.encode(audio.buffer, audio.readSize)
}
is Audio.Error -> {
@@ -126,21 +136,24 @@ class VoiceRecorderImpl @Inject constructor(
audioReader = null
encoder.release()
if (cancelled) {
deleteRecording()
levels.clear()
}
_state.emit(
when (val file = outputFile) {
null -> VoiceRecorderState.Idle
else -> VoiceRecorderState.Finished(
file = file,
mimeType = fileConfig.mimeType,
waveform = levels.resample(100),
)
lock.withLock {
if (cancelled) {
deleteRecording()
levels.clear()
}
)
_state.emit(
when (val file = outputFile) {
null -> VoiceRecorderState.Idle
else -> VoiceRecorderState.Finished(
file = file,
mimeType = fileConfig.mimeType,
waveform = levels.resample(100),
)
}
)
}
}
/**