#include "audio_codec.h" #include "esp_log.h" #include "es7210.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/semphr.h" static const char *TAG = "AudioCodec"; // 静态成员初始化 AudioCodec* AudioCodec::instance_ = nullptr; SemaphoreHandle_t AudioCodec::mutex_ = nullptr; AudioCodec::AudioCodec() : board_handle_(nullptr), is_initialized_(false), current_mode_(AUDIO_CODEC_MODE_DECODE), current_volume_(100) { } AudioCodec::~AudioCodec() { Deinitialize(); } AudioCodec* AudioCodec::GetInstance() { // 双重检查锁定模式确保线程安全 if (instance_ == nullptr) { if (mutex_ == nullptr) { mutex_ = xSemaphoreCreateMutex(); } if (xSemaphoreTake(mutex_, portMAX_DELAY) == pdTRUE) { if (instance_ == nullptr) { instance_ = new AudioCodec(); } xSemaphoreGive(mutex_); } } return instance_; } esp_err_t AudioCodec::Initialize() { if (is_initialized_) { ESP_LOGW(TAG, "AudioCodec already initialized"); return ESP_OK; } ESP_LOGI(TAG, "Initializing AudioCodec"); esp_err_t ret = InitializeBoard(); if (ret != ESP_OK) { ESP_LOGE(TAG, "Failed to initialize audio board: %s", esp_err_to_name(ret)); return ret; } // 先设置初始化标志,然后启动编解码器 is_initialized_ = true; // 默认启用双向模式,同时支持播放和录音 ret = StartCodec(AUDIO_CODEC_MODE_BOTH); if (ret != ESP_OK) { ESP_LOGE(TAG, "Failed to start codec in both mode: %s", esp_err_to_name(ret)); is_initialized_ = false; // 如果启动失败,重置标志 return ret; } ESP_LOGI(TAG, "AudioCodec initialized successfully with both encode and decode enabled"); return ESP_OK; } esp_err_t AudioCodec::InitializeBoard() { // 初始化音频板 board_handle_ = audio_board_init(); if (board_handle_ == nullptr) { ESP_LOGE(TAG, "Failed to initialize audio board"); return ESP_FAIL; } ESP_LOGI(TAG, "Audio board initialized successfully"); return ESP_OK; } esp_err_t AudioCodec::StartCodec(audio_codec_mode_t mode) { // 检查音频板是否已初始化,而不是检查整体初始化状态 if (board_handle_ == nullptr) { ESP_LOGE(TAG, "Audio board not initialized"); return ESP_ERR_INVALID_STATE; } esp_err_t ret = ESP_OK; switch (mode) { case AUDIO_CODEC_MODE_DECODE: ESP_LOGI(TAG, "Starting codec in decode mode"); ret = audio_hal_ctrl_codec(board_handle_->audio_hal, AUDIO_HAL_CODEC_MODE_DECODE, AUDIO_HAL_CTRL_START); break; case AUDIO_CODEC_MODE_ENCODE: ESP_LOGI(TAG, "Starting codec in encode mode"); ret = audio_hal_ctrl_codec(board_handle_->audio_hal, AUDIO_HAL_CODEC_MODE_ENCODE, AUDIO_HAL_CTRL_START); if (ret == ESP_OK) { // 设置ADC音量 ret = audio_hal_set_volume(board_handle_->adc_hal, 100); if (ret != ESP_OK) { ESP_LOGW(TAG, "Failed to set ADC volume: %s", esp_err_to_name(ret)); } // 设置ES7210麦克风增益 ret = es7210_adc_set_gain((es7210_input_mics_t)(ES7210_INPUT_MIC1 | ES7210_INPUT_MIC2 | ES7210_INPUT_MIC3), GAIN_37_5DB); if (ret != ESP_OK) { ESP_LOGW(TAG, "Failed to set ES7210 gain: %s", esp_err_to_name(ret)); } else { ESP_LOGI(TAG, "ES7210 gain set to 37.5dB"); } } break; case AUDIO_CODEC_MODE_BOTH: ESP_LOGI(TAG, "Starting codec in both modes"); ret = audio_hal_ctrl_codec(board_handle_->audio_hal, AUDIO_HAL_CODEC_MODE_BOTH, AUDIO_HAL_CTRL_START); if (ret == ESP_OK) { // 同时设置播放和录音参数 audio_hal_set_volume(board_handle_->adc_hal, 100); es7210_adc_set_gain((es7210_input_mics_t)(ES7210_INPUT_MIC1 | ES7210_INPUT_MIC2 | ES7210_INPUT_MIC3), GAIN_37_5DB); } break; default: ESP_LOGE(TAG, "Invalid codec mode: %d", mode); return ESP_ERR_INVALID_ARG; } if (ret != ESP_OK) { ESP_LOGE(TAG, "Failed to start codec: %s", esp_err_to_name(ret)); return ret; } current_mode_ = mode; // 设置初始音量(仅在播放模式下) if (mode == AUDIO_CODEC_MODE_DECODE || mode == AUDIO_CODEC_MODE_BOTH) { SetVolume(current_volume_); } ESP_LOGI(TAG, "Codec started successfully in mode %d", mode); return ESP_OK; } esp_err_t AudioCodec::StopCodec() { if (!is_initialized_) { ESP_LOGW(TAG, "AudioCodec not initialized"); return ESP_OK; } ESP_LOGI(TAG, "Stopping codec"); // 修复:直接使用audio_hal_codec_mode_t类型 esp_err_t ret = audio_hal_ctrl_codec(board_handle_->audio_hal, (audio_hal_codec_mode_t)current_mode_, AUDIO_HAL_CTRL_STOP); if (ret != ESP_OK) { ESP_LOGW(TAG, "Failed to stop codec: %s", esp_err_to_name(ret)); } return ret; } esp_err_t AudioCodec::SetVolume(uint8_t volume) { if (!is_initialized_) { ESP_LOGE(TAG, "AudioCodec not initialized"); return ESP_ERR_INVALID_STATE; } if (volume > 100) { ESP_LOGW(TAG, "Volume %d exceeds maximum, setting to 100", volume); volume = 100; } // 转换为HAL音量范围 (0-63) int hal_volume = (volume * 63) / 100; esp_err_t ret = audio_hal_set_volume(board_handle_->audio_hal, hal_volume); if (ret != ESP_OK) { ESP_LOGE(TAG, "Failed to set volume: %s", esp_err_to_name(ret)); return ret; } current_volume_ = volume; ESP_LOGI(TAG, "Volume set to %d%% (HAL volume: %d)", volume, hal_volume); return ESP_OK; } esp_err_t AudioCodec::GetVolume(uint8_t* volume) { if (!volume) { return ESP_ERR_INVALID_ARG; } *volume = current_volume_; return ESP_OK; } esp_err_t AudioCodec::SetAdcVolume(uint8_t volume) { if (!is_initialized_) { ESP_LOGE(TAG, "AudioCodec not initialized"); return ESP_ERR_INVALID_STATE; } if (volume > 100) { volume = 100; } esp_err_t ret = audio_hal_set_volume(board_handle_->adc_hal, volume); if (ret != ESP_OK) { ESP_LOGE(TAG, "Failed to set ADC volume: %s", esp_err_to_name(ret)); return ret; } ESP_LOGI(TAG, "ADC volume set to %d", volume); return ESP_OK; } audio_board_handle_t AudioCodec::GetBoardHandle() { return board_handle_; } bool AudioCodec::IsInitialized() { return is_initialized_; } esp_err_t AudioCodec::Deinitialize() { if (!is_initialized_) { return ESP_OK; } ESP_LOGI(TAG, "Deinitializing AudioCodec"); StopCodec(); Cleanup(); is_initialized_ = false; ESP_LOGI(TAG, "AudioCodec deinitialized"); return ESP_OK; } void AudioCodec::Cleanup() { if (board_handle_) { audio_board_deinit(board_handle_); board_handle_ = nullptr; } }