ascii-chat 0.8.38
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
opus_codec.c File Reference

Opus audio codec implementation. More...

Go to the source code of this file.

Functions

opus_codec_t * opus_codec_create_encoder (opus_application_t application, int sample_rate, int bitrate)
 
opus_codec_t * opus_codec_create_decoder (int sample_rate)
 
size_t opus_codec_encode (opus_codec_t *codec, const float *samples, int num_samples, uint8_t *out_data, size_t out_size)
 
int opus_codec_decode (opus_codec_t *codec, const uint8_t *data, size_t data_len, float *out_samples, int out_num_samples)
 
asciichat_error_t opus_codec_set_bitrate (opus_codec_t *codec, int bitrate)
 
int opus_codec_get_bitrate (opus_codec_t *codec)
 
asciichat_error_t opus_codec_set_dtx (opus_codec_t *codec, int enable)
 
void opus_codec_destroy (opus_codec_t *codec)
 

Detailed Description

Opus audio codec implementation.

Definition in file opus_codec.c.

Function Documentation

◆ opus_codec_create_decoder()

opus_codec_t * opus_codec_create_decoder ( int  sample_rate)

Definition at line 62 of file opus_codec.c.

62 {
63 if (sample_rate <= 0) {
64 SET_ERRNO(ERROR_INVALID_PARAM, "Invalid sample rate: %d", sample_rate);
65 return NULL;
66 }
67
68 opus_codec_t *codec = SAFE_MALLOC(sizeof(opus_codec_t), opus_codec_t *);
69 if (!codec) {
70 SET_ERRNO(ERROR_MEMORY, "Failed to allocate opus codec context");
71 return NULL;
72 }
73
74 // Create decoder
75 int error = OPUS_OK;
76 codec->decoder = opus_decoder_create(sample_rate, 1, &error);
77 if (error != OPUS_OK || !codec->decoder) {
78 SET_ERRNO(ERROR_AUDIO, "Failed to create Opus decoder: %s", opus_strerror(error));
79 SAFE_FREE(codec);
80 return NULL;
81 }
82
83 codec->encoder = NULL;
84 codec->sample_rate = sample_rate;
85 codec->bitrate = 0; // N/A for decoder
86 codec->tmp_buffer = NULL;
87
88 log_debug("Opus decoder created: sample_rate=%d", sample_rate);
89
90 return codec;
91}

Referenced by handle_stream_start_packet(), and session_host_start_render().

◆ opus_codec_create_encoder()

opus_codec_t * opus_codec_create_encoder ( opus_application_t  application,
int  sample_rate,
int  bitrate 
)

Definition at line 18 of file opus_codec.c.

18 {
19 if (sample_rate <= 0 || bitrate <= 0) {
20 SET_ERRNO(ERROR_INVALID_PARAM, "Invalid codec parameters: sample_rate=%d, bitrate=%d", sample_rate, bitrate);
21 return NULL;
22 }
23
24 opus_codec_t *codec = SAFE_MALLOC(sizeof(opus_codec_t), opus_codec_t *);
25 if (!codec) {
26 SET_ERRNO(ERROR_MEMORY, "Failed to allocate opus codec context");
27 return NULL;
28 }
29
30 // Create encoder
31 int error = OPUS_OK;
32 codec->encoder = opus_encoder_create(sample_rate, 1, (int)application, &error);
33 if (error != OPUS_OK || !codec->encoder) {
34 SET_ERRNO(ERROR_AUDIO, "Failed to create Opus encoder: %s", opus_strerror(error));
35 SAFE_FREE(codec);
36 return NULL;
37 }
38
39 // Set bitrate
40 error = opus_encoder_ctl(codec->encoder, OPUS_SET_BITRATE(bitrate));
41 if (error != OPUS_OK) {
42 SET_ERRNO(ERROR_AUDIO, "Failed to set Opus bitrate: %s", opus_strerror(error));
43 opus_encoder_destroy(codec->encoder);
44 SAFE_FREE(codec);
45 return NULL;
46 }
47
48 codec->decoder = NULL;
49 codec->sample_rate = sample_rate;
50 codec->bitrate = bitrate;
51 codec->tmp_buffer = NULL;
52
53 log_debug("Opus encoder created: sample_rate=%d, bitrate=%d bps", sample_rate, bitrate);
54
55 return codec;
56}

Referenced by client_audio_render_thread(), session_host_start_render(), and session_participant_start_audio_capture().

◆ opus_codec_decode()

int opus_codec_decode ( opus_codec_t *  codec,
const uint8_t *  data,
size_t  data_len,
float *  out_samples,
int  out_num_samples 
)

Definition at line 128 of file opus_codec.c.

129 {
130 if (!codec || !codec->decoder || !out_samples || out_num_samples <= 0) {
131 SET_ERRNO(ERROR_INVALID_PARAM,
132 "Invalid decode parameters: codec=%p, decoder=%p, out_samples=%p, out_num_samples=%d", (void *)codec,
133 (void *)(codec ? codec->decoder : NULL), (void *)out_samples, out_num_samples);
134 return -1;
135 }
136
137 // If data is NULL, use PLC (Packet Loss Concealment)
138 if (!data || data_len == 0) {
139 log_debug_every(LOG_RATE_VERY_FAST, "Opus PLC (Packet Loss Concealment)");
140 int samples = opus_decode_float(codec->decoder, NULL, 0, out_samples, out_num_samples, 0);
141 if (samples < 0) {
142 SET_ERRNO(ERROR_AUDIO, "Opus PLC failed: %s", opus_strerror(samples));
143 return -1;
144 }
145 return samples;
146 }
147
148 // Decode frame
149 int samples = opus_decode_float(codec->decoder, data, (opus_int32)data_len, out_samples, out_num_samples, 0);
150
151 if (samples < 0) {
152 SET_ERRNO(ERROR_AUDIO, "Opus decoding failed: %s", opus_strerror(samples));
153 return -1;
154 }
155
156 return samples;
157}

Referenced by handle_audio_opus_batch_packet(), and handle_audio_opus_packet().

◆ opus_codec_destroy()

void opus_codec_destroy ( opus_codec_t *  codec)

Definition at line 215 of file opus_codec.c.

215 {
216 if (!codec) {
217 return;
218 }
219
220 if (codec->encoder) {
221 opus_encoder_destroy(codec->encoder);
222 codec->encoder = NULL;
223 }
224
225 if (codec->decoder) {
226 opus_decoder_destroy(codec->decoder);
227 codec->decoder = NULL;
228 }
229
230 if (codec->tmp_buffer) {
231 SAFE_FREE(codec->tmp_buffer);
232 codec->tmp_buffer = NULL;
233 }
234
235 SAFE_FREE(codec);
236}

Referenced by cleanup_client_media_buffers(), client_audio_render_thread(), session_host_destroy(), session_host_start_render(), session_host_stop_render(), and session_participant_destroy().

◆ opus_codec_encode()

size_t opus_codec_encode ( opus_codec_t *  codec,
const float *  samples,
int  num_samples,
uint8_t *  out_data,
size_t  out_size 
)

Definition at line 97 of file opus_codec.c.

98 {
99 if (!codec || !codec->encoder || !samples || num_samples <= 0 || !out_data || out_size == 0) {
100 SET_ERRNO(ERROR_INVALID_PARAM,
101 "Invalid encode parameters: codec=%p, encoder=%p, samples=%p, num_samples=%d, out_data=%p, "
102 "out_size=%zu",
103 (void *)codec, (void *)(codec ? codec->encoder : NULL), (const void *)samples, num_samples,
104 (void *)out_data, out_size);
105 return 0;
106 }
107
108 // Encode frame
109 opus_int32 encoded_bytes = opus_encode_float(codec->encoder, samples, num_samples, out_data, (opus_int32)out_size);
110
111 if (encoded_bytes < 0) {
112 SET_ERRNO(ERROR_AUDIO, "Opus encoding failed: %s", opus_strerror((int)encoded_bytes));
113 return 0;
114 }
115
116 if (encoded_bytes == 0) {
117 // DTX frame (silence) - encoder produced zero bytes
118 log_debug_every(LOG_RATE_VERY_FAST, "Opus DTX frame (silence detected)");
119 }
120
121 return (size_t)encoded_bytes;
122}

Referenced by client_audio_render_thread().

◆ opus_codec_get_bitrate()

int opus_codec_get_bitrate ( opus_codec_t *  codec)

Definition at line 180 of file opus_codec.c.

180 {
181 if (!codec || !codec->encoder) {
182 SET_ERRNO(ERROR_INVALID_PARAM, "Invalid codec for bitrate query");
183 return -1;
184 }
185
186 opus_int32 bitrate = 0;
187 int error = opus_encoder_ctl(codec->encoder, OPUS_GET_BITRATE(&bitrate));
188 if (error != OPUS_OK) {
189 SET_ERRNO(ERROR_AUDIO, "Failed to get Opus bitrate: %s", opus_strerror(error));
190 return -1;
191 }
192
193 return (int)bitrate;
194}

◆ opus_codec_set_bitrate()

asciichat_error_t opus_codec_set_bitrate ( opus_codec_t *  codec,
int  bitrate 
)

Definition at line 163 of file opus_codec.c.

163 {
164 if (!codec || !codec->encoder || bitrate <= 0) {
165 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid bitrate parameters: codec=%p, encoder=%p, bitrate=%d", (void *)codec,
166 (void *)(codec ? codec->encoder : NULL), bitrate);
167 }
168
169 int error = opus_encoder_ctl(codec->encoder, OPUS_SET_BITRATE(bitrate));
170 if (error != OPUS_OK) {
171 return SET_ERRNO(ERROR_AUDIO, "Failed to set Opus bitrate: %s", opus_strerror(error));
172 }
173
174 codec->bitrate = bitrate;
175 log_debug("Opus bitrate changed to %d bps", bitrate);
176
177 return ASCIICHAT_OK;
178}

◆ opus_codec_set_dtx()

asciichat_error_t opus_codec_set_dtx ( opus_codec_t *  codec,
int  enable 
)

Definition at line 196 of file opus_codec.c.

196 {
197 if (!codec || !codec->encoder) {
198 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid codec for DTX configuration");
199 }
200
201 int error = opus_encoder_ctl(codec->encoder, OPUS_SET_DTX(enable ? 1 : 0));
202 if (error != OPUS_OK) {
203 return SET_ERRNO(ERROR_AUDIO, "Failed to set Opus DTX: %s", opus_strerror(error));
204 }
205
206 log_debug("Opus DTX %s", enable ? "enabled" : "disabled");
207
208 return ASCIICHAT_OK;
209}