Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion esphome/components/adf_pipeline/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ async def setup_pipeline_controller(cntrl, config: dict) -> None:
@coroutine_with_priority(55.0)
async def to_code(config):
cg.add_define("USE_ESP_ADF_VAD")

cg.add_platformio_option("build_unflags", "-Wl,--end-group")

cg.add_platformio_option(
Expand Down
17 changes: 11 additions & 6 deletions esphome/components/adf_pipeline/adf_audio_element.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,14 @@ typedef struct {
int channels;
} pcm_format;


enum class PipelineElementState : uint8_t { UNINITIALIZED = 0, INITIALIZED, PREPARE, PREPARING, WAIT_FOR_PREPARATION_DONE, READY };
enum class PipelineElementState : uint8_t {
UNINITIALIZED = 0,
INITIALIZED,
PREPARE,
PREPARING,
WAIT_FOR_PREPARATION_DONE,
READY
};

class ADFPipeline;
class ADFPipelineElement;
Expand Down Expand Up @@ -60,16 +66,15 @@ class ADFPipelineElement {
virtual void on_pipeline_status_change() {}
virtual void on_settings_request(AudioPipelineSettingsRequest &request) {}


std::vector<audio_element_handle_t> get_adf_elements() { return sdk_audio_elements_; }
std::string get_adf_element_tag(int element_indx);
bool init_adf_elements() { return init_adf_elements_(); }
void destroy_adf_elements() {clear_adf_elements_();}
void destroy_adf_elements() { clear_adf_elements_(); }
virtual void prepare_elements() {}

void set_pipeline(ADFPipeline *pipeline) { pipeline_ = pipeline; }
virtual bool is_ready() {return true;}
virtual bool requires_destruction_on_stop(){ return false; }
virtual bool is_ready() { return true; }
virtual bool requires_destruction_on_stop() { return false; }

protected:
friend class ADFPipeline;
Expand Down
56 changes: 26 additions & 30 deletions esphome/components/adf_pipeline/adf_audio_process.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#include "adf_audio_process.h"


#ifdef USE_ESP_IDF
#include "adf_pipeline.h"

Expand All @@ -12,17 +11,17 @@ namespace esp_adf {
static const char *const TAG = "esp_audio_processors";

typedef struct rsp_filter {
resample_info_t *resample_info;
unsigned char *out_buf;
unsigned char *in_buf;
void *rsp_hd;
int in_offset;
int8_t flag; //the flag must be 0 or 1. 1 means the parameter in `resample_info_t` changed. 0 means the parameter in `resample_info_t` is original.
resample_info_t *resample_info;
unsigned char *out_buf;
unsigned char *in_buf;
void *rsp_hd;
int in_offset;
int8_t flag; // the flag must be 0 or 1. 1 means the parameter in `resample_info_t` changed. 0 means the parameter in
// `resample_info_t` is original.
} rsp_filter_t;


bool ADFResampler::init_adf_elements_(){
rsp_filter_cfg_t rsp_cfg = {
bool ADFResampler::init_adf_elements_() {
rsp_filter_cfg_t rsp_cfg = {
.src_rate = this->src_rate_,
.src_ch = this->src_num_channels_,
.dest_rate = this->dst_rate_,
Expand All @@ -42,51 +41,48 @@ bool ADFResampler::init_adf_elements_(){
.task_prio = RSP_FILTER_TASK_PRIO,
.stack_in_ext = true,
};
this->sdk_resampler_= rsp_filter_init(&rsp_cfg);
this->sdk_resampler_ = rsp_filter_init(&rsp_cfg);
sdk_audio_elements_.push_back(this->sdk_resampler_);
sdk_element_tags_.push_back("resampler");
return true;
}

void ADFResampler::on_settings_request(AudioPipelineSettingsRequest &request){
void ADFResampler::on_settings_request(AudioPipelineSettingsRequest &request) {
bool settings_changed = false;
if( request.sampling_rate > -1 ){
if( request.sampling_rate != this->src_rate_ )
{
if (request.sampling_rate > -1) {
if (request.sampling_rate != this->src_rate_) {
this->src_rate_ = request.sampling_rate;
settings_changed = true;
}
uint32_t dst_rate = request.final_sampling_rate > -1 ? request.final_sampling_rate : this->src_rate_;
if( dst_rate != this->dst_rate_ )
{
if (dst_rate != this->dst_rate_) {
this->dst_rate_ = dst_rate;
settings_changed = true;
}
}
if( request.number_of_channels > -1 ){
if( request.number_of_channels != this->src_num_channels_ )
{
if (request.number_of_channels > -1) {
if (request.number_of_channels != this->src_num_channels_) {
this->src_num_channels_ = request.number_of_channels;
settings_changed = true;
}
uint32_t dst_num_channels = request.final_number_of_channels > -1 ? request.final_number_of_channels : this->src_num_channels_;
if( dst_num_channels != this->dst_num_channels_ )
{
uint32_t dst_num_channels =
request.final_number_of_channels > -1 ? request.final_number_of_channels : this->src_num_channels_;
if (dst_num_channels != this->dst_num_channels_) {
this->dst_num_channels_ = dst_num_channels;
settings_changed = true;
}
}
esph_log_d(TAG, "New settings: SRC: rate: %d, ch: %d DST: rate: %d, ch: %d ", this->src_rate_,this->src_num_channels_, this->dst_rate_, this->dst_num_channels_);
esph_log_d(TAG, "New settings: SRC: rate: %d, ch: %d DST: rate: %d, ch: %d ", this->src_rate_,
this->src_num_channels_, this->dst_rate_, this->dst_num_channels_);

if( this->sdk_resampler_ && settings_changed)
{
if( audio_element_get_state(this->sdk_resampler_) == AEL_STATE_RUNNING)
{
if (this->sdk_resampler_ && settings_changed) {
if (audio_element_get_state(this->sdk_resampler_) == AEL_STATE_RUNNING) {
audio_element_stop(this->sdk_resampler_);
audio_element_wait_for_stop(this->sdk_resampler_);
}
esph_log_d(TAG, "New settings: SRC: rate: %d, ch: %d DST: rate: %d, ch: %d ", this->src_rate_, this->src_num_channels_, this->dst_rate_, this->dst_num_channels_);
rsp_filter_t *filter = (rsp_filter_t *)audio_element_getdata(this->sdk_resampler_);
esph_log_d(TAG, "New settings: SRC: rate: %d, ch: %d DST: rate: %d, ch: %d ", this->src_rate_,
this->src_num_channels_, this->dst_rate_, this->dst_num_channels_);
rsp_filter_t *filter = (rsp_filter_t *) audio_element_getdata(this->sdk_resampler_);
resample_info_t &resample_info = *(filter->resample_info);
resample_info.src_rate = this->src_rate_;
resample_info.dest_rate = this->dst_rate_;
Expand Down
2 changes: 1 addition & 1 deletion esphome/components/adf_pipeline/adf_audio_process.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class ADFResampler : public ADFPipelineProcessElement {

protected:
bool init_adf_elements_() override;
//void clear_adf_elements_() override;
// void clear_adf_elements_() override;
void on_settings_request(AudioPipelineSettingsRequest &request) override;

int src_rate_{16000};
Expand Down
19 changes: 8 additions & 11 deletions esphome/components/adf_pipeline/adf_audio_sinks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ namespace esp_adf {
static const char *const TAG = "esp_audio_sinks";

bool PCMSink::init_adf_elements_() {
if ( this->sdk_audio_elements_.size() ){
if (this->sdk_audio_elements_.size()) {
esph_log_e(TAG, "Called init, but elements already created.");
return true;
}
assert( this->adf_raw_stream_reader_ == nullptr );
assert(this->adf_raw_stream_reader_ == nullptr);

raw_stream_cfg_t raw_cfg = {
.type = AUDIO_STREAM_READER,
Expand All @@ -29,8 +29,8 @@ bool PCMSink::init_adf_elements_() {
return true;
}

void PCMSink::clear_adf_elements_(){
//make sure that audio_element_deinit was called before for freeing allocated memory
void PCMSink::clear_adf_elements_() {
// make sure that audio_element_deinit was called before for freeing allocated memory
this->adf_raw_stream_reader_ = nullptr;
this->sdk_audio_elements_.clear();
this->sdk_element_tags_.clear();
Expand All @@ -47,13 +47,11 @@ int PCMSink::stream_read_bytes(char *buffer, int len) {
}

void PCMSink::on_settings_request(AudioPipelineSettingsRequest &request) {
if (request.bit_depth > 0 && (uint8_t) request.bit_depth != this->bits_per_sample_ ){
if ( request.bit_depth == 16 || request.bit_depth == 24 || request.bit_depth == 32 )
{
esph_log_d(TAG, "Set bitdepth to %d", request.bit_depth );
if (request.bit_depth > 0 && (uint8_t) request.bit_depth != this->bits_per_sample_) {
if (request.bit_depth == 16 || request.bit_depth == 24 || request.bit_depth == 32) {
esph_log_d(TAG, "Set bitdepth to %d", request.bit_depth);
this->bits_per_sample_ = request.bit_depth;
}
else {
} else {
request.failed = true;
request.failed_by = this;
}
Expand All @@ -66,7 +64,6 @@ void PCMSink::on_settings_request(AudioPipelineSettingsRequest &request) {
}
}


} // namespace esp_adf
} // namespace esphome

Expand Down
55 changes: 22 additions & 33 deletions esphome/components/adf_pipeline/adf_audio_sources.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ static const char *const TAG = "esp_audio_sources";
HTTPStreamReaderAndDecoder
*/


bool HTTPStreamReaderAndDecoder::init_adf_elements_() {
if (sdk_audio_elements_.size() > 0)
return true;
Expand All @@ -26,7 +25,7 @@ bool HTTPStreamReaderAndDecoder::init_adf_elements_() {
http_cfg.task_core = 0;
http_cfg.out_rb_size = 4 * 1024;
http_stream_reader_ = http_stream_init(&http_cfg);
http_stream_reader_->buf_size = 1024;
http_stream_reader_->buf_size = 1024;
audio_element_set_uri(this->http_stream_reader_, this->current_url_.c_str());

sdk_audio_elements_.push_back(this->http_stream_reader_);
Expand All @@ -43,27 +42,21 @@ bool HTTPStreamReaderAndDecoder::init_adf_elements_() {
}

void HTTPStreamReaderAndDecoder::clear_adf_elements_() {
//make sure that deinit of pipeline was called first
// make sure that deinit of pipeline was called first
this->sdk_audio_elements_.clear();
this->sdk_element_tags_.clear();
this->element_state_ = PipelineElementState::UNINITIALIZED;
}

void HTTPStreamReaderAndDecoder::reset_() {
this->element_state_ = PipelineElementState::INITIALIZED;
}
void HTTPStreamReaderAndDecoder::reset_() { this->element_state_ = PipelineElementState::INITIALIZED; }

void HTTPStreamReaderAndDecoder::set_stream_uri(const std::string& new_url) {
this->current_url_ = new_url;
}
void HTTPStreamReaderAndDecoder::set_stream_uri(const std::string &new_url) { this->current_url_ = new_url; }

void HTTPStreamReaderAndDecoder::prepare_elements(){
this->element_state_ = PipelineElementState::PREPARE;
}
void HTTPStreamReaderAndDecoder::prepare_elements() { this->element_state_ = PipelineElementState::PREPARE; }

// called while pipeline is in PREPARING state
bool HTTPStreamReaderAndDecoder::is_ready(){
switch(this->element_state_){
bool HTTPStreamReaderAndDecoder::is_ready() {
switch (this->element_state_) {
case PipelineElementState::READY:
return true;
case PipelineElementState::PREPARE:
Expand All @@ -79,35 +72,33 @@ bool HTTPStreamReaderAndDecoder::is_ready(){
}

// Start pipeline elements necessary for receiving audio settings from stream
void HTTPStreamReaderAndDecoder::start_prepare_pipeline_(){
if( audio_element_run(this->http_stream_reader_) != ESP_OK )
{
void HTTPStreamReaderAndDecoder::start_prepare_pipeline_() {
if (audio_element_run(this->http_stream_reader_) != ESP_OK) {
esph_log_e(TAG, "Starting http streamer failed");
}
if( audio_element_run(this->decoder_) != ESP_OK ){
if (audio_element_run(this->decoder_) != ESP_OK) {
esph_log_e(TAG, "Starting decoder streamer failed");
}
if( audio_element_resume(this->http_stream_reader_, 0, 2000 / portTICK_RATE_MS) != ESP_OK)
{
if (audio_element_resume(this->http_stream_reader_, 0, 2000 / portTICK_RATE_MS) != ESP_OK) {
esph_log_e(TAG, "Resuming http streamer failed");
}
if( audio_element_resume(this->decoder_, 0, 2000 / portTICK_RATE_MS) != ESP_OK ){
if (audio_element_resume(this->decoder_, 0, 2000 / portTICK_RATE_MS) != ESP_OK) {
esph_log_e(TAG, "Resuming decoder failed");
}
esph_log_d(TAG, "Streamer status: %d", audio_element_get_state(this->http_stream_reader_) );
esph_log_d(TAG, "decoder status: %d", audio_element_get_state(this->decoder_) );
esph_log_d(TAG, "Streamer status: %d", audio_element_get_state(this->http_stream_reader_));
esph_log_d(TAG, "decoder status: %d", audio_element_get_state(this->decoder_));
}

void HTTPStreamReaderAndDecoder::terminate_prepare_pipeline_(){
void HTTPStreamReaderAndDecoder::terminate_prepare_pipeline_() {
audio_element_stop(this->http_stream_reader_);
audio_element_stop(this->decoder_);
this->element_state_ = PipelineElementState::WAIT_FOR_PREPARATION_DONE;
}

bool HTTPStreamReaderAndDecoder::set_ready_when_prepare_pipeline_stopped_(){
bool HTTPStreamReaderAndDecoder::set_ready_when_prepare_pipeline_stopped_() {
bool stopped = audio_element_wait_for_stop_ms(this->http_stream_reader_, 0) == ESP_OK;
stopped = stopped && audio_element_wait_for_stop_ms(this->decoder_, 0) == ESP_OK;
if( stopped ){
stopped = stopped && audio_element_wait_for_stop_ms(this->decoder_, 0) == ESP_OK;
if (stopped) {
audio_element_reset_state(this->http_stream_reader_);
audio_element_reset_state(this->decoder_);
audio_element_reset_input_ringbuf(this->decoder_);
Expand All @@ -117,7 +108,7 @@ bool HTTPStreamReaderAndDecoder::set_ready_when_prepare_pipeline_stopped_(){
return stopped;
}

//wait for audio information in stream and send new audio settings to pipeline
// wait for audio information in stream and send new audio settings to pipeline
void HTTPStreamReaderAndDecoder::sdk_event_handler_(audio_event_iface_msg_t &msg) {
audio_element_handle_t mp3_decoder = this->decoder_;
if (msg.source_type == AUDIO_ELEMENT_TYPE_ELEMENT && msg.source == (void *) mp3_decoder &&
Expand All @@ -138,8 +129,7 @@ void HTTPStreamReaderAndDecoder::sdk_event_handler_(audio_event_iface_msg_t &msg
}

// necessary audio information has been received, terminate preparation pipeline
if( this->element_state_ == PipelineElementState::PREPARING )
{
if (this->element_state_ == PipelineElementState::PREPARING) {
this->terminate_prepare_pipeline_();
}
}
Expand All @@ -162,8 +152,8 @@ bool PCMSource::init_adf_elements_() {
return true;
}

//int PCMSource::stream_write(char *buffer, int len) { return len ? raw_stream_write(adf_raw_stream_writer_, buffer, len) : 0; }

// int PCMSource::stream_write(char *buffer, int len) { return len ? raw_stream_write(adf_raw_stream_writer_, buffer,
// len) : 0; }

int PCMSource::stream_write(char *buffer, int len) {
int ret = audio_element_output(this->adf_raw_stream_writer_, buffer, len);
Expand All @@ -175,7 +165,6 @@ int PCMSource::stream_write(char *buffer, int len) {
return ret;
}


bool PCMSource::has_buffered_data() const {
ringbuf_handle_t rb = audio_element_get_output_ringbuf(adf_raw_stream_writer_);
return rb_bytes_filled(rb) > 0;
Expand Down
4 changes: 1 addition & 3 deletions esphome/components/adf_pipeline/adf_audio_sources.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class ADFPipelineSourceElement : public ADFPipelineElement {

class HTTPStreamReaderAndDecoder : public ADFPipelineSourceElement {
public:
void set_stream_uri(const std::string& new_url);
void set_stream_uri(const std::string &new_url);
const std::string get_name() override { return "HTTPStreamReader"; }
bool is_ready() override;
void prepare_elements() override;
Expand All @@ -30,14 +30,12 @@ class HTTPStreamReaderAndDecoder : public ADFPipelineSourceElement {
void sdk_event_handler_(audio_event_iface_msg_t &msg);
void cfg_event_handler_(audio_event_iface_msg_t &msg);


PipelineElementState element_state_{PipelineElementState::UNINITIALIZED};
std::string current_url_{"https://dl.espressif.com/dl/audio/ff-16b-2c-44100hz.mp3"};
audio_element_handle_t http_stream_reader_{};
audio_element_handle_t decoder_{};
};


class PCMSource : public ADFPipelineSourceElement {
public:
const std::string get_name() override { return "PCMSource"; }
Expand Down
Loading