#include #include #include "opus_codec.h" #include "opus.h" #include "debug_config.h" #define OPUS_DEFAULT_SAMPLE_RATE 48000 #define OPUS_DEFAULT_BITRATE 32000 #define OPUS_DEFAULT_COMPLEXITY 5 #define OPUS_DEFAULT_FRAME_MS 20 struct opus_codec_encoder { OpusEncoder* opus_enc; int sample_rate; int channels; int frame_samples; }; struct opus_codec_decoder { OpusDecoder* opus_dec; int sample_rate; int channels; }; static int frame_samples_for_rate(int sample_rate) { return sample_rate * OPUS_DEFAULT_FRAME_MS / 1000; } opus_codec_encoder_t* opus_codec_encoder_create(int sample_rate, int channels) { int err; opus_codec_encoder_t* enc; if (sample_rate <= 0) sample_rate = OPUS_DEFAULT_SAMPLE_RATE; if (channels <= 0 || channels > 2) channels = 1; enc = (opus_codec_encoder_t*)calloc(1, sizeof(*enc)); if (!enc) { DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "opus_codec_encoder_create: OOM"); return NULL; } enc->sample_rate = sample_rate; enc->channels = channels; enc->frame_samples = frame_samples_for_rate(sample_rate); enc->opus_enc = opus_encoder_create(sample_rate, channels, OPUS_APPLICATION_VOIP, &err); if (err != OPUS_OK) { DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "opus_codec_encoder_create: opus_encoder_create failed: %s (%d)", opus_codec_strerror(err), err); free(enc); return NULL; } opus_encoder_ctl(enc->opus_enc, OPUS_SET_BITRATE(OPUS_DEFAULT_BITRATE)); opus_encoder_ctl(enc->opus_enc, OPUS_SET_COMPLEXITY(OPUS_DEFAULT_COMPLEXITY)); opus_encoder_ctl(enc->opus_enc, OPUS_SET_SIGNAL(OPUS_AUTO)); DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "opus_codec_encoder_create: ok rate=%d ch=%d frame_samples=%d bitrate=%d", sample_rate, channels, enc->frame_samples, OPUS_DEFAULT_BITRATE); return enc; } void opus_codec_encoder_destroy(opus_codec_encoder_t* enc) { if (!enc) return; DEBUG_DEBUG(DEBUG_CATEGORY_GENERAL, "opus_codec_encoder_destroy"); if (enc->opus_enc) opus_encoder_destroy(enc->opus_enc); free(enc); } int opus_codec_encode(opus_codec_encoder_t* enc, const int16_t* pcm, int frame_samples, uint8_t* out, int out_cap) { if (!enc || !pcm || !out || out_cap <= 0 || frame_samples <= 0) { DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "opus_codec_encode: invalid args"); return -1; } int result = opus_encode(enc->opus_enc, pcm, frame_samples, out, out_cap); if (result < 0) { DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "opus_codec_encode: encode failed: %s (%d), pcm_samples=%d cap=%d", opus_codec_strerror(result), result, frame_samples, out_cap); } return result; } opus_codec_decoder_t* opus_codec_decoder_create(int sample_rate, int channels) { int err; opus_codec_decoder_t* dec; if (sample_rate <= 0) sample_rate = OPUS_DEFAULT_SAMPLE_RATE; if (channels <= 0 || channels > 2) channels = 1; dec = (opus_codec_decoder_t*)calloc(1, sizeof(*dec)); if (!dec) { DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "opus_codec_decoder_create: OOM"); return NULL; } dec->sample_rate = sample_rate; dec->channels = channels; dec->opus_dec = opus_decoder_create(sample_rate, channels, &err); if (err != OPUS_OK) { DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "opus_codec_decoder_create: opus_decoder_create failed: %s (%d)", opus_codec_strerror(err), err); free(dec); return NULL; } DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "opus_codec_decoder_create: ok rate=%d ch=%d", sample_rate, channels); return dec; } void opus_codec_decoder_destroy(opus_codec_decoder_t* dec) { if (!dec) return; DEBUG_DEBUG(DEBUG_CATEGORY_GENERAL, "opus_codec_decoder_destroy"); if (dec->opus_dec) opus_decoder_destroy(dec->opus_dec); free(dec); } int opus_codec_decode(opus_codec_decoder_t* dec, const uint8_t* data, int len, int16_t* pcm, int frame_samples) { if (!dec || !pcm || frame_samples <= 0) { DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "opus_codec_decode: invalid args"); return -1; } int result = opus_decode(dec->opus_dec, data, len, pcm, frame_samples, 0); if (result < 0) { DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "opus_codec_decode: decode failed: %s (%d), len=%d", opus_codec_strerror(result), result, len); } return result; } int opus_codec_encoder_bitrate_set(opus_codec_encoder_t* enc, int bitrate_bps) { if (!enc || !enc->opus_enc) return -1; return opus_encoder_ctl(enc->opus_enc, OPUS_SET_BITRATE(bitrate_bps)); } int opus_codec_encoder_complexity_set(opus_codec_encoder_t* enc, int complexity) { if (!enc || !enc->opus_enc) return -1; return opus_encoder_ctl(enc->opus_enc, OPUS_SET_COMPLEXITY(complexity)); } int opus_codec_encoder_signal_set(opus_codec_encoder_t* enc, int signal_type) { if (!enc || !enc->opus_enc) return -1; return opus_encoder_ctl(enc->opus_enc, OPUS_SET_SIGNAL(signal_type)); } const char* opus_codec_strerror(int err) { switch (err) { case OPUS_OK: return "OK"; case OPUS_BAD_ARG: return "BAD_ARG"; case OPUS_BUFFER_TOO_SMALL: return "BUFFER_TOO_SMALL"; case OPUS_INTERNAL_ERROR: return "INTERNAL_ERROR"; case OPUS_INVALID_PACKET: return "INVALID_PACKET"; case OPUS_UNIMPLEMENTED: return "UNIMPLEMENTED"; case OPUS_INVALID_STATE: return "INVALID_STATE"; case OPUS_ALLOC_FAIL: return "ALLOC_FAIL"; default: return "UNKNOWN"; } }