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.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -106,6 +107,12 @@ public final class UsbAlsaManager {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of connected MIDI devices
|
||||||
|
*/
|
||||||
|
private final HashMap<String, UsbMidiDevice>
|
||||||
|
mMidiDevices = new HashMap<String, UsbMidiDevice>();
|
||||||
|
|
||||||
// UsbMidiDevice for USB peripheral mode (gadget) device
|
// UsbMidiDevice for USB peripheral mode (gadget) device
|
||||||
private UsbMidiDevice mPeripheralMidiDevice = null;
|
private UsbMidiDevice mPeripheralMidiDevice = null;
|
||||||
|
|
||||||
@@ -249,6 +256,8 @@ public final class UsbAlsaManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addMidiDevice(deviceAddress, usbDevice, parser, cardRec);
|
||||||
|
|
||||||
logDevices("deviceAdded()");
|
logDevices("deviceAdded()");
|
||||||
|
|
||||||
if (DEBUG) {
|
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*/) {
|
/* package */ synchronized void usbDeviceRemoved(String deviceAddress/*UsbDevice usbDevice*/) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Slog.d(TAG, "deviceRemoved(" + deviceAddress + ")");
|
Slog.d(TAG, "deviceRemoved(" + deviceAddress + ")");
|
||||||
@@ -269,6 +326,13 @@ public final class UsbAlsaManager {
|
|||||||
selectDefaultDevice(); // if there any external devices left, select one of them
|
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()");
|
logDevices("usbDeviceRemoved()");
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -324,6 +388,12 @@ public final class UsbAlsaManager {
|
|||||||
usbAlsaDevice.dump(dump, "alsa_devices", UsbAlsaManagerProto.ALSA_DEVICES);
|
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);
|
dump.end(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -444,9 +444,13 @@ public class UsbHostManager {
|
|||||||
} else {
|
} else {
|
||||||
Slog.e(TAG, "Universal Midi Device is null.");
|
Slog.e(TAG, "Universal 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()) {
|
if (parser.containsLegacyMidiDeviceEndpoint()) {
|
||||||
UsbDirectMidiDevice midiDevice = UsbDirectMidiDevice.create(mContext,
|
midiDevice = UsbDirectMidiDevice.create(mContext,
|
||||||
newDevice, parser, false, uniqueUsbDeviceIdentifier);
|
newDevice, parser, false, uniqueUsbDeviceIdentifier);
|
||||||
if (midiDevice != null) {
|
if (midiDevice != null) {
|
||||||
midiDevices.add(midiDevice);
|
midiDevices.add(midiDevice);
|
||||||
@@ -454,6 +458,7 @@ public class UsbHostManager {
|
|||||||
Slog.e(TAG, "Legacy Midi Device is null.");
|
Slog.e(TAG, "Legacy Midi Device is null.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!midiDevices.isEmpty()) {
|
if (!midiDevices.isEmpty()) {
|
||||||
mMidiDevices.put(deviceAddress, midiDevices);
|
mMidiDevices.put(deviceAddress, midiDevices);
|
||||||
|
|||||||
@@ -79,6 +79,10 @@ public final class UsbConfigDescriptor extends UsbDescriptor {
|
|||||||
mInterfaceDescriptors.add(interfaceDesc);
|
mInterfaceDescriptors.add(interfaceDesc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ArrayList<UsbInterfaceDescriptor> getInterfaceDescriptors() {
|
||||||
|
return mInterfaceDescriptors;
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isAudioInterface(UsbInterfaceDescriptor descriptor) {
|
private boolean isAudioInterface(UsbInterfaceDescriptor descriptor) {
|
||||||
return descriptor.getUsbClass() == UsbDescriptor.CLASSID_AUDIO
|
return descriptor.getUsbClass() == UsbDescriptor.CLASSID_AUDIO
|
||||||
&& descriptor.getUsbSubclass() == UsbDescriptor.AUDIO_AUDIOSTREAMING;
|
&& descriptor.getUsbSubclass() == UsbDescriptor.AUDIO_AUDIOSTREAMING;
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ public final class UsbDescriptorParser {
|
|||||||
private UsbDeviceDescriptor mDeviceDescriptor;
|
private UsbDeviceDescriptor mDeviceDescriptor;
|
||||||
private UsbConfigDescriptor mCurConfigDescriptor;
|
private UsbConfigDescriptor mCurConfigDescriptor;
|
||||||
private UsbInterfaceDescriptor mCurInterfaceDescriptor;
|
private UsbInterfaceDescriptor mCurInterfaceDescriptor;
|
||||||
|
private UsbEndpointDescriptor mCurEndpointDescriptor;
|
||||||
|
|
||||||
// The AudioClass spec implemented by the AudioClass Interfaces
|
// The AudioClass spec implemented by the AudioClass Interfaces
|
||||||
// This may well be different than the overall USB Spec.
|
// This may well be different than the overall USB Spec.
|
||||||
@@ -165,7 +166,7 @@ public final class UsbDescriptorParser {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case UsbDescriptor.DESCRIPTORTYPE_ENDPOINT:
|
case UsbDescriptor.DESCRIPTORTYPE_ENDPOINT:
|
||||||
descriptor = new UsbEndpointDescriptor(length, type);
|
descriptor = mCurEndpointDescriptor = new UsbEndpointDescriptor(length, type);
|
||||||
if (mCurInterfaceDescriptor != null) {
|
if (mCurInterfaceDescriptor != null) {
|
||||||
mCurInterfaceDescriptor.addEndpointDescriptor(
|
mCurInterfaceDescriptor.addEndpointDescriptor(
|
||||||
(UsbEndpointDescriptor) descriptor);
|
(UsbEndpointDescriptor) descriptor);
|
||||||
@@ -265,6 +266,9 @@ public final class UsbDescriptorParser {
|
|||||||
+ Integer.toHexString(subClass));
|
+ Integer.toHexString(subClass));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (mCurEndpointDescriptor != null && descriptor != null) {
|
||||||
|
mCurEndpointDescriptor.setClassSpecificEndpointDescriptor(descriptor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -795,6 +799,84 @@ public final class UsbDescriptorParser {
|
|||||||
return count;
|
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
|
* @hide
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -79,6 +79,8 @@ public class UsbEndpointDescriptor extends UsbDescriptor {
|
|||||||
private byte mRefresh;
|
private byte mRefresh;
|
||||||
private byte mSyncAddress;
|
private byte mSyncAddress;
|
||||||
|
|
||||||
|
private UsbDescriptor mClassSpecificEndpointDescriptor;
|
||||||
|
|
||||||
public UsbEndpointDescriptor(int length, byte type) {
|
public UsbEndpointDescriptor(int length, byte type) {
|
||||||
super(length, type);
|
super(length, type);
|
||||||
mHierarchyLevel = 4;
|
mHierarchyLevel = 4;
|
||||||
@@ -112,6 +114,14 @@ public class UsbEndpointDescriptor extends UsbDescriptor {
|
|||||||
return mEndpointAddress & UsbEndpointDescriptor.MASK_ENDPOINT_DIRECTION;
|
return mEndpointAddress & UsbEndpointDescriptor.MASK_ENDPOINT_DIRECTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setClassSpecificEndpointDescriptor(UsbDescriptor descriptor) {
|
||||||
|
mClassSpecificEndpointDescriptor = descriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
UsbDescriptor getClassSpecificEndpointDescriptor() {
|
||||||
|
return mClassSpecificEndpointDescriptor;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a UsbEndpoint that this UsbEndpointDescriptor is describing.
|
* Returns a UsbEndpoint that this UsbEndpointDescriptor is describing.
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user