Encode & decode

Packet inspection

Packet inspection

getPacketInfo reads the header of a raw Opus packet and reports what it contains — duration, frame count, channels, and bandwidth — without decoding the audio. It is the cheap way to validate an incoming packet or to learn its shape before you hand it to a decoder.

import { getPacketInfo } from "libopus-wasm";

const info = await getPacketInfo(packet);
info.durationMs;      // 20
info.frames;          // 1
info.samples;         // 960  (per channel, at the given sample rate)
info.samplesPerFrame; // 960
info.channels;        // 1 | 2
info.sampleRate;      // 48000
info.bandwidth;       // Bandwidth.Fullband

Like the factories, the first call lazily loads the shared WASM module; later calls are cheap.

#Sample rate

Opus packets do not carry their sample rate in band, so durationMs, samples, and samplesPerFrame are computed against the rate you pass — 48000 Hz by default. Pass the rate the stream was encoded at to get accurate timing:

const info = await getPacketInfo(packet, { sampleRate: 16000 });

Only the supported rates (8000, 12000, 16000, 24000, 48000) are accepted; anything else throws a RangeError.

#What you get back

FieldTypeMeaning
durationMsnumberTotal audio in the packet, 2.5120 ms.
framesnumberOpus frames packed into the packet (148).
samplesnumberTotal samples per channel at sampleRate.
samplesPerFramenumberSamples per channel in one frame.
channels1 | 2Channel count encoded in the packet.
sampleRateSampleRateThe rate the figures were computed against.
bandwidthBandwidthCoded bandwidth — NarrowbandFullband.

samples === frames * samplesPerFrame, and durationMs === samples / sampleRate * 1000. The result is read-only.

#Sizing a decoder

Use the duration to confirm a packet fits a decoder's output capacity before decoding:

const info = await getPacketInfo(packet);
if (info.durationMs > 60) {
  // larger than this decoder's 60 ms buffer — raise maxFrameSize or skip.
}
const frame = decoder.decode(packet);

#Invalid packets

A corrupt or truncated packet surfaces the libopus error as an OpusError; an empty Uint8Array throws a RangeError before reaching WASM.

import { OpusError } from "libopus-wasm";

try {
  await getPacketInfo(suspectPacket);
} catch (err) {
  if (err instanceof OpusError) {
    // not a valid Opus packet
  }
}

#Next