Skip to content

Crashing for ~2% of users. #446

@darajava

Description

@darajava

Package version
5.2.0

Environment

  • Android

Describe the bug

I'm getting sporadic reports from users on strange phones saying the app is crashing.

I get a log of this crash log in Google Play:

com.llfbandit.record.record.encoder.MediaCodecEncoder.stopAndRelease

java.lang.IllegalStateException

Exception java.lang.IllegalStateException:
  at android.media.MediaCodec.native_stop
  at android.media.MediaCodec.stop (MediaCodec.java:2338)
  at com.llfbandit.record.record.encoder.MediaCodecEncoder.stopAndRelease (MediaCodecEncoder.kt)
  at com.llfbandit.record.record.encoder.MediaCodecEncoder.onError (MediaCodecEncoder.kt)
  at com.llfbandit.record.record.encoder.MediaCodecEncoder.processOutputBuffer (MediaCodecEncoder.kt)
  at com.llfbandit.record.record.encoder.MediaCodecEncoder.access$processOutputBuffer (MediaCodecEncoder.kt)
  at com.llfbandit.record.record.encoder.MediaCodecEncoder$AudioRecorderCodecCallback.onOutputBufferAvailable (MediaCodecEncoder.kt)
  at android.media.MediaCodec$EventHandler.handleCallback (MediaCodec.java:1854)
  at android.media.MediaCodec$EventHandler.handleMessage (MediaCodec.java:1752)
  at android.os.Handler.dispatchMessage (Handler.java:106)
  at android.os.Looper.loopOnce (Looper.java:241)
  at android.os.Looper.loop (Looper.java:358)
  at android.os.HandlerThread.run (HandlerThread.java:67)

Gemini's output (if it's helpful, probably not)

Summary

The app crashed because of an IllegalStateException thrown by the android.media.MediaCodec class's native_stop method. This happened while the MediaCodecEncoder class was trying to stop and release the MediaCodec instance, specifically within the stopAndRelease method called from onError. This suggests a problem occurred during audio encoding and the encoder attempted to handle the error, leading to the crash in the native_stop method. The crash originated from within an onOutputBufferAvailable callback, which is triggered when encoded audio data is available. This implies the error and subsequent crash happened during audio processing.

Potential Solutions

Handle potential errors during MediaCodec.stop(): The IllegalStateException in MediaCodec.native_stop often arises when MediaCodec.stop() is called in an invalid state. This could be due to the codec already being stopped, released, or encountering an error during a previous operation. A try-catch block should be implemented around the MediaCodec.stop() call within the stopAndRelease method to handle this exception and prevent the crash. This is the most likely cause of the crash given the stack trace.
try {
    mediaCodec.stop()
} catch (e: IllegalStateException) {
    // Log the error and potentially attempt recovery or cleanup
    Log.e("MediaCodecEncoder", "Error stopping MediaCodec", e)
    // Consider releasing resources here or setting a flag to prevent further operations
} finally {
    // Release resources like the MediaCodec instance in the finally block 
    mediaCodec.release()
    mediaCodec = null
}
Ensure correct synchronization and state management: The IllegalStateException could also occur due to incorrect synchronization of operations on the MediaCodec instance. Since the error occurs in the onOutputBufferAvailable callback, ensure that all operations on the MediaCodec, such as stop() and release(), are handled correctly within the HandlerThread associated with the codec. Any concurrent access or modification of the codec's state from different threads should be synchronized appropriately using locks or other synchronization mechanisms. A potential improvement might be to use a dedicated lock for the MediaCodec instance and acquire it before any interaction with the codec.
private val mediaCodecLock = ReentrantLock()
// ... later when interacting with the MediaCodec ...
mediaCodecLock.withLock { 
    try {
        mediaCodec?.stop()
    } catch (e: IllegalStateException) { 
        // Handle Exception
    } finally {
       mediaCodec?.release()
       mediaCodec = null
    }
}

Check for configuration errors or unsupported parameters: While less likely given the location of the crash within the stop() method, double-check that the MediaCodec is configured correctly with supported parameters for the target device. Invalid or unsupported settings might lead to internal errors within the codec, potentially causing issues during stop and release. The MediaFormat used to configure the MediaCodec should be reviewed to ensure compatibility. Pay particular attention to sample rate, bit rate, and profile/level settings, as these are common sources of compatibility issues. It is advisable to consult the Android documentation for MediaCodec and MediaFormat to understand the supported parameters for different devices and Android versions.

To Reproduce

I have not been able to reproduce this issue, but it's happening to about 2% of people.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions