From bd270386573150ffad6c6a3839513cfcb0444a68 Mon Sep 17 00:00:00 2001 From: guojia'nan <1667869633@qq.com> Date: Thu, 4 Jul 2024 16:17:40 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AC=AC=E5=9B=9B=E6=AC=A1=E4=BD=9C=E4=B8=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 7/homework4/include/baidu_cloud.h | 8 + 7/homework4/include/http.h | 9 + 7/homework4/include/key1.h | 13 ++ 7/homework4/include/key_common.h | 7 + 7/homework4/include/record.h | 55 ++++++ 7/homework4/src/baidu_cloud.c | 96 +++++++++++ 7/homework4/src/http.c | 95 +++++++++++ 7/homework4/src/key1.c | 148 ++++++++++++++++ 7/homework4/src/key_common.c | 37 ++++ 7/homework4/src/main.c | 27 +++ 7/homework4/src/record.c | 273 ++++++++++++++++++++++++++++++ 11 files changed, 768 insertions(+) create mode 100644 7/homework4/include/baidu_cloud.h create mode 100644 7/homework4/include/http.h create mode 100644 7/homework4/include/key1.h create mode 100644 7/homework4/include/key_common.h create mode 100644 7/homework4/include/record.h create mode 100644 7/homework4/src/baidu_cloud.c create mode 100644 7/homework4/src/http.c create mode 100644 7/homework4/src/key1.c create mode 100644 7/homework4/src/key_common.c create mode 100644 7/homework4/src/main.c create mode 100644 7/homework4/src/record.c diff --git a/7/homework4/include/baidu_cloud.h b/7/homework4/include/baidu_cloud.h new file mode 100644 index 0000000..fd3af00 --- /dev/null +++ b/7/homework4/include/baidu_cloud.h @@ -0,0 +1,8 @@ +#ifndef _BAIDU_CLOUD_H_ +#define _BAIDU_CLOUD_H_ + +char *baidu_get_access_token(const char *api_key, const char *secret_key); +char *extract_result(const char *response); +char *baidu_recognize_speech(const char *filename, const char *token, long *response_code); + +#endif diff --git a/7/homework4/include/http.h b/7/homework4/include/http.h new file mode 100644 index 0000000..866c7d5 --- /dev/null +++ b/7/homework4/include/http.h @@ -0,0 +1,9 @@ +#ifndef _HTTP_H_ +#define _HTTP_H_ + +#include + +char *http_get(const char *url); +char *http_post(const char *url, const char *data, size_t data_size, long *response_code, const char *contentType); + +#endif diff --git a/7/homework4/include/key1.h b/7/homework4/include/key1.h new file mode 100644 index 0000000..7f19514 --- /dev/null +++ b/7/homework4/include/key1.h @@ -0,0 +1,13 @@ +#ifndef _KEY1_H_ +#define _KEY1_H_ + +/** + * 按键1控制录音 + * @param pcm_device: PCM设备名 + * @param channels: 声道数 + * @param sample_rate: 采样率 + * @param filename: 输出文件名 + */ +void key1_record_control(const char *pcm_device, unsigned int channels, unsigned int sample_rate, const char *filename); + +#endif // _KEY1_H_ diff --git a/7/homework4/include/key_common.h b/7/homework4/include/key_common.h new file mode 100644 index 0000000..7381214 --- /dev/null +++ b/7/homework4/include/key_common.h @@ -0,0 +1,7 @@ +#ifndef _KEY_COMMON_H_ +#define _KEY_COMMON_H_ +#include + +struct gpiod_line *gpio_init(const char *chip_label, unsigned int line_num, const char *consumer); + +#endif // _KEY_COMMON_H_ diff --git a/7/homework4/include/record.h b/7/homework4/include/record.h new file mode 100644 index 0000000..d8a16eb --- /dev/null +++ b/7/homework4/include/record.h @@ -0,0 +1,55 @@ +#ifndef _RECORD_H_ +#define _RECORD_H_ + +#include + +// 定义一个结构体来保存音频捕捉的状态 +typedef struct +{ + snd_pcm_t *pcm_handle; // PCM捕捉句柄 + FILE *output_file; // PCM输出文件句柄 + char *buffer; // 缓冲区 + snd_pcm_uframes_t period_size; // 缓冲区帧数 + volatile int recording; // 标志位,用于控制录音的开始和停止 + pthread_t thread; // 录音线程 +} audio_record_context_t; + +/** + * 初始化音频捕捉 + * @param pcm_device: PCM设备名称 + * @param channels: 声道数 + * @param sample_rate: 采样率 + * @param filename: 输出文件名称 + * @return: 音频捕捉上下文 + */ +audio_record_context_t *audio_record_init(const char *pcm_device, unsigned int channels, unsigned int sample_rate, const char *filename); + +/** + * 重新初始化音频捕捉 + * @param context: 音频捕捉上下文 + * @param pcm_device: PCM设备名称 + * @param channels: 声道数 + * @param sample_rate: 采样率 + * @param filename: 输出文件名称 + */ +void audio_record_reinit(audio_record_context_t *context, const char *pcm_device, unsigned int channels, unsigned int sample_rate, const char *filename); + +/** + * 开始录音 + * @param context: 音频捕捉上下文 + */ +void audio_record_start(audio_record_context_t *context); + +/** + * 停止录音 + * @param context: 音频捕捉上下文 + */ +void audio_record_stop(audio_record_context_t *context); + +/** + * 清理资源并安全退出程序 + * @param context: 音频捕捉上下文 + */ +void audio_record_cleanup(audio_record_context_t *context); + +#endif // _RECORD_H_ diff --git a/7/homework4/src/baidu_cloud.c b/7/homework4/src/baidu_cloud.c new file mode 100644 index 0000000..c8e78e3 --- /dev/null +++ b/7/homework4/src/baidu_cloud.c @@ -0,0 +1,96 @@ +#include "baidu_cloud.h" +#include "http.h" +#include +#include +#include +#include + +#define TOKEN_URL "https://aip.baidubce.com/oauth/2.0/token" +#define ASR_URL "https://vop.baidu.com/server_api" + +char *baidu_get_access_token(const char *api_key, const char *secret_key) { + char url[1024]; + snprintf(url, sizeof(url), "%s?grant_type=client_credentials&client_id=%s&client_secret=%s", TOKEN_URL, api_key, secret_key); + + char *response = http_get(url); + if (!response) { + fprintf(stderr, "Failed to get response for token request\n"); + return NULL; + } + + cJSON *json = cJSON_Parse(response); + if (!json) { + fprintf(stderr, "Failed to parse JSON from token response\n"); + free(response); + return NULL; + } + + cJSON *token = cJSON_GetObjectItem(json, "access_token"); + if (!token || !cJSON_IsString(token)) { + fprintf(stderr, "Access token not found in response\n"); + cJSON_Delete(json); + free(response); + return NULL; + } + + char *access_token = strdup(token->valuestring); + cJSON_Delete(json); + free(response); + return access_token; +} + +char *extract_result(const char *response) { + cJSON *json = cJSON_Parse(response); + if (!json) { + fprintf(stderr, "解析JSON失败\n"); + return NULL; + } + + cJSON *result = cJSON_GetObjectItemCaseSensitive(json, "result"); + if (!cJSON_IsArray(result) || cJSON_GetArraySize(result) == 0) { + cJSON_Delete(json); + fprintf(stderr, "结果数组不存在或为空\n"); + return NULL; + } + + // 提取第一个识别结果 + cJSON *first_result = cJSON_GetArrayItem(result, 0); + if (!cJSON_IsString(first_result)) { + cJSON_Delete(json); + fprintf(stderr, "结果格式错误\n"); + return NULL; + } + + char *recognition_result = strdup(first_result->valuestring); + cJSON_Delete(json); + return recognition_result; +} + +char *baidu_recognize_speech(const char *filename, const char *token, long *response_code) { + FILE *file = fopen(filename, "rb"); + if (!file) { + perror("Failed to open file for reading"); + return NULL; + } + + fseek(file, 0, SEEK_END); + size_t size = ftell(file); + rewind(file); + + char *data = malloc(size); + if (!data) { + fclose(file); + fprintf(stderr, "Failed to allocate memory for audio data\n"); + return NULL; + } + + fread(data, 1, size, file); + fclose(file); + + char url[1024]; + snprintf(url, sizeof(url), "%s?token=%s&cuid=7smartspeaker&dev_pid=1536", ASR_URL, token); + + char *response = http_post(url, data, size, response_code, "audio/pcm; rate=16000"); + free(data); + return response; +} diff --git a/7/homework4/src/http.c b/7/homework4/src/http.c new file mode 100644 index 0000000..e9a5943 --- /dev/null +++ b/7/homework4/src/http.c @@ -0,0 +1,95 @@ +#include "http.h" +#include +#include +#include +#include + +struct Memory { + char *response; + size_t size; +}; + +static size_t write_callback(void *contents, size_t size, size_t nmemb, void *userp) { + size_t real_size = size * nmemb; + struct Memory *mem = (struct Memory *)userp; + + char *ptr = realloc(mem->response, mem->size + real_size + 1); + if (!ptr) { + printf("Not enough memory (realloc returned NULL)\n"); + return 0; + } + + mem->response = ptr; + memcpy(&(mem->response[mem->size]), contents, real_size); + mem->size += real_size; + mem->response[mem->size] = '\0'; + return real_size; +} + +char *http_get(const char *url) { + CURL *curl; + CURLcode res; + struct Memory chunk = {0}; + + chunk.response = malloc(1); + chunk.size = 0; + + curl = curl_easy_init(); + if (curl) { + curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk); + + res = curl_easy_perform(curl); + if (res != CURLE_OK) { + fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); + free(chunk.response); + chunk.response = NULL; + } + + curl_easy_cleanup(curl); + } + + return chunk.response; +} + +char *http_post(const char *url, const char *data, size_t data_size, long *response_code, const char *contentType) { + CURL *curl; + CURLcode res; + struct Memory chunk = {0}; + + chunk.response = malloc(1); + chunk.size = 0; + + struct curl_slist *headers = NULL; + char content_type_header[128] = {0}; + sprintf(content_type_header, "Content-Type: %s", contentType); + headers = curl_slist_append(headers, content_type_header); + + curl = curl_easy_init(); + if (curl) { + curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_POST, 1L); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, data_size); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk); + + res = curl_easy_perform(curl); + if (res != CURLE_OK) { + fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); + free(chunk.response); + chunk.response = NULL; + } + + if (response_code) { + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, response_code); + } + + curl_easy_cleanup(curl); + curl_slist_free_all(headers); + } + + return chunk.response; +} diff --git a/7/homework4/src/key1.c b/7/homework4/src/key1.c new file mode 100644 index 0000000..d7cb776 --- /dev/null +++ b/7/homework4/src/key1.c @@ -0,0 +1,148 @@ +#include "key1.h" +#include "key_common.h" +#include "record.h" +#include +#include +#include + +#define GPIO_CHIP_LABEL "GPIOF" +#define GPIO_LINE 9 +#define CONSUMER "key1" +#define API_KEY "1sy2fb2e6j7dmZqX9siYj6aa" +#define SECRET_KEY "uj7d4Z2XmdhMvum6qEzOcbsEMxtTC1iX" + +typedef struct +{ + const char *pcm_device; + unsigned int channels; + unsigned int sample_rate; + const char *filename; +} key1_thread_args_t; + +/** + * 按键1录音控制线程函数 + * @param args: 线程参数 + * @return: NULL + */ +static void *key1_thread_func(void *args) +{ + key1_thread_args_t *thread_args = (key1_thread_args_t *)args; + + // 初始化音频捕捉上下文 + audio_record_context_t *context = audio_record_init(thread_args->pcm_device, thread_args->channels, thread_args->sample_rate, thread_args->filename); + if (!context) + { + fprintf(stderr, "初始化音频捕捉上下文失败\n"); + free(thread_args); // 释放内存 + return NULL; + } + + // 初始化GPIO按键 + struct gpiod_line *line = gpio_init(GPIO_CHIP_LABEL, GPIO_LINE, CONSUMER); + if (!line) + { + audio_record_cleanup(context); // 清理音频捕捉上下文 + free(thread_args); // 释放内存 + return NULL; + } + + pthread_detach(pthread_self()); // 在资源初始化后分离线程 + + // 获取初始按键状态 + int last_value = gpiod_line_get_value(line); + + // 获取百度云Access Token + char *token = baidu_get_access_token(API_KEY, SECRET_KEY); + + // 持续监控按键状态 + while (1) + { + int value = gpiod_line_get_value(line); + + if (value != last_value) + { + if (value == 0) + { + printf("按键按下,开始录音\n"); + audio_record_reinit(context, thread_args->pcm_device, thread_args->channels, thread_args->sample_rate, thread_args->filename); + audio_record_start(context); + } + else + { + printf("按键释放,停止录音\n"); + audio_record_stop(context); + + // 调用语音识别API + printf("开始语音识别...\n"); + long response_code = 0; // 初始化响应码 + char *recognition_result = baidu_recognize_speech(thread_args->filename, token, &response_code); + + if (recognition_result != NULL) + { + if (response_code == 200) + { + char *result = extract_result(recognition_result); + if (result) + { + printf("识别结果:%s\n", result); + free(result); + } + else + { + fprintf(stderr, "Failed to extract result\n"); + } + } + else + { + fprintf(stderr, "HTTP request failed with code %ld\n", response_code); + } + free(recognition_result); + } + else + { + fprintf(stderr, "Failed to recognize speech\n"); + } + free(recognition_result); + } + last_value = value; + } + usleep(100000); // 延迟100毫秒 + } + + // 关闭GPIO芯片 + gpiod_chip_close(gpiod_line_get_chip(line)); + audio_record_cleanup(context); // 清理音频捕捉上下文 + free(thread_args); // 释放内存 + return NULL; +} + +/** + * 按键1控制录音 + * @param pcm_device: PCM设备名 + * @param channels: 声道数 + * @param sample_rate: 采样率 + * @param filename: 输出文件名 + */ +void key1_record_control(const char *pcm_device, unsigned int channels, unsigned int sample_rate, const char *filename) +{ + pthread_t key1_thread; + key1_thread_args_t *args = (key1_thread_args_t *)malloc(sizeof(key1_thread_args_t)); + if (!args) + { + perror("内存分配失败"); + return; + } + + args->pcm_device = pcm_device; + args->channels = channels; + args->sample_rate = sample_rate; + args->filename = filename; + + // 创建按键1录音控制线程 + if (pthread_create(&key1_thread, NULL, key1_thread_func, args) != 0) + { + perror("创建按键1录音控制线程失败"); + free(args); // 如果线程创建失败,释放内存 + return; + } +} diff --git a/7/homework4/src/key_common.c b/7/homework4/src/key_common.c new file mode 100644 index 0000000..f72fc4e --- /dev/null +++ b/7/homework4/src/key_common.c @@ -0,0 +1,37 @@ +#include "key_common.h" +#include +#include + +/** + * 初始化GPIO芯片和线 + * @param chip_label: GPIO芯片标签 + * @param line_num: GPIO线号 + * @param consumer: 消费者名称 + * @return: 初始化成功返回GPIO线指针,失败返回NULL + */ +struct gpiod_line *gpio_init(const char *chip_label, unsigned int line_num, const char *consumer) +{ + struct gpiod_chip *chip = gpiod_chip_open_by_label(chip_label); + if (!chip) + { + perror("打开GPIO芯片失败!"); + return NULL; + } + + struct gpiod_line *line = gpiod_chip_get_line(chip, line_num); + if (!line) + { + perror("获取GPIO线失败!"); + gpiod_chip_close(chip); + return NULL; + } + + if (gpiod_line_request_input(line, consumer)) + { + perror("请求将GPIO线设置为输入模式失败!"); + gpiod_chip_close(chip); + return NULL; + } + + return line; +} diff --git a/7/homework4/src/main.c b/7/homework4/src/main.c new file mode 100644 index 0000000..32f16d6 --- /dev/null +++ b/7/homework4/src/main.c @@ -0,0 +1,27 @@ +#include "key1.h" +#include "key2.h" +#include "key3.h" +#include + +int main(void) +{ + const char *pcm_device = "hw:0,1"; + unsigned int channels = 2; + unsigned int sample_rate = 16000; + const char *filename = "output.pcm"; + + // 调用按键1录音控制函数 + key1_record_control(pcm_device, channels, sample_rate, filename); + // 调用按键2音量增加控制函数 + key2_control("hw:0", "PCM"); + // 调用按键3音量降低控制函数 + key3_control("hw:0", "PCM"); + + // 主线程保持运行状态 + while (1) + { + sleep(1); // 每秒钟睡眠一次 + } + + return 0; +} diff --git a/7/homework4/src/record.c b/7/homework4/src/record.c new file mode 100644 index 0000000..4f5eff8 --- /dev/null +++ b/7/homework4/src/record.c @@ -0,0 +1,273 @@ +#include "record.h" +#include +#include +#include + +#define PCM_FORMAT SND_PCM_FORMAT_S16_LE // PCM格式:16位小端 + +/** + * 清理资源并安全退出程序 + * @param context: 音频捕捉上下文 + */ +void audio_record_cleanup(audio_record_context_t *context) +{ + if (context->buffer) + { + free(context->buffer); // 释放缓冲区 + context->buffer = NULL; + } + if (context->output_file) + { + fclose(context->output_file); // 关闭文件 + context->output_file = NULL; + } + if (context->pcm_handle) + { + snd_pcm_drain(context->pcm_handle); // 清空PCM捕捉缓冲区 + snd_pcm_close(context->pcm_handle); // 关闭PCM设备 + context->pcm_handle = NULL; + } + free(context); // 释放上下文结构体 + printf("Record Complete!\n"); +} + +/** + * 配置PCM设备参数 + * @param context: 音频捕捉上下文 + * @param pcm_device: PCM设备名称 + * @param channels: 声道数 + * @param sample_rate: 采样率 + */ +static int audio_record_configure_pcm(audio_record_context_t *context, const char *pcm_device, unsigned int channels, unsigned int sample_rate) +{ + int err; + snd_pcm_hw_params_t *hw_params; + unsigned int rate = sample_rate; + int dir; + unsigned int actual_rate; + + // 打开PCM设备用于音频捕捉 + if ((err = snd_pcm_open(&context->pcm_handle, pcm_device, SND_PCM_STREAM_CAPTURE, 0)) < 0) + { + fprintf(stderr, "Error opening PCM device %s: %s\n", pcm_device, snd_strerror(err)); + return err; + } + + // 分配硬件参数对象 + snd_pcm_hw_params_alloca(&hw_params); + + // 初始化硬件参数结构体的默认值 + if ((err = snd_pcm_hw_params_any(context->pcm_handle, hw_params)) < 0) + { + fprintf(stderr, "Cannot initialize hardware parameter structure: %s\n", snd_strerror(err)); + return err; + } + + // 设置访问类型为交错模式 + if ((err = snd_pcm_hw_params_set_access(context->pcm_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) + { + fprintf(stderr, "Error setting access type: %s\n", snd_strerror(err)); + return err; + } + + // 设置PCM数据格式 + if ((err = snd_pcm_hw_params_set_format(context->pcm_handle, hw_params, PCM_FORMAT)) < 0) + { + fprintf(stderr, "Error setting format: %s\n", snd_strerror(err)); + return err; + } + + // 设置声道数 + if ((err = snd_pcm_hw_params_set_channels(context->pcm_handle, hw_params, channels)) < 0) + { + fprintf(stderr, "Error setting channels: %s\n", snd_strerror(err)); + return err; + } + + // 设置采样率 + if ((err = snd_pcm_hw_params_set_rate_near(context->pcm_handle, hw_params, &rate, &dir)) < 0) + { + fprintf(stderr, "Error setting sample rate: %s\n", snd_strerror(err)); + return err; + } + + // 设置硬件参数 + if ((err = snd_pcm_hw_params(context->pcm_handle, hw_params)) < 0) + { + fprintf(stderr, "Error setting hardware parameters: %s\n", snd_strerror(err)); + return err; + } + + // 获取周期大小(帧数) + snd_pcm_hw_params_get_period_size(hw_params, &context->period_size, &dir); + + // 获取实际的采样率 + snd_pcm_hw_params_get_rate(hw_params, &actual_rate, &dir); + + // 为捕获数据分配缓冲区 + context->buffer = (char *)malloc(snd_pcm_frames_to_bytes(context->pcm_handle, context->period_size)); + if (!context->buffer) + { + fprintf(stderr, "Cannot allocate buffer\n"); + return -ENOMEM; + } + + // 打印当前参数 + printf("PCM Device: %s\n", pcm_device); + printf("Channels: %u\n", channels); + printf("Sample Rate: %u Hz\n", actual_rate); + printf("Period Size: %lu frames\n", context->period_size); + + return 0; +} + +/** + * 打开输出文件 + * @param context: 音频捕捉上下文 + * @param filename: 输出文件名称 + */ +static int audio_record_open_output_file(audio_record_context_t *context, const char *filename) +{ + context->output_file = fopen(filename, "wb"); + if (!context->output_file) + { + fprintf(stderr, "Cannot open output file\n"); + return -ENOENT; + } + return 0; +} + +/** + * 录音线程函数 + * @param arg: 音频捕捉上下文 + */ +static void *audio_record_thread(void *arg) +{ + audio_record_context_t *context = (audio_record_context_t *)arg; + printf("Recording... Press Ctrl+C to stop.\n"); + while (context->recording) + { + int pcm = snd_pcm_readi(context->pcm_handle, context->buffer, context->period_size); + if (pcm == -EPIPE) + { + fprintf(stderr, "Overrun occurred\n"); + snd_pcm_prepare(context->pcm_handle); // 准备PCM设备 + } + else if (pcm < 0) + { + fprintf(stderr, "Error reading from PCM device: %s\n", snd_strerror(pcm)); + context->recording = 0; // 停止录音 + } + else + { + fwrite(context->buffer, snd_pcm_frames_to_bytes(context->pcm_handle, pcm), 1, context->output_file); + } + } + return NULL; +} + +/** + * 开始录音 + * @param context: 音频捕捉上下文 + */ +void audio_record_start(audio_record_context_t *context) +{ + if (context->recording) + { + printf("Recording is already in progress.\n"); + return; + } + context->recording = 1; // 设置录音标志位 + pthread_create(&context->thread, NULL, audio_record_thread, context); +} + +/** + * 停止录音 + * @param context: 音频捕捉上下文 + */ +void audio_record_stop(audio_record_context_t *context) +{ + if (!context->recording) + { + printf("Recording is not in progress.\n"); + return; + } + context->recording = 0; // 清除录音标志位 + pthread_join(context->thread, NULL); + if (context->output_file) + { + fclose(context->output_file); // 关闭文件 + context->output_file = NULL; + } +} + +/** + * 初始化音频捕捉 + * @param pcm_device: PCM设备名称 + * @param channels: 声道数 + * @param sample_rate: 采样率 + * @param filename: 输出文件名称 + * @return: 音频捕捉上下文 + */ +audio_record_context_t *audio_record_init(const char *pcm_device, unsigned int channels, unsigned int sample_rate, const char *filename) +{ + // 分配音频捕捉上下文结构体 + audio_record_context_t *context = (audio_record_context_t *)malloc(sizeof(audio_record_context_t)); + if (!context) + { + fprintf(stderr, "Cannot allocate audio_record_context_t\n"); + return NULL; + } + + // 初始化上下文的成员变量 + context->pcm_handle = NULL; + context->output_file = NULL; + context->buffer = NULL; + context->period_size = 0; + context->recording = 0; + + // 配置PCM设备参数 + if (audio_record_configure_pcm(context, pcm_device, channels, sample_rate) != 0) + { + free(context); + return NULL; + } + + return context; +} + +/** + * 重新初始化音频捕捉 + * @param context: 音频捕捉上下文 + * @param pcm_device: PCM设备名称 + * @param channels: 声道数 + * @param sample_rate: 采样率 + * @param filename: 输出文件名称 + */ +void audio_record_reinit(audio_record_context_t *context, const char *pcm_device, unsigned int channels, unsigned int sample_rate, const char *filename) +{ + if (context->buffer) + { + free(context->buffer); // 释放缓冲区 + context->buffer = NULL; + } + if (context->pcm_handle) + { + snd_pcm_drain(context->pcm_handle); // 清空PCM捕捉缓冲区 + snd_pcm_close(context->pcm_handle); // 关闭PCM设备 + context->pcm_handle = NULL; + } + + // 配置PCM设备参数 + if (audio_record_configure_pcm(context, pcm_device, channels, sample_rate) != 0) + { + free(context); + return; + } + + // 打开输出文件 + if (audio_record_open_output_file(context, filename) != 0) + { + audio_record_cleanup(context); + } +} -- Gitee