DrKLO/Telegram · 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 Opus extension native (.so) libraries are not packaged/loadable. It is the first check in the constructor, before any secure-decode or initialization-data validation, so the decoder cannot start without the native libs.

Source

Thrown at TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/opus/OpusDecoder.java:85

   * @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 45ab8f4308)

Solutions

  1. Package the Opus extension native libraries for all target ABIs.
  2. Guard on OpusLibrary.isAvailable() before enabling the Opus extension renderer; fall back to a platform Opus decoder if present.
  3. Verify abiFilters and packagingOptions preserve the Opus .so files.

Example fix

// before
if (OpusLibrary.isAvailable()) { /* never reached */ }

// after
android {
  defaultConfig { ndk { abiFilters 'armeabi-v7a','arm64-v8a','x86','x86_64' } }
}
Defensive patterns

Strategy: validation

Validate before calling

// guard on Opus library availability before enabling the Opus renderer
if (OpusLibrary.isAvailable()) {
  renderers.add(new OpusRenderer(...));
} else { /* rely on a platform Opus decoder if present */ }

Try / catch

try { new OpusDecoder(nIn, nOut, bufSize, init, crypto, outputFloat); }
catch (OpusDecoderException e) { /* fall back to platform Opus decoder */ }

Prevention

When it happens

Trigger: Constructing OpusDecoder (via the Opus renderer) on an APK/device where the Opus native libraries are absent or not packaged for the current ABI.

Common situations: Opus extension not included in the build; abiFilters omitting the device ABI; release packaging stripping the .so files; running on an emulator whose ABI has no matching lib.

Related errors


AI-assisted analysis of DrKLO/Telegram@45ab8f4308 (2026-08-14). Data as JSON: /api/errors/58d45d181f1bb485. Report an issue: GitHub.