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 const char* mime() override { return "audio/opus"; }
140
141 void setOutput(Print& out_stream) override { p_print = &out_stream; }
142
143 AudioInfo audioInfo() override { return cfg; }
144
147
149 TRACED();
151 cfg = settings;
153 return begin();
154 }
155
156 bool begin() override {
157 TRACED();
159 LOGE("Sample rate not supported: %d", cfg.sample_rate);
160 return false;
161 }
164 assert(outbuf.data() != nullptr);
165
166 int err;
167 dec = opus_multistream_decoder_create(cfg.sample_rate, cfg.channels,
169 cfg.mapping, &err);
170 if (err != OPUS_OK || dec == nullptr) {
171 LOGE(
172 "opus_multistream_decoder_create: %s for sample_rate: %d, "
173 "channels:%d, streams:%d, coupled:%d",
174 opus_strerror(err), cfg.sample_rate, cfg.channels, cfg.streams,
176 return false;
177 }
178 active = true;
179 return true;
180 }
181
182 void end() override {
183 TRACED();
184 if (dec != nullptr) {
185 opus_multistream_decoder_destroy(dec);
186 dec = nullptr;
187 }
188 if (release_on_end) {
189 outbuf.resize(0);
190 }
191 active = false;
192 }
193
194 void setAudioInfo(AudioInfo from) override {
195 bool channels_changed = info.channels != from.channels;
197 info = from;
199 cfg.channels = from.channels;
201 // Also (re)initialize when the codec was never started: relying on
202 // channels_changed alone misses the very first call whenever the real
203 // channel count happens to equal AudioInfo's own default (DEFAULT_CHANNELS
204 // == 2, i.e. plain stereo) - info.channels then already equals
205 // from.channels before any real begin() has happened, so the decoder was
206 // silently left uninitialized (active == false) despite looking
207 // "unchanged".
208 if (channels_changed || !active) {
210 end();
211 begin();
212 }
213 }
214
215 size_t write(const uint8_t* data, size_t len) override {
216 if (!active || p_print == nullptr) return 0;
217 LOGD("OpusMultiStreamAudioDecoder::write: %d", (int)len);
218 int in_band_forward_error_correction = 0;
219 int frame_count = cfg.max_buffer_size / cfg.channels / sizeof(opus_int16);
220 int out_samples = opus_multistream_decode(
221 dec, (uint8_t*)data, len, (opus_int16*)outbuf.data(), frame_count,
222 in_band_forward_error_correction);
223 if (out_samples < 0) {
224 LOGW("opus_multistream_decode: %s", opus_strerror(out_samples));
225 } else if (out_samples > 0) {
226 int out_bytes = out_samples * cfg.channels * sizeof(int16_t);
227 LOGD("opus_multistream_decode: %d", out_bytes);
228 int open = out_bytes;
229 int processed = 0;
230 while (open > 0) {
231 int to_write = std::min(open, cfg.max_buffer_write_size);
232 int written = p_print->write(outbuf.data() + processed, to_write);
233 open -= written;
234 processed += written;
235 }
236 }
237 return len;
238 }
239
240 operator bool() override { return active; }
241
242 void setReleaseOnEnd(bool flag) { release_on_end = flag; }
243
244 protected:
245 Print* p_print = nullptr;
246 OpusMSDecoder* dec = nullptr;
248 bool active = false;
250 const uint32_t valid_rates[5] = {8000, 12000, 16000, 24000, 48000};
251 bool release_on_end = false;
252
253 bool isValidRate(int rate) {
254 for (auto& valid : valid_rates) {
255 if (valid == rate) return true;
256 }
257 return false;
258 }
259};
260
277 public:
279
281
282 void setOutput(Print& out_stream) override { p_print = &out_stream; }
283
284 const char* mime() override { return "audio/opus"; }
285
286 void setAudioInfo(AudioInfo from) override {
287 LOGD("OpusMultiStreamAudioEncoder::setAudioInfo: sample_rate: %d, channels: %d",
288 from.sample_rate, from.channels);
291 cfg.channels = from.channels;
293 // Restart the encoder
294 if (enc != nullptr) {
295 end();
296 begin();
297 }
298 }
299
300 bool begin() override {
301 LOGD("OpusMultiStreamAudioEncoder::begin: sample_rate: %d, channels: %d",
303 int err;
304 int size =
305 getFrameSizeSamples(cfg.sample_rate) * cfg.channels * sizeof(int16_t);
306 frame.resize(size);
307 assert(frame.data() != nullptr);
308
309 // make sure that the channel mapping is set up correctly
311
312 int packet_len =
314 packet.resize(packet_len);
315 assert(packet.data() != nullptr);
316 enc = opus_multistream_encoder_create(cfg.sample_rate, cfg.channels,
318 cfg.mapping, cfg.application, &err);
319 if (err != OPUS_OK || enc == nullptr) {
320 LOGE(
321 "opus_multistream_encoder_create: %s for sample_rate: %d, "
322 "channels:%d, streams:%d, coupled:%d",
323 opus_strerror(err), cfg.sample_rate, cfg.channels, cfg.streams,
325 return false;
326 }
327 is_open = settings();
328 return is_open;
329 }
330
332
334
336 cfg = settings;
337 return begin();
338 }
339
340 void end() override {
341 if (frame_pos > 0) {
342 memset(frame.data() + frame_pos, 0, frame.size() - frame_pos);
343 encodeFrame();
344 frame_pos = 0;
345 }
346 if (enc != nullptr) {
347 opus_multistream_encoder_destroy(enc);
348 enc = nullptr;
349 }
350 is_open = false;
351 }
352
353 size_t write(const uint8_t* data, size_t len) override {
354 if (!is_open || p_print == nullptr) return 0;
355 LOGD("OpusMultiStreamAudioEncoder::write: %d", (int)len);
356 for (int j = 0; j < len; j++) {
357 encodeByte(data[j]);
358 }
359 return len;
360 }
361
362 operator bool() override { return is_open; }
363
364 bool isOpen() { return is_open; }
365
367 if (enc == nullptr) return 0;
368 opus_int32 samples = 0;
369 if (opus_multistream_encoder_ctl(enc, OPUS_GET_LOOKAHEAD(&samples)) !=
370 OPUS_OK) {
371 return 0;
372 }
373 return samples > 0 ? samples : 0;
374 }
375
377
379 int bytesPerSample = cfg.channels * (int)sizeof(int16_t);
380 if (bytesPerSample <= 0) return 0;
381 return frame_pos / bytesPerSample;
382 }
383
384 uint16_t samplesPerFrame() { return frameSizeSamples(); }
385
386 protected:
387 Print* p_print = nullptr;
388 OpusMSEncoder* enc = nullptr;
390 bool is_open = false;
393 int frame_pos = 0;
394
395 void encodeByte(uint8_t data) {
396 frame[frame_pos++] = data;
397 if (frame_pos >= frame.size()) {
398 encodeFrame();
399 frame_pos = 0;
400 }
401 }
402
403 void encodeFrame() {
404 if (frame.size() > 0) {
405 int frames = frame.size() / cfg.channels / sizeof(int16_t);
406 LOGD("opus_multistream_encode - frame_size: %d", frames);
407 int len = opus_multistream_encode(enc, (opus_int16*)frame.data(), frames,
408 packet.data(), packet.size());
409 if (len < 0) {
410 LOGE("opus_multistream_encode: %s", opus_strerror(len));
411 } else if (len > 0) {
412 LOGD("opus_multistream_encode: %d", len);
413 int eff = p_print->write(packet.data(), len);
414 if (eff != len) {
415 LOGE("encodeFrame data lost: %d->%d", len, eff);
416 }
417 }
418 }
419 }
420
421 int getFrameSizeSamples(int sampling_rate) {
422 switch (cfg.frame_sizes_ms_x2) {
423 case OPUS_FRAMESIZE_2_5_MS:
424 return sampling_rate / 400;
425 case OPUS_FRAMESIZE_5_MS:
426 return sampling_rate / 200;
427 case OPUS_FRAMESIZE_10_MS:
428 return sampling_rate / 100;
429 case OPUS_FRAMESIZE_20_MS:
430 return sampling_rate / 50;
431 case OPUS_FRAMESIZE_40_MS:
432 return sampling_rate / 25;
433 case OPUS_FRAMESIZE_60_MS:
434 return 3 * sampling_rate / 50;
435 case OPUS_FRAMESIZE_80_MS:
436 return 4 * sampling_rate / 50;
437 case OPUS_FRAMESIZE_100_MS:
438 return 5 * sampling_rate / 50;
439 case OPUS_FRAMESIZE_120_MS:
440 return 6 * sampling_rate / 50;
441 }
442 return sampling_rate / 100;
443 }
444
445 bool settings() {
446 bool ok = true;
447 if (cfg.bitrate >= 0 &&
448 opus_multistream_encoder_ctl(enc, OPUS_SET_BITRATE(cfg.bitrate)) !=
449 OPUS_OK) {
450 LOGE("invalid bitrate: %d", cfg.bitrate);
451 ok = false;
452 }
453 if (cfg.force_channel >= 0 &&
454 opus_multistream_encoder_ctl(
455 enc, OPUS_SET_FORCE_CHANNELS(cfg.force_channel)) != OPUS_OK) {
456 LOGE("invalid force_channel: %d", cfg.force_channel);
457 ok = false;
458 }
459 if (cfg.vbr >= 0 &&
460 opus_multistream_encoder_ctl(enc, OPUS_SET_VBR(cfg.vbr)) != OPUS_OK) {
461 LOGE("invalid vbr: %d", cfg.vbr);
462 ok = false;
463 }
464 if (cfg.vbr_constraint >= 0 &&
465 opus_multistream_encoder_ctl(
466 enc, OPUS_SET_VBR_CONSTRAINT(cfg.vbr_constraint)) != OPUS_OK) {
467 LOGE("invalid vbr_constraint: %d", cfg.vbr_constraint);
468 ok = false;
469 }
470 if (cfg.complexity >= 0 &&
471 opus_multistream_encoder_ctl(
472 enc, OPUS_SET_COMPLEXITY(cfg.complexity)) != OPUS_OK) {
473 LOGE("invalid complexity: %d", cfg.complexity);
474 ok = false;
475 }
476 if (cfg.max_bandwidth >= 0 &&
477 opus_multistream_encoder_ctl(
478 enc, OPUS_SET_MAX_BANDWIDTH(cfg.max_bandwidth)) != OPUS_OK) {
479 LOGE("invalid max_bandwidth: %d", cfg.max_bandwidth);
480 ok = false;
481 }
482 if (cfg.signal >= 0 && opus_multistream_encoder_ctl(
483 enc, OPUS_SET_SIGNAL(cfg.signal)) != OPUS_OK) {
484 LOGE("invalid signal: %d", cfg.signal);
485 ok = false;
486 }
487 if (cfg.inband_fec >= 0 &&
488 opus_multistream_encoder_ctl(
489 enc, OPUS_SET_INBAND_FEC(cfg.inband_fec)) != OPUS_OK) {
490 LOGE("invalid inband_fec: %d", cfg.inband_fec);
491 ok = false;
492 }
493 if (cfg.packet_loss_perc >= 0 &&
494 opus_multistream_encoder_ctl(
495 enc, OPUS_SET_PACKET_LOSS_PERC(cfg.packet_loss_perc)) != OPUS_OK) {
496 LOGE("invalid pkt_loss: %d", cfg.packet_loss_perc);
497 ok = false;
498 }
499 if (cfg.lsb_depth >= 0 &&
500 opus_multistream_encoder_ctl(enc, OPUS_SET_LSB_DEPTH(cfg.lsb_depth)) !=
501 OPUS_OK) {
502 LOGE("invalid lsb_depth: %d", cfg.lsb_depth);
503 ok = false;
504 }
505 if (cfg.prediction_disabled >= 0 &&
506 opus_multistream_encoder_ctl(
507 enc, OPUS_SET_PREDICTION_DISABLED(cfg.prediction_disabled)) !=
508 OPUS_OK) {
509 LOGE("invalid pred_disabled: %d", cfg.prediction_disabled);
510 ok = false;
511 }
512 if (cfg.use_dtx >= 0 && opus_multistream_encoder_ctl(
513 enc, OPUS_SET_DTX(cfg.use_dtx)) != OPUS_OK) {
514 LOGE("invalid use_dtx: %d", cfg.use_dtx);
515 ok = false;
516 }
517 if (cfg.frame_sizes_ms_x2 > 0 &&
518 opus_multistream_encoder_ctl(
519 enc, OPUS_SET_EXPERT_FRAME_DURATION(cfg.frame_sizes_ms_x2)) !=
520 OPUS_OK) {
521 LOGE("invalid frame_sizes_ms_x2: %d", cfg.frame_sizes_ms_x2);
522 ok = false;
523 }
524 return ok;
525 }
526};
527
528} // 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:175
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:248
void setOutput(Print &out_stream) override
Defines where the decoded result is written to.
Definition CodecOpusMultiStream.h:141
Vector< uint8_t > outbuf
Definition CodecOpusMultiStream.h:249
OpusMultiStreamSettings & defaultConfig()
Definition CodecOpusMultiStream.h:146
OpusMultiStreamAudioDecoder(Print &out_stream)
Definition CodecOpusMultiStream.h:134
void setAudioInfo(AudioInfo from) override
for most decoders this is not needed
Definition CodecOpusMultiStream.h:194
bool begin(OpusMultiStreamSettings settings)
Definition CodecOpusMultiStream.h:148
void end() override
Definition CodecOpusMultiStream.h:182
OpusMultiStreamAudioDecoder(bool releaseOnEnd=false)
Definition CodecOpusMultiStream.h:131
size_t write(const uint8_t *data, size_t len) override
Definition CodecOpusMultiStream.h:215
OpusMultiStreamSettings & config()
Definition CodecOpusMultiStream.h:145
OpusMultiStreamSettings cfg
Definition CodecOpusMultiStream.h:247
const uint32_t valid_rates[5]
Definition CodecOpusMultiStream.h:250
bool release_on_end
Definition CodecOpusMultiStream.h:251
bool isValidRate(int rate)
Definition CodecOpusMultiStream.h:253
void setReleaseOnEnd(bool flag)
Definition CodecOpusMultiStream.h:242
const char * mime() override
Provides the mime type of the data that is expected by this decoder.
Definition CodecOpusMultiStream.h:139
bool begin() override
Definition CodecOpusMultiStream.h:156
Print * p_print
Definition CodecOpusMultiStream.h:245
AudioInfo audioInfo() override
provides the actual input AudioInfo
Definition CodecOpusMultiStream.h:143
OpusMSDecoder * dec
Definition CodecOpusMultiStream.h:246
Encoder for Opus multistream audio. Supports up to 255 channels by combining multiple Opus streams in...
Definition CodecOpusMultiStream.h:276
bool is_open
Definition CodecOpusMultiStream.h:390
void setOutput(Print &out_stream) override
Default output assignment (encoders may override to store Print reference)
Definition CodecOpusMultiStream.h:282
bool begin(OpusMultiStreamEncoderSettings settings)
Definition CodecOpusMultiStream.h:335
OpusMSEncoder * enc
Definition CodecOpusMultiStream.h:388
OpusMultiStreamEncoderSettings & defaultConfig()
Definition CodecOpusMultiStream.h:333
bool isOpen()
Definition CodecOpusMultiStream.h:364
uint16_t samplesPerFrame()
Optional rtsp function: provide samples per the frame.
Definition CodecOpusMultiStream.h:384
OpusMultiStreamEncoderSettings cfg
Definition CodecOpusMultiStream.h:389
int frameSizeSamples()
Definition CodecOpusMultiStream.h:376
void setAudioInfo(AudioInfo from) override
Defines the sample rate, number of channels and bits per sample.
Definition CodecOpusMultiStream.h:286
void end() override
Definition CodecOpusMultiStream.h:340
void encodeFrame()
Definition CodecOpusMultiStream.h:403
int lookaheadSamples()
Definition CodecOpusMultiStream.h:366
size_t write(const uint8_t *data, size_t len) override
Definition CodecOpusMultiStream.h:353
OpusMultiStreamAudioEncoder(Print &out)
Definition CodecOpusMultiStream.h:280
OpusMultiStreamEncoderSettings & config()
Definition CodecOpusMultiStream.h:331
int pendingSamples()
Definition CodecOpusMultiStream.h:378
bool settings()
Definition CodecOpusMultiStream.h:445
const char * mime() override
Provides the mime type of the encoded result.
Definition CodecOpusMultiStream.h:284
Vector< uint8_t > packet
Definition CodecOpusMultiStream.h:392
int frame_pos
Definition CodecOpusMultiStream.h:393
bool begin() override
Definition CodecOpusMultiStream.h:300
Print * p_print
Definition CodecOpusMultiStream.h:387
Vector< uint8_t > frame
Definition CodecOpusMultiStream.h:391
void encodeByte(uint8_t data)
Definition CodecOpusMultiStream.h:395
int getFrameSizeSamples(int sampling_rate)
Definition CodecOpusMultiStream.h:421
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