arduino-audio-tools
Loading...
Searching...
No Matches
CodecOpusMultiStream.h
Go to the documentation of this file.
1// CodecOpusMultiStream.h
2#pragma once
3
5#include "Print.h"
6#include "opus.h"
7#include "opus/opus_multistream.h"
8
9#ifndef OPUS_ENC_MAX_BUFFER_SIZE
10#define OPUS_ENC_MAX_BUFFER_SIZE 2048
11#endif
12
13#ifndef OPUS_DEC_MAX_BUFFER_SIZE
14#define OPUS_DEC_MAX_BUFFER_SIZE 4 * 1024
15#endif
16
17namespace audio_tools {
18
31
39 sample_rate = 48000;
40 channels = 2;
41 bits_per_sample = 16;
42 }
45 int streams = 1;
48 unsigned char mapping[255] = {};
49
54 break;
57 break;
58 default:
59 break;
60 }
61 }
62
64 memset(mapping, 0, sizeof(mapping));
65 if (channels == 1) {
66 streams = 1;
68 mapping[0] = 0;
69 } else if (channels == 2) {
70 streams = 1;
72 mapping[0] = 0;
73 mapping[1] = 1;
74 } else {
77 for (int i = 0; i < channels; i++) {
78 mapping[i] = i;
79 }
80 }
81 }
82
84 memset(mapping, 0, sizeof(mapping));
87 for (int i = 0; i < channels; i++) {
88 mapping[i] = i;
89 }
90 }
91};
92
117
131 public:
132 OpusMultiStreamAudioDecoder(bool releaseOnEnd = false)
133 : release_on_end(releaseOnEnd) {}
134
136 TRACED();
137 setOutput(out_stream);
138 }
139
140 const char* mime() override { return "audio/opus"; }
141
142 void setOutput(Print& out_stream) override { p_print = &out_stream; }
143
144 AudioInfo audioInfo() override { return cfg; }
145
148
150 TRACED();
152 cfg = settings;
154 return begin();
155 }
156
157 bool begin() override {
158 TRACED();
160 LOGE("Sample rate not supported: %d", cfg.sample_rate);
161 return false;
162 }
165 assert(outbuf.data() != nullptr);
166
167 int err;
168 dec = opus_multistream_decoder_create(cfg.sample_rate, cfg.channels,
170 cfg.mapping, &err);
171 if (err != OPUS_OK || dec == nullptr) {
172 LOGE(
173 "opus_multistream_decoder_create: %s for sample_rate: %d, "
174 "channels:%d, streams:%d, coupled:%d",
175 opus_strerror(err), cfg.sample_rate, cfg.channels, cfg.streams,
177 return false;
178 }
179 active = true;
180 return true;
181 }
182
183 void end() override {
184 TRACED();
185 if (dec != nullptr) {
186 opus_multistream_decoder_destroy(dec);
187 dec = nullptr;
188 }
189 if (release_on_end) {
190 outbuf.resize(0);
191 }
192 active = false;
193 }
194
195 void setAudioInfo(AudioInfo from) override {
196 bool channels_changed = info.channels != from.channels;
198 info = from;
200 cfg.channels = from.channels;
202 // Also (re)initialize when the codec was never started: relying on
203 // channels_changed alone misses the very first call whenever the real
204 // channel count happens to equal AudioInfo's own default (DEFAULT_CHANNELS
205 // == 2, i.e. plain stereo) - info.channels then already equals
206 // from.channels before any real begin() has happened, so the decoder was
207 // silently left uninitialized (active == false) despite looking
208 // "unchanged".
209 if (channels_changed || !active) {
211 end();
212 begin();
213 }
214 }
215
216 size_t write(const uint8_t* data, size_t len) override {
217 if (!active || p_print == nullptr) return 0;
218 LOGD("OpusMultiStreamAudioDecoder::write: %d", (int)len);
219 int in_band_forward_error_correction = 0;
220 int frame_count = cfg.max_buffer_size / cfg.channels / sizeof(opus_int16);
221 int out_samples = opus_multistream_decode(
222 dec, (uint8_t*)data, len, (opus_int16*)outbuf.data(), frame_count,
223 in_band_forward_error_correction);
224 if (out_samples < 0) {
225 LOGW("opus_multistream_decode: %s", opus_strerror(out_samples));
226 } else if (out_samples > 0) {
227 int out_bytes = out_samples * cfg.channels * sizeof(int16_t);
228 LOGD("opus_multistream_decode: %d", out_bytes);
229 int open = out_bytes;
230 int processed = 0;
231 while (open > 0) {
232 int to_write = std::min(open, cfg.max_buffer_write_size);
233 int written = p_print->write(outbuf.data() + processed, to_write);
234 open -= written;
235 processed += written;
236 }
237 }
238 return len;
239 }
240
241 operator bool() override { return active; }
242
243 void setReleaseOnEnd(bool flag) { release_on_end = flag; }
244
245 protected:
246 Print* p_print = nullptr;
247 OpusMSDecoder* dec = nullptr;
249 bool active = false;
251 const uint32_t valid_rates[5] = {8000, 12000, 16000, 24000, 48000};
252 bool release_on_end = false;
253
254 bool isValidRate(int rate) {
255 for (auto& valid : valid_rates) {
256 if (valid == rate) return true;
257 }
258 return false;
259 }
260};
261
278 public:
280
282
283 void setOutput(Print& out_stream) override { p_print = &out_stream; }
284
285 const char* mime() override { return "audio/opus"; }
286
287 void setAudioInfo(AudioInfo from) override {
288 LOGD("OpusMultiStreamAudioEncoder::setAudioInfo: sample_rate: %d, channels: %d",
289 from.sample_rate, from.channels);
292 cfg.channels = from.channels;
294 // Restart the encoder
295 if (enc != nullptr) {
296 end();
297 begin();
298 }
299 }
300
301 bool begin() override {
302 LOGD("OpusMultiStreamAudioEncoder::begin: sample_rate: %d, channels: %d",
304 int err;
305 int size =
307 frame.resize(size);
308 assert(frame.data() != nullptr);
309
310 // make sure that the channel mapping is set up correctly
312
313 int packet_len =
315 packet.resize(packet_len);
316 assert(packet.data() != nullptr);
317 enc = opus_multistream_encoder_create(cfg.sample_rate, cfg.channels,
319 cfg.mapping, cfg.application, &err);
320 if (err != OPUS_OK || enc == nullptr) {
321 LOGE(
322 "opus_multistream_encoder_create: %s for sample_rate: %d, "
323 "channels:%d, streams:%d, coupled:%d",
324 opus_strerror(err), cfg.sample_rate, cfg.channels, cfg.streams,
326 return false;
327 }
328 is_open = settings();
329 return is_open;
330 }
331
333
335
337 cfg = settings;
338 return begin();
339 }
340
341 void end() override {
342 if (frame_pos > 0) {
343 memset(frame.data() + frame_pos, 0, frame.size() - frame_pos);
344 encodeFrame();
345 frame_pos = 0;
346 }
347 if (enc != nullptr) {
348 opus_multistream_encoder_destroy(enc);
349 enc = nullptr;
350 }
351 is_open = false;
352 }
353
354 size_t write(const uint8_t* data, size_t len) override {
355 if (!is_open || p_print == nullptr) return 0;
356 LOGD("OpusMultiStreamAudioEncoder::write: %d", (int)len);
357 for (int j = 0; j < len; j++) {
358 encodeByte(data[j]);
359 }
360 return len;
361 }
362
363 operator bool() override { return is_open; }
364
365 bool isOpen() { return is_open; }
366
368 if (enc == nullptr) return 0;
369 opus_int32 samples = 0;
370 if (opus_multistream_encoder_ctl(enc, OPUS_GET_LOOKAHEAD(&samples)) !=
371 OPUS_OK) {
372 return 0;
373 }
374 return samples > 0 ? samples : 0;
375 }
376
378
380 int bytesPerSample = cfg.channels * (int)sizeof(int16_t);
381 if (bytesPerSample <= 0) return 0;
382 return frame_pos / bytesPerSample;
383 }
384
385 uint16_t samplesPerFrame() { return frameSizeSamples(); }
386
387 protected:
388 Print* p_print = nullptr;
389 OpusMSEncoder* enc = nullptr;
391 bool is_open = false;
394 int frame_pos = 0;
395
396 void encodeByte(uint8_t data) {
397 frame[frame_pos++] = data;
398 if (frame_pos >= frame.size()) {
399 encodeFrame();
400 frame_pos = 0;
401 }
402 }
403
404 void encodeFrame() {
405 if (frame.size() > 0) {
406 int frames = frame.size() / cfg.channels / sizeof(int16_t);
407 LOGD("opus_multistream_encode - frame_size: %d", frames);
408 int len = opus_multistream_encode(enc, (opus_int16*)frame.data(), frames,
409 packet.data(), packet.size());
410 if (len < 0) {
411 LOGE("opus_multistream_encode: %s", opus_strerror(len));
412 } else if (len > 0) {
413 LOGD("opus_multistream_encode: %d", len);
414 int eff = p_print->write(packet.data(), len);
415 if (eff != len) {
416 LOGE("encodeFrame data lost: %d->%d", len, eff);
417 }
418 }
419 }
420 }
421
422 int getFrameSizeSamples(int sampling_rate) {
423 switch (cfg.frame_sizes_ms_x2) {
424 case OPUS_FRAMESIZE_2_5_MS:
425 return sampling_rate / 400;
426 case OPUS_FRAMESIZE_5_MS:
427 return sampling_rate / 200;
428 case OPUS_FRAMESIZE_10_MS:
429 return sampling_rate / 100;
430 case OPUS_FRAMESIZE_20_MS:
431 return sampling_rate / 50;
432 case OPUS_FRAMESIZE_40_MS:
433 return sampling_rate / 25;
434 case OPUS_FRAMESIZE_60_MS:
435 return 3 * sampling_rate / 50;
436 case OPUS_FRAMESIZE_80_MS:
437 return 4 * sampling_rate / 50;
438 case OPUS_FRAMESIZE_100_MS:
439 return 5 * sampling_rate / 50;
440 case OPUS_FRAMESIZE_120_MS:
441 return 6 * sampling_rate / 50;
442 }
443 return sampling_rate / 100;
444 }
445
446 bool settings() {
447 bool ok = true;
448 if (cfg.bitrate >= 0 &&
449 opus_multistream_encoder_ctl(enc, OPUS_SET_BITRATE(cfg.bitrate)) !=
450 OPUS_OK) {
451 LOGE("invalid bitrate: %d", cfg.bitrate);
452 ok = false;
453 }
454 if (cfg.force_channel >= 0 &&
455 opus_multistream_encoder_ctl(
456 enc, OPUS_SET_FORCE_CHANNELS(cfg.force_channel)) != OPUS_OK) {
457 LOGE("invalid force_channel: %d", cfg.force_channel);
458 ok = false;
459 }
460 if (cfg.vbr >= 0 &&
461 opus_multistream_encoder_ctl(enc, OPUS_SET_VBR(cfg.vbr)) != OPUS_OK) {
462 LOGE("invalid vbr: %d", cfg.vbr);
463 ok = false;
464 }
465 if (cfg.vbr_constraint >= 0 &&
466 opus_multistream_encoder_ctl(
467 enc, OPUS_SET_VBR_CONSTRAINT(cfg.vbr_constraint)) != OPUS_OK) {
468 LOGE("invalid vbr_constraint: %d", cfg.vbr_constraint);
469 ok = false;
470 }
471 if (cfg.complexity >= 0 &&
472 opus_multistream_encoder_ctl(
473 enc, OPUS_SET_COMPLEXITY(cfg.complexity)) != OPUS_OK) {
474 LOGE("invalid complexity: %d", cfg.complexity);
475 ok = false;
476 }
477 if (cfg.max_bandwidth >= 0 &&
478 opus_multistream_encoder_ctl(
479 enc, OPUS_SET_MAX_BANDWIDTH(cfg.max_bandwidth)) != OPUS_OK) {
480 LOGE("invalid max_bandwidth: %d", cfg.max_bandwidth);
481 ok = false;
482 }
483 if (cfg.signal >= 0 && opus_multistream_encoder_ctl(
484 enc, OPUS_SET_SIGNAL(cfg.signal)) != OPUS_OK) {
485 LOGE("invalid signal: %d", cfg.signal);
486 ok = false;
487 }
488 if (cfg.inband_fec >= 0 &&
489 opus_multistream_encoder_ctl(
490 enc, OPUS_SET_INBAND_FEC(cfg.inband_fec)) != OPUS_OK) {
491 LOGE("invalid inband_fec: %d", cfg.inband_fec);
492 ok = false;
493 }
494 if (cfg.packet_loss_perc >= 0 &&
495 opus_multistream_encoder_ctl(
496 enc, OPUS_SET_PACKET_LOSS_PERC(cfg.packet_loss_perc)) != OPUS_OK) {
497 LOGE("invalid pkt_loss: %d", cfg.packet_loss_perc);
498 ok = false;
499 }
500 if (cfg.lsb_depth >= 0 &&
501 opus_multistream_encoder_ctl(enc, OPUS_SET_LSB_DEPTH(cfg.lsb_depth)) !=
502 OPUS_OK) {
503 LOGE("invalid lsb_depth: %d", cfg.lsb_depth);
504 ok = false;
505 }
506 if (cfg.prediction_disabled >= 0 &&
507 opus_multistream_encoder_ctl(
508 enc, OPUS_SET_PREDICTION_DISABLED(cfg.prediction_disabled)) !=
509 OPUS_OK) {
510 LOGE("invalid pred_disabled: %d", cfg.prediction_disabled);
511 ok = false;
512 }
513 if (cfg.use_dtx >= 0 && opus_multistream_encoder_ctl(
514 enc, OPUS_SET_DTX(cfg.use_dtx)) != OPUS_OK) {
515 LOGE("invalid use_dtx: %d", cfg.use_dtx);
516 ok = false;
517 }
518 if (cfg.frame_sizes_ms_x2 > 0 &&
519 opus_multistream_encoder_ctl(
520 enc, OPUS_SET_EXPERT_FRAME_DURATION(cfg.frame_sizes_ms_x2)) !=
521 OPUS_OK) {
522 LOGE("invalid frame_sizes_ms_x2: %d", cfg.frame_sizes_ms_x2);
523 ok = false;
524 }
525 return ok;
526 }
527};
528
529} // namespace audio_tools
#define LOGW(...)
Definition AudioLoggerIDF.h:29
#define TRACED()
Definition AudioLoggerIDF.h:31
#define LOGD(...)
Definition AudioLoggerIDF.h:27
#define LOGE(...)
Definition AudioLoggerIDF.h:30
#define OPUS_DEC_MAX_BUFFER_SIZE
Definition CodecOpus.h:12
#define OPUS_ENC_MAX_BUFFER_SIZE
Definition CodecOpus.h:8
#define assert(T)
Definition avr.h:10
Definition Arduino.h:56
virtual size_t write(const uint8_t *data, size_t len)
Definition Arduino.h:120
Decoding of encoded audio into PCM data.
Definition AudioCodecsBase.h:19
AudioInfo info
Definition AudioCodecsBase.h:80
void setAudioInfo(AudioInfo from) override
for most decoders this is not needed
Definition AudioCodecsBase.h:32
Encoding of PCM data.
Definition AudioCodecsBase.h:101
void setAudioInfo(AudioInfo from) override
Defines the sample rate, number of channels and bits per sample.
Definition AudioCodecsBase.h:110
void notifyAudioChange(AudioInfo info)
Definition AudioTypes.h:180
Decoder for the Opus multistream audio format. Supports up to 255 channels by combining multiple Opus...
Definition CodecOpusMultiStream.h:130
bool active
Definition CodecOpusMultiStream.h:249
void setOutput(Print &out_stream) override
Defines where the decoded result is written to.
Definition CodecOpusMultiStream.h:142
Vector< uint8_t > outbuf
Definition CodecOpusMultiStream.h:250
OpusMultiStreamSettings & defaultConfig()
Definition CodecOpusMultiStream.h:147
OpusMultiStreamAudioDecoder(Print &out_stream)
Definition CodecOpusMultiStream.h:135
void setAudioInfo(AudioInfo from) override
for most decoders this is not needed
Definition CodecOpusMultiStream.h:195
bool begin(OpusMultiStreamSettings settings)
Definition CodecOpusMultiStream.h:149
void end() override
Definition CodecOpusMultiStream.h:183
OpusMultiStreamAudioDecoder(bool releaseOnEnd=false)
Definition CodecOpusMultiStream.h:132
size_t write(const uint8_t *data, size_t len) override
Definition CodecOpusMultiStream.h:216
OpusMultiStreamSettings & config()
Definition CodecOpusMultiStream.h:146
OpusMultiStreamSettings cfg
Definition CodecOpusMultiStream.h:248
const uint32_t valid_rates[5]
Definition CodecOpusMultiStream.h:251
bool release_on_end
Definition CodecOpusMultiStream.h:252
bool isValidRate(int rate)
Definition CodecOpusMultiStream.h:254
void setReleaseOnEnd(bool flag)
Definition CodecOpusMultiStream.h:243
const char * mime() override
Provides the mime type of the data that is expected by this decoder.
Definition CodecOpusMultiStream.h:140
bool begin() override
Definition CodecOpusMultiStream.h:157
Print * p_print
Definition CodecOpusMultiStream.h:246
AudioInfo audioInfo() override
provides the actual input AudioInfo
Definition CodecOpusMultiStream.h:144
OpusMSDecoder * dec
Definition CodecOpusMultiStream.h:247
Encoder for Opus multistream audio. Supports up to 255 channels by combining multiple Opus streams in...
Definition CodecOpusMultiStream.h:277
bool is_open
Definition CodecOpusMultiStream.h:391
void setOutput(Print &out_stream) override
Default output assignment (encoders may override to store Print reference)
Definition CodecOpusMultiStream.h:283
bool begin(OpusMultiStreamEncoderSettings settings)
Definition CodecOpusMultiStream.h:336
OpusMSEncoder * enc
Definition CodecOpusMultiStream.h:389
OpusMultiStreamEncoderSettings & defaultConfig()
Definition CodecOpusMultiStream.h:334
bool isOpen()
Definition CodecOpusMultiStream.h:365
uint16_t samplesPerFrame()
Optional rtsp function: provide samples per the frame.
Definition CodecOpusMultiStream.h:385
OpusMultiStreamEncoderSettings cfg
Definition CodecOpusMultiStream.h:390
int frameSizeSamples()
Definition CodecOpusMultiStream.h:377
void setAudioInfo(AudioInfo from) override
Defines the sample rate, number of channels and bits per sample.
Definition CodecOpusMultiStream.h:287
void end() override
Definition CodecOpusMultiStream.h:341
void encodeFrame()
Definition CodecOpusMultiStream.h:404
int lookaheadSamples()
Definition CodecOpusMultiStream.h:367
size_t write(const uint8_t *data, size_t len) override
Definition CodecOpusMultiStream.h:354
OpusMultiStreamAudioEncoder(Print &out)
Definition CodecOpusMultiStream.h:281
OpusMultiStreamEncoderSettings & config()
Definition CodecOpusMultiStream.h:332
int pendingSamples()
Definition CodecOpusMultiStream.h:379
bool settings()
Definition CodecOpusMultiStream.h:446
const char * mime() override
Provides the mime type of the encoded result.
Definition CodecOpusMultiStream.h:285
Vector< uint8_t > packet
Definition CodecOpusMultiStream.h:393
int frame_pos
Definition CodecOpusMultiStream.h:394
bool begin() override
Definition CodecOpusMultiStream.h:301
Print * p_print
Definition CodecOpusMultiStream.h:388
Vector< uint8_t > frame
Definition CodecOpusMultiStream.h:392
void encodeByte(uint8_t data)
Definition CodecOpusMultiStream.h:396
int getFrameSizeSamples(int sampling_rate)
Definition CodecOpusMultiStream.h:422
Vector implementation which provides the most important methods as defined by std::vector....
Definition Vector.h:21
bool resize(size_t newSize, T value)
Definition Vector.h:266
T * data()
Definition Vector.h:321
int size()
Definition Vector.h:178
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition LMSEchoCancellationStream.h:6
opus_channel_mapping_enum_t
Defines the channel mapping scenarios for Opus MultiStream: default is OPUS_CHANNEL_MAPPING_COMBINED ...
Definition CodecOpusMultiStream.h:26
@ OPUS_CHANNEL_MAPPING_CUSTOM
Definition CodecOpusMultiStream.h:29
@ OPUS_CHANNEL_MAPPING_COMBINED
Definition CodecOpusMultiStream.h:27
@ OPUS_CHANNEL_MAPPING_SEPARATE
Definition CodecOpusMultiStream.h:28
Basic Audio information which drives e.g. I2S.
Definition AudioTypes.h:56
sample_rate_t sample_rate
Sample Rate: e.g 44100.
Definition AudioTypes.h:58
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition AudioTypes.h:60
uint8_t bits_per_sample
Number of bits per sample (int16_t = 16 bits)
Definition AudioTypes.h:62
Settings for Opus MultiStream Encoder.
Definition CodecOpusMultiStream.h:98
int vbr
Definition CodecOpusMultiStream.h:105
int vbr_constraint
Definition CodecOpusMultiStream.h:106
int frame_sizes_ms_x2
Definition CodecOpusMultiStream.h:115
OpusMultiStreamEncoderSettings()
Definition CodecOpusMultiStream.h:99
int inband_fec
Definition CodecOpusMultiStream.h:110
int use_dtx
Definition CodecOpusMultiStream.h:114
int packet_loss_perc
Definition CodecOpusMultiStream.h:111
int complexity
Definition CodecOpusMultiStream.h:107
int force_channel
Definition CodecOpusMultiStream.h:104
int signal
Definition CodecOpusMultiStream.h:109
int bitrate
Definition CodecOpusMultiStream.h:103
int prediction_disabled
Definition CodecOpusMultiStream.h:113
int max_bandwidth
Definition CodecOpusMultiStream.h:108
int lsb_depth
Definition CodecOpusMultiStream.h:112
int application
Definition CodecOpusMultiStream.h:102
Settings for Opus MultiStream Decoder.
Definition CodecOpusMultiStream.h:37
void setupSeparateChannelsMapping()
Definition CodecOpusMultiStream.h:83
unsigned char mapping[255]
Definition CodecOpusMultiStream.h:48
void setupDefaultMapping()
Definition CodecOpusMultiStream.h:63
int coupled_streams
Definition CodecOpusMultiStream.h:46
int max_buffer_size
Definition CodecOpusMultiStream.h:43
int streams
Definition CodecOpusMultiStream.h:45
opus_channel_mapping_enum_t default_channel_mapping
Definition CodecOpusMultiStream.h:47
int max_buffer_write_size
Definition CodecOpusMultiStream.h:44
void setupChannelMapping()
Definition CodecOpusMultiStream.h:50
OpusMultiStreamSettings()
Definition CodecOpusMultiStream.h:38