linux设备UAC配置
在USB协议和嵌入式开发中,Gadget UAC 是 USB Audio Class(UAC)
在USB Gadget
框架下的实现。它允许设备通过USB接口模拟音频设备(如麦克风、扬声器或声卡),与主机(如PC)进行音频数据传输。
一、Gadget UAC的核心概念
USB Gadget框架
USB Gadget
是Linux内核中的一种驱动模型,用于将嵌入式设备配置为USB
从设备(如U盘、键盘、声卡等)。
通过动态配置(如ConfigFS),开发者可以灵活定义设备的功能,例如同时支持音频传输(UAC)和调试(ADB)。
USB Audio Class(UAC)
UAC是USB协议中定义的音频设备标准,分为UAC1
(兼容USB Audio 1.0
规范)和UAC2
(支持更高音质和功能,如多声道、高采样率)。
在Gadget模式下,嵌入式Linux设备可通过UAC协议将自身模拟为USB麦克风、扬声器或全双工声卡,实现音频输入输出功能。
简单来说就是完成设备端UAC的配置之后,将设备通过USB口插入到电脑上,电脑会直接将其视为一个音频输入/出设备,电脑播放音频信息时,会将音频信息发送到USB声卡中,设备端写一个程序直接读声卡的音频数据就能得到电脑端播放的音频数据。同类,设备端向USB声卡中写入数据,电脑端就可以直接读出后播放了。可以将这个USB声卡视为设备与电脑双方互发音频数据的桥梁。
二、UAC的实现
需要内核先使能两个选项
Location:-> Device Drivers-> USB support-> USB Gadget Support-> Audio Class 1.0-> Audio Class 2.0
UAC的配置脚本(RK平台)
可查看RK的官方文档信息:
https://github.com/mfkiwl/rk-open-docs/blob/master/USB/Rockchip_Developer_Guide_USB_Gadget_UAC_CN.md
一下是配置脚本文件:
#!/bin/sh
#
# setup configfs for adbd, usb mass storage and MTP....
# For kernel v4.4 usb configfs
#UAC=uac2USB_ATTRIBUTE=0x409
USB_GROUP=rockchip
USB_SKELETON=b.1CONFIGFS_DIR=/sys/kernel/config
USB_CONFIGFS_DIR=${CONFIGFS_DIR}/usb_gadget/${USB_GROUP}
USB_STRINGS_DIR=${USB_CONFIGFS_DIR}/strings/${USB_ATTRIBUTE}
USB_FUNCTIONS_DIR=${USB_CONFIGFS_DIR}/functions
USB_CONFIGS_DIR=${USB_CONFIGFS_DIR}/configs/${USB_SKELETON}function_init()
{mkdir ${USB_FUNCTIONS_DIR}/${UAC}.gs0
}configfs_init()
{echo "Debug: configfs_init"mkdir /dev/usb-ffsmount -t configfs none ${CONFIGFS_DIR}mkdir ${USB_CONFIGFS_DIR} -m 0770echo 0x2207 > ${USB_CONFIGFS_DIR}/idVendorecho 0x0310 > ${USB_CONFIGFS_DIR}/bcdDeviceecho 0x0200 > ${USB_CONFIGFS_DIR}/bcdUSBmkdir ${USB_STRINGS_DIR} -m 0770SERIAL=`cat /proc/cpuinfo | grep Serial | awk '{print $3}'`if [ -z $SERIAL ];thenSERIAL=0123456789ABCDEFfiecho $SERIAL > ${USB_STRINGS_DIR}/serialnumberecho "rockchip" > ${USB_STRINGS_DIR}/manufacturerecho "rv1109" > ${USB_STRINGS_DIR}/productfunction_initmkdir ${USB_CONFIGS_DIR} -m 0770mkdir ${USB_CONFIGS_DIR}/strings/${USB_ATTRIBUTE} -m 0770
}parameter_init()
{if [ "$UAC" == "uac2" ]; thenCONFIG_STRING=uac2echo "parameter_init ${CONFIG_STRING}"elif [ "$UAC" == "uac1" ];thenCONFIG_STRING=uac1echo "parameter_init ${CONFIG_STRING}"elseecho "parameter_init ${UAC} is invalid"fi
}config_init()
{UAC_GS0=${USB_FUNCTIONS_DIR}/${UAC}.gs0echo 3 > ${UAC_GS0}/p_chmaskecho 2 > ${UAC_GS0}/p_ssizeecho 8000,16000,48000,44100 > ${UAC_GS0}/p_srateecho 3 > ${UAC_GS0}/c_chmaskecho 2 > ${UAC_GS0}/c_ssizeecho 8000,16000,48000,44100 > ${UAC_GS0}/c_srate
}syslink_function()
{ln -s ${USB_FUNCTIONS_DIR}/$1 ${USB_CONFIGS_DIR}/f${USB_FUNCTIONS_CNT}let USB_FUNCTIONS_CNT=USB_FUNCTIONS_CNT+1
}bind_functions()
{USB_FUNCTIONS_CNT=1if [ "$UAC" == "uac2" ]; thensyslink_function uac2.gs0elif [ "$UAC" == "uac1" ];thensyslink_function uac1.gs0elseecho "parameter_init ${UAC} is invalid"fiecho ${CONFIG_STRING} > ${USB_CONFIGS_DIR}/strings/${USB_ATTRIBUTE}/configuration
}program_kill()
{P_PID=`ps | grep $1 | grep -v grep | awk '{print $1}'`test -z ${P_PID} || kill -9 ${P_PID}
}usb_device_stop()
{echo "none" > ${USB_CONFIGFS_DIR}/UDCprogram_kill adbdprogram_kill mtp-serverls ${USB_CONFIGS_DIR} | grep f[0-9] | xargs -I {} rm ${USB_CONFIGS_DIR}/{}
}case "$1" in
start)echo "usb_config in $1"DIR=$(cd `dirname $0`; pwd)parameter_initif [ -z $CONFIG_STRING ]; thenecho "$0: no function be selected"exit 0fitest -d ${USB_CONFIGFS_DIR} || configfs_initecho 0x0019 > ${USB_CONFIGFS_DIR}/idProductconfig_initbind_functionssleep 1UDC=`ls /sys/class/udc/| awk '{print $1}'`echo $UDC > ${USB_CONFIGFS_DIR}/UDC;;
stop)usb_device_stop;;
restart|reload)# Do restart usb by udevecho "USB_FORCE_CHANGED" >> /tmp/.usb_configusb_device_stopsleep 1$0 start# Don't forget to clear "USB_FORCE_CHANGED"sed -i "/USB_FORCE_CHANGED/d" /tmp/.usb_config;;
*)echo "Usage: $0 {start|stop|restart}"exit 1
esacexit 0
UAC应用配置
UAC功能使能后,会生成对应的控制节点。应用可通过对应的控制节点,设置UAC支持的采样率,声道数量,以及数据类型
UAC1: /sys/kernel/config/usb_gadget/rockchip/functions/uac1.gs0
UAC2: /sys/kernel/config/usb_gadget/rockchip/functions/uac2.gs0
ls
c_chmask c_srate c_ssize p_chmask p_srate p_ssize req_number
其中,c_xxx 节点表示UAC2录音控制节点(Capture),p_xxx表示UAC2放音的控制节点(Playback)。
- UAC录音控制节点(c_xxx):定义主设备(例如PC)端发送音频数据给从设备(例如RV1126/RV1109),
- USB声卡支持的参数(采样率,声道数,格式)。
- UAC放音控制节点(p_xxx):定义从设备(例如RV1126/RV1109)端发送音频数据给主设备(例如PC),
- USB声卡支持的参数(采样率,声道数,格式)。
控制节点具体说明如下:
x_chmask:
录/放音声道数mask值(每个bit 1表示一个声道)。对于2声道音频,其值为3(0b‘11)。
x_srate:
录/放音的采样率,Rockchip UAC支持多采样率。
x_ssize:
录/放音数据的类型,单位bytes,对弈PCM_16的数据,其值为2.
例如:
设置UAC2 声卡支持采样率8K,16K,44.1K,48K,2 channels,PCM_16的数据。同理可对UAC2录音进行设置。
注意:如果UAC设备只支持放音/录音某单项功能,可通过设置x_chmask值为0,从而屏蔽掉对应功能。
比如:某UAC设备上只有mic,没有speaker,因此该设备只支持录音(数据从UAC设备–>主设备),不支持播放(数据从主设备–>UAC设备),因此可设置其c_chmask
的值为0
来禁止UAC设备的播放功能。同理,可设置p_chmask
的值为0
来禁止UAC设备的录音(数据从UAC设备–>主设备)。
如上设置后,PC/TV和设备间传递音频数据,必须符合以上设置,否则ALSA打开USB声卡会失败。可根据自己的实际需求,设置UAC声卡支持的参数。
需要注意的是,以上设置过程需要UAC功能使能前设置,UAC启用之后,将无法进行设置。
三、UAC_APP
app的实现思路主要是根据对USB uevent事件的监听,根据是事件来实现对USB声卡的读写操作。
参考文件:
git clone https://gitee.com/zxz_FINE/uac_app.git