DrKLO/Telegram · error · OpusDecoderException
Invalid pre-skip or seek pre-roll
Error message
Invalid pre-skip or seek pre-roll
What it means
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.
Source
Thrown at TMessagesProj/src/main/java/com/google/android/exoplayer2/ext/opus/OpusDecoder.java:97
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);
if (headerBytes.length < 19) {
throw new OpusDecoderException("Invalid header length");
}
channelCount = getChannelCount(headerBytes);
if (channelCount > 8) {
throw new OpusDecoderException("Invalid channel count: " + channelCount);
}
int gain = readSignedLittleEndian16(headerBytes, 16);
byte[] streamMap = new byte[8];
int numStreams;
int numCoupled;View on GitHub (pinned to 45ab8f4308)
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.
Example fix
// before - wrong: 4-byte buffers init.add(intToBytes(codecDelayNs)); init.add(intToBytes(seekPreRollNs)); // after ByteBuffer b = ByteBuffer.allocate(8).order(ByteOrder.nativeOrder()); b.putLong(codecDelayNs); init.add(b.array()); ByteBuffer p = ByteBuffer.allocate(8).order(ByteOrder.nativeOrder()); p.putLong(seekPreRollNs); init.add(p.array());
Defensive patterns
Strategy: validation
Validate before calling
List<byte[]> init = format.initializationData;
if (init.size() == 3 && (init.get(1).length != 8 || init.get(2).length != 8)) {
throw new IllegalArgumentException(
"Opus codec-delay/seek-pre-roll buffers must each be 8 bytes");
}
new OpusDecoder(NUM_BUFFERS, NUM_BUFFERS, initSize, init, cryptoConfig, outputFloat); Try / catch
try {
new OpusDecoder(..., format.initializationData, cryptoConfig, outputFloat);
} catch (OpusDecoderException e) {
if (e.getMessage().contains("pre-skip or seek pre-roll")) {
// rebuild init with two 8-byte native longs, or use a single-element list
} else { throw e; }
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Invalid initialization data size
- Invalid header length
- Invalid channel count: {channelCount}
- Invalid header, missing stream map
- Opus decoder does not support secure decode
AI-assisted analysis of DrKLO/Telegram@45ab8f4308 (2026-08-14).
Data as JSON: /api/errors/a545d63270607daf.
Report an issue: GitHub.