diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt index a39ca814a6..10d3857096 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt @@ -1931,10 +1931,14 @@ class ConversationActivityV2 : ScreenLockActionBarActivity(), InputBarDelegate, private fun sendAttachments( attachments: List, body: String?, - quotedMessage: MessageRecord? = binding.inputBar?.quote, + quotedMessage: MessageRecord? = binding.inputBar.quote, linkPreview: LinkPreview? = null ): Pair? { - val recipient = viewModel.recipient ?: return null + if (viewModel.recipient == null) { + Log.w(TAG, "Cannot send attachments to a null recipient") + return null + } + val recipient = viewModel.recipient!! val sentTimestamp = SnodeAPI.nowWithOffset viewModel.beforeSendingAttachments() diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VoiceMessageView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VoiceMessageView.kt index 6d0d332ca0..f77d11a277 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VoiceMessageView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VoiceMessageView.kt @@ -68,8 +68,7 @@ class VoiceMessageView @JvmOverloads constructor( return } - val player = AudioSlidePlayer.createFor(context.applicationContext, audioSlide, this) - this.player = player + this.player = AudioSlidePlayer.createFor(context.applicationContext, audioSlide, this) // This sets the final duration of the uploaded voice message (audioSlide.asAttachment() as? DatabaseAttachment)?.let { attachment -> diff --git a/libsession/src/main/java/org/session/libsession/messaging/jobs/AttachmentDownloadJob.kt b/libsession/src/main/java/org/session/libsession/messaging/jobs/AttachmentDownloadJob.kt index 559f7c4cfa..1fe1f54800 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/jobs/AttachmentDownloadJob.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/jobs/AttachmentDownloadJob.kt @@ -1,6 +1,5 @@ package org.session.libsession.messaging.jobs -import okhttp3.HttpUrl import okhttp3.HttpUrl.Companion.toHttpUrlOrNull import org.session.libsession.database.MessageDataProvider import org.session.libsession.database.StorageProtocol @@ -150,7 +149,7 @@ class AttachmentDownloadJob(val attachmentID: Long, val databaseMessageID: Long) // process the duration try { InputStreamMediaDataSource(getInputStream(tempFile, attachment)).use { mediaDataSource -> - val durationMs = (DecodedAudio.create(mediaDataSource).totalDuration / 1000.0).toLong() + val durationMs = (DecodedAudio.create(mediaDataSource).totalDurationMicroseconds / 1000.0).toLong() messageDataProvider.updateAudioAttachmentDuration( attachment.attachmentId, durationMs, diff --git a/libsession/src/main/java/org/session/libsession/messaging/jobs/AttachmentUploadJob.kt b/libsession/src/main/java/org/session/libsession/messaging/jobs/AttachmentUploadJob.kt index c08b15e260..d1edfb240b 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/jobs/AttachmentUploadJob.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/jobs/AttachmentUploadJob.kt @@ -57,6 +57,7 @@ class AttachmentUploadJob(val attachmentID: Long, val threadID: String, val mess val attachment = messageDataProvider.getScaledSignalAttachmentStream(attachmentID) ?: return handleFailure(dispatcherName, Error.NoAttachment) val openGroup = storage.getOpenGroup(threadID.toLong()) + if (openGroup != null) { val keyAndResult = upload(attachment, openGroup.server, false) { OpenGroupApi.upload(it, openGroup.room, openGroup.server) @@ -114,20 +115,25 @@ class AttachmentUploadJob(val attachmentID: Long, val threadID: String, val mess delegate?.handleJobSucceeded(this, dispatcherName) val messageDataProvider = MessagingModuleConfiguration.shared.messageDataProvider messageDataProvider.handleSuccessfulAttachmentUpload(attachmentID, attachment, attachmentKey, uploadResult) - if (attachment.contentType.startsWith("audio/")) { - // process the duration + + // Outgoing voice messages do not have their final duration set because older Android versions (API 28 and below) + // can have bugs where the media duration is calculated incorrectly. In such cases we leave the correct "interim" + // voice message duration as the final duration as we know that it'll be correct.. + if (attachment.contentType.startsWith("audio/") && !attachment.voiceNote) { + // ..but for outgoing audio files we do process the duration to the best of our ability. try { val inputStream = messageDataProvider.getAttachmentStream(attachmentID)!!.inputStream!! InputStreamMediaDataSource(inputStream).use { mediaDataSource -> - val durationMs = (DecodedAudio.create(mediaDataSource).totalDuration / 1000.0).toLong() + val durationMS = (DecodedAudio.create(mediaDataSource).totalDurationMicroseconds / 1000.0).toLong() messageDataProvider.getDatabaseAttachment(attachmentID)?.attachmentId?.let { attachmentId -> - messageDataProvider.updateAudioAttachmentDuration(attachmentId, durationMs, threadID.toLong()) + messageDataProvider.updateAudioAttachmentDuration(attachmentId, durationMS, threadID.toLong()) } } } catch (e: Exception) { Log.e("Loki", "Couldn't process audio attachment", e) } } + val storage = MessagingModuleConfiguration.shared.storage storage.getMessageSendJob(messageSendJobID)?.let { val destination = it.destination as? Destination.OpenGroup ?: return@let diff --git a/libsession/src/main/java/org/session/libsession/utilities/DecodedAudio.kt b/libsession/src/main/java/org/session/libsession/utilities/DecodedAudio.kt index a342ee1ae5..6c293fb11b 100644 --- a/libsession/src/main/java/org/session/libsession/utilities/DecodedAudio.kt +++ b/libsession/src/main/java/org/session/libsession/utilities/DecodedAudio.kt @@ -53,8 +53,8 @@ class DecodedAudio { val sampleRate: Int - /** In microseconds. */ - val totalDuration: Long + /** In microseconds. There are 1 million microseconds in a second. */ + val totalDurationMicroseconds: Long val channels: Int @@ -96,15 +96,15 @@ class DecodedAudio { channels = mediaFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT) sampleRate = mediaFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE) // On some old APIs (23) this field might be missing. - totalDuration = if (mediaFormat.containsKey(MediaFormat.KEY_DURATION)) { + totalDurationMicroseconds = if (mediaFormat.containsKey(MediaFormat.KEY_DURATION)) { mediaFormat.getLong(MediaFormat.KEY_DURATION) } else { -1L } // Expected total number of samples per channel. - val expectedNumSamples = if (totalDuration >= 0) { - ((totalDuration / 1000000f) * sampleRate + 0.5f).toInt() + val expectedNumSamples = if (totalDurationMicroseconds >= 0) { + ((totalDurationMicroseconds / 1000000f) * sampleRate + 0.5f).toInt() } else { Int.MAX_VALUE }