我正在努力如何从连接的USB麦克风捕获音频流 . 我曾尝试使用带有 MediaRecorder.AudioSource.MICMediaCapture 作为源,但录音质量不高't quite usable for me and you can'确定音频源是USB还是内置设备麦克风 . 我需要的是使用USB音频功能,但到目前为止我无法取得任何进展 .

使用第三方库对我来说太过分了,因为我只需要从麦克风接收音频数据流,其余的处理工作已经完成并正常工作,只有音频源是问题 .

我需要做的是:

  • 检查设备是否连接了USB麦克风 .

  • 了解该设备的特性(支持采样率,通道等)

  • 录制音频数据

到目前为止我做了什么:

生成连接的USB设备列表,该类为 UsbConstants.USB_CLASS_AUDIO

private static final String ACTION_USB_PERMISSION = PACKAGE_NAME  + ".USB_PERMISSION";
private UsbManager mUsbManAndroid;
private Map<String, UsbDevice> mAndroidDeviceMap;
private PendingIntent mPermissionIntent;

private ArrayList<UsbDeviceListItem> getUSBDevicesList() {
    // Enumerate USB devices
    mAndroidDeviceMap = mUsbManAndroid.getDeviceList();
    ArrayList<UsbDeviceListItem> usbDevicesList = new ArrayList<>();

    for (String key : mAndroidDeviceMap.keySet()) {
        UsbDevice device = mAndroidDeviceMap.get(key);

        // Check the device class
        if (device.getDeviceClass() == UsbConstants.USB_CLASS_AUDIO) {
            usbDevicesList.add(usbDeviceToListItem(key, device));
        } else if (device.getDeviceClass() == UsbConstants.USB_CLASS_PER_INTERFACE) {
            UsbInterface interface;
            for (int i = 0; i < device.getInterfaceCount(); i++) {
                // Check if at least one interface is audio
                interface = device.getInterface(i);

                if (interface != null && interface.getInterfaceClass() == UsbConstants.USB_CLASS_AUDIO) {
                    usbDevicesList.add(usbDeviceToSysBusUsbDevice(key, device));
                    break;
                }
            }
        }
    }

    /////////////////////////////////////////////////////////
    // Here goes some code to identify the device using
    // linux shell commands if device SDK version is older 
    // than 21 (Lollipop). In older versions of Android
    // we can't get device's Vendor and Device names using
    // Android API, we need to use some linux shell commands.
    /////////////////////////////////////////////////////////


    return usbDevicesList;
}

从列表中请求对所选USB设备的权限:

mUsbDeviceList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
     @Override
     public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
         UsbDeviceListItem usbDeviceItem = (UsbDeviceListItem) mUsbDeviceList.getItemAtPosition(i);
         UsbDevice device = mAndroidDeviceMap.get(usbDeviceItem.getDevicePath());

         manager.requestPermission(device, mPermissionIntent);
     }
 });

许可广播接收者:

private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (ACTION_USB_PERMISSION.equals(action)) {
            synchronized (this) {
                UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);

                if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                    if(device != null){
                        streamFromUsbDevice(device)
                    }
                }
                else {
                    Toast.makeText(SensorActivity.this, "Permission denied for device " + device,
                            Toast.LENGTH_SHORT).show();
                }
            }
        }
    }
};

用于从USB设备读取数据的示例方法

private void streamFromUSBDevice(UsbDevice device) {
    UsbEndpoint endpoint;
    UsbInterface usbInterface;

    ////////////////////////////////////////////////////////////////
    // Here was code for finding the first audio interface with its
    // endpoint. But because I failed to make it work I was manually
    // getting them by index.
    ////////////////////////////////////////////////////////////////

    usbInterface = device.getInterface(2);
    endpoint = usbInterface.getEndpoint(0);

    if (endpoint == null)  {
        Log.i(TAG, getString(R.string.endpoint_not_found));
        notifyUser(R.string.endpoint_not_found);
        return;
    }

    Log.i(TAG, R.string.connecting_to_usb_device);
    notifyUser(R.string.connecting_to_usb_device);

    UsbDeviceConnection connection = manager.openDevice(device);
    connection.claimInterface(usbInterface, true);

    while (true) {
        if (!isRecording) {
            // Close the connection to the usb device
            connection.close();

            notifyUser(R.string.status_idle);                
            break;
        }

        UsbRequest request = new UsbRequest();
        request.initialize(connection, endpoint);

        byte[] buffer = new byte[endpoint.getMaxPacketSize()];

        final ByteBuffer buf = ByteBuffer.wrap(buffer);

        Log.i(TAG, "Requesting queue...");
        if (!request.queue(buf, buffer.length)) {
            Log.e(TAG, getString(R.string.error_queue_request)));
            notifyUser(R.string.error_queue_request);
            isRecording = false;
            break;
        }

        Log.i(TAG, "Requesting response...");
        final UsbRequest response = connection.requestWait();

        if (response == null) {
            Log.e(TAG, "Null response!");
            notifyUser(R.string.null_response);
            isRecording = false;
            break;
        }


        final int nRead = buf.position();

        if (nRead > 0) {
            Log.i(TAG, "Streaming " + nRead + " bytes to UI");
            Bundle args = new Bundle();
            args.putShortArray(ARG_RECORDED_DATA, byte2short(buffer));

            sendMessageToUI(SHOW_AUDIO_DATA_PACKET, args, null);
        } else {
            Log.e(TAG, "No data in buffer!");
            notifyUser(R.string_empty_buffer);

            isRecording = false;
            break;
        }
    }
}

我从这里得到的是 request.queue() 总是返回 false .

我也尝试使用 connection.bulkTransfer(endpoint, buffer, buffer.length, 0); 方法,但结果总是 -1 .

如果有人遇到类似情况请帮助 .

附:我在日志中收到的错误是: UsbRequestJNI: request is closed in native_queue .