Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: audio converting error on lower APIs [WPB-11242] #3467

Merged
merged 5 commits into from
Sep 25, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import android.media.MediaExtractor
import android.media.MediaFormat
import android.media.MediaMuxer
import android.media.MediaRecorder
import android.os.ParcelFileDescriptor
import com.wire.android.appLogger
import com.wire.android.util.dispatchers.DispatcherProvider
import com.wire.android.util.fileDateTime
Expand Down Expand Up @@ -224,11 +225,19 @@ class AudioMediaRecorder @Inject constructor(
var codec: MediaCodec? = null
var muxer: MediaMuxer? = null
var fileInputStream: FileInputStream? = null
var parcelFileDescriptor: ParcelFileDescriptor? = null
var success = true

try {
val inputFile = File(inputFilePath)
fileInputStream = FileInputStream(inputFile)

val outputFile = mp4OutputPath?.toFile()
parcelFileDescriptor = ParcelFileDescriptor.open(
outputFile,
ParcelFileDescriptor.MODE_READ_WRITE or ParcelFileDescriptor.MODE_CREATE
)

val mediaExtractor = MediaExtractor()
mediaExtractor.setDataSource(inputFilePath)

Expand All @@ -245,12 +254,14 @@ class AudioMediaRecorder @Inject constructor(
codec.start()

val bufferInfo = MediaCodec.BufferInfo()
muxer = MediaMuxer(mp4OutputPath.toString(), MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4)
muxer = MediaMuxer(parcelFileDescriptor.fileDescriptor, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4)
var trackIndex = -1
var sawInputEOS = false
var sawOutputEOS = false

var retryCount = 0
var presentationTimeUs = 0L
val bytesPerSample = (BITS_PER_SAMPLE / BITS_PER_BYTE) * AUDIO_CHANNELS

while (!sawOutputEOS && retryCount < MAX_RETRY_COUNT) {
if (!sawInputEOS) {
Expand All @@ -264,8 +275,11 @@ class AudioMediaRecorder @Inject constructor(
codec.queueInputBuffer(inputBufferIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM)
sawInputEOS = true
} else {
val presentationTimeUs = System.nanoTime() / NANOSECONDS_IN_MICROSECOND
val numSamples = sampleSize / bytesPerSample
val bufferDurationUs = (numSamples * MICROSECONDS_PER_SECOND) / SAMPLING_RATE
codec.queueInputBuffer(inputBufferIndex, 0, sampleSize, presentationTimeUs, 0)

presentationTimeUs += bufferDurationUs
}
}
}
Expand All @@ -284,8 +298,7 @@ class AudioMediaRecorder @Inject constructor(
val outputBuffer = codec.getOutputBuffer(outputBufferIndex)

if (bufferInfo.flags and MediaCodec.BUFFER_FLAG_CODEC_CONFIG != 0) {
codec.releaseOutputBuffer(outputBufferIndex, false)
continue
bufferInfo.size = 0
}

if (bufferInfo.size != 0 && outputBuffer != null) {
Expand Down Expand Up @@ -315,40 +328,43 @@ class AudioMediaRecorder @Inject constructor(
}
if (retryCount >= MAX_RETRY_COUNT) {
appLogger.e("Reached maximum retries without receiving output from codec.")
return@withContext false
success = false
}

true
} catch (e: IllegalStateException) {
appLogger.e("Could not convert wav to mp4: ${e.message}", throwable = e)
false
} catch (e: IOException) {
appLogger.e("Could not convert wav to mp4: ${e.message}", throwable = e)
false
} catch (e: NullPointerException) {
} catch (e: Exception) {
appLogger.e("Could not convert wav to mp4: ${e.message}", throwable = e)
false
success = false
} finally {
try {
fileInputStream?.close()
} catch (e: IOException) {
} catch (e: Exception) {
appLogger.e("Could not close FileInputStream: ${e.message}", throwable = e)
success = false
}

try {
muxer?.stop()
muxer?.release()
} catch (e: IllegalStateException) {
} catch (e: Exception) {
appLogger.e("Could not stop or release MediaMuxer: ${e.message}", throwable = e)
success = false
}

try {
codec?.stop()
codec?.release()
} catch (e: IllegalStateException) {
} catch (e: Exception) {
appLogger.e("Could not stop or release MediaCodec: ${e.message}", throwable = e)
success = false
}

try {
parcelFileDescriptor?.close()
} catch (e: Exception) {
appLogger.e("Could not close ParcelFileDescriptor: ${e.message}", throwable = e)
success = false
}
}
success
}

companion object {
Expand Down Expand Up @@ -378,7 +394,7 @@ class AudioMediaRecorder @Inject constructor(

private const val BIT_RATE = 64000
private const val TIMEOUT_US: Long = 10000
const val NANOSECONDS_IN_MICROSECOND = 1000
const val MICROSECONDS_PER_SECOND = 1_000_000L
const val MAX_RETRY_COUNT = 100
const val RETRY_DELAY_IN_MILLIS = 100L
}
Expand Down
Loading