我正在努力从连接的 USB 麦克风捕获音频流。我曾尝试使用MediaCapture
withMediaRecorder.AudioSource.MIC
作为源,但录制质量对我来说不太有用,您无法确定音频源是否真的是 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。
如果有人遇到类似情况,请帮忙。
PS我在日志中收到的错误是:UsbRequestJNI: request is closed in native_queue
。