Libopus API Error Handling and Parameter Validation
The Libopus audio codec library manages runtime errors and invalid parameter configurations through a system of standardized integer error codes returned by its API functions. This article explains how libopus indicates failures during encoder and decoder initialization, control operations (CTLs), and processing, detailing the specific error codes and best practices for detecting them in C/C++ applications.
Standard Libopus Error Codes
Libopus defines a set of negative integer constants in the
opus_defines.h header to represent various error states.
When an API call fails, it returns one of these specific codes:
OPUS_OK(0): The operation completed successfully.OPUS_BAD_ARG(-1): One or more passed arguments are invalid (e.g., invalid sample rate, channel count, or null pointers).OPUS_BUFFER_TOO_SMALL(-2): The provided output buffer is too small to hold the compressed or decompressed data.OPUS_INTERNAL_ERROR(-3): An internal logic error or assertion failure occurred.OPUS_INVALID_PACKET(-4): The compressed packet passed to the decoder is corrupted or invalid.OPUS_UNIMPLEMENTED(-5): The requested mode, CTL, or option is not implemented.OPUS_INVALID_STATE(-6): An encoder or decoder state representation is invalid or corrupted.OPUS_ALLOC_FAIL(-7): Memory allocation failed during state creation.
Error Reporting in State Creation
When allocating and initializing encoders or decoders, libopus provides two patterns for error reporting depending on whether you allocate memory dynamically or statically.
1.
Dynamic Allocation (opus_encoder_create /
opus_decoder_create)
These functions return a pointer to the newly allocated state
structure. Because a pointer cannot directly return an integer error
code, the functions accept a pointer to an integer
(int *error) as their last argument.
int error;
OpusEncoder *enc = opus_encoder_create(48000, 2, OPUS_APPLICATION_AUDIO, &error);
if (error != OPUS_OK) {
// Handle initialization failure (e.g., invalid sample rate of 48000 or channel count)
printf("Failed to create encoder: %s\n", opus_strerror(error));
}2. Static
Allocation (opus_encoder_init /
opus_decoder_init)
If you allocate the memory manually, you pass the memory block to the initialization function. These functions return the error code directly as an integer.
int error = opus_encoder_init(enc_state, 48000, 2, OPUS_APPLICATION_AUDIO);
if (error != OPUS_OK) {
// Handle initialization failure
}Error Reporting in Encoder and Decoder CTLs
Libopus uses a macro-based system (opus_encoder_ctl and
opus_decoder_ctl) to configure parameters like bitrate,
complexity, and VBR.
If you attempt to configure an invalid parameter value (such as a negative bitrate or an unsupported complexity value), the CTL function returns a negative error code directly.
int result = opus_encoder_ctl(enc, OPUS_SET_BITRATE(-5000)); // Invalid negative bitrate
if (result != OPUS_OK) {
// result will be OPUS_BAD_ARG (-1)
printf("CTL Configuration failed: %s\n", opus_strerror(result));
}Error Reporting During Encoding and Decoding
During the active streaming phase, the functions
opus_encode, opus_encode_float,
opus_decode, and opus_decode_float return
values that must be verified:
- Success: The functions return a positive integer representing the number of bytes written to the output packet (for encoders) or the number of decoded samples per channel (for decoders).
- Failure: The functions return a negative integer corresponding to one of the standard libopus error codes.
unsigned char compressed_packet[512];
opus_int32 packet_size = opus_encode(enc, pcm_buffer, frame_size, compressed_packet, sizeof(compressed_packet));
if (packet_size < 0) {
// An error occurred during encoding
int error_code = (int)packet_size;
printf("Encoding failed: %s\n", opus_strerror(error_code));
} else {
// Encoding succeeded; packet_size contains the byte count of the compressed payload
}Obtaining Human-Readable Error Messages
To simplify debugging and logging, the libopus API provides the
helper function opus_strerror(). This function takes any
libopus error code as an integer and returns a pointer to a static,
read-only string describing the error.
const char *error_msg = opus_strerror(OPUS_BAD_ARG);
// error_msg points to "invalid argument"