5

我正在努力从连接的 USB 麦克风捕获音频流。我曾尝试使用MediaCapturewithMediaRecorder.AudioSource.MIC作为源,但录制质量对我来说不太有用,您无法确定音频源是否真的是 USB 或内置设备麦克风。我需要的是使用 USB 音频功能,但到目前为止我无法取得任何进展。

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

我需要做的是:

  1. 检查是否有 USB 麦克风连接到设备。
  2. 找出此设备具有哪些特性(支持的采样率、通道等)
  3. 录制音频数据

到目前为止我所做的:

生成连接的 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

如果有人遇到类似情况,请帮忙。

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

4

0 回答 0