Decode Opus Audio Frames Using Libopus API

This guide explains how to decode compressed Opus audio frames into raw PCM data using the standard libopus C API. It covers the essential steps of initializing the decoder, processing compressed packets, handling packet loss, and properly freeing resources.

1. Initialize the Decoder

To start decoding, you must first allocate and initialize an OpusDecoder state. This requires specifying the sample rate (typically 8000, 12000, 16000, 24000, or 48000 Hz) and the number of channels (1 for mono, 2 for stereo).

#include <opus.h>

int error;
// Initialize decoder for 48 kHz, stereo
OpusDecoder *decoder = opus_decoder_create(48000, 2, &error);

if (error != OPUS_OK) {
    // Handle initialization error (e.g., OPUS_BAD_ARG or OPUS_ALLOC_FAIL)
}

2. Prepare the Buffers

You need an input buffer containing the compressed Opus frame and an output buffer to store the decoded PCM samples. Opus frames typically contain 2.5 ms to 120 ms of audio. At 48 kHz, a 120 ms frame contains 5760 samples per channel.

// Input: Compressed Opus packet data and its size in bytes
const unsigned char *compressed_data = ...; 
opus_int32 compressed_length = ...; 

// Output: Buffer for decoded PCM samples (16-bit integers)
#define MAX_FRAME_SIZE 5760 // Maximum samples per channel for 120 ms at 48 kHz
#define CHANNELS 2
opus_int16 out_pcm[MAX_FRAME_SIZE * CHANNELS];

3. Decode the Frame

Use the opus_decode function to perform the actual decoding. This function processes one compressed frame at a time.

int decoded_samples = opus_decode(
    decoder, 
    compressed_data, 
    compressed_length, 
    out_pcm, 
    MAX_FRAME_SIZE, 
    0 // decode_fec flag (0 for normal decoding)
);

if (decoded_samples < 0) {
    // Handle decoding error (e.g., OPUS_INVALID_PACKET)
    int error_code = decoded_samples;
} else {
    // Success: 'decoded_samples' contains the number of samples per channel written to out_pcm
}

Parameter Details:

4. Handle Packet Loss (Optional)

If a packet is lost in transmission, you can trigger the decoder’s Packet Loss Concealment (PLC) system. To do this, pass NULL for the data buffer and 0 for the length.

int decoded_samples = opus_decode(
    decoder, 
    NULL,          // NULL indicates a lost packet
    0, 
    out_pcm, 
    MAX_FRAME_SIZE, 
    0              // decode_fec is ignored when data is NULL
);

5. Clean Up

Once you are finished decoding the audio stream, you must free the memory allocated for the decoder instance.

opus_decoder_destroy(decoder);