Files
xiaozhi-esp32/main/audio/audio_codec.cc
2025-09-13 23:40:38 +08:00

151 lines
4.6 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "audio_codec.h"
#include "board.h"
#include "settings.h"
#include <esp_log.h>
#include <cstring>
#include <driver/i2s_common.h>
#define TAG "AudioCodec"
AudioCodec::AudioCodec() {
}
AudioCodec::~AudioCodec() {
}
void AudioCodec::OutputData(std::vector<int16_t>& data) {
Write(data.data(), data.size());
}
bool AudioCodec::InputData(std::vector<int16_t>& data) {
int samples = Read(data.data(), data.size());
if (samples > 0) {
return true;
}
return false;
}
void AudioCodec::Start() {
Settings settings("audio", false);
output_volume_ = settings.GetInt("output_volume", output_volume_);
if (output_volume_ <= 0) {
ESP_LOGW(TAG, "Output volume value (%d) is too small, setting to default (10)", output_volume_);
output_volume_ = 10;
}
// 保存原始输出采样率
if (original_output_sample_rate_ == 0){
original_output_sample_rate_ = output_sample_rate_;
ESP_LOGI(TAG, "Saved original output sample rate: %d Hz", original_output_sample_rate_);
}
if (tx_handle_ != nullptr) {
ESP_ERROR_CHECK(i2s_channel_enable(tx_handle_));
}
if (rx_handle_ != nullptr) {
ESP_ERROR_CHECK(i2s_channel_enable(rx_handle_));
}
EnableInput(true);
EnableOutput(true);
ESP_LOGI(TAG, "Audio codec started");
}
void AudioCodec::SetOutputVolume(int volume) {
output_volume_ = volume;
ESP_LOGI(TAG, "Set output volume to %d", output_volume_);
Settings settings("audio", true);
settings.SetInt("output_volume", output_volume_);
}
void AudioCodec::EnableInput(bool enable) {
if (enable == input_enabled_) {
return;
}
input_enabled_ = enable;
ESP_LOGI(TAG, "Set input enable to %s", enable ? "true" : "false");
}
void AudioCodec::EnableOutput(bool enable) {
if (enable == output_enabled_) {
return;
}
output_enabled_ = enable;
ESP_LOGI(TAG, "Set output enable to %s", enable ? "true" : "false");
}
bool AudioCodec::SetOutputSampleRate(int sample_rate) {
// 特殊处理:如果传入 -1表示重置到原始采样率
if (sample_rate == -1) {
if (original_output_sample_rate_ > 0) {
sample_rate = original_output_sample_rate_;
ESP_LOGI(TAG, "Resetting to original output sample rate: %d Hz", sample_rate);
} else {
ESP_LOGW(TAG, "Original sample rate not available, cannot reset");
return false;
}
}
if (sample_rate <= 0 || sample_rate > 192000) {
ESP_LOGE(TAG, "Invalid sample rate: %d", sample_rate);
return false;
}
if (output_sample_rate_ == sample_rate) {
ESP_LOGI(TAG, "Sample rate already set to %d Hz", sample_rate);
return true;
}
if (tx_handle_ == nullptr) {
ESP_LOGW(TAG, "TX handle is null, only updating sample rate variable");
output_sample_rate_ = sample_rate;
return true;
}
ESP_LOGI(TAG, "Changing output sample rate from %d to %d Hz", output_sample_rate_, sample_rate);
// 先尝试禁用 I2S 通道(如果已启用的话)
bool was_enabled = false;
esp_err_t disable_ret = i2s_channel_disable(tx_handle_);
if (disable_ret == ESP_OK) {
was_enabled = true;
ESP_LOGI(TAG, "Disabled I2S TX channel for reconfiguration");
} else if (disable_ret == ESP_ERR_INVALID_STATE) {
// 通道可能已经是禁用状态,这是正常的
ESP_LOGI(TAG, "I2S TX channel was already disabled");
} else {
ESP_LOGW(TAG, "Failed to disable I2S TX channel: %s", esp_err_to_name(disable_ret));
}
// 重新配置 I2S 时钟
i2s_std_clk_config_t clk_cfg = {
.sample_rate_hz = (uint32_t)sample_rate,
.clk_src = I2S_CLK_SRC_DEFAULT,
.mclk_multiple = I2S_MCLK_MULTIPLE_256,
#ifdef I2S_HW_VERSION_2
.ext_clk_freq_hz = 0,
#endif
};
esp_err_t ret = i2s_channel_reconfig_std_clock(tx_handle_, &clk_cfg);
// 重新启用通道(无论之前是什么状态,现在都需要启用以便播放音频)
esp_err_t enable_ret = i2s_channel_enable(tx_handle_);
if (enable_ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to enable I2S TX channel: %s", esp_err_to_name(enable_ret));
} else {
ESP_LOGI(TAG, "Enabled I2S TX channel");
}
if (ret == ESP_OK) {
output_sample_rate_ = sample_rate;
ESP_LOGI(TAG, "Successfully changed output sample rate to %d Hz", sample_rate);
return true;
} else {
ESP_LOGE(TAG, "Failed to change sample rate to %d Hz: %s", sample_rate, esp_err_to_name(ret));
return false;
}
}