Process AUDIO_OPUS_BATCH packet - efficient Opus-encoded audio batch from client.
Handles batched Opus-encoded audio frames sent by the client. This provides ~98% bandwidth reduction compared to raw PCM audio while maintaining excellent audio quality.
1167 {
1168 log_debug_every(LOG_RATE_SLOW, "Received Opus audio batch from client %u (len=%zu)", atomic_load(&client->client_id),
1169 len);
1170
1171 VALIDATE_NOTNULL_DATA(client, data, "AUDIO_OPUS_BATCH");
1172 VALIDATE_AUDIO_STREAM_ENABLED(client, "AUDIO_OPUS_BATCH");
1173 VALIDATE_RESOURCE_INITIALIZED(client, client->opus_decoder, "Opus decoder");
1174
1175
1176 const uint8_t *opus_data = NULL;
1177 size_t opus_size = 0;
1178 const uint16_t *frame_sizes = NULL;
1179 int sample_rate = 0;
1180 int frame_duration = 0;
1181 int frame_count = 0;
1182
1183 asciichat_error_t result =
packet_parse_opus_batch(data, len, &opus_data, &opus_size, &frame_sizes, &sample_rate,
1184 &frame_duration, &frame_count);
1185
1186 if (result != ASCIICHAT_OK) {
1188 return;
1189 }
1190
1191 VALIDATE_NONZERO(client, frame_count, "frame_count", "AUDIO_OPUS_BATCH");
1192 VALIDATE_NONZERO(client, opus_size, "opus_size", "AUDIO_OPUS_BATCH");
1193
1194
1195 int samples_per_frame = (sample_rate * frame_duration) / 1000;
1196 VALIDATE_RANGE(client, samples_per_frame, 1, 4096, "samples_per_frame", "AUDIO_OPUS_BATCH");
1197
1198
1199
1200
1201#define OPUS_DECODE_STATIC_MAX_SAMPLES (32 * 960)
1203
1204 size_t total_samples = (size_t)samples_per_frame * (size_t)frame_count;
1205 float *decoded_samples;
1206 bool used_malloc = false;
1207
1209 decoded_samples = static_decode_buffer;
1210 } else {
1211
1212 log_warn("Client %u: Large audio batch requires malloc (%zu samples)", atomic_load(&client->client_id),
1213 total_samples);
1214 decoded_samples = SAFE_MALLOC(total_samples * sizeof(float), float *);
1215 if (!decoded_samples) {
1216 SET_ERRNO(ERROR_MEMORY, "Failed to allocate buffer for Opus decoded samples");
1217 return;
1218 }
1219 used_malloc = true;
1220 }
1221
1222
1223 int total_decoded = 0;
1224 size_t opus_offset = 0;
1225
1226 for (int i = 0; i < frame_count; i++) {
1227
1228 size_t frame_size = (size_t)NET_TO_HOST_U16(frame_sizes[i]);
1229
1230
1231 if (frame_size > 0) {
1232 log_debug_every(LOG_RATE_DEFAULT, "Client %u: Opus frame %d: size=%zu, first_bytes=[0x%02x,0x%02x,0x%02x,0x%02x]",
1233 atomic_load(&client->client_id), i, frame_size, opus_data[opus_offset] & 0xFF,
1234 frame_size > 1 ? (opus_data[opus_offset + 1] & 0xFF) : 0,
1235 frame_size > 2 ? (opus_data[opus_offset + 2] & 0xFF) : 0,
1236 frame_size > 3 ? (opus_data[opus_offset + 3] & 0xFF) : 0);
1237 }
1238
1239 if (opus_offset + frame_size > opus_size) {
1240 log_error("Client %u: Frame %d size overflow (offset=%zu, frame_size=%zu, total=%zu)",
1241 atomic_load(&client->client_id), i + 1, opus_offset, frame_size, opus_size);
1242 if (used_malloc) {
1243 SAFE_FREE(decoded_samples);
1244 }
1245 return;
1246 }
1247
1248
1249
1250 if ((size_t)total_decoded + (size_t)samples_per_frame > total_samples) {
1251 log_error("Client %u: Opus decode would overflow buffer (decoded=%d, frame_samples=%d, max=%zu)",
1252 atomic_load(&client->client_id), total_decoded, samples_per_frame, total_samples);
1253 if (used_malloc) {
1254 SAFE_FREE(decoded_samples);
1255 }
1256 return;
1257 }
1258
1259 int decoded_count =
opus_codec_decode((opus_codec_t *)client->opus_decoder, &opus_data[opus_offset], frame_size,
1260 &decoded_samples[total_decoded], samples_per_frame);
1261
1262 if (decoded_count < 0) {
1263 log_error("Client %u: Opus decoding failed for frame %d/%d (size=%zu)", atomic_load(&client->client_id), i + 1,
1264 frame_count, frame_size);
1265 if (used_malloc) {
1266 SAFE_FREE(decoded_samples);
1267 }
1268 return;
1269 }
1270
1271 total_decoded += decoded_count;
1272 opus_offset += frame_size;
1273 }
1274
1275 log_debug_every(LOG_RATE_DEFAULT, "Client %u: Decoded %d Opus frames -> %d samples", atomic_load(&client->client_id),
1276 frame_count, total_decoded);
1277
1278
1279 static int server_decode_count = 0;
1280 server_decode_count++;
1281 if (total_decoded > 0 && (server_decode_count <= 10 || server_decode_count % 100 == 0)) {
1282 float peak = 0.0f, rms = 0.0f;
1283 for (int i = 0; i < total_decoded && i < 100; i++) {
1284 float abs_val = fabsf(decoded_samples[i]);
1285 if (abs_val > peak)
1286 peak = abs_val;
1287 rms += decoded_samples[i] * decoded_samples[i];
1288 }
1289 rms = sqrtf(rms / (total_decoded > 100 ? 100 : total_decoded));
1290
1291 log_info("SERVER OPUS DECODE #%d from client %u: decoded_rms=%.6f, opus_first4=[0x%02x,0x%02x,0x%02x,0x%02x]",
1292 server_decode_count, atomic_load(&client->client_id), rms, opus_size > 0 ? opus_data[0] : 0,
1293 opus_size > 1 ? opus_data[1] : 0, opus_size > 2 ? opus_data[2] : 0, opus_size > 3 ? opus_data[3] : 0);
1294 }
1295
1296
1297
1298
1299 if (client->incoming_audio_buffer && total_decoded > 0) {
1300 asciichat_error_t result =
audio_ring_buffer_write(client->incoming_audio_buffer, decoded_samples, total_decoded);
1301 if (result != ASCIICHAT_OK) {
1302 log_error("Client %u: Failed to write decoded audio to buffer: %d", atomic_load(&client->client_id), result);
1303 }
1304 }
1305
1306 if (used_malloc) {
1307 SAFE_FREE(decoded_samples);
1308 }
1309}
asciichat_error_t audio_ring_buffer_write(audio_ring_buffer_t *rb, const float *data, int samples)
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 packet_parse_opus_batch(const void *packet_data, size_t packet_len, const uint8_t **out_opus_data, size_t *out_opus_size, const uint16_t **out_frame_sizes, int *out_sample_rate, int *out_frame_duration, int *out_frame_count)
#define OPUS_DECODE_STATIC_MAX_SAMPLES
void disconnect_client_for_bad_data(client_info_t *client, const char *format,...)