Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9106ef94 authored by Robert Wu's avatar Robert Wu Committed by Android (Google) Code Review
Browse files

Merge "Use ALSA for USB MIDI 1.0 devices"

parents d8e7d6c9 768236ce
Loading
Loading
Loading
Loading
+70 −0
Original line number Diff line number Diff line
@@ -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);
    }

+13 −8
Original line number Diff line number Diff line
@@ -444,9 +444,13 @@ public class UsbHostManager {
                        } else {
                            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()) {
                        UsbDirectMidiDevice midiDevice = UsbDirectMidiDevice.create(mContext,
                            midiDevice = UsbDirectMidiDevice.create(mContext,
                                    newDevice, parser, false, uniqueUsbDeviceIdentifier);
                            if (midiDevice != null) {
                                midiDevices.add(midiDevice);
@@ -454,6 +458,7 @@ public class UsbHostManager {
                                Slog.e(TAG, "Legacy Midi Device is null.");
                            }
                        }
                    }

                    if (!midiDevices.isEmpty()) {
                        mMidiDevices.put(deviceAddress, midiDevices);
+4 −0
Original line number Diff line number Diff line
@@ -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;
+83 −1
Original line number Diff line number Diff line
@@ -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
     */
+10 −0
Original line number Diff line number Diff line
@@ -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.
    */