{"record":{"id":"a545d63270607daf","repo":"DrKLO/Telegram","slug":"invalid-pre-skip-or-seek-pre-roll","errorCode":null,"errorMessage":"Invalid pre-skip or seek pre-roll","messagePattern":"Invalid pre-skip or seek pre-roll","errorType":"exception","errorClass":"OpusDecoderException","httpStatus":null,"severity":"error","filePath":"TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/opus/OpusDecoder.java","lineNumber":97,"sourceCode":"      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);\n    if (channelCount > 8) {\n      throw new OpusDecoderException(\"Invalid channel count: \" + channelCount);\n    }\n    int gain = readSignedLittleEndian16(headerBytes, 16);\n\n    byte[] streamMap = new byte[8];\n    int numStreams;\n    int numCoupled;","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/DrKLO/Telegram/blob/45ab8f4308496e1f01026a97fcdb0d58a5274474/TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/opus/OpusDecoder.java#L79-L115","documentation":"When initializationData has 3 elements, the constructor insists that elements at index 1 (codec delay) and index 2 (seek pre-roll) are each exactly 8 bytes long, since they are read as native-order longs holding nanosecond values (see getPreSkipSamples/getSeekPreRollSamples). If either buffer is not 8 bytes the decoder rejects the data as malformed pre-skip/pre-roll.","triggerScenarios":"A 3-element initializationData list whose trailing buffers are the wrong length - e.g. a custom muxer wrote codec delay as a 4-byte int, or the extractor emitted a truncated buffer.","commonSituations":"Home-grown Opus muxers/demuxers that do not follow ExoPlayer's 8-byte-long convention for codec delay and seek pre-roll; test fixtures with placeholder byte arrays of the wrong size.","solutions":["Emit codec delay and seek pre-roll as 8-byte native-order longs (nanoseconds) in initializationData[1] and [2].","If you only have a header, pass a single-element list (initializationData.size() == 1) so the decoder falls back to parsing pre-skip from the header and the default 3840-sample pre-roll."],"exampleFix":"// before - wrong: 4-byte buffers\ninit.add(intToBytes(codecDelayNs));\ninit.add(intToBytes(seekPreRollNs));\n\n// after\nByteBuffer b = ByteBuffer.allocate(8).order(ByteOrder.nativeOrder());\nb.putLong(codecDelayNs); init.add(b.array());\nByteBuffer p = ByteBuffer.allocate(8).order(ByteOrder.nativeOrder());\np.putLong(seekPreRollNs); init.add(p.array());","handlingStrategy":"validation","validationCode":"List<byte[]> init = format.initializationData;\nif (init.size() == 3 && (init.get(1).length != 8 || init.get(2).length != 8)) {\n  throw new IllegalArgumentException(\n      \"Opus codec-delay/seek-pre-roll buffers must each be 8 bytes\");\n}\nnew OpusDecoder(NUM_BUFFERS, NUM_BUFFERS, initSize, init, cryptoConfig, outputFloat);","typeGuard":null,"tryCatchPattern":"try {\n  new OpusDecoder(..., format.initializationData, cryptoConfig, outputFloat);\n} catch (OpusDecoderException e) {\n  if (e.getMessage().contains(\"pre-skip or seek pre-roll\")) {\n    // rebuild init with two 8-byte native longs, or use a single-element list\n  } else { throw e; }\n}","preventionTips":["Emit codec delay and seek pre-roll as 8-byte native-order longs (nanoseconds).","If you only have a header, pass a single-element initializationData list."],"tags":["opus","decoder","format-validation","exoplayer","audio"],"backgroundTag":null,"analyzedSha":"45ab8f4308496e1f01026a97fcdb0d58a5274474","analyzedAt":"2026-08-14T05:19:30.815Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}