如何在没有外部库的情况下从USB麦克风录制高质量音频

时间:2016-12-02 12:47:48

标签: android android-studio audio usb android-usb

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

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

我需要做的是:

  1. 检查设备是否连接了USB麦克风。
  2. 了解此设备的特性(支持采样率,频道等)
  3. 录制音频数据
  4. 到目前为止我做了什么:

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

    如果某人处于类似情况,请提供帮助。

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

0 个答案:

没有答案