Re-enable the parts of the audio pipeline that are working
This commit is contained in:
@@ -43,9 +43,11 @@ auto AudioPlayback::create(drivers::GpioExpander* expander,
|
||||
playback->ConnectElements(codec.get(), sink.get());
|
||||
|
||||
// Launch!
|
||||
/*
|
||||
playback->element_handles_.push_back(StartAudioTask("src", source));
|
||||
playback->element_handles_.push_back(StartAudioTask("dec", codec));
|
||||
playback->element_handles_.push_back(StartAudioTask("sink", sink));
|
||||
*/
|
||||
|
||||
return playback;
|
||||
}
|
||||
|
||||
@@ -106,6 +106,8 @@ auto FatfsAudioInput::ProcessIdle() -> cpp::result<void, AudioProcessingError> {
|
||||
read_size = file_buffer_.begin() - file_buffer_write_pos_;
|
||||
}
|
||||
|
||||
ESP_LOGI(kTag, "reading up to %d bytes", (int) read_size);
|
||||
|
||||
UINT bytes_read = 0;
|
||||
FRESULT result =
|
||||
f_read(¤t_file_, std::addressof(file_buffer_write_pos_),
|
||||
@@ -115,6 +117,8 @@ auto FatfsAudioInput::ProcessIdle() -> cpp::result<void, AudioProcessingError> {
|
||||
return cpp::fail(IO_ERROR);
|
||||
}
|
||||
|
||||
ESP_LOGI(kTag, "actual read size %d bytes", (int) bytes_read);
|
||||
|
||||
if (f_eof(¤t_file_)) {
|
||||
f_close(¤t_file_);
|
||||
is_file_open_ = false;
|
||||
@@ -130,7 +134,8 @@ auto FatfsAudioInput::ProcessIdle() -> cpp::result<void, AudioProcessingError> {
|
||||
}
|
||||
|
||||
// Now stream data into the output buffer until it's full.
|
||||
while (1) {
|
||||
while (GetRingBufferDistance() > 0) {
|
||||
ESP_LOGI(kTag, "writing up to %d bytes", (int) GetRingBufferDistance());
|
||||
ChunkWriteResult result = chunk_writer_->WriteChunkToStream(
|
||||
[&](cpp::span<std::byte> d) { return SendChunk(d); }, kServiceInterval);
|
||||
|
||||
@@ -146,6 +151,8 @@ auto FatfsAudioInput::ProcessIdle() -> cpp::result<void, AudioProcessingError> {
|
||||
return cpp::fail(IO_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
auto FatfsAudioInput::SendChunk(cpp::span<std::byte> dest) -> size_t {
|
||||
|
||||
+47
-36
@@ -4,9 +4,9 @@
|
||||
|
||||
#include "assert.h"
|
||||
#include "driver/i2c.h"
|
||||
#include "driver/i2s.h"
|
||||
#include "driver/i2s_common.h"
|
||||
#include "driver/i2s_std.h"
|
||||
#include "driver/i2s_types.h"
|
||||
#include "driver/i2s_types_legacy.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "hal/i2c_types.h"
|
||||
@@ -28,45 +28,43 @@ static const AudioDac::BitsPerSample kDefaultBps = AudioDac::BPS_16;
|
||||
|
||||
auto AudioDac::create(GpioExpander* expander)
|
||||
-> cpp::result<std::unique_ptr<AudioDac>, Error> {
|
||||
|
||||
// TODO: tune.
|
||||
i2s_chan_handle_t i2s_handle;
|
||||
i2s_chan_config_t channel_config = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_MASTER);
|
||||
i2s_new_channel(&channel_config, &i2s_handle, NULL);
|
||||
//
|
||||
// First, instantiate the instance so it can do all of its power on
|
||||
// configuration.
|
||||
std::unique_ptr<AudioDac> dac = std::make_unique<AudioDac>(expander);
|
||||
std::unique_ptr<AudioDac> dac = std::make_unique<AudioDac>(expander, i2s_handle);
|
||||
|
||||
// Whilst we wait for the initial boot, we can work on installing the I2S
|
||||
// driver.
|
||||
i2s_config_t i2s_config = {
|
||||
// static_cast bc esp-adf uses enums incorrectly
|
||||
.mode = static_cast<i2s_mode_t>(I2S_MODE_MASTER | I2S_MODE_TX),
|
||||
.sample_rate = 44100,
|
||||
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
|
||||
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
|
||||
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
|
||||
.intr_alloc_flags = ESP_INTR_FLAG_LOWMED,
|
||||
// TODO(jacqueline): tune dma buffer size. this seems very smol.
|
||||
.dma_buf_count = 8,
|
||||
.dma_buf_len = 64,
|
||||
.use_apll = false,
|
||||
.tx_desc_auto_clear = false,
|
||||
.fixed_mclk = 0,
|
||||
.mclk_multiple = I2S_MCLK_MULTIPLE_512, // TODO: double check
|
||||
.bits_per_chan = I2S_BITS_PER_CHAN_DEFAULT,
|
||||
i2s_std_config_t i2s_config = {
|
||||
.clk_cfg = dac->clock_config_,
|
||||
.slot_cfg = dac->slot_config_,
|
||||
.gpio_cfg = {
|
||||
.mclk = GPIO_NUM_0,
|
||||
.bclk = GPIO_NUM_26,
|
||||
.ws = GPIO_NUM_27,
|
||||
.dout = GPIO_NUM_5,
|
||||
.din = I2S_GPIO_UNUSED,
|
||||
.invert_flags = {
|
||||
.mclk_inv = false,
|
||||
.bclk_inv = false,
|
||||
.ws_inv = false,
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
if (esp_err_t err =
|
||||
i2s_driver_install(kI2SPort, &i2s_config, 0, NULL) != ESP_OK) {
|
||||
ESP_LOGE(kTag, "failed to configure i2s pins %x", err);
|
||||
if (esp_err_t err = i2s_channel_init_std_mode(i2s_handle, &i2s_config) != ESP_OK) {
|
||||
ESP_LOGE(kTag, "failed to initialise i2s channel %x", err);
|
||||
return cpp::fail(Error::FAILED_TO_INSTALL_I2S);
|
||||
}
|
||||
|
||||
i2s_pin_config_t pin_config = {.mck_io_num = GPIO_NUM_0,
|
||||
.bck_io_num = GPIO_NUM_26,
|
||||
.ws_io_num = GPIO_NUM_27,
|
||||
.data_out_num = GPIO_NUM_5,
|
||||
.data_in_num = I2S_PIN_NO_CHANGE};
|
||||
if (esp_err_t err = i2s_set_pin(kI2SPort, &pin_config) != ESP_OK) {
|
||||
ESP_LOGE(kTag, "failed to configure i2s pins %x", err);
|
||||
return cpp::fail(Error::FAILED_TO_INSTALL_I2S);
|
||||
}
|
||||
// TODO: does starting the channel mean the dac will boot into a more
|
||||
// meaningful state?
|
||||
i2s_channel_enable(dac->i2s_handle_);
|
||||
|
||||
// Now let's double check that the DAC itself came up whilst we we working.
|
||||
bool is_booted = dac->WaitForPowerState(
|
||||
@@ -92,13 +90,17 @@ auto AudioDac::create(GpioExpander* expander)
|
||||
return dac;
|
||||
}
|
||||
|
||||
AudioDac::AudioDac(GpioExpander* gpio) : gpio_(gpio) {
|
||||
AudioDac::AudioDac(GpioExpander* gpio, i2s_chan_handle_t i2s_handle) : gpio_(gpio),
|
||||
i2s_handle_(i2s_handle),
|
||||
clock_config_(I2S_STD_CLK_DEFAULT_CONFIG(48000)),
|
||||
slot_config_(I2S_STD_MSB_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_32BIT, I2S_SLOT_MODE_STEREO)) {
|
||||
gpio_->set_pin(GpioExpander::AUDIO_POWER_ENABLE, true);
|
||||
gpio_->Write();
|
||||
}
|
||||
|
||||
AudioDac::~AudioDac() {
|
||||
i2s_driver_uninstall(kI2SPort);
|
||||
i2s_channel_disable(i2s_handle_);
|
||||
i2s_del_channel(i2s_handle_);
|
||||
gpio_->set_pin(GpioExpander::AUDIO_POWER_ENABLE, false);
|
||||
gpio_->Write();
|
||||
}
|
||||
@@ -136,7 +138,7 @@ bool AudioDac::WaitForPowerState(
|
||||
if (has_matched) {
|
||||
break;
|
||||
} else {
|
||||
ESP_LOGI(kTag, "Waiting for power state (was %d %x)", result.first,
|
||||
ESP_LOGI(kTag, "Waiting for power state (was %d 0x%x)", result.first,
|
||||
(uint8_t)result.second);
|
||||
vTaskDelay(pdMS_TO_TICKS(1));
|
||||
}
|
||||
@@ -148,14 +150,23 @@ auto AudioDac::Reconfigure(BitsPerSample bps, SampleRate rate) -> bool {
|
||||
// TODO(jacqueline): investigate how reliable the auto-clocking of the dac
|
||||
// is. We might need to explicit reconfigure the dac here as well if it's not
|
||||
// good enough.
|
||||
i2s_set_clk(kI2SPort, rate, bps, I2S_CHANNEL_STEREO);
|
||||
i2s_channel_disable(i2s_handle_);
|
||||
|
||||
slot_config_.slot_bit_width = (i2s_slot_bit_width_t) bps;
|
||||
i2s_channel_reconfig_std_slot(i2s_handle_, &slot_config_);
|
||||
|
||||
// TODO: update mclk multiple as well if needed?
|
||||
clock_config_.sample_rate_hz = rate;
|
||||
i2s_channel_reconfig_std_clock(i2s_handle_, &clock_config_);
|
||||
|
||||
i2s_channel_enable(i2s_handle_);
|
||||
return true;
|
||||
}
|
||||
|
||||
auto AudioDac::WriteData(const cpp::span<std::byte>& data, TickType_t max_wait)
|
||||
-> std::size_t {
|
||||
std::size_t res = 0;
|
||||
i2s_write(kI2SPort, data.data(), data.size(), &res, max_wait);
|
||||
i2s_channel_write(i2s_handle_, data.data(), data.size(), &res, max_wait);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,13 +3,15 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "driver/i2s_types.h"
|
||||
#include "esp_err.h"
|
||||
#include "freertos/portmacro.h"
|
||||
#include "hal/i2s_types.h"
|
||||
#include "result.hpp"
|
||||
#include "span.hpp"
|
||||
#include "driver/i2s_types_legacy.h"
|
||||
#include "driver/i2s_std.h"
|
||||
|
||||
#include "gpio_expander.hpp"
|
||||
|
||||
@@ -29,7 +31,7 @@ class AudioDac {
|
||||
static auto create(GpioExpander* expander)
|
||||
-> cpp::result<std::unique_ptr<AudioDac>, Error>;
|
||||
|
||||
AudioDac(GpioExpander* gpio);
|
||||
AudioDac(GpioExpander* gpio, i2s_chan_handle_t i2s_handle);
|
||||
~AudioDac();
|
||||
|
||||
/**
|
||||
@@ -54,9 +56,9 @@ class AudioDac {
|
||||
std::pair<bool, PowerState> ReadPowerState();
|
||||
|
||||
enum BitsPerSample {
|
||||
BPS_16 = I2S_BITS_PER_SAMPLE_16BIT,
|
||||
BPS_24 = I2S_BITS_PER_SAMPLE_24BIT,
|
||||
BPS_32 = I2S_BITS_PER_SAMPLE_32BIT
|
||||
BPS_16 = I2S_DATA_BIT_WIDTH_16BIT,
|
||||
BPS_24 = I2S_DATA_BIT_WIDTH_24BIT,
|
||||
BPS_32 = I2S_DATA_BIT_WIDTH_32BIT,
|
||||
};
|
||||
enum SampleRate {
|
||||
SAMPLE_RATE_44_1 = 44100,
|
||||
@@ -75,6 +77,10 @@ class AudioDac {
|
||||
|
||||
private:
|
||||
GpioExpander* gpio_;
|
||||
i2s_chan_handle_t i2s_handle_;
|
||||
|
||||
i2s_std_clk_config_t clock_config_;
|
||||
i2s_std_slot_config_t slot_config_;
|
||||
|
||||
/*
|
||||
* Pools the power state for up to 10ms, waiting for the given predicate to
|
||||
|
||||
+1
-4
@@ -122,8 +122,6 @@ extern "C" void app_main(void) {
|
||||
(void*)lvglArgs, 1, sLvglStack,
|
||||
&sLvglTaskBuffer, 1);
|
||||
|
||||
// TODO(jacqueline): re-enable this once our pipeline works.
|
||||
/*
|
||||
ESP_LOGI(TAG, "Init audio pipeline");
|
||||
auto playback_res = audio::AudioPlayback::create(expander, storage);
|
||||
if (playback_res.has_error()) {
|
||||
@@ -132,10 +130,9 @@ extern "C" void app_main(void) {
|
||||
}
|
||||
std::shared_ptr<audio::AudioPlayback> playback =
|
||||
std::move(playback_res.value());
|
||||
*/
|
||||
|
||||
ESP_LOGI(TAG, "Launch console");
|
||||
console::AppConsole console(nullptr);
|
||||
console::AppConsole console(playback.get());
|
||||
console.Launch();
|
||||
|
||||
while (1) {
|
||||
|
||||
Reference in New Issue
Block a user