Merge "Use ALSA for USB MIDI 1.0 devices" into tm-qpr-dev

This commit is contained in:
TreeHugger Robot
2023-01-26 14:08:05 +00:00
committed by Android (Google) Code Review
5 changed files with 180 additions and 9 deletions

View File

@@ -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);
}

View File

@@ -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.");
}
}
}

View File

@@ -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;

View File

@@ -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
*/

View File

@@ -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.
*/