forked from xiaozhi/xiaozhi-esp32
fit the memory usage for esp32c3
This commit is contained in:
@@ -9,34 +9,48 @@
|
||||
#define TAG "AudioCodec"
|
||||
|
||||
AudioCodec::AudioCodec() {
|
||||
audio_event_group_ = xEventGroupCreate();
|
||||
}
|
||||
|
||||
AudioCodec::~AudioCodec() {
|
||||
if (audio_input_task_ != nullptr) {
|
||||
vTaskDelete(audio_input_task_);
|
||||
}
|
||||
if (audio_output_task_ != nullptr) {
|
||||
vTaskDelete(audio_output_task_);
|
||||
}
|
||||
if (audio_event_group_ != nullptr) {
|
||||
vEventGroupDelete(audio_event_group_);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioCodec::OnInputData(std::function<void(std::vector<int16_t>&& data)> callback) {
|
||||
on_input_data_ = callback;
|
||||
void AudioCodec::OnInputReady(std::function<bool()> callback) {
|
||||
on_input_ready_ = callback;
|
||||
}
|
||||
|
||||
void AudioCodec::OnOutputReady(std::function<bool()> callback) {
|
||||
on_output_ready_ = callback;
|
||||
}
|
||||
|
||||
void AudioCodec::OutputData(std::vector<int16_t>& data) {
|
||||
std::lock_guard<std::mutex> lock(audio_output_queue_mutex_);
|
||||
audio_output_queue_.emplace_back(std::move(data));
|
||||
audio_output_queue_cv_.notify_one();
|
||||
Write(data.data(), data.size());
|
||||
}
|
||||
|
||||
bool AudioCodec::InputData(std::vector<int16_t>& data) {
|
||||
int duration = 30;
|
||||
int input_frame_size = input_sample_rate_ / 1000 * duration * input_channels_;
|
||||
|
||||
data.resize(input_frame_size);
|
||||
int samples = Read(data.data(), data.size());
|
||||
if (samples > 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
IRAM_ATTR bool AudioCodec::on_sent(i2s_chan_handle_t handle, i2s_event_data_t *event, void *user_ctx) {
|
||||
auto audio_codec = (AudioCodec*)user_ctx;
|
||||
xEventGroupSetBits(audio_codec->audio_event_group_, AUDIO_EVENT_OUTPUT_DONE);
|
||||
if (audio_codec->output_enabled_ && audio_codec->on_output_ready_) {
|
||||
return audio_codec->on_output_ready_();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
IRAM_ATTR bool AudioCodec::on_recv(i2s_chan_handle_t handle, i2s_event_data_t *event, void *user_ctx) {
|
||||
auto audio_codec = (AudioCodec*)user_ctx;
|
||||
if (audio_codec->input_enabled_ && audio_codec->on_input_ready_) {
|
||||
return audio_codec->on_input_ready_();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -44,85 +58,20 @@ void AudioCodec::Start() {
|
||||
Settings settings("audio", false);
|
||||
output_volume_ = settings.GetInt("output_volume", output_volume_);
|
||||
|
||||
// 注册音频输出回调
|
||||
i2s_event_callbacks_t callbacks = {};
|
||||
callbacks.on_sent = on_sent;
|
||||
i2s_channel_register_event_callback(tx_handle_, &callbacks, this);
|
||||
// 注册音频数据回调
|
||||
i2s_event_callbacks_t rx_callbacks = {};
|
||||
rx_callbacks.on_recv = on_recv;
|
||||
i2s_channel_register_event_callback(rx_handle_, &rx_callbacks, this);
|
||||
|
||||
i2s_event_callbacks_t tx_callbacks = {};
|
||||
tx_callbacks.on_sent = on_sent;
|
||||
i2s_channel_register_event_callback(tx_handle_, &tx_callbacks, this);
|
||||
|
||||
ESP_ERROR_CHECK(i2s_channel_enable(tx_handle_));
|
||||
ESP_ERROR_CHECK(i2s_channel_enable(rx_handle_));
|
||||
|
||||
EnableInput(true);
|
||||
EnableOutput(true);
|
||||
|
||||
// 创建音频输入任务
|
||||
if (audio_input_task_ == nullptr) {
|
||||
xTaskCreate([](void* arg) {
|
||||
auto audio_device = (AudioCodec*)arg;
|
||||
audio_device->InputTask();
|
||||
}, "audio_input", 4096 * 2, this, 3, &audio_input_task_);
|
||||
}
|
||||
// 创建音频输出任务
|
||||
if (audio_output_task_ == nullptr) {
|
||||
xTaskCreate([](void* arg) {
|
||||
auto audio_device = (AudioCodec*)arg;
|
||||
audio_device->OutputTask();
|
||||
}, "audio_output", 4096 * 2, this, 3, &audio_output_task_);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioCodec::InputTask() {
|
||||
int duration = 30;
|
||||
int input_frame_size = input_sample_rate_ / 1000 * duration * input_channels_;
|
||||
|
||||
while (true) {
|
||||
std::vector<int16_t> input_data(input_frame_size);
|
||||
int samples = Read(input_data.data(), input_data.size());
|
||||
if (samples > 0) {
|
||||
if (on_input_data_) {
|
||||
on_input_data_(std::move(input_data));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioCodec::OutputTask() {
|
||||
while (true) {
|
||||
std::unique_lock<std::mutex> lock(audio_output_queue_mutex_);
|
||||
if (!audio_output_queue_cv_.wait_for(lock, std::chrono::seconds(30), [this]() {
|
||||
return !audio_output_queue_.empty();
|
||||
})) {
|
||||
// If timeout, disable output
|
||||
EnableOutput(false);
|
||||
continue;
|
||||
}
|
||||
auto data = std::move(audio_output_queue_.front());
|
||||
audio_output_queue_.pop_front();
|
||||
lock.unlock();
|
||||
|
||||
if (!output_enabled_) {
|
||||
EnableOutput(true);
|
||||
}
|
||||
|
||||
xEventGroupClearBits(audio_event_group_, AUDIO_EVENT_OUTPUT_DONE);
|
||||
Write(data.data(), data.size());
|
||||
audio_output_queue_cv_.notify_all();
|
||||
}
|
||||
}
|
||||
|
||||
void AudioCodec::WaitForOutputDone() {
|
||||
// Wait for the output queue to be empty and the output is done
|
||||
std::unique_lock<std::mutex> lock(audio_output_queue_mutex_);
|
||||
audio_output_queue_cv_.wait(lock, [this]() {
|
||||
return audio_output_queue_.empty();
|
||||
});
|
||||
lock.unlock();
|
||||
xEventGroupWaitBits(audio_event_group_, AUDIO_EVENT_OUTPUT_DONE, pdFALSE, pdFALSE, portMAX_DELAY);
|
||||
}
|
||||
|
||||
void AudioCodec::ClearOutputQueue() {
|
||||
std::lock_guard<std::mutex> lock(audio_output_queue_mutex_);
|
||||
audio_output_queue_.clear();
|
||||
}
|
||||
|
||||
void AudioCodec::SetOutputVolume(int volume) {
|
||||
|
||||
@@ -2,21 +2,15 @@
|
||||
#define _AUDIO_CODEC_H
|
||||
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <freertos/event_groups.h>
|
||||
#include <driver/i2s_std.h>
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <list>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
||||
#include "board.h"
|
||||
|
||||
#define AUDIO_EVENT_OUTPUT_DONE (1 << 0)
|
||||
|
||||
class AudioCodec {
|
||||
public:
|
||||
AudioCodec();
|
||||
@@ -27,10 +21,10 @@ public:
|
||||
virtual void EnableOutput(bool enable);
|
||||
|
||||
void Start();
|
||||
void OnInputData(std::function<void(std::vector<int16_t>&& data)> callback);
|
||||
void OutputData(std::vector<int16_t>& data);
|
||||
void WaitForOutputDone();
|
||||
void ClearOutputQueue();
|
||||
bool InputData(std::vector<int16_t>& data);
|
||||
void OnOutputReady(std::function<bool()> callback);
|
||||
void OnInputReady(std::function<bool()> callback);
|
||||
|
||||
inline bool duplex() const { return duplex_; }
|
||||
inline bool input_reference() const { return input_reference_; }
|
||||
@@ -41,18 +35,12 @@ public:
|
||||
inline int output_volume() const { return output_volume_; }
|
||||
|
||||
private:
|
||||
TaskHandle_t audio_input_task_ = nullptr;
|
||||
TaskHandle_t audio_output_task_ = nullptr;
|
||||
std::function<void(std::vector<int16_t>&& data)> on_input_data_;
|
||||
std::list<std::vector<int16_t>> audio_output_queue_;
|
||||
std::mutex audio_output_queue_mutex_;
|
||||
std::condition_variable audio_output_queue_cv_;
|
||||
EventGroupHandle_t audio_event_group_ = nullptr;
|
||||
std::function<bool()> on_input_ready_;
|
||||
std::function<bool()> on_output_ready_;
|
||||
|
||||
IRAM_ATTR static bool on_recv(i2s_chan_handle_t handle, i2s_event_data_t *event, void *user_ctx);
|
||||
IRAM_ATTR static bool on_sent(i2s_chan_handle_t handle, i2s_event_data_t *event, void *user_ctx);
|
||||
|
||||
void InputTask();
|
||||
void OutputTask();
|
||||
|
||||
protected:
|
||||
i2s_chan_handle_t tx_handle_ = nullptr;
|
||||
i2s_chan_handle_t rx_handle_ = nullptr;
|
||||
|
||||
@@ -28,7 +28,7 @@ BoxAudioCodec::BoxAudioCodec(void* i2c_master_handle, int input_sample_rate, int
|
||||
|
||||
// Output
|
||||
audio_codec_i2c_cfg_t i2c_cfg = {
|
||||
.port = I2C_NUM_1,
|
||||
.port = (i2c_port_t)1,
|
||||
.addr = es8311_addr,
|
||||
.bus_handle = i2c_master_handle,
|
||||
};
|
||||
@@ -96,8 +96,8 @@ void BoxAudioCodec::CreateDuplexChannels(gpio_num_t mclk, gpio_num_t bclk, gpio_
|
||||
i2s_chan_config_t chan_cfg = {
|
||||
.id = I2S_NUM_0,
|
||||
.role = I2S_ROLE_MASTER,
|
||||
.dma_desc_num = 6,
|
||||
.dma_frame_num = 240,
|
||||
.dma_desc_num = 2,
|
||||
.dma_frame_num = 240 * 3,
|
||||
.auto_clear_after_cb = true,
|
||||
.auto_clear_before_cb = false,
|
||||
.intr_priority = 0,
|
||||
|
||||
186
main/audio_codecs/es8311_audio_codec.cc
Normal file
186
main/audio_codecs/es8311_audio_codec.cc
Normal file
@@ -0,0 +1,186 @@
|
||||
#include "es8311_audio_codec.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
|
||||
static const char TAG[] = "Es8311AudioCodec";
|
||||
|
||||
Es8311AudioCodec::Es8311AudioCodec(void* i2c_master_handle, i2c_port_t i2c_port, int input_sample_rate, int output_sample_rate,
|
||||
gpio_num_t mclk, gpio_num_t bclk, gpio_num_t ws, gpio_num_t dout, gpio_num_t din,
|
||||
gpio_num_t pa_pin, uint8_t es8311_addr) {
|
||||
duplex_ = true; // 是否双工
|
||||
input_reference_ = false; // 是否使用参考输入,实现回声消除
|
||||
input_channels_ = 1; // 输入通道数
|
||||
input_sample_rate_ = input_sample_rate;
|
||||
output_sample_rate_ = output_sample_rate;
|
||||
|
||||
CreateDuplexChannels(mclk, bclk, ws, dout, din);
|
||||
|
||||
// Do initialize of related interface: data_if, ctrl_if and gpio_if
|
||||
audio_codec_i2s_cfg_t i2s_cfg = {
|
||||
.port = I2S_NUM_0,
|
||||
.rx_handle = rx_handle_,
|
||||
.tx_handle = tx_handle_,
|
||||
};
|
||||
data_if_ = audio_codec_new_i2s_data(&i2s_cfg);
|
||||
assert(data_if_ != NULL);
|
||||
|
||||
// Output
|
||||
audio_codec_i2c_cfg_t i2c_cfg = {
|
||||
.port = i2c_port,
|
||||
.addr = es8311_addr,
|
||||
.bus_handle = i2c_master_handle,
|
||||
};
|
||||
ctrl_if_ = audio_codec_new_i2c_ctrl(&i2c_cfg);
|
||||
assert(ctrl_if_ != NULL);
|
||||
|
||||
gpio_if_ = audio_codec_new_gpio();
|
||||
assert(gpio_if_ != NULL);
|
||||
|
||||
es8311_codec_cfg_t es8311_cfg = {};
|
||||
es8311_cfg.ctrl_if = ctrl_if_;
|
||||
es8311_cfg.gpio_if = gpio_if_;
|
||||
es8311_cfg.codec_mode = ESP_CODEC_DEV_WORK_MODE_BOTH;
|
||||
es8311_cfg.pa_pin = pa_pin;
|
||||
es8311_cfg.use_mclk = true;
|
||||
es8311_cfg.hw_gain.pa_voltage = 5.0;
|
||||
es8311_cfg.hw_gain.codec_dac_voltage = 3.3;
|
||||
codec_if_ = es8311_codec_new(&es8311_cfg);
|
||||
assert(codec_if_ != NULL);
|
||||
|
||||
esp_codec_dev_cfg_t dev_cfg = {
|
||||
.dev_type = ESP_CODEC_DEV_TYPE_OUT,
|
||||
.codec_if = codec_if_,
|
||||
.data_if = data_if_,
|
||||
};
|
||||
output_dev_ = esp_codec_dev_new(&dev_cfg);
|
||||
assert(output_dev_ != NULL);
|
||||
dev_cfg.dev_type = ESP_CODEC_DEV_TYPE_IN;
|
||||
input_dev_ = esp_codec_dev_new(&dev_cfg);
|
||||
assert(input_dev_ != NULL);
|
||||
|
||||
ESP_LOGI(TAG, "Es8311AudioCodec initialized");
|
||||
}
|
||||
|
||||
Es8311AudioCodec::~Es8311AudioCodec() {
|
||||
ESP_ERROR_CHECK(esp_codec_dev_close(output_dev_));
|
||||
esp_codec_dev_delete(output_dev_);
|
||||
ESP_ERROR_CHECK(esp_codec_dev_close(input_dev_));
|
||||
esp_codec_dev_delete(input_dev_);
|
||||
|
||||
audio_codec_delete_codec_if(codec_if_);
|
||||
audio_codec_delete_ctrl_if(ctrl_if_);
|
||||
audio_codec_delete_gpio_if(gpio_if_);
|
||||
audio_codec_delete_data_if(data_if_);
|
||||
}
|
||||
|
||||
void Es8311AudioCodec::CreateDuplexChannels(gpio_num_t mclk, gpio_num_t bclk, gpio_num_t ws, gpio_num_t dout, gpio_num_t din) {
|
||||
assert(input_sample_rate_ == output_sample_rate_);
|
||||
|
||||
i2s_chan_config_t chan_cfg = {
|
||||
.id = I2S_NUM_0,
|
||||
.role = I2S_ROLE_MASTER,
|
||||
.dma_desc_num = 2,
|
||||
.dma_frame_num = 240 * 3,
|
||||
.auto_clear_after_cb = true,
|
||||
.auto_clear_before_cb = false,
|
||||
.intr_priority = 0,
|
||||
};
|
||||
ESP_ERROR_CHECK(i2s_new_channel(&chan_cfg, &tx_handle_, &rx_handle_));
|
||||
|
||||
i2s_std_config_t std_cfg = {
|
||||
.clk_cfg = {
|
||||
.sample_rate_hz = (uint32_t)output_sample_rate_,
|
||||
.clk_src = I2S_CLK_SRC_DEFAULT,
|
||||
.ext_clk_freq_hz = 0,
|
||||
.mclk_multiple = I2S_MCLK_MULTIPLE_256
|
||||
},
|
||||
.slot_cfg = {
|
||||
.data_bit_width = I2S_DATA_BIT_WIDTH_16BIT,
|
||||
.slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO,
|
||||
.slot_mode = I2S_SLOT_MODE_STEREO,
|
||||
.slot_mask = I2S_STD_SLOT_BOTH,
|
||||
.ws_width = I2S_DATA_BIT_WIDTH_16BIT,
|
||||
.ws_pol = false,
|
||||
.bit_shift = true,
|
||||
.left_align = true,
|
||||
.big_endian = false,
|
||||
.bit_order_lsb = false
|
||||
},
|
||||
.gpio_cfg = {
|
||||
.mclk = mclk,
|
||||
.bclk = bclk,
|
||||
.ws = ws,
|
||||
.dout = dout,
|
||||
.din = din,
|
||||
.invert_flags = {
|
||||
.mclk_inv = false,
|
||||
.bclk_inv = false,
|
||||
.ws_inv = false
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_handle_, &std_cfg));
|
||||
ESP_ERROR_CHECK(i2s_channel_init_std_mode(rx_handle_, &std_cfg));
|
||||
ESP_LOGI(TAG, "Duplex channels created");
|
||||
}
|
||||
|
||||
void Es8311AudioCodec::SetOutputVolume(int volume) {
|
||||
ESP_ERROR_CHECK(esp_codec_dev_set_out_vol(output_dev_, volume));
|
||||
AudioCodec::SetOutputVolume(volume);
|
||||
}
|
||||
|
||||
void Es8311AudioCodec::EnableInput(bool enable) {
|
||||
if (enable == input_enabled_) {
|
||||
return;
|
||||
}
|
||||
if (enable) {
|
||||
esp_codec_dev_sample_info_t fs = {
|
||||
.bits_per_sample = 16,
|
||||
.channel = 1,
|
||||
.channel_mask = 0,
|
||||
.sample_rate = (uint32_t)output_sample_rate_,
|
||||
.mclk_multiple = 0,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_codec_dev_open(input_dev_, &fs));
|
||||
ESP_ERROR_CHECK(esp_codec_dev_set_in_gain(input_dev_, 40.0));
|
||||
} else {
|
||||
ESP_ERROR_CHECK(esp_codec_dev_close(input_dev_));
|
||||
}
|
||||
AudioCodec::EnableInput(enable);
|
||||
}
|
||||
|
||||
void Es8311AudioCodec::EnableOutput(bool enable) {
|
||||
if (enable == output_enabled_) {
|
||||
return;
|
||||
}
|
||||
if (enable) {
|
||||
// Play 16bit 1 channel
|
||||
esp_codec_dev_sample_info_t fs = {
|
||||
.bits_per_sample = 16,
|
||||
.channel = 1,
|
||||
.channel_mask = 0,
|
||||
.sample_rate = (uint32_t)output_sample_rate_,
|
||||
.mclk_multiple = 0,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_codec_dev_open(output_dev_, &fs));
|
||||
ESP_ERROR_CHECK(esp_codec_dev_set_out_vol(output_dev_, output_volume_));
|
||||
} else {
|
||||
ESP_ERROR_CHECK(esp_codec_dev_close(output_dev_));
|
||||
}
|
||||
AudioCodec::EnableOutput(enable);
|
||||
}
|
||||
|
||||
int Es8311AudioCodec::Read(int16_t* dest, int samples) {
|
||||
if (input_enabled_) {
|
||||
ESP_ERROR_CHECK_WITHOUT_ABORT(esp_codec_dev_read(input_dev_, (void*)dest, samples * sizeof(int16_t)));
|
||||
}
|
||||
return samples;
|
||||
}
|
||||
|
||||
int Es8311AudioCodec::Write(const int16_t* data, int samples) {
|
||||
if (output_enabled_) {
|
||||
ESP_ERROR_CHECK_WITHOUT_ABORT(esp_codec_dev_write(output_dev_, (void*)data, samples * sizeof(int16_t)));
|
||||
}
|
||||
return samples;
|
||||
}
|
||||
36
main/audio_codecs/es8311_audio_codec.h
Normal file
36
main/audio_codecs/es8311_audio_codec.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#ifndef _ES8311_AUDIO_CODEC_H
|
||||
#define _ES8311_AUDIO_CODEC_H
|
||||
|
||||
#include "audio_codec.h"
|
||||
|
||||
#include <driver/i2c.h>
|
||||
#include <esp_codec_dev.h>
|
||||
#include <esp_codec_dev_defaults.h>
|
||||
|
||||
class Es8311AudioCodec : public AudioCodec {
|
||||
private:
|
||||
const audio_codec_data_if_t* data_if_ = nullptr;
|
||||
const audio_codec_ctrl_if_t* ctrl_if_ = nullptr;
|
||||
const audio_codec_if_t* codec_if_ = nullptr;
|
||||
const audio_codec_gpio_if_t* gpio_if_ = nullptr;
|
||||
|
||||
esp_codec_dev_handle_t output_dev_ = nullptr;
|
||||
esp_codec_dev_handle_t input_dev_ = nullptr;
|
||||
|
||||
void CreateDuplexChannels(gpio_num_t mclk, gpio_num_t bclk, gpio_num_t ws, gpio_num_t dout, gpio_num_t din);
|
||||
|
||||
virtual int Read(int16_t* dest, int samples) override;
|
||||
virtual int Write(const int16_t* data, int samples) override;
|
||||
|
||||
public:
|
||||
Es8311AudioCodec(void* i2c_master_handle, i2c_port_t i2c_port, int input_sample_rate, int output_sample_rate,
|
||||
gpio_num_t mclk, gpio_num_t bclk, gpio_num_t ws, gpio_num_t dout, gpio_num_t din,
|
||||
gpio_num_t pa_pin, uint8_t es8311_addr);
|
||||
virtual ~Es8311AudioCodec();
|
||||
|
||||
virtual void SetOutputVolume(int volume) override;
|
||||
virtual void EnableInput(bool enable) override;
|
||||
virtual void EnableOutput(bool enable) override;
|
||||
};
|
||||
|
||||
#endif // _ES8311_AUDIO_CODEC_H
|
||||
@@ -23,8 +23,8 @@ NoAudioCodec::NoAudioCodec(int input_sample_rate, int output_sample_rate, gpio_n
|
||||
i2s_chan_config_t chan_cfg = {
|
||||
.id = I2S_NUM_0,
|
||||
.role = I2S_ROLE_MASTER,
|
||||
.dma_desc_num = 6,
|
||||
.dma_frame_num = 240,
|
||||
.dma_desc_num = 2,
|
||||
.dma_frame_num = 240 * 3,
|
||||
.auto_clear_after_cb = false,
|
||||
.auto_clear_before_cb = false,
|
||||
.intr_priority = 0,
|
||||
@@ -75,7 +75,7 @@ NoAudioCodec::NoAudioCodec(int input_sample_rate, int output_sample_rate, gpio_n
|
||||
|
||||
// Create a new channel for speaker
|
||||
i2s_chan_config_t chan_cfg = {
|
||||
.id = I2S_NUM_0,
|
||||
.id = (i2s_port_t)0,
|
||||
.role = I2S_ROLE_MASTER,
|
||||
.dma_desc_num = 6,
|
||||
.dma_frame_num = 240,
|
||||
@@ -120,7 +120,7 @@ NoAudioCodec::NoAudioCodec(int input_sample_rate, int output_sample_rate, gpio_n
|
||||
ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_handle_, &std_cfg));
|
||||
|
||||
// Create a new channel for MIC
|
||||
chan_cfg.id = I2S_NUM_1;
|
||||
chan_cfg.id = (i2s_port_t)1;
|
||||
ESP_ERROR_CHECK(i2s_new_channel(&chan_cfg, nullptr, &rx_handle_));
|
||||
std_cfg.clk_cfg.sample_rate_hz = (uint32_t)input_sample_rate_;
|
||||
std_cfg.gpio_cfg.bclk = mic_sck;
|
||||
|
||||
Reference in New Issue
Block a user