3. 实现最小音频HAL模块骨架
任务说明
在音频HAL实现中,audio_hw_device结构体包含一个函数指针get_next_device,用于遍历系统中所有音频设备。本案例实现该函数,使其能够枚举系统中的音频设备(如扬声器、耳机、麦克风等),并为每个设备返回完整的描述信息(设备类型、设备ID、设备名称、采样率范围、通道掩码等)。
核心数据结构
// 设备描述结构体
typedef struct audio_device_description {
char device_id[32]; // 设备唯一标识
char device_name[64]; // 设备名称
audio_devices_t type; // 设备类型(扬声器/耳机/麦克风等)
uint32_t sample_rates; // 支持的采样率掩码
uint32_t channel_mask; // 支持的通道掩码
uint32_t formats; // 支持的音频格式掩码
} audio_device_description_t;
// 设备节点(链表节点)
typedef struct audio_device_node {
audio_device_description_t desc;
struct audio_device_node *next;
} audio_device_node_t;
// HAL设备结构体(简化)
typedef struct audio_hw_device {
// ... 其他成员
audio_device_node_t *device_list; // 设备链表头
audio_device_node_t *current; // 当前遍历位置
int (*get_next_device)(struct audio_hw_device *dev, audio_device_description_t *desc);
} audio_hw_device_t;
实现代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
// 音频设备类型定义(简化)
typedef enum {
AUDIO_DEVICE_OUT_SPEAKER = 0x2,
AUDIO_DEVICE_OUT_WIRED_HEADSET = 0x8,
AUDIO_DEVICE_IN_BUILTIN_MIC = 0x10000,
AUDIO_DEVICE_IN_WIRED_HEADSET = 0x20000
} audio_devices_t;
// 采样率掩码
#define SAMPLE_RATE_44100 (1 << 0)
#define SAMPLE_RATE_48000 (1 << 1)
// 通道掩码
#define CHANNEL_MONO 0x1
#define CHANNEL_STEREO 0x3
// 格式掩码
#define FORMAT_PCM_16BIT 0x1
#define FORMAT_PCM_24BIT 0x2
// 设备描述结构体
typedef struct audio_device_description {
char device_id[32];
char device_name[64];
audio_devices_t type;
uint32_t sample_rates;
uint32_t channel_mask;
uint32_t formats;
} audio_device_description_t;
// 设备节点
typedef struct audio_device_node {
audio_device_description_t desc;
struct audio_device_node *next;
} audio_device_node_t;
// HAL设备结构体
typedef struct audio_hw_device {
audio_device_node_t *device_list;
audio_device_node_t *current;
int (*get_next_device)(struct audio_hw_device *dev, audio_device_description_t *desc);
} audio_hw_device_t;
// 创建设备节点
static audio_device_node_t* create_device_node(
const char *id, const char *name, audio_devices_t type,
uint32_t rates, uint32_t channels, uint32_t formats) {
audio_device_node_t *node = (audio_device_node_t*)calloc(1, sizeof(audio_device_node_t));
if (!node) return NULL;
strncpy(node->desc.device_id, id, sizeof(node->desc.device_id) - 1);
strncpy(node->desc.device_name, name, sizeof(node->desc.device_name) - 1);
node->desc.type = type;
node->desc.sample_rates = rates;
node->desc.channel_mask = channels;
node->desc.formats = formats;
node->next = NULL;
return node;
}
// 初始化设备列表(模拟系统探测)
static void init_device_list(audio_hw_device_t *hw_dev) {
audio_device_node_t *speaker = create_device_node(
"out_speaker", "Builtin Speaker", AUDIO_DEVICE_OUT_SPEAKER,
SAMPLE_RATE_44100 | SAMPLE_RATE_48000, CHANNEL_STEREO, FORMAT_PCM_16BIT);
audio_device_node_t *headset_out = create_device_node(
"out_headset", "Wired Headset", AUDIO_DEVICE_OUT_WIRED_HEADSET,
SAMPLE_RATE_44100 | SAMPLE_RATE_48000, CHANNEL_STEREO, FORMAT_PCM_16BIT | FORMAT_PCM_24BIT);
audio_device_node_t *mic = create_device_node(
"in_builtin_mic", "Builtin Microphone", AUDIO_DEVICE_IN_BUILTIN_MIC,
SAMPLE_RATE_44100 | SAMPLE_RATE_48000, CHANNEL_MONO, FORMAT_PCM_16BIT);
audio_device_node_t *headset_in = create_device_node(
"in_headset_mic", "Headset Microphone", AUDIO_DEVICE_IN_WIRED_HEADSET,
SAMPLE_RATE_44100 | SAMPLE_RATE_48000, CHANNEL_MONO, FORMAT_PCM_16BIT);
// 构建链表:扬声器 -> 耳机输出 -> 内置麦克风 -> 耳机麦克风
hw_dev->device_list = speaker;
speaker->next = headset_out;
headset_out->next = mic;
mic->next = headset_in;
hw_dev->current = hw_dev->device_list;
}
// get_next_device 实现
static int get_next_device_impl(audio_hw_device_t *hw_dev, audio_device_description_t *desc) {
if (!hw_dev || !desc) return -1;
if (!hw_dev->current) return 0; // 遍历结束
// 拷贝当前设备描述
*desc = hw_dev->current->desc;
hw_dev->current = hw_dev->current->next;
return 1; // 返回1表示成功获取一个设备
}
// 释放设备链表
static void free_device_list(audio_hw_device_t *hw_dev) {
audio_device_node_t *node = hw_dev->device_list;
while (node) {
audio_device_node_t *next = node->next;
free(node);
node = next;
}
hw_dev->device_list = NULL;
hw_dev->current = NULL;
}
// 主函数:演示枚举过程
int main() {
audio_hw_device_t hw_dev;
memset(&hw_dev, 0, sizeof(hw_dev));
hw_dev.get_next_device = get_next_device_impl;
// 初始化设备列表
init_device_list(&hw_dev);
// 枚举所有设备
audio_device_description_t desc;
int count = 0;
printf("=== Audio Device Enumeration ===\n");
while (hw_dev.get_next_device(&hw_dev, &desc) > 0) {
count++;
printf("Device[%d]:\n", count);
printf(" ID: %s\n", desc.device_id);
printf(" Name: %s\n", desc.device_name);
printf(" Type: 0x%x\n", desc.type);
printf(" Rates: %s%s\n",
(desc.sample_rates & SAMPLE_RATE_44100) ? "44100 " : "",
(desc.sample_rates & SAMPLE_RATE_48000) ? "48000" : "");
printf(" ChMask: 0x%x\n", desc.channel_mask);
printf(" Format: 0x%x\n\n", desc.formats);
}
printf("Total devices: %d\n", count);
// 重置遍历位置(模拟重新枚举)
hw_dev.current = hw_dev.device_list;
printf("\n=== Second Enumeration (reset) ===\n");
count = 0;
while (hw_dev.get_next_device(&hw_dev, &desc) > 0) {
count++;
printf("Device[%d]: %s (%s)\n", count, desc.device_name, desc.device_id);
}
printf("Total devices: %d\n", count);
// 清理
free_device_list(&hw_dev);
return 0;
}
关键实现说明
- 链表结构:使用单向链表存储设备描述,
device_list指向链表头,current记录当前遍历位置。 - 遍历语义:
get_next_device每次调用返回当前设备描述并将current后移;返回0表示遍历结束,返回-1表示参数错误。 - 重置机制:将
current重新指向链表头即可开始新一轮枚举,符合HAL中重新扫描设备的需求。 - 设备描述:包含设备ID、名称、类型、采样率、通道掩码和格式掩码,覆盖了HAL层设备描述的核心字段。
编译与运行
gcc -o audio_enum audio_enum.c
./audio_enum
预期输出
=== Audio Device Enumeration ===
Device[1]:
ID: out_speaker
Name: Builtin Speaker
Type: 0x2
Rates: 44100 48000
ChMask: 0x3
Format: 0x1
Device[2]:
ID: out_headset
Name: Wired Headset
Type: 0x8
Rates: 44100 48000
ChMask: 0x3
Format: 0x3
Device[3]:
ID: in_builtin_mic
Name: Builtin Microphone
Type: 0x10000
Rates: 44100 48000
ChMask: 0x1
Format: 0x1
Device[4]:
ID: in_headset_mic
Name: Headset Microphone
Type: 0x20000
Rates: 44100 48000
ChMask: 0x1
Format: 0x1
Total devices: 4
=== Second Enumeration (reset) ===
Device[1]: Builtin Speaker (out_speaker)
Device[2]: Wired Headset (out_headset)
Device[3]: Builtin Microphone (in_builtin_mic)
Device[4]: Headset Microphone (in_headset_mic)
Total devices: 4
验证方法
运行程序后,观察输出是否包含4个设备且字段完整。验证要点:
- 第一次枚举输出4个设备,每个设备包含ID、名称、类型、采样率、通道掩码和格式掩码;
- 第二次枚举(重置后)同样输出4个设备,证明遍历位置可重置;
- 设备顺序与链表构建顺序一致(扬声器→耳机输出→内置麦克风→耳机麦克风);
- 当
current为NULL时,get_next_device返回0,循环正常终止。
判定标准
- 程序编译无错误,运行后输出4个设备的完整描述信息;
- 设备ID、名称、类型与
init_device_list中初始化数据完全一致; - 第二次枚举输出与第一次相同,证明
current重置机制有效; - 遍历结束后再次调用
get_next_device返回0,不会越界访问。