diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/asset/Asset.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/asset/Asset.kt index 435971068ab..41a78d869d5 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/asset/Asset.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/asset/Asset.kt @@ -64,7 +64,7 @@ fun isDisplayableImageMimeType(mimeType: String): Boolean = mimeType in setOf( ) fun isAudioMimeType(mimeType: String): Boolean = mimeType in setOf( - "audio/mp3", "audio/mpeg", "audio/ogg", "audio/wav", "audio/x-wav", "audio/x-pn-wav" + "audio/mp3", "audio/mp4", "audio/mpeg", "audio/ogg", "audio/wav", "audio/x-wav", "audio/x-pn-wav" ) fun isVideoMimeType(mimeType: String): Boolean = mimeType in setOf( diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/asset/AssetMapper.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/asset/AssetMapper.kt index 753c94ca6f6..d25b09dad07 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/asset/AssetMapper.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/asset/AssetMapper.kt @@ -212,6 +212,13 @@ class AssetMapperImpl( ) ) + is Audio -> Asset.Original.MetaData.Audio( + audio = Asset.AudioMetaData( + durationInMillis = metadata.durationMs, + normalizedLoudness = metadata.normalizedLoudness?.let { ByteArr(it) } + ) + ) + else -> null } ), diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/asset/ScheduleNewAssetMessageUseCase.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/asset/ScheduleNewAssetMessageUseCase.kt index e4a024f8652..dd7d081992b 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/asset/ScheduleNewAssetMessageUseCase.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/asset/ScheduleNewAssetMessageUseCase.kt @@ -25,6 +25,7 @@ import com.wire.kalium.cryptography.utils.generateRandomAES256Key import com.wire.kalium.logic.CoreFailure import com.wire.kalium.logic.data.asset.AssetRepository import com.wire.kalium.logic.data.asset.UploadedAssetId +import com.wire.kalium.logic.data.asset.isAudioMimeType import com.wire.kalium.logic.data.asset.isDisplayableImageMimeType import com.wire.kalium.logic.data.id.ConversationId import com.wire.kalium.logic.data.message.AssetContent @@ -85,7 +86,8 @@ interface ScheduleNewAssetMessageUseCase { assetName: String, assetMimeType: String, assetWidth: Int?, - assetHeight: Int? + assetHeight: Int?, + audioLengthInMs: Long ): ScheduleNewAssetMessageResult } @@ -118,6 +120,7 @@ internal class ScheduleNewAssetMessageUseCaseImpl( assetMimeType: String, assetWidth: Int?, assetHeight: Int?, + audioLengthInMs: Long ): ScheduleNewAssetMessageResult { slowSyncRepository.slowSyncStatus.first { it is SlowSyncStatus.Complete @@ -142,6 +145,7 @@ internal class ScheduleNewAssetMessageUseCaseImpl( assetWidth = assetWidth, assetHeight = assetHeight, expireAfter = messageTimer, + audioLengthInMs = audioLengthInMs, expectsReadConfirmation = expectsReadConfirmation ).onSuccess { (currentAssetMessageContent, message) -> // We schedule the asset upload and return Either.Right so later it's transformed to Success(message.id) @@ -186,6 +190,7 @@ internal class ScheduleNewAssetMessageUseCaseImpl( assetWidth: Int?, assetHeight: Int?, expireAfter: Duration?, + audioLengthInMs: Long, expectsReadConfirmation: Boolean ): Either> = currentClientIdProvider().flatMap { currentClientId -> // Create a temporary asset key and domain @@ -208,6 +213,7 @@ internal class ScheduleNewAssetMessageUseCaseImpl( sha256Key = SHA256Key(byteArrayOf()), // Asset ID will be replaced with right value after asset upload assetId = UploadedAssetId(generatedAssetUuid, tempAssetDomain), + audioLengthInMs = audioLengthInMs ) val message = Message.Regular( @@ -307,6 +313,13 @@ internal class ScheduleNewAssetMessageUseCaseImpl( AssetContent.AssetMetadata.Image(assetWidth, assetHeight) } + isAudioMimeType(mimeType) -> { + AssetContent.AssetMetadata.Audio( + durationMs = audioLengthInMs, + normalizedLoudness = null + ) + } + else -> null }, remoteData = AssetContent.RemoteData( @@ -345,5 +358,6 @@ private data class AssetMessageMetadata( val assetWidth: Int?, val assetHeight: Int?, val otrKey: AES256Key, - val sha256Key: SHA256Key + val sha256Key: SHA256Key, + val audioLengthInMs: Long ) diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/asset/AssetMapperTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/asset/AssetMapperTest.kt new file mode 100644 index 00000000000..62deef5e627 --- /dev/null +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/asset/AssetMapperTest.kt @@ -0,0 +1,93 @@ +/* + * Wire + * Copyright (C) 2023 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.kalium.logic.data.asset + +import com.wire.kalium.logic.data.message.AssetContent +import com.wire.kalium.logic.data.message.EncryptionAlgorithmMapper +import com.wire.kalium.logic.data.message.Message +import com.wire.kalium.logic.data.message.MessageContent +import com.wire.kalium.logic.data.message.MessageEncryptionAlgorithm +import com.wire.kalium.protobuf.messages.Asset +import com.wire.kalium.util.KaliumDispatcher +import io.mockative.Mock +import io.mockative.classOf +import io.mockative.mock +import kotlinx.coroutines.test.runTest +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertNull + +class AssetMapperTest { + + @Test + fun givenAudioAssetContent_whenMappingToProtoAssetMessage_thenReturnCorrectProtoAudioMetadata() = runTest { + // given + val audioMetadata = AssetContent.AssetMetadata.Audio( + durationMs = 4444, + normalizedLoudness = null + ) + val messageContent = MessageContent.Asset( + value = AssetContent( + sizeInBytes = 10000, + name = "audio.m4a", + mimeType = "audio/mp4", + metadata = audioMetadata, + remoteData = AssetContent.RemoteData( + otrKey = byteArrayOf(), + sha256 = byteArrayOf(), + assetId = "abcd-1234", + assetToken = "token", + assetDomain = "domain", + encryptionAlgorithm = MessageEncryptionAlgorithm.AES_GCM + ), + uploadStatus = Message.UploadStatus.FAILED_UPLOAD, + downloadStatus = Message.DownloadStatus.NOT_DOWNLOADED + ) + ) + val (_, mapper) = Arrangement() + .arrange() + + // when + val result = mapper.fromAssetContentToProtoAssetMessage( + messageContent = messageContent, + expectsReadConfirmation = true + ) + + // then + assertEquals( + audioMetadata.durationMs, + (result.original?.metaData as Asset.Original.MetaData.Audio).value.durationInMillis + ) + assertNull( + (result.original?.metaData as Asset.Original.MetaData.Audio).value.normalizedLoudness + ) + } + + private class Arrangement { + + @Mock + val dispatcher = mock(classOf()) + + val mapper = AssetMapperImpl( + encryptionAlgorithmMapper = EncryptionAlgorithmMapper(), + dispatcher = dispatcher + ) + + fun arrange() = this to mapper + } +} diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/asset/ScheduleNewAssetMessageUseCaseTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/asset/ScheduleNewAssetMessageUseCaseTest.kt index 6abd04ca9e8..81735b49b61 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/asset/ScheduleNewAssetMessageUseCaseTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/asset/ScheduleNewAssetMessageUseCaseTest.kt @@ -102,7 +102,8 @@ class ScheduleNewAssetMessageUseCaseTest { assetName = assetName, assetMimeType = "text/plain", assetWidth = null, - assetHeight = null + assetHeight = null, + audioLengthInMs = 0 ) advanceUntilIdle() @@ -134,7 +135,8 @@ class ScheduleNewAssetMessageUseCaseTest { assetName = assetName, assetMimeType = "text/plain", assetWidth = null, - assetHeight = null + assetHeight = null, + audioLengthInMs = 0 ) advanceUntilIdle() @@ -166,7 +168,8 @@ class ScheduleNewAssetMessageUseCaseTest { assetName = assetName, assetMimeType = "text/plain", assetWidth = null, - assetHeight = null + assetHeight = null, + audioLengthInMs = 0 ) advanceUntilIdle() @@ -205,7 +208,8 @@ class ScheduleNewAssetMessageUseCaseTest { assetName = assetName, assetMimeType = "text/plain", assetWidth = null, - assetHeight = null + assetHeight = null, + audioLengthInMs = 0 ) advanceUntilIdle() @@ -250,7 +254,8 @@ class ScheduleNewAssetMessageUseCaseTest { assetName = assetName, assetMimeType = "text/plain", assetWidth = null, - assetHeight = null + assetHeight = null, + audioLengthInMs = 0 ) advanceUntilIdle() @@ -289,7 +294,8 @@ class ScheduleNewAssetMessageUseCaseTest { assetName = assetName, assetMimeType = "text/plain", assetWidth = null, - assetHeight = null + assetHeight = null, + audioLengthInMs = 0 ) advanceUntilIdle() @@ -336,7 +342,8 @@ class ScheduleNewAssetMessageUseCaseTest { assetName = assetName, assetMimeType = "text/plain", assetWidth = null, - assetHeight = null + assetHeight = null, + audioLengthInMs = 0 ) advanceUntilIdle() @@ -390,7 +397,8 @@ class ScheduleNewAssetMessageUseCaseTest { assetName = assetName, assetMimeType = "text/plain", assetWidth = null, - assetHeight = null + assetHeight = null, + audioLengthInMs = 0 ) advanceUntilIdle() @@ -434,7 +442,8 @@ class ScheduleNewAssetMessageUseCaseTest { assetName = assetName, assetMimeType = "text/plain", assetWidth = null, - assetHeight = null + assetHeight = null, + audioLengthInMs = 0 ) advanceUntilIdle() @@ -476,7 +485,8 @@ class ScheduleNewAssetMessageUseCaseTest { assetName = assetName, assetMimeType = "text/plain", assetWidth = null, - assetHeight = null + assetHeight = null, + audioLengthInMs = 0 ) advanceUntilIdle() diff --git a/testservice/src/main/kotlin/com/wire/kalium/testservice/managed/ConversationRepository.kt b/testservice/src/main/kotlin/com/wire/kalium/testservice/managed/ConversationRepository.kt index f7797f22714..8b0401c8399 100644 --- a/testservice/src/main/kotlin/com/wire/kalium/testservice/managed/ConversationRepository.kt +++ b/testservice/src/main/kotlin/com/wire/kalium/testservice/managed/ConversationRepository.kt @@ -326,6 +326,7 @@ sealed class ConversationRepository { type, null, null, + 0L ) } when (sendResult) { @@ -406,6 +407,7 @@ sealed class ConversationRepository { "image", type, width, height, + 0L ) if (sendResult is ScheduleNewAssetMessageResult.Failure) { if (sendResult.coreFailure is StorageFailure.Generic) {