Skip to content

Commit

Permalink
opus ogg decoder
Browse files Browse the repository at this point in the history
  • Loading branch information
pschatzmann committed Aug 31, 2022
1 parent 1d9269f commit b644345
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 51 deletions.
38 changes: 19 additions & 19 deletions src/AudioCodecs/CodecOpusOgg.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,18 @@ struct __attribute__((packed)) OpusOggCommentHeader {
*/
class OpusOggDecoder : public OggContainerDecoder {
public:
OpusOggDecoder() = default;

/// Defines the output Stream
void setOutputStream(Print &out_stream) override {
LOGD(LOG_METHOD);
dec.setOutputStream(out_stream);
p_print = &opus;
}
OpusOggDecoder() {
p_codec = &dec; // OpusAudioDecoder
};

/// Provides access to the Opus configuration
OpusSettings &config() { return dec.config(); }

void begin(OpusSettings settings) {
OggContainerDecoder::begin();
dec.begin(settings);
}

void begin() override {
LOGD(LOG_METHOD);
OggContainerDecoder::begin();
Expand All @@ -60,7 +60,7 @@ class OpusOggDecoder : public OggContainerDecoder {
protected:
OpusOggHeader header;
OpusAudioDecoder dec;
EncodedAudioStream opus{(Print *)nullptr, &dec};
//EncodedAudioStream opus{(Print *)nullptr, &dec};

virtual void beginOfSegment(ogg_packet *op) {
LOGD("bos");
Expand All @@ -85,13 +85,17 @@ class OpusOggDecoder : public OggContainerDecoder {
*/
class OpusOggEncoder : public OggContainerEncoder {
public:
OpusOggEncoder() = default;
OpusOggEncoder() {
p_codec = &enc; // OpusAudioEncoder
};

/// Defines the output Stream
void setOutputStream(Print &out_stream) override {
LOGD(LOG_METHOD);
enc.setOutputStream(out_stream);
p_print = &opus;
/// Provides access to the configuration
OpusEncoderSettings &config() { return enc.config(); }
OpusEncoderSettings &defaultConfig() { return enc.config(); }

void begin(OpusEncoderSettings settings) {
cfg = settings;
begin();
}

void begin() override {
Expand All @@ -109,14 +113,10 @@ class OpusOggEncoder : public OggContainerEncoder {
/// Provides "audio/opus"
const char *mime() override { return "audio/opus"; }

/// Provides access to the Opus configuration
OpusEncoderSettings &config() { return enc.config(); }

protected:
OpusOggHeader header;
OpusOggCommentHeader comment;
OpusAudioEncoder enc;
EncodedAudioStream opus{(Print *)nullptr, &enc};
ogg_packet oh1;

bool writeHeader() override {
Expand Down
53 changes: 39 additions & 14 deletions src/AudioCodecs/ContainerOgg.h
Original file line number Diff line number Diff line change
Expand Up @@ -219,8 +219,9 @@ class OggContainerEncoder : public AudioEncoder {
p_print = &out_stream;
} else {
EncodedAudioStream* eas = new EncodedAudioStream();
eas->begin(&out_stream, p_codec);
p_print = eas;
eas->begin(&codec_buffer, p_codec);
p_encoded_audio_stream = eas;
p_print = &out_stream;
}
}

Expand All @@ -239,6 +240,7 @@ class OggContainerEncoder : public AudioEncoder {
virtual void begin() override {
LOGD(LOG_METHOD);
is_open = true;
codec_buffer.begin();
if (p_oggz == nullptr) {
p_oggz = oggz_new(OGGZ_WRITE | OGGZ_NONSTRICT | OGGZ_AUTO);
serialno = oggz_serialno_new(p_oggz);
Expand Down Expand Up @@ -269,22 +271,39 @@ class OggContainerEncoder : public AudioEncoder {
p_oggz = nullptr;
}

/// Writes Ogg Packet
/// Writes raw data to be encoded and packaged
virtual size_t write(const void *in_ptr, size_t in_size) override {
if (!is_open || p_print == nullptr) return 0;
LOGD("write: %d", (int) in_size);

op.packet = (uint8_t *)in_ptr;
op.bytes = in_size;
op.granulepos = granulepos +=
in_size / sizeof(int16_t) / cfg.channels; // sample
op.b_o_s = false;
op.e_o_s = false;
op.packetno = packetno++;
if (!writePacket(op, OGGZ_FLUSH_AFTER)) {
return 0;
}
if (p_codec!=nullptr){
// encode the data
size_t eff = p_encoded_audio_stream->write((uint8_t*)in_ptr, in_size);
if (eff!=in_size){
LOGE("Write overflow");
}
// get the result from the buffer
void *encoded_data = buffer.address();
int enoded_size = buffer.available();

op.packet = (uint8_t *)encoded_data;
op.bytes = enoded_size;
} else {
op.packet = (uint8_t *)in_ptr;
op.bytes = in_size;
}
if (op.bytes>0){
buffer.reset();
op.granulepos = granulepos +=
in_size / sizeof(int16_t) / cfg.channels; // sample
op.b_o_s = false;
op.e_o_s = false;
op.packetno = packetno++;
is_audio = true;
if (!writePacket(op, OGGZ_FLUSH_AFTER)) {
return 0;
}
}
// trigger pysical write
while ((oggz_write(p_oggz, in_size)) > 0)
;
Expand All @@ -297,8 +316,11 @@ class OggContainerEncoder : public AudioEncoder {
bool isOpen() { return is_open; }

protected:
AudioEncoder* p_codec = nullptr;
Print *p_print = nullptr;
Print *p_encoded_audio_stream = nullptr;
SingleBuffer<uint8_t> buffer{1024};
CallbackBufferedStream<uint8_t> codec_buffer{buffer};
AudioEncoder* p_codec = nullptr;
volatile bool is_open;
OGGZ *p_oggz = nullptr;
ogg_packet op;
Expand All @@ -307,6 +329,7 @@ class OggContainerEncoder : public AudioEncoder {
size_t packetno = 0;
long serialno = -1;
AudioBaseInfo cfg;
bool is_audio = false;

virtual bool writePacket(ogg_packet &op, int flag = 0) {
LOGD("writePacket: %d", (int) op.bytes);
Expand All @@ -326,6 +349,7 @@ class OggContainerEncoder : public AudioEncoder {
oh.packetno = packetno++;
oh.b_o_s = true;
oh.e_o_s = false;
is_audio = false;
return writePacket(oh);
}

Expand All @@ -337,6 +361,7 @@ class OggContainerEncoder : public AudioEncoder {
op.packetno = packetno++;
op.b_o_s = false;
op.e_o_s = true;
is_audio = false;
return writePacket(op, OGGZ_FLUSH_AFTER);
}

Expand Down
10 changes: 5 additions & 5 deletions src/AudioEffects/SoundGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ class NoiseGenerator : public SoundGenerator<T> {


/**
* @brief Provides 0 as sound data. This can be used e.g. to test the output functionality which should optimally just output
* @brief Provides a fixed value (e.g. 0) as sound data. This can be used e.g. to test the output functionality which should optimally just output
* silence and no artifacts.
* @author Phil Schatzmann
* @copyright GPLv3
Expand All @@ -303,17 +303,17 @@ template <class T>
class SilenceGenerator : public SoundGenerator<T> {
public:
// the scale defines the max value which is generated
SilenceGenerator(double scale=1.0) {
this->scale = scale;
SilenceGenerator(T value=0) {
this->value = value;
}

/// Provides a single sample
T readSample() {
return 0; // return 0
return value; // return 0
}

protected:
double scale;
T value;

};

Expand Down
6 changes: 5 additions & 1 deletion src/AudioTools/AudioStreams.h
Original file line number Diff line number Diff line change
Expand Up @@ -772,6 +772,10 @@ class CallbackBufferedStream : public AudioStreamX {
remove_oldest_data = autoRemoveOldestDataIfFull;
}

CallbackBufferedStream(BaseBuffer<T> &buffer){
callback_buffer_ptr = &buffer;
}

virtual ~CallbackBufferedStream() { delete callback_buffer_ptr; }

/// Activates the output
Expand Down Expand Up @@ -828,7 +832,7 @@ class CallbackBufferedStream : public AudioStreamX {
}

protected:
NBuffer<T> *callback_buffer_ptr;
BaseBuffer<T> *callback_buffer_ptr;
bool active;
bool remove_oldest_data;

Expand Down
17 changes: 5 additions & 12 deletions tests/codec/opusogg/opusogg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
#include "AudioCodecs/CodecOpusOgg.h"

int sample_rate = 24000;
int channels = 2; // The stream will have 2 channels
int channels = 1; // The stream will have 2 channels
int application = OPUS_APPLICATION_AUDIO; // Opus application

SineWaveGenerator<int16_t> sineWave( 32000); // subclass of SoundGenerator with max amplitude of 32000
Expand All @@ -21,22 +21,15 @@ CsvStream<int16_t> out(Serial, channels); // Output of sound on desktop
OpusOggEncoder enc;
OpusOggDecoder dec;
EncodedAudioStream decoder(out, dec); // encode and write
HexDumpStream hex(Serial);
EncodedAudioStream encoder(&hex, &enc); // encode and write
EncodedAudioStream encoder(&decoder, &enc); // encode and write
//EncodedAudioStream encoder(&decoder, &enc); // encode and write
StreamCopy copier(encoder, sound);

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);
AudioLogger::instance().begin(Serial, AudioLogger::Warning);



// Setup sine wave
auto cfgs = sineWave.defaultConfig();
Expand Down

0 comments on commit b644345

Please sign in to comment.