3. 音频流接口备用设置切换
任务说明
在USB音频设备中,同一音频流接口常需支持多种采样率与通道数组合(如48kHz/2ch与96kHz/2ch)。本案例实现备用设置(Alternate Setting)切换逻辑:当主机请求切换到特定设置号时,设备端动态更新当前采样率与通道数,并确保端点带宽描述符与所选设置匹配。
核心实现
// audio_if_alt_setting.h
#ifndef AUDIO_IF_ALT_SETTING_H
#define AUDIO_IF_ALT_SETTING_H
#include <stdint.h>
#define ALT_SETTING_COUNT 2
typedef struct {
uint8_t alt_setting_id; // 备用设置号(0=零带宽,1=48k/2ch,2=96k/2ch)
uint32_t sample_rate; // 采样率 Hz
uint8_t channel_count; // 通道数
uint16_t ep_max_packet; // 端点最大包字节数(按帧计算)
} audio_alt_setting_t;
// 音频流接口当前状态
typedef struct {
uint8_t active_alt; // 当前激活的备用设置号
uint32_t sample_rate;
uint8_t channel_count;
uint16_t ep_max_packet;
} audio_stream_state_t;
// 查询备用设置表(由具体设备实现)
const audio_alt_setting_t* audio_get_alt_table(void);
uint8_t audio_get_alt_count(void);
// 切换备用设置
int audio_switch_alt_setting(audio_stream_state_t* state, uint8_t alt_id);
#endif // AUDIO_IF_ALT_SETTING_H
// audio_if_alt_setting.c
#include "audio_if_alt_setting.h"
// 设备支持的备用设置表(实际设备可在此扩展)
static const audio_alt_setting_t alt_table[ALT_SETTING_COUNT] = {
{ .alt_setting_id = 1, .sample_rate = 48000, .channel_count = 2, .ep_max_packet = 192 }, // 48kHz, 2ch, 16bit
{ .alt_setting_id = 2, .sample_rate = 96000, .channel_count = 2, .ep_max_packet = 384 }, // 96kHz, 2ch, 16bit
};
const audio_alt_setting_t* audio_get_alt_table(void) {
return alt_table;
}
uint8_t audio_get_alt_count(void) {
return ALT_SETTING_COUNT;
}
int audio_switch_alt_setting(audio_stream_state_t* state, uint8_t alt_id) {
if (state == NULL) return -1;
if (alt_id == 0) {
// 零带宽设置:停止传输
state->active_alt = 0;
state->sample_rate = 0;
state->channel_count = 0;
state->ep_max_packet = 0;
return 0;
}
const audio_alt_setting_t* table = audio_get_alt_table();
uint8_t count = audio_get_alt_count();
for (uint8_t i = 0; i < count; i++) {
if (table[i].alt_setting_id == alt_id) {
state->active_alt = alt_id;
state->sample_rate = table[i].sample_rate;
state->channel_count = table[i].channel_count;
state->ep_max_packet = table[i].ep_max_packet;
return 0;
}
}
return -2; // 不支持的设置号
}
// 使用示例(主机请求切换设置时调用)
#include <stdio.h>
#include "audio_if_alt_setting.h"
int main(void) {
audio_stream_state_t stream = {0};
// 模拟主机请求切换到备用设置1(48kHz/2ch)
int ret = audio_switch_alt_setting(&stream, 1);
if (ret == 0) {
printf("切换到设置1: %lu Hz, %u ch, EP包=%u\n",
(unsigned long)stream.sample_rate, stream.channel_count, stream.ep_max_packet);
}
// 模拟切换到备用设置2(96kHz/2ch)
ret = audio_switch_alt_setting(&stream, 2);
if (ret == 0) {
printf("切换到设置2: %lu Hz, %u ch, EP包=%u\n",
(unsigned long)stream.sample_rate, stream.channel_count, stream.ep_max_packet);
}
// 模拟切换到零带宽(停止传输)
ret = audio_switch_alt_setting(&stream, 0);
if (ret == 0) {
printf("切换到设置0: 传输停止\n");
}
// 测试非法设置号
ret = audio_switch_alt_setting(&stream, 5);
if (ret != 0) {
printf("非法设置号返回: %d\n", ret);
}
return 0;
}
编译与运行
# 编译(Linux/macOS)
gcc -Wall -o alt_setting_test audio_if_alt_setting.c main.c
# 运行
./alt_setting_test
验证方法
程序输出应严格符合以下顺序与内容:
切换到设置1: 48000 Hz, 2 ch, EP包=192
切换到设置2: 96000 Hz, 2 ch, EP包=384
切换到设置0: 传输停止
非法设置号返回: -2
判定通过条件:
- 设置1与设置2切换后,
sample_rate、channel_count、ep_max_packet与表中定义完全一致; - 切换到设置0时所有状态清零;
- 请求不存在的设置号返回
-2且不改变当前状态。
USB集成说明
在实际USB音频设备中,audio_switch_alt_setting应在标准USB请求SET_INTERFACE的处理函数中被调用,传入的alt_id即请求中的bAlternateSetting值。切换成功后需同步更新端点描述符中的wMaxPacketSize,并重新配置FIFO/ DMA缓冲区以匹配新的采样率与通道数。零带宽设置(alt=0)用于释放总线带宽。