From 2a7d3f0d9e9c9dc27a565e0e05c6273f642e0271 Mon Sep 17 00:00:00 2001 From: Colin Date: Sat, 10 Jan 2026 00:37:05 +0800 Subject: [PATCH] Update record auto flow. --- main/asr.c | 7 +- main/main.c | 5 +- main/record.c | 246 +++++++++++++++++++++++++++++++++++++++++--------- main/record.h | 2 +- 4 files changed, 210 insertions(+), 50 deletions(-) diff --git a/main/asr.c b/main/asr.c index 3b66557..0683eba 100644 --- a/main/asr.c +++ b/main/asr.c @@ -216,6 +216,9 @@ esp_err_t _http_event_handler(esp_http_client_event_t* evt) { case HTTP_EVENT_ERROR: ESP_LOGE(TAG, "HTTP request error"); break; + case HTTP_EVENT_DISCONNECTED: + ESP_LOGW(TAG, "HTTP disconnected"); + break; default: break; } @@ -317,7 +320,7 @@ void send_audio_transcription(const char* filepath) { .event_handler = _http_event_handler, .buffer_size = 4096, .buffer_size_tx = 4096, - .timeout_ms = 60000, // Increased timeout to 60 seconds + .timeout_ms = 120000, // Increased timeout to 120 seconds to handle network interruptions .skip_cert_common_name_check = false, // Don't skip cert name check .keep_alive_enable = true, .use_global_ca_store = true, @@ -382,6 +385,8 @@ void send_audio_transcription(const char* filepath) { } } else { ESP_LOGE(TAG, "HTTP request failed: %s", esp_err_to_name(err)); + // Wait a bit to allow WiFi to reconnect if needed + vTaskDelay(pdMS_TO_TICKS(2000)); } // 清理 diff --git a/main/main.c b/main/main.c index 3733334..e663963 100644 --- a/main/main.c +++ b/main/main.c @@ -314,9 +314,8 @@ void app_main(void) { // vTaskDelay(pdMS_TO_TICKS(1000)); // } - for (int i = 0; i < 2; i++) { - ESP_ERROR_CHECK(record_wav(rx_chan)); - } + // Record for 2 cycles as before + ESP_ERROR_CHECK(record_wav(rx_chan, 2)); esp_pm_config_esp32_t pm_config = { .max_freq_mhz = 240, .min_freq_mhz = 240, .light_sleep_enable = false}; diff --git a/main/record.c b/main/record.c index bad2ec4..f86682a 100644 --- a/main/record.c +++ b/main/record.c @@ -44,24 +44,20 @@ esp_err_t wait_for_time_sync(int timeout_seconds) { int retry = 0; const int max_retry = timeout_seconds; + // Wait for the SNTP sync status to be complete while (esp_sntp_get_sync_status() == SNTP_SYNC_STATUS_RESET && retry < max_retry) { ESP_LOGI(TAG, "等待NTP时间同步... (%d/%d)", retry + 1, max_retry); vTaskDelay(pdMS_TO_TICKS(1000)); retry++; - - time(&now); - localtime_r(&now, &timeinfo); - - // 检查时间是否有效(2000年之后) - if (timeinfo.tm_year > 100) { - ESP_LOGW(TAG, "时间未同步,正在等待NTP..."); - return ESP_OK; - } } - if (retry >= max_retry) { - ESP_LOGE(TAG, "NTP同步超时"); + // Get the current time after sync attempt + time(&now); + localtime_r(&now, &timeinfo); + + if (timeinfo.tm_year < 100) { + ESP_LOGE(TAG, "NTP同步失败或超时,时间无效"); return ESP_ERR_TIMEOUT; } @@ -69,51 +65,211 @@ esp_err_t wait_for_time_sync(int timeout_seconds) { return ESP_OK; } -char* get_file_name_from_time(void) { - wait_for_time_sync(10); +char* get_file_name_from_time_now(void) { + time(&now); + localtime_r(&now, &timeinfo); strftime(record_file_name, 48, "/sdcard/Record_%Y%m%d%H%M%S.wav", &timeinfo); return record_file_name; } -esp_err_t record_wav(i2s_chan_handle_t i2s_rx_chan) { - esp_err_t ret = ESP_OK; +// Queue to communicate between recording task and ASR task +static QueueHandle_t asr_queue = NULL; - uint32_t byte_rate = I2S_SAMPLE_RATE * I2S_CHAN_NUM * I2S_SAMPLE_BITS / 8; - uint32_t wav_size = byte_rate * RECORD_TIME_SEC; +// Counter for total recordings expected and completed +static volatile uint32_t total_recordings_expected = 0; +static volatile uint32_t total_recordings_completed = 0; - const wav_header_t wav_header = WAV_HEADER_PCM_DEFAULT( - wav_size, I2S_SAMPLE_BITS, I2S_SAMPLE_RATE, I2S_CHAN_NUM); +// Structure to pass parameters to the recording task +typedef struct { + i2s_chan_handle_t i2s_rx_chan; + int loop_count; +} record_task_params_t; - get_file_name_from_time(); - ESP_LOGI(TAG, "Opening file %s", record_file_name); - FILE* f = fopen(record_file_name, "w"); - ESP_LOGI(TAG, "fopen error: %s", strerror(errno)); - ESP_RETURN_ON_FALSE(f, ESP_FAIL, TAG, "error while opening wav file"); +// Task for recording audio and saving to file +static void record_task(void* pvParameters) { + record_task_params_t* params = (record_task_params_t*)pvParameters; + i2s_chan_handle_t i2s_rx_chan = params->i2s_rx_chan; + int loop_count = params->loop_count; - ESP_RETURN_ON_FALSE(fwrite(&wav_header, sizeof(wav_header_t), 1, f), ESP_FAIL, - TAG, "error while writing wav header"); + // Free the parameters since they're no longer needed + free(params); - /* Start recording */ - size_t wav_written = 0; - static int16_t i2s_readraw_buff[DMA_BUF_LEN * sizeof(int16_t)]; ESP_ERROR_CHECK(i2s_channel_enable(i2s_rx_chan)); - while (wav_written < wav_size) { - if (wav_written % byte_rate < sizeof(i2s_readraw_buff)) { - ESP_LOGI(TAG, "Recording: %" PRIu32 "/%ds", wav_written / byte_rate + 1, - RECORD_TIME_SEC); + + for (int i = 0; i < loop_count; i++) { + ESP_LOGI(TAG, "Starting recording cycle %d/%d", i + 1, loop_count); + + esp_err_t ret = ESP_OK; + + uint32_t byte_rate = I2S_SAMPLE_RATE * I2S_CHAN_NUM * I2S_SAMPLE_BITS / 8; + uint32_t wav_size = byte_rate * RECORD_TIME_SEC; + + const wav_header_t wav_header = WAV_HEADER_PCM_DEFAULT( + wav_size, I2S_SAMPLE_BITS, I2S_SAMPLE_RATE, I2S_CHAN_NUM); + + get_file_name_from_time_now(); + ESP_LOGI(TAG, "Opening file %s", record_file_name); + FILE* f = fopen(record_file_name, "w"); + ESP_LOGI(TAG, "fopen error: %s", strerror(errno)); + if (f == NULL) { + ESP_LOGE(TAG, "error while opening wav file"); + continue; // Move to the next iteration + } + + if (fwrite(&wav_header, sizeof(wav_header_t), 1, f) != 1) { + ESP_LOGE(TAG, "error while writing wav header"); + fclose(f); + continue; // Move to the next iteration + } + + /* Start recording */ + size_t wav_written = 0; + static int16_t i2s_readraw_buff[DMA_BUF_LEN * sizeof(int16_t)]; + while (wav_written < wav_size) { + if (wav_written % byte_rate < sizeof(i2s_readraw_buff)) { + ESP_LOGI(TAG, "Recording: %" PRIu32 "/%ds", wav_written / byte_rate + 1, + RECORD_TIME_SEC); + } + size_t bytes_read = 0; + ESP_ERROR_CHECK(i2s_channel_read(i2s_rx_chan, i2s_readraw_buff, + sizeof(i2s_readraw_buff), &bytes_read, + pdMS_TO_TICKS(100))); + /* Write the samples to the WAV file */ + if (fwrite(i2s_readraw_buff, bytes_read, 1, f) != 1) { + ESP_LOGE(TAG, "error while writing samples to wav file"); + fclose(f); + continue; // Move to the next iteration + } + wav_written += bytes_read; + } + + ESP_LOGI(TAG, "Recording done! Flushing file buffer"); + fclose(f); + + // Send signal to ASR task with the recorded file name + char* file_name_copy = malloc(strlen(record_file_name) + 1); + if (file_name_copy != NULL) { + strcpy(file_name_copy, record_file_name); + + // Send the file name to the ASR queue + if (xQueueSend(asr_queue, &file_name_copy, portMAX_DELAY) != pdTRUE) { + ESP_LOGE(TAG, "Failed to send file name to ASR queue"); + free(file_name_copy); + } + } else { + ESP_LOGE(TAG, "Failed to allocate memory for file name copy"); + } + + ESP_LOGI(TAG, "Completed recording cycle %d/%d", i + 1, loop_count); + + // Optional: Add a small delay between recordings to ensure file operations + // complete + if (i < loop_count - 1) { + vTaskDelay(pdMS_TO_TICKS(500)); } - size_t bytes_read = 0; - ESP_ERROR_CHECK(i2s_channel_read(i2s_rx_chan, i2s_readraw_buff, - sizeof(i2s_readraw_buff), &bytes_read, - pdMS_TO_TICKS(100))); - /* Write the samples to the WAV file */ - ESP_RETURN_ON_FALSE(fwrite(i2s_readraw_buff, bytes_read, 1, f), ESP_FAIL, - TAG, "error while writing samples to wav file"); - wav_written += bytes_read; } i2s_channel_disable(i2s_rx_chan); - ESP_LOGI(TAG, "Recording done! Flushing file buffer"); - fclose(f); - send_audio_transcription(record_file_name); - return ret; + + // Delete this task as it's done + vTaskDelete(NULL); +} + +// Task for performing ASR processing +static void asr_task(void* pvParameters) { + char* received_file_name = NULL; + + while (1) { + // Wait for a file name from the recording task + if (xQueueReceive(asr_queue, &received_file_name, portMAX_DELAY) == + pdTRUE) { + if (received_file_name != NULL) { + // Check if this is a termination signal + if (strcmp(received_file_name, "TERMINATE") == 0) { + free(received_file_name); + break; // Exit the loop to terminate the task + } + + ESP_LOGI(TAG, "Received file for ASR: %s", received_file_name); + + // Perform ASR processing + send_audio_transcription(received_file_name); + + // Free the received file name + free(received_file_name); + received_file_name = NULL; + + // Increment the completed counter + total_recordings_completed++; + } + } + } + + // Task is terminating + vTaskDelete(NULL); +} + +esp_err_t record_wav(i2s_chan_handle_t i2s_rx_chan, int loop_count) { + // Reset counters + total_recordings_expected = loop_count; + total_recordings_completed = 0; + + // Create the queue if it doesn't exist + if (asr_queue == NULL) { + asr_queue = xQueueCreate( + loop_count + 2, + sizeof(char*)); // Queue size adjusted for expected recordings + if (asr_queue == NULL) { + ESP_LOGE(TAG, "Failed to create ASR queue"); + return ESP_FAIL; + } + } + + // Create the ASR processing task if it doesn't exist + static TaskHandle_t asr_task_handle = NULL; + if (asr_task_handle == NULL) { + BaseType_t task_ret = xTaskCreate(asr_task, "asr_task", 4096, NULL, + tskIDLE_PRIORITY + 2, &asr_task_handle); + if (task_ret != pdTRUE) { + ESP_LOGE(TAG, "Failed to create ASR task"); + return ESP_FAIL; + } + } + + // Prepare parameters for the recording task + record_task_params_t* params = malloc(sizeof(record_task_params_t)); + if (params == NULL) { + ESP_LOGE(TAG, "Failed to allocate memory for recording task parameters"); + return ESP_FAIL; + } + params->i2s_rx_chan = i2s_rx_chan; + params->loop_count = loop_count; + + // Create the recording task with parameters + TaskHandle_t record_task_handle = NULL; + BaseType_t task_ret = xTaskCreate(record_task, "record_task", 4096, params, + tskIDLE_PRIORITY + 3, &record_task_handle); + if (task_ret != pdTRUE) { + ESP_LOGE(TAG, "Failed to create recording task"); + free(params); + return ESP_FAIL; + } + + // Wait for the recording task to complete + while (record_task_handle != NULL) { + vTaskDelay(pdMS_TO_TICKS(100)); // Check every 100ms + + // Check if the recording task still exists + if (eTaskGetState(record_task_handle) == eDeleted) { + record_task_handle = NULL; + } + } + + // Wait for all ASR processing to complete + while (total_recordings_completed < total_recordings_expected) { + ESP_LOGI(TAG, "Waiting for ASR processing: %d/%d completed", + total_recordings_completed, total_recordings_expected); + vTaskDelay(pdMS_TO_TICKS(1000)); // Check every second + } + + return ESP_OK; } \ No newline at end of file diff --git a/main/record.h b/main/record.h index 20e256b..9936259 100644 --- a/main/record.h +++ b/main/record.h @@ -1,6 +1,6 @@ #include "base.h" -esp_err_t record_wav(i2s_chan_handle_t i2s_rx_chan); +esp_err_t record_wav(i2s_chan_handle_t i2s_rx_chan, int loop_count); void get_time_init(); esp_err_t print_current_time();