Update record auto flow.

This commit is contained in:
Colin 2026-01-10 00:37:05 +08:00
parent f04bdac2af
commit 2a7d3f0d9e
4 changed files with 210 additions and 50 deletions

View File

@ -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));
}
// 清理

View File

@ -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};

View File

@ -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;
}

View File

@ -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();