{"record":{"id":"56880c37a0d6e7b2","repo":"google/ExoPlayer","slug":"failed-to-load-decoder-native-libraries-56880c","errorCode":null,"errorMessage":"Failed to load decoder native libraries","messagePattern":"Failed to load decoder native libraries","errorType":"exception","errorClass":"OpusDecoderException","httpStatus":null,"severity":"critical","filePath":"extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/OpusDecoder.java","lineNumber":93,"sourceCode":"   * @param initializationData Codec-specific initialization data. The first element must contain an\n   *     opus header. Optionally, the list may contain two additional buffers, which must contain\n   *     the encoder delay and seek pre roll values in nanoseconds, encoded as longs.\n   * @param cryptoConfig The {@link CryptoConfig} object required for decoding encrypted content.\n   *     May be null and can be ignored if decoder does not handle encrypted content.\n   * @param outputFloat Forces the decoder to output float PCM samples when set\n   * @throws OpusDecoderException Thrown if an exception occurs when initializing the decoder.\n   */\n  public OpusDecoder(\n      int numInputBuffers,\n      int numOutputBuffers,\n      int initialInputBufferSize,\n      List<byte[]> initializationData,\n      @Nullable CryptoConfig cryptoConfig,\n      boolean outputFloat)\n      throws OpusDecoderException {\n    super(new DecoderInputBuffer[numInputBuffers], new SimpleDecoderOutputBuffer[numOutputBuffers]);\n    if (!OpusLibrary.isAvailable()) {\n      throw new OpusDecoderException(\"Failed to load decoder native libraries\");\n    }\n    this.cryptoConfig = cryptoConfig;\n    if (cryptoConfig != null && !OpusLibrary.opusIsSecureDecodeSupported()) {\n      throw new OpusDecoderException(\"Opus decoder does not support secure decode\");\n    }\n    int initializationDataSize = initializationData.size();\n    if (initializationDataSize != 1 && initializationDataSize != 3) {\n      throw new OpusDecoderException(\"Invalid initialization data size\");\n    }\n    if (initializationDataSize == 3\n        && (initializationData.get(1).length != 8 || initializationData.get(2).length != 8)) {\n      throw new OpusDecoderException(\"Invalid pre-skip or seek pre-roll\");\n    }\n    preSkipSamples = getPreSkipSamples(initializationData);\n    seekPreRollSamples = getSeekPreRollSamples(initializationData);\n    skipSamples = preSkipSamples;\n\n    byte[] headerBytes = initializationData.get(0);","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/google/ExoPlayer/blob/dd430f7053a1a3958deea3ead6a0565150c06bfc/extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/OpusDecoder.java#L75-L111","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","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)."],"exampleFix":"// before\nDefaultRenderersFactory f = new DefaultRenderersFactory(context); // extension renderer throws on Opus\n\n// after\nDefaultRenderersFactory f = new DefaultRenderersFactory(context)\n    .setEnableDecoderFallback(true); // fall back to framework Opus decoder","handlingStrategy":"validation","validationCode":"if (OpusLibrary.isAvailable()) { /* safe to use extension OpusRenderer */ } else { /* use framework decoder or report unsupported */ }","typeGuard":null,"tryCatchPattern":"catch (OpusDecoderException e) { if (e.getMessage().contains(\"native libraries\")) { fallBackToFrameworkDecoder(); } else throw e; }","preventionTips":["Verify libopusJNI.so ships for all target ABIs (APK Analyzer).","Prefer Media3 prebuilt decoder extensions over custom NDK builds.","Enable renderer fallback in DefaultRenderersFactory."],"tags":["opus","native","jni","decoder","initialization"],"backgroundTag":null,"analyzedSha":"dd430f7053a1a3958deea3ead6a0565150c06bfc","analyzedAt":"2026-08-14T12:22:02.982Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}