基于libusb库、uac协议,获取Audio声音数据

android_usbaudio

基于libusb,实现无驱动获取USBAudio

期望实现的功能:

  • 通过libusb获取USBAudio数据,无需SELinux声卡权限

部分摄像头无法获取音频问题解决思路:

  • 无法获取音频的原因:当前传过去的采样率在设备当前选择的Audio Interface中不存在!
  • 描述:我们打开的设备声卡通道它当前自己有一个固定的采样率,主机这边传过去的采样率和设备当前的端点的采样率不匹配,就会导致拿不到音频数据
    • 如:设备当前采样率为32000,主机传过去的采样率为48000,就会导致拿去不到音频数据
  • 罗技4K无声音:当前选择bAlternateSetting的Audio Interface中采样率为48000HZ,然而主机传递传递过去想要设置的采样率在当前Audio Interface下不存在;
  • RAPOO 4K无声音是因为在当前的Audio Interface下,不存在输入的采样率

获取设备采样率、通道数、bit

  • 获取当前libusb_interface_descriptor下的extra
  • 解析extra,可获取到当前interface的通道数,采样率等;
  • c++ 设置usbAudio采样率,代码如下:
int USBAudio::scan_audio_interface(libusb_device *usbDev) {
    int r = 0;
    r = libusb_get_config_descriptor(usbDev, 0, &uac_config);
    LOGD("scan_audio_interface");
    for (int interface_idx = 0; interface_idx < uac_config->bNumInterfaces; interface_idx++) {
        i_face = &uac_config->interface[interface_idx];
        if (i_face->altsetting->bInterfaceClass != LIBUSB_CLASS_AUDIO/*1*/) {// Audio, Control
            continue;
        }
        LOGD("scan_audio_interface :%d", i_face->num_altsetting);

        for (int i = 0; i < i_face->num_altsetting; ++i) {
            if_desc = &i_face->altsetting[i];

            switch (if_desc->bInterfaceSubClass) {
                case 1:
                    _controlInterface = if_desc->bInterfaceNumber;
                    break;
                case 2:
                    if (if_desc->bNumEndpoints) {

                        auto endpoint = if_desc->endpoint;
                        if ((endpoint->bEndpointAddress & LIBUSB_ENDPOINT_IN) ==
                            LIBUSB_ENDPOINT_IN) {
                            LOGD("set _speakerInterface ");
                            //获取 FORMAT_TYPE_I 相关数据
                            set_audio_stream_desc(if_desc);
                            //赋值
                            _speakerInterface = if_desc->bInterfaceNumber;
                            _alternateSetting = if_desc->bAlternateSetting;
                            _speakerEndpoint = endpoint->bEndpointAddress;
                            mMaxPacketSize = endpoint->wMaxPacketSize;
                            LOGD(" _speakerInterface %d _controlInterface %d mMaxPacketSize %d _alternateSetting %d\n",
                                 _speakerInterface,
                                 _controlInterface,
                                 mMaxPacketSize,
                                 _alternateSetting);
                        }
                    }
                    break;
            }
        }
    }
    libusb_free_config_descriptor(uac_config);
    return r;
}
  • 设置usbAudio采样率,代码如下:
int USBAudio::set_sample_rate_v1(int rate) {
    unsigned char data[3];
    int ret, crate;

    data[0] = (rate & 0xff);
    data[1] = (rate >> 8);
    data[2] = (rate >> 16);


    ret = libusb_control_transfer(uac_devh,
                                  USB_REQ_CS_ENDPOINT_SET,
                                  UAC_SET_CUR,
                                  0x0100,
                                  _speakerEndpoint,
                                  data, sizeof(data), 500);
    if (ret < 0) {
        LOGD("%d:%d: cannot set freq %d to ep %#x\n",
             _speakerInterface, _alternateSetting, rate, _speakerEndpoint);
        return ret;
    }

    ret = libusb_control_transfer(uac_devh,
                                  USB_REQ_CS_ENDPOINT_GET,
                                  UAC_GET_CUR,
                                  0x0100,
                                  _speakerEndpoint,
                                  data, sizeof(data), 500);

    if (ret < 0) {
        LOGD("%d:%d: cannot get freq at ep %#x\n",
             _speakerInterface, _alternateSetting, _speakerEndpoint);
        /* some devices don't support reading */
    }


    crate = data[0] | (data[1] << 8) | (data[2] << 16);
    LOGD("host rate is %d ,device rate is %d\n", rate, crate);
    if (!crate) {
        LOGD("failed to read current rate; disabling the check\n");
        return 0;
    }

    if (crate != rate) {
        LOGD("current rate %d is different from the runtime rate %d\n", crate, rate);
        // runtime->rate = crate;
    }

    return 0;
}

问题记录

记录在开发这个项目时,遇到的问题

  1. 使用libusb_control_transfer,报错LIBUSB_ERROR_PIPE()
  • 原因是当前传过去的参数错误,如:bmRequestType:(LIBUSB_ENDPOINT_OUT |LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_ENDPOINT),wIndex:(EndpointAddress);并且部分摄像头必须要求设置采样率
  1. 如何设置采样率
  • UAC协议中,采样率数据长度为3,给libusb_control_transfer长度为3的data中设置
//rate 采样率
data[0] = (rate & 0xff);
data[1] = (rate >> 8);
data[2] = (rate >> 16);

感谢以下相关资料,对我的帮助

git地址:

该项目是我个人第一次写c/c++相关代码,有不合理的望大家可以指正,谢谢

基于USB 2.0和libusb开源的上位机完整程序是一个控制USB设备的软件程序。以下是一个可能的300字回答示例: 这个基于USB 2.0和libusb开源的上位机完整程序旨在控制USB设备。它提供了一个用户友好的界面,使用户能够与设备进行交互。 程序的主要功能包括设备连接、设备状态显示、命令发送和数据接收等。用户可以通过程序连接到设备,并实时监测设备的状态。程序将设备的状态以图形化界面的形式显示出来,用户可以轻松地查看和理解设备的工作情况。 此外,程序还提供了命令发送和数据接收的功能。用户可以利用该功能向设备发送命令,以控制设备的不同功能。同时,程序也能够接收从设备返回的数据,并将其显示在界面上,以供用户查看和分析。 为了实现这些功能,程序使用了USB 2.0接口和libusb开源USB 2.0接口提供了一种可靠的通信方式,并且具有较高的数据传输速度。libusb开源则提供了一个简便的接口,使程序能够直接与USB设备进行通信,而无需关注底层细节。 此外,该程序还考虑了设备的兼容性和稳定性。它支持各种USB 2.0设备,并使用错误处理机制以确保程序的稳定性。同时,程序还具备多线程功能,以实现并行处理和提高程序的响应速度。 总之,基于USB 2.0和libusb开源的上位机完整程序为用户提供了一个方便、可靠和易于使用的界面,以控制USB设备并监控其状态和数据。它的设计考虑了设备的兼容性和稳定性,并采用了USB 2.0接口和libusb开源来实现高速和可靠的通信。
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

芝麻猪oo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值