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