多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

TinyUSB 主机端 USB 音频采集与回放实战:基于 TUH_AUDIO 的 UAC1/UAC2 设备驱动示例解析

TinyUSB 主机端 USB 音频采集与回放实战:基于 TUH_AUDIO 的 UAC1/UAC2 设备驱动示例解析 嵌入式驱动开发通信物联网【免费下载链接】tinyusbAn open source cross-platform USB stack for embedded system项目地址https://gitcode.com/gh_mirrors/ti/tinyusb点击查看免费下载导读audio_host 示例是 TinyUSB 主机栈Host Stack中针对 USB Audio 类UAC 1.0 / UAC 2.0设备的高层驱动 TUH_AUDIO 的完整参考实现。它演示了如何用一套类似 WASAPI/ALSA 的帧级 FIFO API从 USB 麦克风采集 S16_LE 音频并回放到扬声器而应用层完全不接触 USB 接口、alternate setting 或端点地址——只按流索引stream index选择{格式, 采样率, 声道数}配置元组。读完本文你将掌握 TUH_AUDIO 的枚举/挂载流程、流配置与异步启停机制、基于 FIFO 的读写模型、音量/静音控制 API以及示例中三阶段仅麦克风 / 仅扬声器 / 回声切换的完整实现。示例目标与核心特性示例的运行效果是将 UAC 1.0 或 UAC 2.0 的 USB 音频设备麦克风、耳机、USB 声卡接入主机端口后板卡自动完成枚举、配置、启流并在三个 5 秒阶段间循环仅麦克风mic-only采集运行数据直接丢弃仅扬声器spk-only播放 1 kHz 正弦测试音回声echo采集数据回环到播放端形成实时回声。从 README 归纳的核心特性包括枚举并挂载 USB Audio Class 1.0 与 2.0 设备发现设备的逻辑流采集/播放及其支持的配置仅离散元组 discrete tuples报告每条流的静音/音量能力与缓存的音量范围配置并启动 S16_LE 采集流44.1 kHz 优先、48 kHz 兜底立体声优先、单声道可接受将采集音频回放到同采样率的 S16_LE 播放流优先同声道数否则做单/双声道转换帧级 FIFO API主循环在采集 FIFO 半满时读取、在播放 FIFO 半空时填充传输回调不参与 FIFO 服务用tuh_audio_start()/tuh_audio_stop()在三阶段间切换异步结果由tuh_audio_event_cb()打印失败的流在 100 ms 后自动重启。支持的设备与驱动边界设备兼容范围示例支持以下 UAC 设备UAC1 设备Type I Format 描述符必须列出离散采样频率bSamFreqType 0UAC2 设备使用直接连接的 Clock Source典型设备形态USB 麦克风、USB 耳机单声道麦克风 扬声器、USB 音频接口。回环功能要求设备存在与采集采样率匹配的 S16_LE 播放流没有播放流的设备退化为仅采集。采样率与声道偏好由 src/audio_app.c 中的宏控制#define AUDIO_MAX_CHANNELS 2 #define SAMPLE_RATES {44100, 48000} #define FEATURE_UNIT_VOLUME_DB (-20 * 256)默认即 44.1 kHz 立体声。非 PCM 格式会被驱动直接拒绝。已知限制与取舍驱动层从 README 的 Limitations and trade-offs 一节需要特别留意以下行为边界反馈端点feedback显式反馈端点支持 10.14 与 16.16 两种反馈值格式隐式反馈 IN 端点被当作普通音频数据端点处理不用于节拍播放节奏。UAC1 非离散频率bSamFreqType 0的 Type I Format 描述符不受支持驱动要求离散采样频率列表。UAC2 时钟拓扑仅支持直接 Clock SourceClock Selector、Clock Multiplier、采样率转换器SRC、Clock Validity 与 Valid Alternate Settings 控件均不处理。频率范围展开上限UAC2 采样频率 RANGE 响应最多展开为CFG_TUH_AUDIO_MAX_SAM_FREQ个离散配置只读 Clock Source 只暴露当前频率。音量控件发现master 静音与音量控制在挂载回调前完成探测。仅逻辑声道有音量的 Feature Unit 也被支持范围从第一个受控声道读取当不存在可写的 master 控件时流音量 SET 会写入所有逻辑声道。类型化 API 假设所有逻辑声道共用同一音量范围需要每声道独立范围的应用应改用底层tuh_audio_control_xfer()。UAC2 音量发现支持常见的单子区间 RANGE 响应。MaxPacketsOnly端点属性不受支持OUT 传输不按wMaxPacketSize补齐填充IN 传输中的填充也不会从上报的音频数据中剔除。构建与烧录CMake 方式推荐cd examples/host/audio_host mkdir -p build cd build cmake -DBOARDyour_board -G Ninja .. cmake --build .your_board替换为目标板卡名如raspberry_pi_pico、stm32f407disco等参考 hw/bsp 下的 board 定义。Make 方式cd examples/host/audio_host make BOARDyour_board all烧录# CMake 方式先列出板卡对应的 flash 目标再选择其一 ninja -t targets ninja audio_host-jlink # 例如支持 J-Link 的板卡 # Make 方式 make BOARDyour_board flash使用流程与运行行为构建并烧录示例到目标板将 USB 音频设备UAC 1.0 或 2.0接入 USB 主机端口打开串口终端观察输出示例将自动执行挂载时打印每条流的静音/音量能力、缓存的音量范围及支持的配置按首选采样率44.1 kHz 优先、48 kHz 兜底立体声优先、单声道可接受查找 S16_LE 采集配置并完成配置在同采样率的 S16_LE 播放配置上回放采集音频优先同声道数直通否则转换读取并解除麦克风/扬声器 Feature Unit 的静音把流音量设置为约 -6 dB仅声道级 Feature Unit 逐逻辑声道更新由audio_app_task()在 FIFO 半满/半空水位线处服务两条 FIFO无采集回环时播放 1 kHz 正弦测试音通过tuh_audio_start()/tuh_audio_stop()循环三个阶段各 5 秒异步结果由tuh_audio_event_cb()打印失败流 100 ms 后自动重启。串口输出示例README 给出的典型输出如下TinyUSB Host USB Audio Example Connect a USB Audio Device (UAC 1.0 or 2.0) to test Audio device mounted: idx0 addr1 capture stream 1, configurations: 2 master mute supported volume range: min-23040 max1536 res256 (1/256 dB) [0] format1 rate44100 channels2 [1] format1 rate48000 channels2 playback stream 0, configurations: 2 master mute supported volume range: min-23040 max1536 res256 (1/256 dB) [0] format1 rate44100 channels2 [1] format1 rate48000 channels2 Configuring 44100 S16_LE capture (2 channels) Microphone configured Microphone master mute: off Microphone master volume: 0 (1/256 dB) Microphone volume set: -1536 (1/256 dB) Configuring 44100 S16_LE playback (2 channels) Speaker configured Speaker master mute: off Speaker master volume: 0 (1/256 dB) Speaker volume set: -1536 (1/256 dB)注意volume range: min-23040 max1536 res256中的音量单位是1/256 dB因此-1536对应 -6 dB与FEATURE_UNIT_VOLUME_DB (-20 * 256)之外的实际设置目标一致示例设置为 -6 dB 级别源码中FEATURE_UNIT_VOLUME_DB定义于 audio_app.c会先被夹取到缓存音量范围内。配置项详解在 src/tusb_config.h 中可修改以下宏。以示例默认值为基准部分默认值定义于 audio_host.h宏示例默认值说明CFG_TUH_AUDIO_MAX1支持的最大音频设备数量对应驱动内部_audioh_itf[CFG_TUH_AUDIO_MAX]实例数组大小CFG_TUH_AUDIO_PROTOCOLSTUH_AUDIO_PROTOCOL_UAC1 \| TUH_AUDIO_PROTOCOL_UAC2编译进驱动的 UAC 协议位掩码示例同时启用 UAC1 与 UAC2CFG_TUH_AUDIO_MAX_SAM_FREQ5每个 alternate settingUAC1或 UAC2 Clock Source 保留的离散频率最大数量CFG_TUH_AUDIO_MAX_AS4每条逻辑流支持的、非零带宽的 Audio Streaming alternate setting 最大数量CFG_TUH_AUDIO_EPIN_BUFSIZE256驱动单次提交的采集IN等时传输最大字节数需要更大每轮询间隔包长的配置会被拒绝。256 可覆盖 2 声道 48 kHz S16_LE192 B及常见端点填充208 BCFG_TUH_AUDIO_EPOUT_BUFSIZE256驱动单次提交的播放OUT等时传输最大字节数CFG_TUH_AUDIO_STREAM_BUFSIZE1024每条流 FIFO 深度字节即 4 个 256 B 包采集 FIFO 满时覆盖最旧帧示例配置中还启用了CFG_TUH_ENABLED 1、CFG_TUH_AUDIO 1并关闭了 HUB/CDC/HID/MSC/VENDOR 等其他主机驱动CFG_TUH_DEVICE_MAX与 HUB 数量联动3 * CFG_TUH_HUB 1。CFG_TUH_AUDIO_EPIN_BUFSIZE/CFG_TUH_AUDIO_EPOUT_BUFSIZE在示例中均设为 256详见 tusb_config.h。驱动原理TUH_AUDIO 的挂载、配置与数据通路挂载期拓扑发现是异步的从 audio_host.c 顶部架构注释可知一个audioh_interface_t代表一个 Audio ControlAC接口且每个方向最多拥有一个逻辑流。挂载链路为USB 枚举 audioh_open() -- 校验并保留 AC 描述符区间 -- 对每个连续 AS 接口执行 audioh_parse_as() | -- 解析协议相关的 AS 与 Format 描述符 | -- 关联数据端点与可选反馈端点 | -- 保存 UAC1 频率列表或 UAC2 Clock Source 引用 -- audioh_link_feature_units() -- tuh_audio_descriptor_cb() audioh_set_config() -- UAC2: audioh_mount_clock_next() 读取 RANGE/CUR - 重建公共配置 -- audioh_mount_feature_unit_next() -- 音量 RANGE 完成 - tuh_audio_mount_cb()关键点设备只有在这些异步探测全部完成后才被报告为 mounted。UAC1 的采样率来自 Format Type 描述符UAC2 则需先向 Clock Source 发起 RANGE 控制请求查询。这也解释了示例为何把挂载后的初始化逻辑放在tuh_audio_mount_cb()中延迟 100 ms 执行的tuh_audio_mount_async()见 audio_app.c——此时音量范围等缓存已就绪。配置与启停本地配置、异步激活驱动把应用可见的配置看成扁平的{format, sample_rate, channels}元组列表内部通过audioh_stream_resolve_config()将公共元组解析回 AS alternate setting 与 rate source 索引。tuh_audio_configure()audio_host.c完成校验设备已挂载、流存在、配置可解析关闭上一配置的端点要求无传输在途初始化帧大小、FIFO 与播放调度器状态采集 FIFO 深度会向下取整为帧大小的整数倍保证覆盖overwrite模式帧安全打开数据端点播放流还会打开显式反馈端点。tuh_audio_start()的协议差异体现在激活顺序上audio_host.c 及audioh_stream_start_active()UAC1先SET_INTERFACE(非零 alt)再对端点执行采样率SET_CUR因为 UAC1 的频率控制目标就是端点UAC2先对可写 Clock Source 执行采样率CUR再SET_INTERFACE(非零 alt)。tuh_audio_start()/tuh_audio_stop()返回true只表示首个控制请求已提交整条链路的完成通过tuh_audio_event_cb()的TUH_AUDIO_EVENT_START_COMPLETE/TUH_AUDIO_EVENT_STOP_COMPLETE上报返回false时不会产生事件。tuh_audio_stop()通过SET_INTERFACE(alt 0)停流并停止本地传输再提交。数据通路一条在途传输 独立 FIFO 服务流启动后每次端点完成回调都准备并提交后继传输audioh_xfer_cb()链路采集IN把完整音频帧拷入带覆盖语义的 FIFO回调tuh_audio_capture_cb()再提交下一个 IN 传输播放OUT回调tuh_audio_playback_cb()计算下一个分数包大小Q16.16 帧率调度target_frames_q16跨反馈更新积分从 FIFO 读完整包或发送静音提交下一个 OUT 传输显式反馈校验并暂存 Q10.14 或 Q16.16 反馈值提交下一个反馈传输。驱动每流保持一条等时传输在途完成后重新提交因此传输节奏跟随端点的bInterval。tuh_audio_read()/tuh_audio_write()只访问流 FIFO无需在传输回调中执行示例正是让主循环中的audio_app_task()在 FIFO 半满/半空水位线处独立读写传输回调仅统计诊断计数mic_cb_count/spk_cb_count每秒经 led_blinking_task 打印清零。播放写满一包后若 FIFO 没有完整轮询间隔数据驱动会发送静音且不消耗不完整的部分数据。等时传输要求主机持续轮询tuh_task()见 main.c 主循环采集 FIFO 能吸收调度间隙并在满时覆盖最旧帧。帧级 API 与格式tuh_audio_stream_config_t定义于 audio_host.h即一个离散配置元组。示例中的选择逻辑audio_app.c按SAMPLE_RATES顺序、声道数从AUDIO_MAX_CHANNELS向下搜索 S16_LE 采集配置播放配置优先取与采集流相同的声道数直连回声否则取相反声道数做转换。采集与播放并发运行时同一 AC 实例内两条流必须使用相同采样率。示例内置的mono_to_stereo()/stereo_to_mono()就地转换audio_app.c展示了如何在不额外分配内存的情况下处理声道不匹配。正弦测试音由 spk_fill_sine 用 64 项查找表峰值 4096即约 -18 dBFS按实际播放声道数逐帧填充相位步进按(SINE_TONE_HZ 32) / sample_rate计算。回调与错误恢复模型TUH_AUDIO 提供以下应用回调均为 weak 弱实现见 audio_host.h回调触发时机示例中的用途tuh_audio_descriptor_cb()枚举期 AC 描述符校验通过后、挂载前需要原始实体控制的应用须在回调返回前拷贝实体 ID/描述符字段挂载后用tuh_audio_control_xfer()使用tuh_audio_mount_cb()全部探测完成后延迟 100 ms 后执行tuh_audio_mount_async()完成配置与启流tuh_audio_umount_cb()设备卸载清空延迟队列并复位流索引与使能标志tuh_audio_capture_cb()IN 传输完成仅统计计数FIFO 服务在主循环tuh_audio_playback_cb()OUT 传输完成、下一包准备前仅统计计数tuh_audio_event_cb()异步 start/stop 完成及不可恢复传输失败打印结果、计数失败、100 ms 后自动重启失败流错误恢复路径TUH_AUDIO_EVENT_XFER_FAILED表示 HCD 无法提交传输或传输以失败结束不是单个丢失等时包的提示驱动在上报失败前已停止该流。示例的tuh_audio_event_cb()audio_app.c把失败流的使能标志复位并通过自研的 4 槽位延迟调用队列app_defer_ms_async()在 100 ms 后调用audio_app_restart_stream()重新tuh_audio_start()驱动保留流配置因此 start 即恢复。整个队列无动态内存分配且挂载/卸载/阶段切换时会清理过期回调避免重启与阶段停止冲突。控制请求 API 补充除上述帧级 API 外audio_host.h 还提供底层原始实体控制tuh_audio_control_xfer()/tuh_audio_control_xfer_sync()按实体 ID 发起类特定请求类型化静音/音量tuh_audio_mute_get/set()、tuh_audio_volume_get/set()及其_sync同步变体音量语义TUH_AUDIO_VOLUME_SILENCEINT16_MIN表示静音SET 接受静音值或缓存范围内的值有限值按从范围最小值起的分辨率步进取整TUH_AUDIO_CHANNEL_MASTER0选 master 声道同步控制请求会阻塞至传输完成仅在流停止时使用否则会打乱流的等时传输并产生可闻的音频伪影。小结audio_host 是 TinyUSB 主机端音频能力的最小完整闭环从 UAC1/UAC2 描述符解析、Clock Source/Feature Unit 异步探测到{format, rate, channels}元组级配置、等时传输调度与帧级 FIFO 读写再到静音/音量控制与失败自动恢复。若需将此示例移植到自己的应用只需替换 audio_app.c 中的配置选择与数据消费逻辑例如改为写入 WAV 文件、经网络转发或做音频处理并依据目标设备在 tusb_config.h 中调整CFG_TUH_AUDIO_*系列参数即可。赞分享嵌入式驱动开发通信物联网【免费下载链接】tinyusbAn open source cross-platform USB stack for embedded system项目地址https://gitcode.com/gh_mirrors/ti/tinyusb点击查看免费下载相关推荐summarize 项目 OpenAI 模型接入指南模型 ID、Fast 服务层级、Thinking 与配置详解summarize 项目 OpenAI 模型接入指南模型 ID、Fast 服务层级、Thinking 与配置详解 本文是 summarize 项目中 Open嵌入式驱动开发通信物联网TinyUSB USB音频设备延迟优化UAC2同步机制实现TinyUSB USB音频设备延迟优化UAC2同步机制实现 1. USB音频开发痛点与解决方案 嵌入式开发者在实现USB音频设备时常面临三大挑战 音频卡顿嵌入式驱动开发通信物联网esp-iot-solution USB Device UAC 组件详解基于 TinyUSB 的 USB 音频设备驱动实践esp iot solution USB Device UAC 组件详解基于 TinyUSB 的 USB 音频设备驱动实践 usb_device_uac 是物联网嵌入式驱动开发硬件开发上一篇终极Windows系统优化工具Chris Titus Techs Windows Utility完全指南下一篇重新定义Windows系统管理体验的创新解决方案Chris Titus Techs Windows Utility深度解析创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表