From adc7fd9363be5590ca86dff1cd34d25f268c27de Mon Sep 17 00:00:00 2001 From: Phil Schatzmann Date: Thu, 1 Sep 2022 10:41:48 +0200 Subject: [PATCH] opus-ogg --- .../test-codec-opus/test-codec-opus.ino | 16 +++-- .../test-codec-opusogg/test-codec-opusogg.ino | 28 ++++----- src/AudioCodecs/CodecOpus.h | 59 +++++++++++-------- src/AudioCodecs/ContainerOgg.h | 6 +- tests/codec/opus/opus.cpp | 12 +--- 5 files changed, 56 insertions(+), 65 deletions(-) diff --git a/examples/tests/codecs/test-codec-opus/test-codec-opus.ino b/examples/tests/codecs/test-codec-opus/test-codec-opus.ino index 8a00c13107..5de71d47c0 100644 --- a/examples/tests/codecs/test-codec-opus/test-codec-opus.ino +++ b/examples/tests/codecs/test-codec-opus/test-codec-opus.ino @@ -13,7 +13,7 @@ #include "AudioCodecs/CodecOpus.h" int sample_rate = 24000; -int channels = 1; // The stream will have 2 channels +int channels = 1; SineWaveGenerator sineWave( 32000); // subclass of SoundGenerator with max amplitude of 32000 GeneratedSoundStream sound( sineWave); // Stream generated from sine wave @@ -42,16 +42,14 @@ void setup() { cfgs.bits_per_sample = 16; sineWave.begin(cfgs, N_B4); - // Opus decoder needs to know the audio info + // Opus encoder and decoder need to know the audio info decoder.begin(cfgs); + encoder.begin(cfgs); - // configure and start encoder - auto encfg = enc.config(); - encfg.copyFrom(cfgs); // use sample rate, channels ... - //encfg.application = OPUS_APPLICATION_RESTRICTED_LOWDELAY; - //encfg.frame_sizes_ms_x2 = OPUS_FRAMESIZE_20_MS; - //encfg.complexity = 5; - encoder.begin(encfg); + // configure additinal parameters + //enc.config().application = OPUS_APPLICATION_RESTRICTED_LOWDELAY; + //enc.config().frame_sizes_ms_x2 = OPUS_FRAMESIZE_20_MS; + //enc.config().complexity = 5; Serial.println("Test started..."); } diff --git a/examples/tests/codecs/test-codec-opusogg/test-codec-opusogg.ino b/examples/tests/codecs/test-codec-opusogg/test-codec-opusogg.ino index 6410537a31..c3567602fd 100644 --- a/examples/tests/codecs/test-codec-opusogg/test-codec-opusogg.ino +++ b/examples/tests/codecs/test-codec-opusogg/test-codec-opusogg.ino @@ -13,14 +13,14 @@ #include "AudioCodecs/CodecOpusOgg.h" int sample_rate = 24000; -int channels = 2; // The stream will have 2 channels -int application = OPUS_APPLICATION_AUDIO; // Opus application +int channels = 1; SineWaveGenerator sineWave( 32000); // subclass of SoundGenerator with max amplitude of 32000 GeneratedSoundStream sound( sineWave); // Stream generated from sine wave -AudioKitStream out; +CsvStream out(Serial,channels); OpusOggEncoder enc; -EncodedAudioStream decoder(&out, new OpusOggDecoder()); // encode and write +OpusOggDecoder dec; +EncodedAudioStream decoder(&out, &dec); // encode and write EncodedAudioStream encoder(&decoder, &enc); // encode and write StreamCopy copier(encoder, sound); @@ -28,14 +28,6 @@ void setup() { Serial.begin(115200); AudioLogger::instance().begin(Serial, AudioLogger::Warning); - // start I2S - Serial.println("starting I2S..."); - auto cfgi = out.defaultConfig(TX_MODE); - cfgi.sample_rate = sample_rate; - cfgi.channels = channels; - cfgi.bits_per_sample = 16; - out.begin(cfgi); - // Setup sine wave auto cfgs = sineWave.defaultConfig(); cfgs.sample_rate = sample_rate; @@ -43,12 +35,14 @@ void setup() { cfgs.bits_per_sample = 16; sineWave.begin(cfgs, N_B4); - // Opus decoder needs to know the audio info - decoder.begin(cfgs); - - // configure and start encoder - enc.config().application = application; + // Opus encoder needs to know the audio info encoder.begin(cfgs); + decoder.begin(); + + // configure additinal parameters + //enc.config().application = OPUS_APPLICATION_RESTRICTED_LOWDELAY; + //enc.config().frame_sizes_ms_x2 = OPUS_FRAMESIZE_20_MS; + //enc.config().complexity = 5; Serial.println("Test started..."); } diff --git a/src/AudioCodecs/CodecOpus.h b/src/AudioCodecs/CodecOpus.h index ba024615ab..79a61aa61c 100644 --- a/src/AudioCodecs/CodecOpus.h +++ b/src/AudioCodecs/CodecOpus.h @@ -4,8 +4,12 @@ #include "Print.h" #include "opus.h" -#ifndef OPUS_MAX_BUFFER_SIZE -#define OPUS_MAX_BUFFER_SIZE (5760) +#ifndef OPUS_ENC_MAX_BUFFER_SIZE +#define OPUS_ENC_MAX_BUFFER_SIZE 2048 +#endif + +#ifndef OPUS_DEC_MAX_BUFFER_SIZE +#define OPUS_DEC_MAX_BUFFER_SIZE 1024 #endif namespace audio_tools { @@ -24,7 +28,7 @@ struct OpusSettings : public AudioBaseInfo { /// must be 16! bits_per_sample = 16; } - int max_buffer_size = OPUS_MAX_BUFFER_SIZE; + int max_buffer_size = OPUS_DEC_MAX_BUFFER_SIZE; }; /** @@ -59,9 +63,10 @@ frame_sizes_ms_x2[9] = {OPUS_FRAMESIZE_2_5_MS,OPUS_FRAMESIZE_5_MS,OPUS_FRAMESIZE **/ struct OpusEncoderSettings : public OpusSettings { - OpusEncoderSettings() : OpusSettings() {} + OpusEncoderSettings() : OpusSettings() { /// Default is 5760 - int max_buffer_size = OPUS_MAX_BUFFER_SIZE; + max_buffer_size = OPUS_ENC_MAX_BUFFER_SIZE; + } /// OPUS_APPLICATION_AUDIO, OPUS_APPLICATION_VOIP, /// OPUS_APPLICATION_RESTRICTED_LOWDELAY int application = OPUS_APPLICATION_AUDIO; @@ -144,6 +149,8 @@ class OpusAudioDecoder : public AudioDecoder { void begin() override { LOGD(LOG_METHOD); outbuf.resize(cfg.max_buffer_size); + assert(outbuf.data() != nullptr); + int err; dec = opus_decoder_create(cfg.sample_rate, cfg.channels, &err); if (err != OPUS_OK) { @@ -193,9 +200,9 @@ class OpusAudioDecoder : public AudioDecoder { Print *p_print = nullptr; AudioBaseInfoDependent *bid = nullptr; OpusSettings cfg; - ::OpusDecoder *dec; + OpusDecoder *dec; bool active; - Vector outbuf; + Vector outbuf{0}; }; /** @@ -228,13 +235,10 @@ class OpusAudioEncoder : public AudioEncoder { /// starts the processing using the actual OpusAudioInfo void begin() override { int err; - packet.resize(cfg.max_buffer_size); - frame.resize(getFrameSizeSamples(cfg.sample_rate) * 2); + int size = getFrameSizeSamples(cfg.sample_rate) * 2; + frame.resize(size); assert(frame.data() != nullptr); - assert(packet.data() != nullptr); - - enc = opus_encoder_create(cfg.sample_rate, cfg.channels, cfg.application, - &err); + enc = opus_encoder_create(cfg.sample_rate, cfg.channels, cfg.application, &err); if (err != OPUS_OK) { LOGE("opus_encoder_create: %s for sample_rate: %d, channels:%d", opus_strerror(err), cfg.sample_rate, cfg.channels); @@ -255,7 +259,7 @@ class OpusAudioEncoder : public AudioEncoder { /// stops the processing void end() override { // flush buffered data - encodeFrame(frame_pos); + encodeFrame(); // release memory opus_encoder_destroy(enc); is_open = false; @@ -265,6 +269,7 @@ class OpusAudioEncoder : public AudioEncoder { size_t write(const void *in_ptr, size_t in_size) { if (!is_open || p_print == nullptr) return 0; + // fill frame uint8_t *p_byte = (uint8_t *)in_ptr; for (int j = 0; j < in_size; j++) { encodeByte(p_byte[j]); @@ -278,11 +283,10 @@ class OpusAudioEncoder : public AudioEncoder { protected: Print *p_print = nullptr; - ::OpusEncoder *enc = nullptr; + OpusEncoder *enc = nullptr; OpusEncoderSettings cfg; bool is_open = false; - Vector packet; - Vector frame; + Vector frame{0}; int frame_pos = 0; void encodeByte(uint8_t data) { @@ -290,23 +294,26 @@ class OpusAudioEncoder : public AudioEncoder { frame[frame_pos++] = data; // if frame is complete -> encode - int frame_size = frame.size(); - if (frame_pos >= frame_size) { - encodeFrame(frame_size); + if (frame_pos >= frame.size()) { + encodeFrame(); frame_pos = 0; } } - void encodeFrame(int lenBytes) { - if (lenBytes > 0) { - int frames = lenBytes / cfg.channels / sizeof(int16_t); + void encodeFrame() { + if (frame.size() > 0) { + // allocate temp buffer on stack + int packet_len = OPUS_ENC_MAX_BUFFER_SIZE > 0 ? OPUS_ENC_MAX_BUFFER_SIZE : 512; + uint8_t packet[packet_len]; + + int frames = frame.size() / cfg.channels / sizeof(int16_t); LOGD("opus_encode - frame_size: %d", frames); int len = opus_encode(enc, (opus_int16 *)frame.data(), frames, - packet.data(), cfg.max_buffer_size); + packet, packet_len); if (len < 0) { LOGE("opus_encode: %s", opus_strerror(len)); - } else if (len > 0 && len <= cfg.max_buffer_size) { - int eff = p_print->write(packet.data(), len); + } else if (len > 0) { + int eff = p_print->write(packet, len); if (eff!=len){ LOGE("encodeFrame data lost"); } diff --git a/src/AudioCodecs/ContainerOgg.h b/src/AudioCodecs/ContainerOgg.h index fcd52fe97a..7b967ff75f 100644 --- a/src/AudioCodecs/ContainerOgg.h +++ b/src/AudioCodecs/ContainerOgg.h @@ -5,8 +5,8 @@ #include "AudioTools/Buffers.h" #include "oggz/oggz.h" -#define OGG_DEFAULT_BUFFER_SIZE (2048) -#define OGG_READ_SIZE 1024 +#define OGG_DEFAULT_BUFFER_SIZE (246) +#define OGG_READ_SIZE (512) namespace audio_tools { @@ -102,7 +102,7 @@ class OggContainerDecoder : public AudioDecoder { } virtual size_t write(const void *in_ptr, size_t in_size) override { - LOGI("write: %u", in_size); + LOGD("write: %u", in_size); if (p_print == nullptr) return 0; // fill buffer diff --git a/tests/codec/opus/opus.cpp b/tests/codec/opus/opus.cpp index 16036fc07d..f2fcbf4058 100644 --- a/tests/codec/opus/opus.cpp +++ b/tests/codec/opus/opus.cpp @@ -12,8 +12,7 @@ #include "AudioCodecs/CodecOpus.h" int sample_rate = 24000; -int channels = 2; // The stream will have 2 channels -int application = OPUS_APPLICATION_AUDIO; // Opus application +int channels = 1; // The stream will have 2 channels SineWaveGenerator sineWave( 32000); // subclass of SoundGenerator with max amplitude of 32000 GeneratedSoundStream sound( sineWave); // Stream generated from sine wave @@ -28,13 +27,6 @@ void setup() { Serial.begin(115200); AudioLogger::instance().begin(Serial, AudioLogger::Debug); - // start I2S - // Serial.println("starting I2S..."); - // auto cfgi = out.defaultConfig(TX_MODE); - // cfgi.sample_rate = sample_rate; - // cfgi.channels = channels; - // cfgi.bits_per_sample = 16; - // out.begin(cfgi); // Setup sine wave auto cfgs = sineWave.defaultConfig(); @@ -47,7 +39,7 @@ void setup() { decoder.begin(cfgs); // configure and start encoder - enc.config().application = application; + enc.config().application = OPUS_APPLICATION_AUDIO; encoder.begin(cfgs); Serial.println("Test started...");