Replymessage unavailable
I had another „chat“ with Google. 😁
Since it seems that we won’t get rid of libvlc anyway, an automation in background, where exoplayer switches automatic to libvlc when an error occurres (I think of the h264 level 6.2 problem back then) without user interaction, could be a solution maybe.
This way a manual selection wouldn’t be necessary anymore.
Google says:
„Seamless libVLC Fallback on ExoPlayer Decoding/Playback Errors
Hi! Since Echogram already has both ExoPlayer (Media3) and libVLC integrated, it would be an incredible UX improvement to implement an automatic background fallback.
Currently, certain video files—like rare H.264 profiles (e.g., Level 6.2 with extreme bitrates), older containers (AVI), or files with broken headers—cause ExoPlayer to fail with a decoder or playback error. Instead of showing an error or an infinite loading spinner, the app could catch this error and silently switch the playback to libVLC at the exact same timestamp.
Implementing this is very straightforward and would take only a couple of hours since both player engines are already in place.
Here is a technical breakdown of how this can be handled in Kotlin/Java:
## 1. Catching the ExoPlayer Error (Player.Listener)
You can attach a Player.Listener to ExoPlayer and listen to onPlayerError. We want to filter for decoding, decoder initialization, or general source loading failures.
exoPlayer.addListener(object : Player.Listener {
override fun onPlayerError(error: PlaybackException) {
// Check if the error is related to decoding or hardware capabilities
if (error.errorCode == PlaybackException.ERROR_CODE_DECODING_FAILED ||
error.errorCode == PlaybackException.ERROR_CODE_DECODER_INIT_FAILED ||
error.errorCode == PlaybackException.ERROR_CODE_IO_UNSPECIFIED) {
// 1. Save the current playback position so the user doesn't lose track
val currentPosition = exoPlayer.currentPosition
// 2. Safely release the ExoPlayer instance
releaseExoPlayer()
// 3. Trigger the libVLC Fallback
switchToLibVlcFallback(videoUrl, currentPosition)
} else {
// Handle other non-playback errors normally
showErrorMessage(error)
}
}
})
## 2. Launching the libVLC Fallback
The fallback function initializes the libVLC engine using the same video URL and applies the saved timestamp so the transition feels as seamless as possible.
private fun switchToLibVlcFallback(url: String, startPositionMs: Long) {
// 1. Show a brief loading spinner if needed while libVLC initializes
showLoadingSpinner()
// 2. Initialize Media with the video URL
val media = Media(libVlcInstance, Uri.parse(url))
// 3. CRITICAL: Pass the exact timestamp from ExoPlayer to libVLC
vlcMediaPlayer.media = media
vlcMediaPlayer.time = startPositionMs
// 4. Start playback
vlcMediaPlayer.play()
}
## 3. Preventing Infinite Loops (Safety Guard)
To prevent the app from getting stuck if a file is completely corrupted (meaning libVLC would crash too), a simple boolean flag like isFallbackActive = true should be set when switching. If libVLC throws an error while isFallbackActive is true, the app should stop trying and display the final error message to the user.
## Why this is great for Echogram:
* Zero added app size: Since libVLC is already bundled, this feature adds pure logic without bloating the APK.
* Bulletproof Playback: It combines the best of both worlds. ExoPlayer stays the lightweight default for 95% of standard/HDR streams, while libVLC acts as the ultimate Swiss Army knife for problematic files.“