{"record":{"id":"11ab05af30cfb9dc","repo":"DrKLO/Telegram","slug":"opus-decoder-does-not-support-secure-decode","errorCode":null,"errorMessage":"Opus decoder does not support secure decode","messagePattern":"Opus decoder does not support secure decode","errorType":"exception","errorClass":"OpusDecoderException","httpStatus":null,"severity":"error","filePath":"TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/opus/OpusDecoder.java","lineNumber":89,"sourceCode":"   *     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);\n    if (headerBytes.length < 19) {\n      throw new OpusDecoderException(\"Invalid header length\");\n    }\n    channelCount = getChannelCount(headerBytes);","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/DrKLO/Telegram/blob/45ab8f4308496e1f01026a97fcdb0d58a5274474/TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/opus/OpusDecoder.java#L71-L107","documentation":"Thrown by the OpusDecoder constructor when a non-null CryptoConfig is supplied (i.e. the stream is encrypted/DRM-protected) but the loaded native libopus does not advertise secure-decode support. The check is OpusLibrary.opusIsSecureDecodeSupported(), a JNI call into the bundled native library; it only returns true if that native build was compiled with the secure-decode entry point. The decoder refuses to start because it cannot decrypt samples without it.","triggerScenarios":"LibopusAudioRenderer.createDecoder (LibopusAudioRenderer.java:110) forwards the Format's cryptoConfig into `new OpusDecoder(...)`. When the stream is DRM-protected (Widevine/ClearKey) cryptoConfig is non-null and the constructor at OpusDecoder.java:88 aborts if the native opusIsSecureDecodeSupported() returns false.","commonSituations":"Shipping the standard non-DRM libopus extension build and then attempting to play ClearKey/Widevine-protected Opus content; swapping in a different decoder extension variant that dropped secure decode; DRM scheme mismatch where OpusLibrary.cryptoType was never configured via OpusLibrary.setLibraries(...).","solutions":["Use a libopus native build compiled with the secure-decode JNI entry point so OpusLibrary.opusIsSecureDecodeSupported() returns true.","If the content is not actually encrypted, ensure cryptoConfig passed to the decoder is null (do not forward a CryptoConfig for clear content).","Fall back to another audio renderer/decoder whose native build supports the required C.CryptoType; gate playback on OpusLibrary.supportsCryptoType(format.cryptoType)."],"exampleFix":"// before\nOpusDecoder decoder = new OpusDecoder(\n    NUM_BUFFERS, NUM_BUFFERS, initialInputBufferSize,\n    format.initializationData, cryptoConfig, outputFloat);\n\n// after\nif (cryptoConfig != null && !OpusLibrary.opusIsSecureDecodeSupported()) {\n  throw new OpusDecoderException(\"Secure decode unavailable; pick another renderer\");\n}\nOpusDecoder decoder = new OpusDecoder(\n    NUM_BUFFERS, NUM_BUFFERS, initialInputBufferSize,\n    format.initializationData, cryptoConfig, outputFloat);","handlingStrategy":"validation","validationCode":"// Before constructing the OpusDecoder for encrypted content\nCryptoConfig cfg = (formatIsEncrypted) ? cryptoConfig : null;\nif (cfg != null\n    && !(OpusLibrary.isAvailable() && OpusLibrary.opusIsSecureDecodeSupported())) {\n  // Do not pass a CryptoConfig: route to a renderer whose native lib supports it.\n  throw new OpusDecoderException(\"Secure Opus decode not available in this native build\");\n}\nnew OpusDecoder(NUM_BUFFERS, NUM_BUFFERS, initSize, format.initializationData, cfg, outputFloat);","typeGuard":null,"tryCatchPattern":"try {\n  decoder = new OpusDecoder(..., cryptoConfig, outputFloat);\n} catch (OpusDecoderException e) {\n  if (e.getMessage().contains(\"secure decode\")) {\n    // switch renderer / report DRM unsupported for Opus\n  } else { throw e; }\n}","preventionTips":["Gate encrypted Opus playback on OpusLibrary.supportsCryptoType(format.cryptoType).","Ship a libopus native build compiled with secure decode when DRM Opus playback is required.","Only forward a non-null CryptoConfig when the content is actually encrypted."],"tags":["opus","drm","decoder","exoplayer","audio","native"],"backgroundTag":null,"analyzedSha":"45ab8f4308496e1f01026a97fcdb0d58a5274474","analyzedAt":"2026-08-14T05:19:30.815Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}