google/ExoPlayer · critical · OpusDecoderException
Failed to load decoder native libraries
Error message
Failed to load decoder native libraries
What it means
OpusDecoder's constructor throws OpusDecoderException('Failed to load decoder native libraries') when OpusLibrary.isAvailable() is false — the native Opus extension (libopusJNI.so plus libopus) was not loadable. The Opus extension, like the FLAC one, is a JNI wrapper over natively compiled code and must be packaged and built separately from core ExoPlayer.
Source
Thrown at extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/OpusDecoder.java:93
* @param initializationData Codec-specific initialization data. The first element must contain an
* opus header. Optionally, the list may contain two additional buffers, which must contain
* the encoder delay and seek pre roll values in nanoseconds, encoded as longs.
* @param cryptoConfig The {@link CryptoConfig} object required for decoding encrypted content.
* May be null and can be ignored if decoder does not handle encrypted content.
* @param outputFloat Forces the decoder to output float PCM samples when set
* @throws OpusDecoderException Thrown if an exception occurs when initializing the decoder.
*/
public OpusDecoder(
int numInputBuffers,
int numOutputBuffers,
int initialInputBufferSize,
List<byte[]> initializationData,
@Nullable CryptoConfig cryptoConfig,
boolean outputFloat)
throws OpusDecoderException {
super(new DecoderInputBuffer[numInputBuffers], new SimpleDecoderOutputBuffer[numOutputBuffers]);
if (!OpusLibrary.isAvailable()) {
throw new OpusDecoderException("Failed to load decoder native libraries");
}
this.cryptoConfig = cryptoConfig;
if (cryptoConfig != null && !OpusLibrary.opusIsSecureDecodeSupported()) {
throw new OpusDecoderException("Opus decoder does not support secure decode");
}
int initializationDataSize = initializationData.size();
if (initializationDataSize != 1 && initializationDataSize != 3) {
throw new OpusDecoderException("Invalid initialization data size");
}
if (initializationDataSize == 3
&& (initializationData.get(1).length != 8 || initializationData.get(2).length != 8)) {
throw new OpusDecoderException("Invalid pre-skip or seek pre-roll");
}
preSkipSamples = getPreSkipSamples(initializationData);
seekPreRollSamples = getSeekPreRollSamples(initializationData);
skipSamples = preSkipSamples;
byte[] headerBytes = initializationData.get(0);View on GitHub (pinned to dd430f7053)
Solutions
- Confirm libopusJNI.so is inside the APK (APK Analyzer -> lib/<abi>/) for every ABI you ship.
- Build the extension from source per extensions/opus README, or switch to androidx.media3 which publishes prebuilt decoder extensions including Opus.
- If you only need Opus passthrough/framework decoding, do not register the extension renderer; let the platform decoder handle audio/opus (Android 5.0+), or enable DefaultRenderersFactory.setEnableDecoderFallback(true).
Example fix
// before
DefaultRenderersFactory f = new DefaultRenderersFactory(context); // extension renderer throws on Opus
// after
DefaultRenderersFactory f = new DefaultRenderersFactory(context)
.setEnableDecoderFallback(true); // fall back to framework Opus decoder Defensive patterns
Strategy: validation
Validate before calling
if (OpusLibrary.isAvailable()) { /* safe to use extension OpusRenderer */ } else { /* use framework decoder or report unsupported */ } Try / catch
catch (OpusDecoderException e) { if (e.getMessage().contains("native libraries")) { fallBackToFrameworkDecoder(); } else throw e; } Prevention
- Verify libopusJNI.so ships for all target ABIs (APK Analyzer).
- Prefer Media3 prebuilt decoder extensions over custom NDK builds.
- Enable renderer fallback in DefaultRenderersFactory.
When it happens
Trigger: Creating an OpusDecoder (directly, or when an OpusRenderer decodes an audio/opus track) on a process where System.loadLibrary("opusJNI") failed: the .so is absent from the APK, the wrong ABI was packaged, or the extension was compiled without its native components.
Common situations: Using a Java-only build of the extension (native build steps skipped); ABI filters excluding the device; R8/manifest packaging stripping the .so; deploying to an emulator whose ABI does not match the packaged libraries; confusing the extension with the platform Opus support (Android 5.0+ has a framework Opus decoder the extension bypasses).
Related errors
- Failed to load decoder native libraries.
- Failed to initialize decoder
- Invalid header length
- Invalid channel count: ${channelCount}
- Invalid header, missing stream map
AI-assisted analysis of google/ExoPlayer@dd430f7053 (2026-08-14).
Data as JSON: /api/errors/56880c37a0d6e7b2.
Report an issue: GitHub.