Browse Source

V0.9.1
1、完成了声卡录音相关的功能

Apple 2 days ago
parent
commit
96cfc1fcb7

+ 1 - 1
External

@@ -1 +1 @@
-Subproject commit 9b6c884563dfecf22d1bfd053ff92829af2493f1
+Subproject commit 03328e357ce4a7f94647a209b3553c1cbfc2a313

+ 425 - 0
demo/RecordAudio/AudioRecord.cpp

@@ -0,0 +1,425 @@
+#include "AudioRecord.h"
+#include "spdlog.h"
+
+
+#include <alsa/pcm.h>
+#include <chrono>
+#include <cstdint>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+#include "spdlog/spdlog.h"
+
+
+/* 获取声卡名称列表 */
+bool getAudioDevices(std::list<AudioDevice_t> &devices)
+{
+	snd_ctl_t *card_handle;
+	snd_ctl_card_info_t *info;
+	int card = -1;
+	while (snd_card_next(&card) >= 0 && card >= 0) 
+	{
+		char name[32];
+		snprintf(name, sizeof(name), "hw:%d", card);
+		
+		if (snd_ctl_open(&card_handle, name, 0) < 0) {
+			continue; // 无法打开声卡
+		}
+
+		snd_ctl_card_info_alloca(&info);
+		if (snd_ctl_card_info(card_handle, info) < 0) {
+			snd_ctl_close(card_handle);
+			continue; // 获取声卡信息失败
+		}
+		AudioDevice_t device;
+		/* 获取声卡信息 */
+		device.CardNumber = card;
+		device.CardID = snd_ctl_card_info_get_id(info);
+		device.CardName = snd_ctl_card_info_get_name(info);
+		device.CardDriver = snd_ctl_card_info_get_driver(info);
+		device.CardLongName = snd_ctl_card_info_get_longname(info);
+		device.CardMixername = snd_ctl_card_info_get_mixername(info);
+		device.CardComponents = snd_ctl_card_info_get_components(info);
+
+		/* 获取声卡中的所有pcm设备 */
+		snd_pcm_info_t *pcm_info;
+		snd_pcm_info_alloca(&pcm_info);
+		int pcmDevice = -1;
+		while(true)
+		{
+			if(snd_ctl_pcm_next_device(card_handle, &pcmDevice) < 0 || pcmDevice < 0) 
+			{
+				break; // 没有更多的PCM设备
+			}
+			snd_pcm_info_set_device(pcm_info, pcmDevice);
+			snd_pcm_info_set_subdevice(pcm_info, 0); // 获取主设备
+			snd_pcm_info_set_stream(pcm_info, SND_PCM_STREAM_CAPTURE); // 获取捕获设备信息
+
+			if(snd_ctl_pcm_info(card_handle, pcm_info) < 0) 
+			{
+				continue; // 获取PCM设备信息失败
+			}
+			PCMDevice_t pcmDeviceInfo;
+			pcmDeviceInfo.PCMDevice = snd_pcm_info_get_device(pcm_info);
+			pcmDeviceInfo.SubDevice = snd_pcm_info_get_subdevice(pcm_info);
+			pcmDeviceInfo.CardNumber = card;
+			pcmDeviceInfo.PCMID = snd_pcm_info_get_id(pcm_info);
+			pcmDeviceInfo.PCMName = snd_pcm_info_get_name(pcm_info);
+			pcmDeviceInfo.PCMSubName = snd_pcm_info_get_subdevice_name(pcm_info);
+
+			// 将PCM设备信息添加到声卡设备列表中
+			device.PCMDevices.push_back(pcmDeviceInfo);
+		}
+		
+		devices.push_back(device);
+
+		snd_ctl_close(card_handle);
+	}
+
+	return true;
+}
+
+bool getPCMAudioDevice(std::list<AudioDeviceDesc_t> &devices)
+{
+	void **hints;
+    int err = snd_device_name_hint(-1, "pcm", &hints);
+    if (err < 0) {
+        SPDLOG_ERROR("无法获取声卡设备信息: {}", snd_strerror(err));
+        return false;
+    }
+	if (hints == NULL) {
+		SPDLOG_ERROR("没有找到任何声卡设备");
+		return false;
+	}
+    void **n = hints;
+    while (*n != NULL) {
+        char *name = snd_device_name_get_hint(*n, "NAME"); // 设备字符
+        char *desc = snd_device_name_get_hint(*n, "DESC"); // 设备描述
+        char *ioid = snd_device_name_get_hint(*n, "IOID"); // 输入/输出类型
+		char *card = snd_device_name_get_hint(*n, "CARD"); // 声卡名称
+		char* devName = snd_device_name_get_hint(*n, "DEV"); /* 设备编号 */
+
+        if (name == nullptr)
+		{
+            continue; // 跳过没有名称的设备
+        }
+		AudioDeviceDesc_t deviceDesc;
+        deviceDesc.DeviceName = name;
+		deviceDesc.DeviceDesc = desc ? desc : "无描述";
+		deviceDesc.IOID = ioid ? ioid : "未知类型";
+		deviceDesc.Card = card ? card : "未知声卡";
+		deviceDesc.DevNum = devName ? devName : "未知设备编号";
+
+		devices.push_back(deviceDesc);
+
+        if (name) free(name);
+        if (desc) free(desc);
+        if (ioid) free(ioid);
+		if (card) free(card);
+		if (devName) free(devName);
+        n++;
+    }
+    snd_device_name_free_hint(hints);
+
+	return true;
+}
+
+// void record(std::string deviceName)
+// {
+// 	uint32_t sample_rate = 44100;
+// 	uint32_t channels = 2;
+// 	int i;
+// 	int err;
+
+// 	long unsigned int rframes = 44100; // 每次读取的帧数
+// 	short* buf = (short*)malloc(rframes * sizeof(short) * channels);
+// 	if (!buf) {
+// 		fprintf(stderr, "Failed to allocate buffer memory\n");
+// 		exit(1);
+// 	}
+// 	snd_pcm_t *capture_handle;
+// 	snd_pcm_hw_params_t *hw_params;
+
+// 	if ((err = snd_pcm_open (&capture_handle, deviceName.c_str(), SND_PCM_STREAM_CAPTURE, 0)) < 0) {
+// 		fprintf (stderr, "cannot open audio device %s (%s)\n", 
+// 			 deviceName.c_str(),
+// 			 snd_strerror (err));
+// 		exit (1);
+// 	}
+// 	/* 给参数分配内存 */
+// 	if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) {
+// 		fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n",
+// 			 snd_strerror (err));
+// 		exit (1);
+// 	}
+// 	/* 初始化硬件参数结构 */
+// 	if ((err = snd_pcm_hw_params_any (capture_handle, hw_params)) < 0) {
+// 		fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n",
+// 			 snd_strerror (err));
+// 		exit (1);
+// 	}
+// 	/* 设置硬件参数 */
+// 	if ((err = snd_pcm_hw_params_set_access (capture_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
+// 		fprintf (stderr, "cannot set access type (%s)\n",
+// 			 snd_strerror (err));
+// 		exit (1);
+// 	}
+// 	/* 设置采样格式 */
+// 	// SND_PCM_FORMAT_S16_LE: 16位小端格式
+// 	// SND_PCM_FORMAT_FLOAT_LE: 32位小端浮点格式
+// 	// SND_PCM_FORMAT_U8: 8位无符号格式
+// 	// SND_PCM_FORMAT_S32_LE: 32位小端整数格式
+// 	// SND_PCM_FORMAT_S24_LE: 24位小端整数格式
+// 	if ((err = snd_pcm_hw_params_set_format (capture_handle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0) {
+// 		fprintf (stderr, "cannot set sample format (%s)\n",
+// 			 snd_strerror (err));
+// 		exit (1);
+// 	}
+// 	/* 设置采样率 */
+// 	if ((err = snd_pcm_hw_params_set_rate_near (capture_handle, hw_params, &sample_rate, 0)) < 0) {
+// 		fprintf (stderr, "cannot set sample rate (%s)\n",
+// 			 snd_strerror (err));
+// 		exit (1);
+// 	}
+// 	/* 设置通道数 */
+// 	if ((err = snd_pcm_hw_params_set_channels (capture_handle, hw_params, channels)) < 0) {
+// 		fprintf (stderr, "cannot set channel count (%s)\n",
+// 			 snd_strerror (err));
+// 		exit (1);
+// 	}
+// 	/* 设置交错模式 */
+// 	err = snd_pcm_hw_params_set_access(capture_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
+// 	if (err < 0) {
+// 		fprintf(stderr, "cannot set interleaved mode (%s)\n", snd_strerror(err));
+// 		exit(1);
+// 	}
+// 	/* 设置周期大小 */
+// 	err = snd_pcm_hw_params_set_period_size(capture_handle, hw_params, 882, 0);
+// 	if (err < 0) {
+// 		fprintf(stderr, "cannot set period size (%s)\n", snd_strerror(err));
+// 		exit(1);
+// 	}
+// 	/* 设置缓冲区大小 */
+// 	err = snd_pcm_hw_params_set_buffer_size(capture_handle, hw_params, 8820);
+// 	if (err < 0) {
+// 		fprintf(stderr, "cannot set buffer size (%s)\n", snd_strerror(err));
+// 		exit(1);
+// 	}
+// 	/* 设置参数给声卡 */
+// 	if ((err = snd_pcm_hw_params (capture_handle, hw_params)) < 0) {
+// 		fprintf (stderr, "cannot set parameters (%s)\n",
+// 			 snd_strerror (err));
+// 		exit (1);
+// 	}
+// 	/* 释放参数内存 */
+// 	snd_pcm_hw_params_free (hw_params);
+
+// 	if ((err = snd_pcm_prepare (capture_handle)) < 0) {
+// 		fprintf (stderr, "cannot prepare audio interface for use (%s)\n",
+// 			 snd_strerror (err));
+// 		exit (1);
+// 	}
+// 	auto f1 = fopen("r1.wav", "wb");
+// 	if(!f1) {
+// 		fprintf(stderr, "Failed to open file for writing\n");
+// 		exit(1);
+// 	}
+// 	std::chrono::steady_clock::time_point start_time = std::chrono::steady_clock::now();
+// 	for (i = 0; i < 10; ++i) 
+// 	{
+// 		long unsigned int readNum;
+// 		start_time = std::chrono::steady_clock::now();
+// 		if ((readNum = snd_pcm_readi (capture_handle, buf, rframes)) != rframes) {
+// 			fprintf (stderr, "read from audio interface failed (%s)\n",
+// 				 snd_strerror (readNum));
+// 			exit (1);
+// 		}
+// 		auto end_time = std::chrono::steady_clock::now();
+// 		auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time);
+// 		SPDLOG_DEBUG("第 {} 次录音,读取数据量: {} 帧,{} 字节,耗时: {} 毫秒", i + 1, readNum, readNum, duration.count());
+
+// 		if (fwrite(buf, sizeof(short), readNum * 2, f1) != readNum * 2) {
+// 			fprintf(stderr, "Failed to write data to file\n");
+// 			fclose(f1);
+// 			exit(1);
+// 		}
+// 	}
+// 	fclose(f1);
+
+// 	snd_pcm_close (capture_handle);
+// 	free(buf);
+// 	printf("录音完成,数据已保存到 r1.wav\n");
+
+// 	exit (0);
+// }
+
+
+
+
+/**
+ * @brief Set the Record Params object
+ * 
+ * @param sampleRate 采样率
+ * @param bits 位深度,支持8位,16位,24位,32位
+ * @param channels 通道数
+ */
+void AudioRecord::setRecordParams(int sampleRate, int bits, int channels)
+{
+	m_sampleRate = sampleRate;
+	m_bitDepth = bits;
+	m_channels = channels;
+	m_oneSampleSize = (m_bitDepth / 8) * m_channels; // 单个采样点的大小,单位字节
+}
+
+
+/* 打开录音通道 */
+bool AudioRecord::openRecordChannel(const std::string &deviceName)
+{
+	m_deviceName = deviceName;
+	/* 计算缓冲区大小和周期大小
+	 * 周期大小是指一个周期有多少个采样点,缓冲区大小是周期大小 * 周期个数,这里不需要设置周期个数
+	 * 直接设置缓冲区大小,系统会自动计算周期个数,缓冲区是个环形队列
+	 * 周期大小最好设置成可以被采样率的整数除尽,每次取出1秒数据的时候,间隔相差时间最短 */
+	snd_pcm_uframes_t buffer_size = m_sampleRate / 5; 		// 设置缓冲区大小为采样率的1/5秒
+	snd_pcm_uframes_t period_size = buffer_size / 10;	 	// 设置周期大小为缓冲区大小的1/10秒
+
+	_snd_pcm_format bit_frame = _snd_pcm_format::SND_PCM_FORMAT_UNKNOWN;
+	if(m_bitDepth == 8)
+	{
+		bit_frame = SND_PCM_FORMAT_S8; // 8位采样格式
+	}
+	else if (m_bitDepth == 16)
+	{
+		bit_frame = SND_PCM_FORMAT_S16_LE; // 16位小端格式
+	}
+	else if (m_bitDepth == 24)
+	{
+		bit_frame = SND_PCM_FORMAT_S24_LE; // 24位小端格式
+	}
+	else if (m_bitDepth == 32)
+	{
+		bit_frame = SND_PCM_FORMAT_S32_LE; // 32位小端格式
+	}
+	else
+	{
+		SPDLOG_ERROR("不支持的采样位深度: {}", m_bitDepth);
+		return false;
+	}
+
+	snd_pcm_hw_params_t *hw_params;
+	int err;
+	/* 打开声卡设备 */
+	if ((err = snd_pcm_open(&m_captureHandle, deviceName.c_str(), SND_PCM_STREAM_CAPTURE, 0)) < 0) {
+		SPDLOG_ERROR("无法打开音频设备 {}: {}", deviceName, snd_strerror(err));
+		return false;
+	}
+	/* 分配硬件参数结构 */
+	if ((err = snd_pcm_hw_params_malloc(&hw_params)) < 0) {
+		SPDLOG_ERROR("无法分配硬件参数结构: {}", snd_strerror(err));
+		snd_pcm_close(m_captureHandle);
+		return false;
+	}
+	/* 初始化硬件参数结构 */
+	if ((err = snd_pcm_hw_params_any(m_captureHandle, hw_params)) < 0) {
+		SPDLOG_ERROR("无法初始化硬件参数结构: {}", snd_strerror(err));
+		goto snd_free;
+		return false;
+	}
+	/* 设置访问类型 */
+	if ((err = snd_pcm_hw_params_set_access(m_captureHandle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
+		SPDLOG_ERROR("无法设置访问类型: {}", snd_strerror(err));
+		goto snd_free;
+		return false;
+	}
+	/* 设置采样格式 */
+	if ((err = snd_pcm_hw_params_set_format(m_captureHandle, hw_params, bit_frame)) < 0) {
+		SPDLOG_ERROR("无法设置采样格式: {}", snd_strerror(err));
+		goto snd_free;
+		return false;
+	}
+	/* 设置采样率 */
+	if ((err = snd_pcm_hw_params_set_rate(m_captureHandle, hw_params, m_sampleRate, 0)) < 0) {
+		SPDLOG_ERROR("无法设置采样率: {}", snd_strerror(err));
+		goto snd_free;
+		return false;
+	}
+	/* 设置通道数 */
+	if ((err = snd_pcm_hw_params_set_channels(m_captureHandle, hw_params, m_channels)) < 0) {
+		SPDLOG_ERROR("无法设置通道数: {}", snd_strerror(err));
+		goto snd_free;
+		return false;
+	}
+	/* 设置缓冲区大小 */
+	if ((err = snd_pcm_hw_params_set_buffer_size(m_captureHandle, hw_params, buffer_size)) < 0) {
+		SPDLOG_ERROR("无法设置缓冲区大小: {}", snd_strerror(err));
+		goto snd_free;
+		return false;
+	}
+	/* 设置周期大小 */
+	if ((err = snd_pcm_hw_params_set_period_size(m_captureHandle, hw_params, period_size, 0)) < 0) {
+		SPDLOG_ERROR("无法设置周期大小: {}", snd_strerror(err));
+		goto snd_free;
+		return false;
+	}
+	/* 应用硬件参数 */
+	if ((err = snd_pcm_hw_params(m_captureHandle, hw_params)) < 0) {
+		SPDLOG_ERROR("无法应用硬件参数: {}", snd_strerror(err));
+		goto snd_free;
+		return false;
+	}
+	/* 释放硬件参数结构 */
+	snd_pcm_hw_params_free(hw_params);
+	/* 准备PCM设备 */
+	if ((err = snd_pcm_prepare(m_captureHandle)) < 0) {
+		SPDLOG_ERROR("无法准备PCM设备: {}", snd_strerror(err));	
+		snd_pcm_close(m_captureHandle);
+		return false;
+	}
+
+	return true;
+
+snd_free:
+	snd_pcm_hw_params_free(hw_params);
+	snd_pcm_close(m_captureHandle);
+	return false;
+}
+
+/**
+ * @brief 读取录音大小
+ * 
+ * @param buffer 数据缓冲区指针
+ * @param bufferSize 缓冲区大小,缓冲区大小需要大于等于 recordFrames * 单个采样点的大小
+ *                   例如:44100帧 * 2通道 * 2字节
+ * @param recordFrames 需要读取的帧数,一帧就是一个采样点,16bit / 2 * 2 通道 = 4字节
+ *                     44100帧就是1秒
+ * @return uint32_t 读取到的字节数
+ */
+int AudioRecord::recordAudio(char* buffer, uint32_t bufferSize, uint32_t recordFrames)
+{
+	if(m_captureHandle == nullptr) 
+	{
+		SPDLOG_WARN("PCM设备未打开,请先调用 openAudioChannel 打开设备");
+		return -1;
+	}
+	if (buffer == nullptr || bufferSize == 0) 
+	{
+		SPDLOG_WARN("缓冲区指针为空或缓冲区大小为0");
+		return -1;
+	}
+	if(recordFrames * m_oneSampleSize > bufferSize) 
+	{
+		SPDLOG_ERROR("缓冲区大小不足,无法存储 {} 帧数据", recordFrames);
+		return -1;
+	}
+	auto readFrames = snd_pcm_readi(m_captureHandle, buffer, recordFrames);
+	if (readFrames < 0)
+	{
+		SPDLOG_ERROR("获取录音数据失败: {}", snd_strerror(readFrames));
+		return -1;
+	}
+	
+	return readFrames * m_oneSampleSize; // 返回读取到的字节数
+}
+
+

+ 107 - 0
demo/RecordAudio/AudioRecord.h

@@ -0,0 +1,107 @@
+#ifndef AUDIORECORD_H
+#define AUDIORECORD_H
+
+
+#include <cstdint>
+#include <list>
+#include <string>
+
+#include <alsa/asoundlib.h>
+#include <alsa/pcm.h>
+
+
+/* 声卡的PCM信息结构体 */
+struct PCMDevice_t
+{
+    unsigned int PCMDevice;         /* PCM设备编号,打开的设备编号就是这个 */
+    unsigned int SubDevice;         /* 子设备编号 */
+    int CardNumber;                 /* 声卡编号 */
+    std::string PCMID;              /* 声卡ID */
+    std::string PCMName;            /* 声卡名称 */
+    std::string PCMSubName;         /* 子设备名称 */
+};
+
+/**
+ * @brief 声卡设备信息结构体
+ * 
+ */
+struct AudioDevice_t
+{
+    int CardNumber;                 /* 声卡编号,打开录音的设备编号是这个 */
+    std::string CardID;             /* 声卡ID */
+    std::string CardName;           /* 声卡名称 */
+    std::string CardDriver;         /* 驱动名称 */
+    std::string CardLongName;       /* 声卡长名称 */
+    std::string CardMixername;      /* 混音器名称 */
+    std::string CardComponents;     /* 组件信息 */
+    std::list<PCMDevice_t> PCMDevices; /* PCM设备列表 */
+};
+
+
+/**
+ * @brief 直接获取到的声卡通道描述符信息,可以直接用来打开
+ * 
+ */
+struct AudioDeviceDesc_t
+{
+    std::string DeviceName;         /* 设备字符名称,可以直接打开 */
+    std::string DeviceDesc;         /* 设备描述 */
+    std::string IOID;               /* 输入/输出类型 */
+    std::string Card;               /* 声卡编号或标识,可能会没有 */
+    std::string DevNum;             /* 设备编号,可能会没有 */
+};
+
+
+/* 获取声卡信息列表,包括可以用来录音的PCM列表 */
+bool getAudioDevices(std::list<AudioDevice_t> &devices);
+/* 获取声卡字符设备名称,可以直接被打开 */
+bool getPCMAudioDevice(std::list<AudioDeviceDesc_t> &devices);
+
+
+/**
+ * @brief 录音类
+ * 
+ */
+class AudioRecord
+{
+
+public:
+    AudioRecord() = default;
+    ~AudioRecord() = default;
+
+    /**
+     * @brief Set the Record Params object
+     * 
+     * @param sampleRate 采样率
+     * @param bits 位深度
+     * @param channels 通道数
+     */
+    void setRecordParams(int sampleRate = 44100, int bits = 16, int channels = 2);
+    /* 打开录音通道,通常的格式: "hw:0:0" */
+    bool openRecordChannel(const std::string &deviceName);
+
+    /**
+     * @brief 读取录音大小
+     * 
+     * @param buffer 数据缓冲区
+     * @param bufferSize 缓冲区大小
+     * @param recordFrames 需要读取的帧数,一帧就是一个采样点,16bit / 2 * 2 通道 = 4字节
+     *                     44100帧就是1秒
+     * @return int 读取到的字节数
+     */
+    int recordAudio(char* buffer, uint32_t bufferSize, uint32_t recordFrames);
+
+private:
+    uint32_t m_sampleRate = 44100;      /* 默认采样率 */
+    int m_bitDepth = 16;                /* 默认位深度 */
+    int m_channels = 2;                 /* 默认通道数 */
+    int m_oneSampleSize = 2;            /* 单个采样点的大小,默认16位小端格式,2字节 */
+    std::string m_deviceName;           /* 设备名称,打开的设备名称 */
+
+    snd_pcm_t* m_captureHandle = nullptr; /* PCM设备句柄 */
+    
+};
+
+
+
+#endif // AUDIORECORD_H

+ 0 - 86
demo/RecordAudio/RecordAudio.cpp

@@ -1,86 +0,0 @@
-#include "RecordAudio.h"
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <alsa/asoundlib.h>
-
-
-void record(int argc, char *argv[])
-{
-	uint32_t sample_rate = 44100;
-	uint32_t channels = 2;
-	int i;
-	int err;
-	short buf[128];
-	snd_pcm_t *capture_handle;
-	snd_pcm_hw_params_t *hw_params;
-
-	if ((err = snd_pcm_open (&capture_handle, argv[1], SND_PCM_STREAM_CAPTURE, 0)) < 0) {
-		fprintf (stderr, "cannot open audio device %s (%s)\n", 
-			 argv[1],
-			 snd_strerror (err));
-		exit (1);
-	}
-	   
-	if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) {
-		fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n",
-			 snd_strerror (err));
-		exit (1);
-	}
-			 
-	if ((err = snd_pcm_hw_params_any (capture_handle, hw_params)) < 0) {
-		fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n",
-			 snd_strerror (err));
-		exit (1);
-	}
-
-	if ((err = snd_pcm_hw_params_set_access (capture_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
-		fprintf (stderr, "cannot set access type (%s)\n",
-			 snd_strerror (err));
-		exit (1);
-	}
-
-	if ((err = snd_pcm_hw_params_set_format (capture_handle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0) {
-		fprintf (stderr, "cannot set sample format (%s)\n",
-			 snd_strerror (err));
-		exit (1);
-	}
-
-	if ((err = snd_pcm_hw_params_set_rate_near (capture_handle, hw_params, &sample_rate, 0)) < 0) {
-		fprintf (stderr, "cannot set sample rate (%s)\n",
-			 snd_strerror (err));
-		exit (1);
-	}
-
-	if ((err = snd_pcm_hw_params_set_channels (capture_handle, hw_params, 2)) < 0) {
-		fprintf (stderr, "cannot set channel count (%s)\n",
-			 snd_strerror (err));
-		exit (1);
-	}
-
-	if ((err = snd_pcm_hw_params (capture_handle, hw_params)) < 0) {
-		fprintf (stderr, "cannot set parameters (%s)\n",
-			 snd_strerror (err));
-		exit (1);
-	}
-
-	snd_pcm_hw_params_free (hw_params);
-
-	if ((err = snd_pcm_prepare (capture_handle)) < 0) {
-		fprintf (stderr, "cannot prepare audio interface for use (%s)\n",
-			 snd_strerror (err));
-		exit (1);
-	}
-
-	for (i = 0; i < 10; ++i) {
-		if ((err = snd_pcm_readi (capture_handle, buf, 128)) != 128) {
-			fprintf (stderr, "read from audio interface failed (%s)\n",
-				 snd_strerror (err));
-			exit (1);
-		}
-	}
-
-	snd_pcm_close (capture_handle);
-	exit (0);
-}

+ 0 - 7
demo/RecordAudio/RecordAudio.h

@@ -1,7 +0,0 @@
-#ifndef RECORDAUDIO_H
-#define RECORDAUDIO_H
-
-
-void record(int argc, char *argv[]);
-
-#endif // RECORDAUDIO_H

+ 53 - 2
demo/RecordAudio/main.cpp

@@ -1,9 +1,11 @@
 #include <QApplication>
 #include "Logs/loginit.h"
+#include "bundled/core.h"
 #include "spdlog/spdlog.h"
 
-#include "RecordAudio.h"
+#include "AudioRecord.h"
 
+#include <fstream>
 
 
 
@@ -15,7 +17,56 @@ int main(int argc, char *argv[])
 
     SPDLOG_INFO("********** RecordAudio **********");
 
-    record(argc, argv);
+    std::list<AudioDevice_t> audioDevices;
+    getAudioDevices(audioDevices);
+    SPDLOG_INFO("可用的声卡设备:");
+    for (const auto &device : audioDevices) {
+        SPDLOG_INFO("声卡编号: {}, ID: {}, 名称: {}, 驱动: {}, 长名称: {}, 混音器名称: {}, 组件信息: {}",
+                    device.CardNumber, device.CardID, device.CardName, device.CardDriver,
+                    device.CardLongName, device.CardMixername, device.CardComponents);
+        for (const auto &pcmDevice : device.PCMDevices) {
+            SPDLOG_INFO("  PCM设备编号: {}, 子设备编号: {}, 声卡ID: {}, 名称: {}, 子设备名称: {}",
+                        pcmDevice.PCMDevice, pcmDevice.SubDevice, pcmDevice.PCMID,
+                        pcmDevice.PCMName, pcmDevice.PCMSubName);
+        }
+    }
+    SPDLOG_INFO("********** 获取声卡设备列表完成 **********");
+    std::list<AudioDeviceDesc_t> audioDeviceDescs;
+    getPCMAudioDevice(audioDeviceDescs);
+
+    SPDLOG_INFO("可用的声卡字符设备:");
+    for (const auto &deviceDesc : audioDeviceDescs) {
+        SPDLOG_INFO("设备名称: {}, 描述: {}, IOID: {}, 声卡: {}, 设备编号: {}",
+                    deviceDesc.DeviceName, deviceDesc.DeviceDesc,
+                    deviceDesc.IOID, deviceDesc.Card, deviceDesc.DevNum);
+    }
+    SPDLOG_INFO("********** 获取声卡字符设备列表完成 **********");
+
+    AudioRecord audioRecord;
+    std::string deviceName = fmt::format("hw:{},{}", audioDevices.front().CardNumber, audioDevices.front().PCMDevices.front().PCMDevice);
+    audioRecord.setRecordParams(44100, 16, 2); // 设置采样率为44100Hz,16位深度,2通道
+    if (!audioRecord.openRecordChannel(deviceName)) {
+        SPDLOG_ERROR("无法打开音频通道: {}", deviceName);
+        return -1;
+    }
+    std::ofstream outFile("recorded_audio.raw", std::ios::binary | std::ios::out | std::ios::trunc);
+    if (!outFile.is_open()) {
+        SPDLOG_ERROR("无法打开输出文件: recorded_audio.raw");
+        return -1;
+    }
+    for(int i = 0; i < 10; ++i) { // 录制10秒
+        char buffer[44100 * 2 * 2]; // 1秒的缓冲区大小,44100帧 * 2通道 * 2字节
+        int bytesRead = audioRecord.recordAudio(buffer, sizeof(buffer), 44100);
+        if (bytesRead < 0) {
+            SPDLOG_ERROR("录音失败");
+            outFile.close();
+            return -1;
+        }
+        outFile.write(buffer, bytesRead);
+        SPDLOG_INFO("已录制 {} 秒音频", i + 1);
+    }
+    outFile.close();
+    SPDLOG_INFO("录音完成,音频数据已保存到 recorded_audio.raw");
 
     return a.exec();
 }