custom
jacqueline 2 years ago
parent 530fd15e66
commit aef2eb7566
  1. 121
      src/drivers/audio_playback.cpp
  2. 33
      src/drivers/i2s_audio_output.cpp
  3. 8
      src/drivers/include/a2dp_audio_output.hpp
  4. 25
      src/drivers/include/audio_output.hpp
  5. 12
      src/drivers/include/audio_playback.hpp
  6. 26
      src/drivers/include/i2s_audio_output.hpp
  7. 5
      src/main/main.cpp

@ -1,36 +1,30 @@
#include "audio_playback.hpp" #include "audio_playback.hpp"
#include "audio_output.hpp" #include "audio_output.hpp"
#include "dac.hpp"
#include <algorithm> #include <algorithm>
#include <cstdint> #include <cstdint>
#include <exception>
#include <memory> #include <memory>
#include <string_view> #include <string_view>
#include "audio_element.h" #include "audio_element.h"
#include "audio_event_iface.h" #include "audio_event_iface.h"
#include "audio_pipeline.h" #include "audio_pipeline.h"
#include "driver/i2s.h"
#include "esp_err.h" #include "esp_err.h"
#include "freertos/portmacro.h"
#include "aac_decoder.h"
#include "amr_decoder.h"
#include "flac_decoder.h"
#include "mp3_decoder.h" #include "mp3_decoder.h"
#include "ogg_decoder.h"
#include "opus_decoder.h"
#include "wav_decoder.h"
static const char* kTag = "PLAYBACK"; static const char* kTag = "PLAYBACK";
static const char* kSource = "src"; static const char* kSource = "src";
static const char* kEncoder = "enc"; static const char* kDecoder = "dec";
static const char* kSink = "sink"; static const char* kSink = "sink";
static bool endsWith(std::string_view str, std::string_view suffix) {
return str.size() >= suffix.size() && 0 == str.compare(str.size()-suffix.size(), suffix.size(), suffix);
}
static void toLower(std::string &str) {
std::transform(str.begin(), str.end(), str.begin(),
[](unsigned char c) { return std::tolower(c); });
}
namespace drivers { namespace drivers {
static audio_element_status_t status_from_the_void(void* status) { static audio_element_status_t status_from_the_void(void* status) {
@ -38,6 +32,16 @@ static audio_element_status_t status_from_the_void(void* status) {
return static_cast<audio_element_status_t>(as_pointer_int); return static_cast<audio_element_status_t>(as_pointer_int);
} }
static bool endsWith(std::string_view str, std::string_view suffix) {
return str.size() >= suffix.size() &&
0 == str.compare(str.size() - suffix.size(), suffix.size(), suffix);
}
static void toLower(std::string& str) {
std::transform(str.begin(), str.end(), str.begin(),
[](unsigned char c) { return std::tolower(c); });
}
auto AudioPlayback::create(std::unique_ptr<IAudioOutput> output) auto AudioPlayback::create(std::unique_ptr<IAudioOutput> output)
-> cpp::result<std::unique_ptr<AudioPlayback>, Error> { -> cpp::result<std::unique_ptr<AudioPlayback>, Error> {
audio_pipeline_handle_t pipeline; audio_pipeline_handle_t pipeline;
@ -67,18 +71,17 @@ auto AudioPlayback::create(std::unique_ptr<IAudioOutput> output)
audio_element_msg_set_listener(output->GetAudioElement(), event_interface); audio_element_msg_set_listener(output->GetAudioElement(), event_interface);
audio_pipeline_register(pipeline, fatfs_stream_reader, kSource); audio_pipeline_register(pipeline, fatfs_stream_reader, kSource);
audio_pipeline_register(pipeline, outut->GetAudioElement(), kSink); audio_pipeline_register(pipeline, output->GetAudioElement(), kSink);
return std::make_unique<AudioPlayback>(output, pipeline, fatfs_stream_reader, event_interface return std::make_unique<AudioPlayback>(output, pipeline, fatfs_stream_reader,
event_interface);
} }
AudioPlayback::AudioPlayback(std::unique_ptr<IAudioOutput> output, AudioPlayback::AudioPlayback(std::unique_ptr<IAudioOutput>& output,
audio_pipeline_handle_t pipeline, audio_pipeline_handle_t pipeline,
audio_element_handle_t source_element, audio_element_handle_t source_element,
audio_event_iface_handle_t event_interface, audio_event_iface_handle_t event_interface)
audio_element_handle_t mp3_decoder) : output_(std::move(output)),
: output_(std::move(outout)),
pipeline_(pipeline), pipeline_(pipeline),
source_element_(source_element), source_element_(source_element),
event_interface_(event_interface) {} event_interface_(event_interface) {}
@ -86,7 +89,8 @@ AudioPlayback::AudioPlayback(std::unique_ptr<IAudioOutput> output,
AudioPlayback::~AudioPlayback() { AudioPlayback::~AudioPlayback() {
audio_pipeline_remove_listener(pipeline_); audio_pipeline_remove_listener(pipeline_);
audio_element_msg_remove_listener(source_element_, event_interface_); audio_element_msg_remove_listener(source_element_, event_interface_);
audio_element_msg_remove_listener(output_->GetAudioElement(), event_interface_); audio_element_msg_remove_listener(output_->GetAudioElement(),
event_interface_);
audio_pipeline_stop(pipeline_); audio_pipeline_stop(pipeline_);
audio_pipeline_wait_for_stop(pipeline_); audio_pipeline_wait_for_stop(pipeline_);
@ -117,7 +121,7 @@ void AudioPlayback::Play(const std::string& filename) {
audio_pipeline_reset_ringbuffer(pipeline_); audio_pipeline_reset_ringbuffer(pipeline_);
audio_pipeline_reset_elements(pipeline_); audio_pipeline_reset_elements(pipeline_);
audio_pipeline_run(pipeline_); audio_pipeline_run(pipeline_);
dac_->WriteVolume(volume_); output_->SetVolume(volume_);
} }
void AudioPlayback::Resume() { void AudioPlayback::Resume() {
@ -143,8 +147,8 @@ void AudioPlayback::ProcessEvents(uint16_t max_time_ms) {
} }
while (1) { while (1) {
audio_event_iface_msg_t event; audio_event_iface_msg_t event;
esp_err_t err = esp_err_t err = audio_event_iface_listen(event_interface_, &event,
audio_event_iface_listen(event_interface_, &event, pdMS_TO_TICKS(max_time_ms)); pdMS_TO_TICKS(max_time_ms));
if (err != ESP_OK) { if (err != ESP_OK) {
ESP_LOGE(kTag, "error listening for event:%x", err); ESP_LOGE(kTag, "error listening for event:%x", err);
continue; continue;
@ -176,7 +180,7 @@ void AudioPlayback::ProcessEvents(uint16_t max_time_ms) {
if (next_filename_ != "") { if (next_filename_ != "") {
Decoder decoder = GetDecoderForFilename(next_filename_); Decoder decoder = GetDecoderForFilename(next_filename_);
if (decoder == decoder_type_) { if (decoder == decoder_type_) {
audio_element_set_uri(source_element_, next_filename_); audio_element_set_uri(source_element_, next_filename_.c_str());
audio_pipeline_reset_ringbuffer(pipeline_); audio_pipeline_reset_ringbuffer(pipeline_);
audio_pipeline_reset_elements(pipeline_); audio_pipeline_reset_elements(pipeline_);
audio_pipeline_change_state(pipeline_, AEL_STATE_INIT); audio_pipeline_change_state(pipeline_, AEL_STATE_INIT);
@ -221,7 +225,7 @@ auto AudioPlayback::GetDecoderForFilename(std::string filename) -> Decoder {
if (endsWith(filename, "mp3")) { if (endsWith(filename, "mp3")) {
return MP3; return MP3;
} }
if (endsWith(filename, "amr") || endsWith(filename, "wamr") { if (endsWith(filename, "amr") || endsWith(filename, "wamr")) {
return AMR; return AMR;
} }
if (endsWith(filename, "opus")) { if (endsWith(filename, "opus")) {
@ -236,38 +240,43 @@ auto AudioPlayback::GetDecoderForFilename(std::string filename) -> Decoder {
if (endsWith(filename, "wav")) { if (endsWith(filename, "wav")) {
return WAV; return WAV;
} }
if (endsWith(filename, "aac") || endsWith(filename, "m4a") || endsWith(filename, "ts") || endsWith(filename, "mp4")) { if (endsWith(filename, "aac") || endsWith(filename, "m4a") ||
endsWith(filename, "ts") || endsWith(filename, "mp4")) {
return AAC; return AAC;
} }
return NONE; return NONE;
} }
auto AudioPlayback::CreateDecoder(Decoder decoder) -> audio_element_handle_t { auto AudioPlayback::CreateDecoder(Decoder decoder) -> audio_element_handle_t {
switch (decoder) { if (decoder == MP3) {
case MP3: mp3_decoder_cfg_t config = DEFAULT_MP3_DECODER_CONFIG();
mp3_decoder_cfg_t config = DEFAULT_MP3_DECODER_CONFIG(); return mp3_decoder_init(&config);
return mp3_decoder_init(&config); }
case AMR: if (decoder == AMR) {
amr_decoder_cfg_t config = DEFAULT_AMR_DECODER_CONFIG(); amr_decoder_cfg_t config = DEFAULT_AMR_DECODER_CONFIG();
return amr_decoder_init(&config); return amr_decoder_init(&config);
case OPUS: }
opus_decoder_cfg_t config = DEFAULT_OPUS_DECODER_CONFIG(); if (decoder == OPUS) {
return decoder_opus_init(&config); opus_decoder_cfg_t config = DEFAULT_OPUS_DECODER_CONFIG();
case OGG: return decoder_opus_init(&config);
ogg_decoder_cfg_t config = DEFAULT_OGG_DECODER_CONFIG(); }
return ogg_decoder_init(&config); if (decoder == OGG) {
case FLAC: ogg_decoder_cfg_t config = DEFAULT_OGG_DECODER_CONFIG();
flac_decoder_cfg_t config = DEFAULT_FLAC_DECODER_CONFIG(); return ogg_decoder_init(&config);
return flac_decoder_init(&config); }
case WAV: if (decoder == FLAC) {
wav_decoder_cfg_t config = DEFAULT_WAV_DECODER_CONFIG(); flac_decoder_cfg_t config = DEFAULT_FLAC_DECODER_CONFIG();
return wav_decoder_init(&config); return flac_decoder_init(&config);
case AAC: }
aac_decoder_cfg_t aac_dec_cfg = DEFAULT_AAC_DECODER_CONFIG(); if (decoder == WAV) {
return aac_decoder_init(&aac_dec_cfg); wav_decoder_cfg_t config = DEFAULT_WAV_DECODER_CONFIG();
default: return wav_decoder_init(&config);
return nullptr; }
if (decoder == AAC) {
aac_decoder_cfg_t config = DEFAULT_AAC_DECODER_CONFIG();
return aac_decoder_init(&config);
} }
return nullptr;
} }
void AudioPlayback::ReconfigurePipeline(Decoder decoder) { void AudioPlayback::ReconfigurePipeline(Decoder decoder) {
@ -276,7 +285,7 @@ void AudioPlayback::ReconfigurePipeline(Decoder decoder) {
} }
if (decoder_type_ != NONE) { if (decoder_type_ != NONE) {
audio_pipeline_unlink(pipeline); audio_pipeline_unlink(pipeline_);
audio_element_msg_remove_listener(decoder_, event_interface_); audio_element_msg_remove_listener(decoder_, event_interface_);
audio_pipeline_unregister(pipeline_, decoder_); audio_pipeline_unregister(pipeline_, decoder_);
audio_element_deinit(decoder_); audio_element_deinit(decoder_);
@ -288,7 +297,7 @@ void AudioPlayback::ReconfigurePipeline(Decoder decoder) {
audio_pipeline_register(pipeline_, decoder_, kDecoder); audio_pipeline_register(pipeline_, decoder_, kDecoder);
audio_element_msg_set_listener(decoder_, event_interface_); audio_element_msg_set_listener(decoder_, event_interface_);
static const char* link_tag[3] = {kSource, kDecoder, kSink}; static const char* link_tag[3] = {kSource, kDecoder, kSink};
audio_pipeline_link(pipeline, &link_tag[0], 3); audio_pipeline_link(pipeline_, &link_tag[0], 3);
} }
} }

@ -1,19 +1,24 @@
#include "i2s_audio_output.hpp" #include "i2s_audio_output.hpp"
#include <algorithm> #include <algorithm>
#include "audio_output.hpp"
#include "gpio-expander.hpp" #include "audio_element.h"
#include "driver/i2s.h"
#include "esp_err.h"
#include "freertos/portmacro.h"
#include "i2s_stream.h"
static const i2s_port_t kI2SPort = I2S_NUM_0; static const i2s_port_t kI2SPort = I2S_NUM_0;
static const char* kTag = "I2SOUT";
namespace drivers { namespace drivers {
auto I2SAudioOutput::create(GpioExpander *expander) auto I2SAudioOutput::create(GpioExpander* expander)
-> cpp::result<std::unique_ptr<I2SAudioOutput>, Error> { -> cpp::result<std::unique_ptr<I2SAudioOutput>, Error> {
// First, we need to perform initial configuration of the DAC chip. // First, we need to perform initial configuration of the DAC chip.
auto dac_result = drivers::AudioDac::create(expander); auto dac_result = drivers::AudioDac::create(expander);
if (dac_result.has_error()) { if (dac_result.has_error()) {
ESP_LOGE(TAG, "failed to init dac: %d", dac_result.error()); ESP_LOGE(kTag, "failed to init dac: %d", dac_result.error());
return cpp::fail(DAC_CONFIG); return cpp::fail(DAC_CONFIG);
} }
std::unique_ptr<AudioDac> dac = std::move(dac_result.value()); std::unique_ptr<AudioDac> dac = std::move(dac_result.value());
@ -54,7 +59,8 @@ auto I2SAudioOutput::create(GpioExpander *expander)
.need_expand = false, .need_expand = false,
.expand_src_bits = I2S_BITS_PER_SAMPLE_16BIT, .expand_src_bits = I2S_BITS_PER_SAMPLE_16BIT,
}; };
i2s_stream_writer = i2s_stream_init(&i2s_stream_config); audio_element_handle_t i2s_stream_writer =
i2s_stream_init(&i2s_stream_config);
if (i2s_stream_writer == NULL) { if (i2s_stream_writer == NULL) {
return cpp::fail(Error::STREAM_INIT); return cpp::fail(Error::STREAM_INIT);
} }
@ -74,8 +80,10 @@ auto I2SAudioOutput::create(GpioExpander *expander)
return std::make_unique<I2SAudioOutput>(dac, i2s_stream_writer); return std::make_unique<I2SAudioOutput>(dac, i2s_stream_writer);
} }
I2SAudioOutput(std::unique<AudioDac> dac, audio_element_handle_t element) : IAudioOutput(element), dac_(dac) {} I2SAudioOutput::I2SAudioOutput(std::unique_ptr<AudioDac>& dac,
~I2SAudioOutput() { audio_element_handle_t element)
: IAudioOutput(element), dac_(std::move(dac)) {}
I2SAudioOutput::~I2SAudioOutput() {
// TODO: power down the DAC. // TODO: power down the DAC.
} }
@ -83,10 +91,9 @@ auto I2SAudioOutput::SetVolume(uint8_t volume) -> void {
dac_->WriteVolume(255); dac_->WriteVolume(255);
} }
auto I2SAudioOutput::Configure(audio_element_info_t info) -> void { auto I2SAudioOutput::Configure(audio_element_info_t& info) -> void {
audio_element_setinfo(element_, &music_info); audio_element_setinfo(element_, &info);
i2s_stream_set_clk(element_, music_info.sample_rates, i2s_stream_set_clk(element_, info.sample_rates, info.bits, info.channels);
music_info.bits, music_info.channels);
} }
} } // namespace drivers

@ -1,15 +1,15 @@
#pragma once #pragma once
#include <cstdint>
#include "audio_common.h" #include "audio_common.h"
#include "audio_element.h" #include "audio_element.h"
#include "audio_output.hpp" #include "audio_output.hpp"
#include <cstdint>
namespace drivers { namespace drivers {
class A2DPAudioOutput : IAudioOutput { class A2DPAudioOutput : IAudioOutput {
public: public:
virtual auto SetVolume(uint8_t volume) -> void; virtual auto SetVolume(uint8_t volume) -> void;
}; };
} // namespace drivers } // namespace drivers

@ -1,27 +1,24 @@
#pragma once #pragma once
#include <cstdint>
#include <memory>
#include "audio_common.h" #include "audio_common.h"
#include "audio_element.h" #include "audio_element.h"
#include <cstdint>
namespace drivers { namespace drivers {
class IAudioOutput { class IAudioOutput {
public: public:
IAudioOutput(audio_element_handle_t element) : element_(element) {} IAudioOutput(audio_element_handle_t element) : element_(element) {}
virtual ~IAudioOutput() { virtual ~IAudioOutput() { audio_element_deinit(element_); }
audio_element_deinit(element_);
}
auto GetAudioElement() -> audio_element_handle_t { auto GetAudioElement() -> audio_element_handle_t { return element_; }
return element_;
}
virtual auto SetVolume(uint8_t volume) -> void = 0; virtual auto SetVolume(uint8_t volume) -> void = 0;
virtual auto Configure(audio_element_info_t info) -> void = 0; virtual auto Configure(audio_element_info_t& info) -> void = 0;
protected: protected:
audio_element_handle_t element_; audio_element_handle_t element_;
}; };
} // namespace drivers } // namespace drivers

@ -32,10 +32,10 @@ class AudioPlayback {
static auto create(std::unique_ptr<IAudioOutput> output) static auto create(std::unique_ptr<IAudioOutput> output)
-> cpp::result<std::unique_ptr<AudioPlayback>, Error>; -> cpp::result<std::unique_ptr<AudioPlayback>, Error>;
AudioPlayback(std::unqiue_ptr<IAudioOutput> output, AudioPlayback(std::unique_ptr<IAudioOutput>& output,
audio_pipeline_handle_t pipeline, audio_pipeline_handle_t pipeline,
audio_element_handle_t source_element, audio_element_handle_t source_element,
audio_event_iface_handle_t event_interface); audio_event_iface_handle_t event_interface);
~AudioPlayback(); ~AudioPlayback();
/* /*
@ -77,10 +77,10 @@ class AudioPlayback {
private: private:
PlaybackState current_state_; PlaybackState current_state_;
enum Decoder {NONE, MP3, AMR, OPUS, OGG, FLAC, WAV, AAC}; enum Decoder { NONE, MP3, AMR, OPUS, OGG, FLAC, WAV, AAC };
auto GetDecoderForFilename(std::string filename) -> Decoder; auto GetDecoderForFilename(std::string filename) -> Decoder;
auto CreateDecoder(Decoder decoder) -> audio_element_handle_t; auto CreateDecoder(Decoder decoder) -> audio_element_handle_t;
void ReconfigurePipeline(); auto ReconfigurePipeline(Decoder decoder) -> void;
std::unique_ptr<IAudioOutput> output_; std::unique_ptr<IAudioOutput> output_;
std::mutex playback_lock_; std::mutex playback_lock_;

@ -1,30 +1,32 @@
#pragma once #pragma once
#include "audio_common.h"
#include "audio_element.h"
#include "audio_output.hpp" #include "audio_output.hpp"
#include "dac.hpp"
#include "gpio-expander.hpp" #include "gpio-expander.hpp"
#include "result.hpp"
#include <cstdint> #include <cstdint>
#include <memory> #include <memory>
#include "result.hpp"
#include "dac.hpp" #include "audio_element.h"
namespace drivers { namespace drivers {
class I2SAudioOutput : public IAudioOutput { class I2SAudioOutput : public IAudioOutput {
public: public:
enum Error { DAC_CONFIG, I2S_CONFIG, STREAM_INIT }; enum Error { DAC_CONFIG, I2S_CONFIG, STREAM_INIT };
static auto create(GpioExpander* expander) static auto create(GpioExpander* expander)
-> cpp::result<std::unique_ptr<I2SAudioOutput>, Error>; -> cpp::result<std::unique_ptr<I2SAudioOutput>, Error>;
I2SAudioOutput(AudioDac* dac, audio_element_handle_t element); I2SAudioOutput(std::unique_ptr<AudioDac>& dac,
audio_element_handle_t element);
~I2SAudioOutput(); ~I2SAudioOutput();
virtual auto SetVolume(uint8_t volume) -> void; virtual auto SetVolume(uint8_t volume) -> void;
virtual auto Configure(audio_element_info_t info) -> void; virtual auto Configure(audio_element_info_t& info) -> void;
private: private:
std::unique_ptr<AudioDac> dac_; std::unique_ptr<AudioDac> dac_;
}; };
} // namespace drivers } // namespace drivers

@ -11,7 +11,8 @@
#include "i2s_audio_output.hpp" #include "i2s_audio_output.hpp"
#include "misc/lv_color.h" #include "misc/lv_color.h"
#include "misc/lv_timer.h" #include "misc/lv_timer.h"
#include "playback.hpp" #include "audio_playback.hpp"
#include "i2s_audio_output.hpp"
#include "spi.hpp" #include "spi.hpp"
#include "storage.hpp" #include "storage.hpp"
@ -119,7 +120,7 @@ extern "C" void app_main(void) {
ESP_LOGE(TAG, "Failed: %d", sink_res.error()); ESP_LOGE(TAG, "Failed: %d", sink_res.error());
return; return;
} }
std::unique_ptr<drivers::AudioOutput> sink = std::move(sink_res.value()); std::unique_ptr<drivers::IAudioOutput> sink = std::move(sink_res.value());
ESP_LOGI(TAG, "Init Audio Pipeline"); ESP_LOGI(TAG, "Init Audio Pipeline");
auto playback_res = drivers::AudioPlayback::create(std::move(sink)); auto playback_res = drivers::AudioPlayback::create(std::move(sink));

Loading…
Cancel
Save