Skip to content

Commit

Permalink
fix: audio message filter toggle (WPB-6406) (#2847)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexandreferris authored Apr 3, 2024
1 parent f71d13e commit 7b1afb5
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ class RecordAudioMessagePlayer @Inject constructor(
suspend fun playAudio(
audioFile: File
) {
if (currentAudioFile != null) {
if (currentAudioFile != null && audioFile.name == currentAudioFile?.name) {
resumeOrPauseAudio()
} else {
stopCurrentlyPlayingAudioMessage()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Wire
* Copyright (C) 2024 Wire Swiss GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.wire.android.ui.home.messagecomposer.recordaudio

import android.content.Context
import com.waz.audioeffect.AudioEffect
import com.wire.android.appLogger
import javax.inject.Singleton
import javax.inject.Inject

@Singleton
class GenerateAudioFileWithEffectsUseCase @Inject constructor() {
/**
* Note: This UseCase can't be tested as we cannot mock `AudioEffect` from AVS.
* Generates audio file with effects on received path from the original file path.
*
* @return Unit, as the content of audio with effects will be saved directly to received file path.
*/
operator fun invoke(
context: Context,
originalFilePath: String,
effectsFilePath: String
) {
val audioEffectsResult = AudioEffect(context)
.applyEffectM4A(
originalFilePath,
effectsFilePath,
AudioEffect.AVS_AUDIO_EFFECT_VOCODER_MED,
true
)

if (audioEffectsResult > -1) {
appLogger.i("[$TAG] -> Audio file with effects generated successfully.")
} else {
appLogger.w("[$TAG] -> There was an issue with generating audio file with effects.")
}
}

private companion object {
const val TAG = "GenerateAudioFileWithEffectsUseCase"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,7 @@ fun RecordAudioButtonEnabled(
buttonColor = colorsScheme().recordAudioStartColor,
bottomText = R.string.record_audio_start_label,
applyAudioFilterState = applyAudioFilterState,
applyAudioFilterClick = applyAudioFilterClick,
isAudioFilterEnabled = true
applyAudioFilterClick = applyAudioFilterClick
)
}

Expand Down Expand Up @@ -144,6 +143,7 @@ fun RecordAudioButtonRecording(
buttonColor = colorsScheme().recordAudioStopColor,
bottomText = R.string.record_audio_recording_label,
buttonState = if (seconds > 0) WireButtonState.Default else WireButtonState.Disabled,
isAudioFilterEnabled = false,
applyAudioFilterState = applyAudioFilterState,
applyAudioFilterClick = { }
)
Expand All @@ -157,7 +157,8 @@ fun RecordAudioButtonSend(
modifier: Modifier,
outputFile: File?,
onPlayAudio: () -> Unit,
onSliderPositionChange: (Int) -> Unit
onSliderPositionChange: (Int) -> Unit,
applyAudioFilterClick: (Boolean) -> Unit
) {
RecordAudioButton(
onClick = onClick,
Expand All @@ -180,7 +181,7 @@ fun RecordAudioButtonSend(
buttonColor = colorsScheme().recordAudioStartColor,
bottomText = R.string.record_audio_send_label,
applyAudioFilterState = applyAudioFilterState,
applyAudioFilterClick = { }
applyAudioFilterClick = applyAudioFilterClick
)
}

Expand All @@ -196,7 +197,7 @@ private fun RecordAudioButton(
buttonState: WireButtonState = WireButtonState.Default,
applyAudioFilterState: Boolean,
applyAudioFilterClick: (Boolean) -> Unit,
isAudioFilterEnabled: Boolean = false
isAudioFilterEnabled: Boolean = true
) {
Column(
modifier = modifier,
Expand Down Expand Up @@ -296,7 +297,8 @@ fun PreviewRecordAudioButtonSend() {
outputFile = null,
onPlayAudio = {},
onSliderPositionChange = {},
applyAudioFilterState = false
applyAudioFilterState = false,
applyAudioFilterClick = {}
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Divider
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
Expand All @@ -37,6 +36,7 @@ import androidx.lifecycle.LifecycleOwner
import com.sebaslogen.resaca.hilt.hiltViewModelScoped
import com.wire.android.ui.common.colorsScheme
import com.wire.android.ui.common.dimensions
import com.wire.android.ui.common.divider.WireDivider
import com.wire.android.ui.common.snackbar.LocalSnackbarHostState
import com.wire.android.ui.home.conversations.model.UriAsset
import com.wire.android.ui.theme.wireColorScheme
Expand Down Expand Up @@ -92,7 +92,7 @@ fun RecordAudioComponent(
.fillMaxHeight()
.background(colorsScheme().background)
) {
Divider(color = MaterialTheme.wireColorScheme.outline)
WireDivider(color = MaterialTheme.wireColorScheme.outline)
RecordAudioButtonClose(
onClick = { viewModel.showDiscardRecordingDialog(onCloseRecordAudio) },
modifier = Modifier
Expand Down Expand Up @@ -120,6 +120,7 @@ fun RecordAudioComponent(

RecordAudioButtonState.READY_TO_SEND -> RecordAudioButtonSend(
applyAudioFilterState = viewModel.state.shouldApplyEffects,
applyAudioFilterClick = viewModel::setApplyEffectsAndPlayAudio,
audioState = viewModel.state.audioState,
onClick = {
viewModel.sendRecording(onAudioRecorded = onAudioRecorded) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ import androidx.compose.runtime.setValue
import androidx.core.net.toUri
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.waz.audioeffect.AudioEffect
import com.wire.android.appLogger
import com.wire.android.datastore.GlobalDataStore
import com.wire.android.media.audiomessage.AudioMediaPlayingState
import com.wire.android.media.audiomessage.AudioState
import com.wire.android.media.audiomessage.RecordAudioMessagePlayer
import com.wire.android.ui.home.conversations.model.UriAsset
Expand Down Expand Up @@ -56,6 +56,7 @@ class RecordAudioViewModel @Inject constructor(
private val recordAudioMessagePlayer: RecordAudioMessagePlayer,
private val observeEstablishedCalls: ObserveEstablishedCallsUseCase,
private val getAssetSizeLimit: GetAssetSizeLimitUseCase,
private val generateAudioFileWithEffects: GenerateAudioFileWithEffectsUseCase,
private val currentScreenManager: CurrentScreenManager,
private val audioMediaRecorder: AudioMediaRecorder,
private val globalDataStore: GlobalDataStore
Expand All @@ -72,6 +73,13 @@ class RecordAudioViewModel @Inject constructor(

fun getInfoMessage(): SharedFlow<UIText> = infoMessage.asSharedFlow()

fun setApplyEffectsAndPlayAudio(enabled: Boolean) {
setShouldApplyEffects(enabled = enabled)
if (state.audioState.audioMediaPlayingState is AudioMediaPlayingState.Playing) {
onPlayAudio()
}
}

fun getPlayableAudioFile(): File? = if (state.shouldApplyEffects) {
state.effectsOutputFile
} else {
Expand Down Expand Up @@ -167,21 +175,11 @@ class RecordAudioViewModel @Inject constructor(
audioMediaRecorder.release()

if (state.originalOutputFile != null && state.effectsOutputFile != null) {
if (state.shouldApplyEffects) {
val result = AudioEffect(context)
.applyEffectM4A(
state.originalOutputFile!!.path,
state.effectsOutputFile!!.path,
AudioEffect.AVS_AUDIO_EFFECT_VOCODER_MED,
true
)

if (result > -1) {
appLogger.i("[$tag] -> Audio file with effects generated successfully.")
} else {
appLogger.w("[$tag] -> There was an issue with generating audio file with effects.")
}
}
generateAudioFileWithEffects(
context = context,
originalFilePath = state.originalOutputFile!!.path,
effectsFilePath = state.effectsOutputFile!!.path
)

state = state.copy(
buttonState = RecordAudioButtonState.READY_TO_SEND,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ class RecordAudioViewModelTest {
fun `given user is recording audio, when stopping the recording, then send audio button is shown`() =
runTest {
// given
val (_, viewModel) = Arrangement()
val (arrangement, viewModel) = Arrangement()
.arrange()

viewModel.startRecording()
Expand All @@ -109,6 +109,13 @@ class RecordAudioViewModelTest {
RecordAudioButtonState.READY_TO_SEND,
viewModel.state.buttonState
)
verify(exactly = 1) {
arrangement.generateAudioFileWithEffects(
context = any(),
originalFilePath = viewModel.state.originalOutputFile!!.path,
effectsFilePath = viewModel.state.effectsOutputFile!!.path
)
}
}

@Test
Expand Down Expand Up @@ -268,6 +275,7 @@ class RecordAudioViewModelTest {
val currentScreenManager = mockk<CurrentScreenManager>()
val getAssetSizeLimit = mockk<GetAssetSizeLimitUseCase>()
val globalDataStore = mockk<GlobalDataStore>()
val generateAudioFileWithEffects = mockk<GenerateAudioFileWithEffectsUseCase>()
val context = mockk<Context>()

val viewModel by lazy {
Expand All @@ -278,6 +286,7 @@ class RecordAudioViewModelTest {
currentScreenManager = currentScreenManager,
audioMediaRecorder = audioMediaRecorder,
getAssetSizeLimit = getAssetSizeLimit,
generateAudioFileWithEffects = generateAudioFileWithEffects,
globalDataStore = globalDataStore
)
}
Expand All @@ -304,6 +313,7 @@ class RecordAudioViewModelTest {
maxSize = GetAssetSizeLimitUseCaseImpl.ASSET_SIZE_DEFAULT_LIMIT_BYTES
)
)
every { generateAudioFileWithEffects(any(), any(), any()) } returns Unit

coEvery { currentScreenManager.observeCurrentScreen(any()) } returns MutableStateFlow(
CurrentScreen.Conversation(
Expand Down

0 comments on commit 7b1afb5

Please sign in to comment.