Skip to content
Merged
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
3 changes: 1 addition & 2 deletions components/esp-box/include/esp-box.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -521,11 +521,10 @@ class EspBox : public BaseComponent {
std::unique_ptr<espp::Task> audio_task_{nullptr};
// i2s / low-level audio
i2s_chan_handle_t audio_tx_handle{nullptr};
i2s_chan_handle_t audio_rx_handle{nullptr};
std::vector<uint8_t> audio_tx_buffer;
StreamBufferHandle_t audio_tx_stream;
i2s_std_config_t audio_std_cfg;
i2s_event_callbacks_t audio_tx_callbacks_;
std::atomic<bool> has_sound{false};

// IMU
std::shared_ptr<Imu> imu_;
Expand Down
80 changes: 22 additions & 58 deletions components/esp-box/src/audio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,6 @@ using namespace espp;
// Audio Functions //
////////////////////////

static TaskHandle_t play_audio_task_handle_ = NULL;

static bool IRAM_ATTR audio_tx_sent_callback(i2s_chan_handle_t handle, i2s_event_data_t *event,
void *user_ctx) {
// notify the main task that we're done
vTaskNotifyGiveFromISR(play_audio_task_handle_, NULL);
return true;
}

bool EspBox::initialize_codec() {
logger_.info("initializing codec");

Expand All @@ -27,15 +18,15 @@ bool EspBox::initialize_codec() {
audio_hal_codec_config_t cfg;
memset(&cfg, 0, sizeof(cfg));
cfg.codec_mode = AUDIO_HAL_CODEC_MODE_DECODE;
cfg.dac_output = AUDIO_HAL_DAC_OUTPUT_LINE1;
cfg.dac_output = AUDIO_HAL_DAC_OUTPUT_ALL; // Enable both L and R outputs
cfg.i2s_iface.bits = AUDIO_HAL_BIT_LENGTH_16BITS;
cfg.i2s_iface.fmt = AUDIO_HAL_I2S_NORMAL;
cfg.i2s_iface.mode = AUDIO_HAL_MODE_SLAVE;
cfg.i2s_iface.samples = AUDIO_HAL_16K_SAMPLES;
cfg.i2s_iface.samples = AUDIO_HAL_48K_SAMPLES;

ret_val |= es8311_codec_init(&cfg);
ret_val |= es8311_set_bits_per_sample(cfg.i2s_iface.bits);
ret_val |= es8311_config_fmt((es_i2s_fmt_t)cfg.i2s_iface.fmt);
ret_val |= es8311_config_fmt(ES_I2S_NORMAL);
ret_val |= es8311_set_bits_per_sample(AUDIO_HAL_BIT_LENGTH_16BITS);
ret_val |= es8311_codec_set_voice_volume(volume_);
ret_val |= es8311_codec_ctrl_state(cfg.codec_mode, AUDIO_HAL_CTRL_START);

Expand All @@ -51,45 +42,25 @@ bool EspBox::initialize_codec() {
bool EspBox::initialize_i2s(uint32_t default_audio_rate) {
logger_.info("initializing i2s driver");
logger_.debug("Using newer I2S standard");
i2s_chan_config_t chan_cfg = {
.id = i2s_port,
.role = I2S_ROLE_MASTER,
.dma_desc_num = 16, // TODO: calculate form audio rate
.dma_frame_num = 48, // TODO: calculate from audio rate
.auto_clear = true,
.auto_clear_before_cb = false,
.allow_pd = false,
.intr_priority = 0,
};

ESP_ERROR_CHECK(i2s_new_channel(&chan_cfg, &audio_tx_handle, nullptr));
i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(i2s_port, I2S_ROLE_MASTER);
chan_cfg.auto_clear = true; // Auto clear the legacy data in the DMA buffer
// chan_cfg.dma_desc_num = 16;
// chan_cfg.dma_frame_num = 48;
ESP_ERROR_CHECK(i2s_new_channel(&chan_cfg, &audio_tx_handle, &audio_rx_handle));

audio_std_cfg = {
.clk_cfg =
{
.sample_rate_hz = default_audio_rate,
.clk_src = I2S_CLK_SRC_DEFAULT,
.ext_clk_freq_hz = 0,
.mclk_multiple = I2S_MCLK_MULTIPLE_256,
},
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(default_audio_rate),
.slot_cfg =
I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO),
.gpio_cfg =
{
.mclk = i2s_mck_io,
.bclk = i2s_bck_io,
.ws = i2s_ws_io,
.dout = i2s_do_io,
.din = i2s_di_io,
.invert_flags =
{
.mclk_inv = false,
.bclk_inv = false,
.ws_inv = false,
},
},
.gpio_cfg = {.mclk = i2s_mck_io,
.bclk = i2s_bck_io,
.ws = i2s_ws_io,
.dout = i2s_do_io,
.din = i2s_di_io,
.invert_flags = {.mclk_inv = false, .bclk_inv = false, .ws_inv = false}},
};
audio_std_cfg.clk_cfg.mclk_multiple = I2S_MCLK_MULTIPLE_256;
// audio_std_cfg.clk_cfg.mclk_multiple = I2S_MCLK_MULTIPLE_256;

ESP_ERROR_CHECK(i2s_channel_init_std_mode(audio_tx_handle, &audio_std_cfg));

Expand All @@ -98,12 +69,6 @@ bool EspBox::initialize_i2s(uint32_t default_audio_rate) {

audio_tx_stream = xStreamBufferCreate(buffer_size * 4, 0);

play_audio_task_handle_ = xTaskGetCurrentTaskHandle();

memset(&audio_tx_callbacks_, 0, sizeof(audio_tx_callbacks_));
audio_tx_callbacks_.on_sent = audio_tx_sent_callback;
i2s_channel_register_event_callback(audio_tx_handle, &audio_tx_callbacks_, NULL);

xStreamBufferReset(audio_tx_stream);

ESP_ERROR_CHECK(i2s_channel_enable(audio_tx_handle));
Expand Down Expand Up @@ -155,7 +120,7 @@ bool EspBox::audio_task_callback(std::mutex &m, std::condition_variable &cv, boo
i2s_channel_write(audio_tx_handle, buffer, buffer_size, NULL, portMAX_DELAY);
} else {
xStreamBufferReceive(audio_tx_stream, buffer, available, 0);
i2s_channel_write(audio_tx_handle, buffer, available, NULL, portMAX_DELAY);
i2s_channel_write(audio_tx_handle, buffer, buffer_size, NULL, portMAX_DELAY);
}
return false; // don't stop the task
}
Expand Down Expand Up @@ -194,6 +159,10 @@ void EspBox::audio_sample_rate(uint32_t sample_rate) {
// stop the channel
i2s_channel_disable(audio_tx_handle);
// update the sample rate
auto err = es8311_codec_set_sample_rate(sample_rate);
if (err != ESP_OK) {
logger_.error("Could not set codec sample rate: {}", err);
}
audio_std_cfg.clk_cfg.sample_rate_hz = sample_rate;
i2s_channel_reconfig_std_clock(audio_tx_handle, &audio_std_cfg.clk_cfg);
// clear the buffer
Expand All @@ -205,11 +174,6 @@ void EspBox::audio_sample_rate(uint32_t sample_rate) {
void EspBox::play_audio(const std::vector<uint8_t> &data) { play_audio(data.data(), data.size()); }

void EspBox::play_audio(const uint8_t *data, uint32_t num_bytes) {
play_audio_task_handle_ = xTaskGetCurrentTaskHandle();
if (has_sound) {
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
}
// don't block here
xStreamBufferSendFromISR(audio_tx_stream, data, num_bytes, NULL);
has_sound = true;
}