Merge "Use ALSA for USB MIDI 1.0 devices" into tm-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
ba856f077c
@@ -36,6 +36,7 @@ import libcore.io.IoUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -106,6 +107,12 @@ public final class UsbAlsaManager {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* List of connected MIDI devices
|
||||
*/
|
||||
private final HashMap<String, UsbMidiDevice>
|
||||
mMidiDevices = new HashMap<String, UsbMidiDevice>();
|
||||
|
||||
// UsbMidiDevice for USB peripheral mode (gadget) device
|
||||
private UsbMidiDevice mPeripheralMidiDevice = null;
|
||||
|
||||
@@ -249,6 +256,8 @@ public final class UsbAlsaManager {
|
||||
}
|
||||
}
|
||||
|
||||
addMidiDevice(deviceAddress, usbDevice, parser, cardRec);
|
||||
|
||||
logDevices("deviceAdded()");
|
||||
|
||||
if (DEBUG) {
|
||||
@@ -256,6 +265,54 @@ public final class UsbAlsaManager {
|
||||
}
|
||||
}
|
||||
|
||||
private void addMidiDevice(String deviceAddress, UsbDevice usbDevice,
|
||||
UsbDescriptorParser parser, AlsaCardsParser.AlsaCardRecord cardRec) {
|
||||
boolean hasMidi = parser.hasMIDIInterface();
|
||||
// UsbHostManager will create UsbDirectMidiDevices instead if MIDI 2 is supported.
|
||||
boolean hasMidi2 = parser.containsUniversalMidiDeviceEndpoint();
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "hasMidi: " + hasMidi + " mHasMidiFeature:" + mHasMidiFeature);
|
||||
Slog.d(TAG, "hasMidi2: " + hasMidi2);
|
||||
}
|
||||
if (mHasMidiFeature && hasMidi && !hasMidi2) {
|
||||
Bundle properties = new Bundle();
|
||||
String manufacturer = usbDevice.getManufacturerName();
|
||||
String product = usbDevice.getProductName();
|
||||
String version = usbDevice.getVersion();
|
||||
String name;
|
||||
if (manufacturer == null || manufacturer.isEmpty()) {
|
||||
name = product;
|
||||
} else if (product == null || product.isEmpty()) {
|
||||
name = manufacturer;
|
||||
} else {
|
||||
name = manufacturer + " " + product;
|
||||
}
|
||||
properties.putString(MidiDeviceInfo.PROPERTY_NAME, name);
|
||||
properties.putString(MidiDeviceInfo.PROPERTY_MANUFACTURER, manufacturer);
|
||||
properties.putString(MidiDeviceInfo.PROPERTY_PRODUCT, product);
|
||||
properties.putString(MidiDeviceInfo.PROPERTY_VERSION, version);
|
||||
properties.putString(MidiDeviceInfo.PROPERTY_SERIAL_NUMBER,
|
||||
usbDevice.getSerialNumber());
|
||||
properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_CARD, cardRec.getCardNum());
|
||||
properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_DEVICE, 0 /*deviceNum*/);
|
||||
properties.putParcelable(MidiDeviceInfo.PROPERTY_USB_DEVICE, usbDevice);
|
||||
|
||||
int numLegacyMidiInputs = parser.calculateNumLegacyMidiInputs();
|
||||
int numLegacyMidiOutputs = parser.calculateNumLegacyMidiOutputs();
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "numLegacyMidiInputs: " + numLegacyMidiInputs);
|
||||
Slog.d(TAG, "numLegacyMidiOutputs:" + numLegacyMidiOutputs);
|
||||
}
|
||||
|
||||
UsbMidiDevice usbMidiDevice = UsbMidiDevice.create(mContext, properties,
|
||||
cardRec.getCardNum(), 0 /*device*/, numLegacyMidiInputs,
|
||||
numLegacyMidiOutputs);
|
||||
if (usbMidiDevice != null) {
|
||||
mMidiDevices.put(deviceAddress, usbMidiDevice);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* package */ synchronized void usbDeviceRemoved(String deviceAddress/*UsbDevice usbDevice*/) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "deviceRemoved(" + deviceAddress + ")");
|
||||
@@ -269,6 +326,13 @@ public final class UsbAlsaManager {
|
||||
selectDefaultDevice(); // if there any external devices left, select one of them
|
||||
}
|
||||
|
||||
// MIDI
|
||||
UsbMidiDevice usbMidiDevice = mMidiDevices.remove(deviceAddress);
|
||||
if (usbMidiDevice != null) {
|
||||
Slog.i(TAG, "USB MIDI Device Removed: " + deviceAddress);
|
||||
IoUtils.closeQuietly(usbMidiDevice);
|
||||
}
|
||||
|
||||
logDevices("usbDeviceRemoved()");
|
||||
|
||||
}
|
||||
@@ -324,6 +388,12 @@ public final class UsbAlsaManager {
|
||||
usbAlsaDevice.dump(dump, "alsa_devices", UsbAlsaManagerProto.ALSA_DEVICES);
|
||||
}
|
||||
|
||||
for (String deviceAddr : mMidiDevices.keySet()) {
|
||||
// A UsbMidiDevice does not have a handle to the UsbDevice anymore
|
||||
mMidiDevices.get(deviceAddr).dump(deviceAddr, dump, "midi_devices",
|
||||
UsbAlsaManagerProto.MIDI_DEVICES);
|
||||
}
|
||||
|
||||
dump.end(token);
|
||||
}
|
||||
|
||||
|
||||
@@ -444,14 +444,19 @@ public class UsbHostManager {
|
||||
} else {
|
||||
Slog.e(TAG, "Universal Midi Device is null.");
|
||||
}
|
||||
}
|
||||
if (parser.containsLegacyMidiDeviceEndpoint()) {
|
||||
UsbDirectMidiDevice midiDevice = UsbDirectMidiDevice.create(mContext,
|
||||
newDevice, parser, false, uniqueUsbDeviceIdentifier);
|
||||
if (midiDevice != null) {
|
||||
midiDevices.add(midiDevice);
|
||||
} else {
|
||||
Slog.e(TAG, "Legacy Midi Device is null.");
|
||||
|
||||
// Use UsbDirectMidiDevice only if this supports MIDI 2.0 as well.
|
||||
// ALSA removes the audio sound card if MIDI interfaces are removed.
|
||||
// This means that as long as ALSA is used for audio, MIDI 1.0 USB
|
||||
// devices should use the ALSA path for MIDI.
|
||||
if (parser.containsLegacyMidiDeviceEndpoint()) {
|
||||
midiDevice = UsbDirectMidiDevice.create(mContext,
|
||||
newDevice, parser, false, uniqueUsbDeviceIdentifier);
|
||||
if (midiDevice != null) {
|
||||
midiDevices.add(midiDevice);
|
||||
} else {
|
||||
Slog.e(TAG, "Legacy Midi Device is null.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -79,6 +79,10 @@ public final class UsbConfigDescriptor extends UsbDescriptor {
|
||||
mInterfaceDescriptors.add(interfaceDesc);
|
||||
}
|
||||
|
||||
ArrayList<UsbInterfaceDescriptor> getInterfaceDescriptors() {
|
||||
return mInterfaceDescriptors;
|
||||
}
|
||||
|
||||
private boolean isAudioInterface(UsbInterfaceDescriptor descriptor) {
|
||||
return descriptor.getUsbClass() == UsbDescriptor.CLASSID_AUDIO
|
||||
&& descriptor.getUsbSubclass() == UsbDescriptor.AUDIO_AUDIOSTREAMING;
|
||||
|
||||
@@ -40,6 +40,7 @@ public final class UsbDescriptorParser {
|
||||
private UsbDeviceDescriptor mDeviceDescriptor;
|
||||
private UsbConfigDescriptor mCurConfigDescriptor;
|
||||
private UsbInterfaceDescriptor mCurInterfaceDescriptor;
|
||||
private UsbEndpointDescriptor mCurEndpointDescriptor;
|
||||
|
||||
// The AudioClass spec implemented by the AudioClass Interfaces
|
||||
// This may well be different than the overall USB Spec.
|
||||
@@ -165,7 +166,7 @@ public final class UsbDescriptorParser {
|
||||
break;
|
||||
|
||||
case UsbDescriptor.DESCRIPTORTYPE_ENDPOINT:
|
||||
descriptor = new UsbEndpointDescriptor(length, type);
|
||||
descriptor = mCurEndpointDescriptor = new UsbEndpointDescriptor(length, type);
|
||||
if (mCurInterfaceDescriptor != null) {
|
||||
mCurInterfaceDescriptor.addEndpointDescriptor(
|
||||
(UsbEndpointDescriptor) descriptor);
|
||||
@@ -265,6 +266,9 @@ public final class UsbDescriptorParser {
|
||||
+ Integer.toHexString(subClass));
|
||||
break;
|
||||
}
|
||||
if (mCurEndpointDescriptor != null && descriptor != null) {
|
||||
mCurEndpointDescriptor.setClassSpecificEndpointDescriptor(descriptor);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -795,6 +799,84 @@ public final class UsbDescriptorParser {
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
private int calculateNumLegacyMidiPorts(boolean isOutput) {
|
||||
// Only look at the first config.
|
||||
UsbConfigDescriptor configDescriptor = null;
|
||||
for (UsbDescriptor descriptor : mDescriptors) {
|
||||
if (descriptor.getType() == UsbDescriptor.DESCRIPTORTYPE_CONFIG) {
|
||||
if (descriptor instanceof UsbConfigDescriptor) {
|
||||
configDescriptor = (UsbConfigDescriptor) descriptor;
|
||||
break;
|
||||
} else {
|
||||
Log.w(TAG, "Unrecognized Config l: " + descriptor.getLength()
|
||||
+ " t:0x" + Integer.toHexString(descriptor.getType()));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (configDescriptor == null) {
|
||||
Log.w(TAG, "Config not found");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ArrayList<UsbInterfaceDescriptor> legacyMidiInterfaceDescriptors =
|
||||
new ArrayList<UsbInterfaceDescriptor>();
|
||||
for (UsbInterfaceDescriptor interfaceDescriptor
|
||||
: configDescriptor.getInterfaceDescriptors()) {
|
||||
if (interfaceDescriptor.getUsbClass() == UsbDescriptor.CLASSID_AUDIO) {
|
||||
if (interfaceDescriptor.getUsbSubclass() == UsbDescriptor.AUDIO_MIDISTREAMING) {
|
||||
UsbDescriptor midiHeaderDescriptor =
|
||||
interfaceDescriptor.getMidiHeaderInterfaceDescriptor();
|
||||
if (midiHeaderDescriptor != null) {
|
||||
if (midiHeaderDescriptor instanceof UsbMSMidiHeader) {
|
||||
UsbMSMidiHeader midiHeader =
|
||||
(UsbMSMidiHeader) midiHeaderDescriptor;
|
||||
if (midiHeader.getMidiStreamingClass() == MS_MIDI_1_0) {
|
||||
legacyMidiInterfaceDescriptors.add(interfaceDescriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
for (UsbInterfaceDescriptor interfaceDescriptor : legacyMidiInterfaceDescriptors) {
|
||||
for (int i = 0; i < interfaceDescriptor.getNumEndpoints(); i++) {
|
||||
UsbEndpointDescriptor endpoint =
|
||||
interfaceDescriptor.getEndpointDescriptor(i);
|
||||
// 0 is output, 1 << 7 is input.
|
||||
if ((endpoint.getDirection() == 0) == isOutput) {
|
||||
UsbDescriptor classSpecificEndpointDescriptor =
|
||||
endpoint.getClassSpecificEndpointDescriptor();
|
||||
if (classSpecificEndpointDescriptor != null
|
||||
&& (classSpecificEndpointDescriptor instanceof UsbACMidi10Endpoint)) {
|
||||
UsbACMidi10Endpoint midiEndpoint =
|
||||
(UsbACMidi10Endpoint) classSpecificEndpointDescriptor;
|
||||
count += midiEndpoint.getNumJacks();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public int calculateNumLegacyMidiInputs() {
|
||||
return calculateNumLegacyMidiPorts(false /*isOutput*/);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public int calculateNumLegacyMidiOutputs() {
|
||||
return calculateNumLegacyMidiPorts(true /*isOutput*/);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
|
||||
@@ -79,6 +79,8 @@ public class UsbEndpointDescriptor extends UsbDescriptor {
|
||||
private byte mRefresh;
|
||||
private byte mSyncAddress;
|
||||
|
||||
private UsbDescriptor mClassSpecificEndpointDescriptor;
|
||||
|
||||
public UsbEndpointDescriptor(int length, byte type) {
|
||||
super(length, type);
|
||||
mHierarchyLevel = 4;
|
||||
@@ -112,6 +114,14 @@ public class UsbEndpointDescriptor extends UsbDescriptor {
|
||||
return mEndpointAddress & UsbEndpointDescriptor.MASK_ENDPOINT_DIRECTION;
|
||||
}
|
||||
|
||||
void setClassSpecificEndpointDescriptor(UsbDescriptor descriptor) {
|
||||
mClassSpecificEndpointDescriptor = descriptor;
|
||||
}
|
||||
|
||||
UsbDescriptor getClassSpecificEndpointDescriptor() {
|
||||
return mClassSpecificEndpointDescriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a UsbEndpoint that this UsbEndpointDescriptor is describing.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user