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

Commit a7e7f94f authored by Paul McLean's avatar Paul McLean
Browse files

Add video class-specific descriptors to UsbDescriptorParser framework.

Also add mHasVideoCapture and mHasVideoPlayback members to UsbDevice.

Bug: 142321590

Test: Build, flash, connect USB Video Camera, examine logs
Change-Id: Ia6ae687182ec0b007c1688478545829395191984
parent 5c12df64
Loading
Loading
Loading
Loading
+32 −5
Original line number Original line Diff line number Diff line
@@ -63,6 +63,8 @@ public class UsbDevice implements Parcelable {
    private final boolean mHasAudioPlayback;
    private final boolean mHasAudioPlayback;
    private final boolean mHasAudioCapture;
    private final boolean mHasAudioCapture;
    private final boolean mHasMidi;
    private final boolean mHasMidi;
    private final boolean mHasVideoPlayback;
    private final boolean mHasVideoCapture;


    /** All interfaces on the device. Initialized on first call to getInterfaceList */
    /** All interfaces on the device. Initialized on first call to getInterfaceList */
    @UnsupportedAppUsage
    @UnsupportedAppUsage
@@ -77,7 +79,8 @@ public class UsbDevice implements Parcelable {
            int protocol, @Nullable String manufacturerName, @Nullable String productName,
            int protocol, @Nullable String manufacturerName, @Nullable String productName,
            @NonNull String version, @NonNull UsbConfiguration[] configurations,
            @NonNull String version, @NonNull UsbConfiguration[] configurations,
            @NonNull IUsbSerialReader serialNumberReader,
            @NonNull IUsbSerialReader serialNumberReader,
            boolean hasAudioPlayback, boolean hasAudioCapture, boolean hasMidi) {
            boolean hasAudioPlayback, boolean hasAudioCapture, boolean hasMidi,
            boolean hasVideoPlayback, boolean hasVideoCapture) {
        mName = Preconditions.checkNotNull(name);
        mName = Preconditions.checkNotNull(name);
        mVendorId = vendorId;
        mVendorId = vendorId;
        mProductId = productId;
        mProductId = productId;
@@ -92,6 +95,8 @@ public class UsbDevice implements Parcelable {
        mHasAudioPlayback = hasAudioPlayback;
        mHasAudioPlayback = hasAudioPlayback;
        mHasAudioCapture = hasAudioCapture;
        mHasAudioCapture = hasAudioCapture;
        mHasMidi = hasMidi;
        mHasMidi = hasMidi;
        mHasVideoPlayback = hasVideoPlayback;
        mHasVideoCapture = hasVideoCapture;


        // Make sure the binder belongs to the system
        // Make sure the binder belongs to the system
        if (ActivityThread.isSystem()) {
        if (ActivityThread.isSystem()) {
@@ -236,6 +241,16 @@ public class UsbDevice implements Parcelable {
        return mHasMidi;
        return mHasMidi;
    }
    }


    /** @hide */
    public boolean getHasVideoPlayback() {
        return mHasVideoPlayback;
    }

    /** @hide */
    public boolean getHasVideoCapture() {
        return mHasVideoCapture;
    }

    /**
    /**
     * Returns the {@link UsbConfiguration} at the given index.
     * Returns the {@link UsbConfiguration} at the given index.
     *
     *
@@ -316,6 +331,8 @@ public class UsbDevice implements Parcelable {
                + ", mHasAudioPlayback=" + mHasAudioPlayback
                + ", mHasAudioPlayback=" + mHasAudioPlayback
                + ", mHasAudioCapture=" + mHasAudioCapture
                + ", mHasAudioCapture=" + mHasAudioCapture
                + ", mHasMidi=" + mHasMidi
                + ", mHasMidi=" + mHasMidi
                + ", mHasVideoCapture=" + mHasVideoCapture
                + ", mHasVideoPlayback=" + mHasVideoPlayback
                + ", mConfigurations=[");
                + ", mConfigurations=[");
        for (int i = 0; i < mConfigurations.length; i++) {
        for (int i = 0; i < mConfigurations.length; i++) {
            builder.append("\n");
            builder.append("\n");
@@ -345,10 +362,12 @@ public class UsbDevice implements Parcelable {
            boolean hasAudioPlayback = in.readInt() == 1;
            boolean hasAudioPlayback = in.readInt() == 1;
            boolean hasAudioCapture = in.readInt() == 1;
            boolean hasAudioCapture = in.readInt() == 1;
            boolean hasMidi = in.readInt() == 1;
            boolean hasMidi = in.readInt() == 1;

            boolean hasVideoPlayback = in.readInt() == 1;
            boolean hasVideoCapture = in.readInt() == 1;
            UsbDevice device = new UsbDevice(name, vendorId, productId, clasz, subClass, protocol,
            UsbDevice device = new UsbDevice(name, vendorId, productId, clasz, subClass, protocol,
                    manufacturerName, productName, version, configurations, serialNumberReader,
                    manufacturerName, productName, version, configurations, serialNumberReader,
                    hasAudioPlayback, hasAudioCapture, hasMidi);
                    hasAudioPlayback, hasAudioCapture, hasMidi,
                    hasVideoPlayback, hasVideoCapture);


            return device;
            return device;
        }
        }
@@ -377,6 +396,8 @@ public class UsbDevice implements Parcelable {
        parcel.writeInt(mHasAudioPlayback ? 1 : 0);
        parcel.writeInt(mHasAudioPlayback ? 1 : 0);
        parcel.writeInt(mHasAudioCapture ? 1 : 0);
        parcel.writeInt(mHasAudioCapture ? 1 : 0);
        parcel.writeInt(mHasMidi ? 1 : 0);
        parcel.writeInt(mHasMidi ? 1 : 0);
        parcel.writeInt(mHasVideoPlayback ? 1 : 0);
        parcel.writeInt(mHasVideoCapture ? 1 : 0);
    }
    }


    public static int getDeviceId(String name) {
    public static int getDeviceId(String name) {
@@ -407,6 +428,8 @@ public class UsbDevice implements Parcelable {
        private final boolean mHasAudioPlayback;
        private final boolean mHasAudioPlayback;
        private final boolean mHasAudioCapture;
        private final boolean mHasAudioCapture;
        private final boolean mHasMidi;
        private final boolean mHasMidi;
        private final boolean mHasVideoPlayback;
        private final boolean mHasVideoCapture;


        // Temporary storage for serial number. Serial number reader need to be wrapped in a
        // Temporary storage for serial number. Serial number reader need to be wrapped in a
        // IUsbSerialReader as they might be used as PII.
        // IUsbSerialReader as they might be used as PII.
@@ -416,7 +439,8 @@ public class UsbDevice implements Parcelable {
                int protocol, @Nullable String manufacturerName, @Nullable String productName,
                int protocol, @Nullable String manufacturerName, @Nullable String productName,
                @NonNull String version, @NonNull UsbConfiguration[] configurations,
                @NonNull String version, @NonNull UsbConfiguration[] configurations,
                @Nullable String serialNumber,
                @Nullable String serialNumber,
                boolean hasAudioPlayback, boolean hasAudioCapture, boolean hasMidi) {
                boolean hasAudioPlayback, boolean hasAudioCapture, boolean hasMidi,
                boolean hasVideoPlayback, boolean hasVideoCapture) {
            mName = Preconditions.checkNotNull(name);
            mName = Preconditions.checkNotNull(name);
            mVendorId = vendorId;
            mVendorId = vendorId;
            mProductId = productId;
            mProductId = productId;
@@ -431,6 +455,8 @@ public class UsbDevice implements Parcelable {
            mHasAudioPlayback = hasAudioPlayback;
            mHasAudioPlayback = hasAudioPlayback;
            mHasAudioCapture = hasAudioCapture;
            mHasAudioCapture = hasAudioCapture;
            mHasMidi = hasMidi;
            mHasMidi = hasMidi;
            mHasVideoPlayback = hasVideoPlayback;
            mHasVideoCapture = hasVideoCapture;
        }
        }


        /**
        /**
@@ -443,7 +469,8 @@ public class UsbDevice implements Parcelable {
        public UsbDevice build(@NonNull IUsbSerialReader serialReader) {
        public UsbDevice build(@NonNull IUsbSerialReader serialReader) {
            return new UsbDevice(mName, mVendorId, mProductId, mClass, mSubclass, mProtocol,
            return new UsbDevice(mName, mVendorId, mProductId, mClass, mSubclass, mProtocol,
                    mManufacturerName, mProductName, mVersion, mConfigurations, serialReader,
                    mManufacturerName, mProductName, mVersion, mConfigurations, serialReader,
                    mHasAudioPlayback, mHasAudioCapture, mHasMidi);
                    mHasAudioPlayback, mHasAudioCapture, mHasMidi,
                    mHasVideoPlayback, mHasVideoCapture);
        }
        }
    }
    }
}
}
+1 −0
Original line number Original line Diff line number Diff line
@@ -52,6 +52,7 @@ abstract class UsbACEndpoint extends UsbDescriptor {
                                                int length, byte type) {
                                                int length, byte type) {
        UsbInterfaceDescriptor interfaceDesc = parser.getCurInterface();
        UsbInterfaceDescriptor interfaceDesc = parser.getCurInterface();
        int subClass = interfaceDesc.getUsbSubclass();
        int subClass = interfaceDesc.getUsbSubclass();
        // TODO shouldn't this switch on subtype?
        switch (subClass) {
        switch (subClass) {
            case AUDIO_AUDIOCONTROL:
            case AUDIO_AUDIOCONTROL:
                if (UsbDescriptorParser.DEBUG) {
                if (UsbDescriptorParser.DEBUG) {
+63 −16
Original line number Original line Diff line number Diff line
@@ -26,7 +26,7 @@ import java.util.ArrayList;
 */
 */
public final class UsbDescriptorParser {
public final class UsbDescriptorParser {
    private static final String TAG = "UsbDescriptorParser";
    private static final String TAG = "UsbDescriptorParser";
    public static final boolean DEBUG = true;
    public static final boolean DEBUG = false;


    private final String mDeviceAddr;
    private final String mDeviceAddr;


@@ -43,6 +43,11 @@ public final class UsbDescriptorParser {
    // Obtained from the first AudioClass Header descriptor.
    // Obtained from the first AudioClass Header descriptor.
    private int mACInterfacesSpec = UsbDeviceDescriptor.USBSPEC_1_0;
    private int mACInterfacesSpec = UsbDeviceDescriptor.USBSPEC_1_0;


    // The VideoClass spec implemented by the VideoClass Interfaces
    // This may well be different than the overall USB Spec.
    // Obtained from the first VidieoClass Header descriptor.
    private int mVCInterfacesSpec = UsbDeviceDescriptor.USBSPEC_1_0;

    /**
    /**
     * Connect this parser to an existing set of already parsed descriptors.
     * Connect this parser to an existing set of already parsed descriptors.
     * This is useful for reporting.
     * This is useful for reporting.
@@ -90,6 +95,14 @@ public final class UsbDescriptorParser {
        return mACInterfacesSpec;
        return mACInterfacesSpec;
    }
    }


    public void setVCInterfaceSpec(int spec) {
        mVCInterfacesSpec = spec;
    }

    public int getVCInterfaceSpec() {
        return mVCInterfacesSpec;
    }

    private class UsbDescriptorsStreamFormatException extends Exception {
    private class UsbDescriptorsStreamFormatException extends Exception {
        String mMessage;
        String mMessage;
        UsbDescriptorsStreamFormatException(String message) {
        UsbDescriptorsStreamFormatException(String message) {
@@ -186,19 +199,20 @@ public final class UsbDescriptorParser {
                            break;
                            break;


                        case UsbDescriptor.CLASSID_VIDEO:
                        case UsbDescriptor.CLASSID_VIDEO:
                            Log.d(TAG, "  UsbDescriptor.CLASSID_VIDEO subType:0x"
                            if (DEBUG) {
                                    + Integer.toHexString(stream.getByte()));
                                Log.d(TAG, "  UsbDescriptor.CLASSID_VIDEO");
                            }
                            descriptor = UsbVCInterface.allocDescriptor(this, stream, length, type);
                            descriptor = UsbVCInterface.allocDescriptor(this, stream, length, type);
                            break;
                            break;


                        case UsbDescriptor.CLASSID_AUDIOVIDEO:
                        case UsbDescriptor.CLASSID_AUDIOVIDEO:
                            Log.d(TAG, "  UsbDescriptor.CLASSID_AUDIOVIDEO subType:0x"
                            if (DEBUG) {
                                    + Integer.toHexString(stream.getByte()));
                                Log.d(TAG, "  UsbDescriptor.CLASSID_AUDIOVIDEO");
                            }
                            break;
                            break;


                        default:
                        default:
                            Log.d(TAG, "  Unparsed Class-specific Interface:0x"
                            Log.w(TAG, "  Unparsed Class-specific");
                                    + Integer.toHexString(mCurInterfaceDescriptor.getUsbClass()));
                            break;
                            break;
                    }
                    }
                }
                }
@@ -206,23 +220,32 @@ public final class UsbDescriptorParser {


            case UsbDescriptor.DESCRIPTORTYPE_CLASSSPECIFIC_ENDPOINT:
            case UsbDescriptor.DESCRIPTORTYPE_CLASSSPECIFIC_ENDPOINT:
                if (mCurInterfaceDescriptor != null) {
                if (mCurInterfaceDescriptor != null) {
                    switch (mCurInterfaceDescriptor.getUsbClass()) {
                    int subClass = mCurInterfaceDescriptor.getUsbClass();
                    switch (subClass) {
                        case UsbDescriptor.CLASSID_AUDIO:
                        case UsbDescriptor.CLASSID_AUDIO:
                            descriptor = UsbACEndpoint.allocDescriptor(this, length, type);
                            descriptor = UsbACEndpoint.allocDescriptor(this, length, type);
                            break;
                            break;
                        case UsbDescriptor.CLASSID_VIDEO:

                            Log.d(TAG, "UsbDescriptor.CLASSID_VIDEO subType:0x"
                        case UsbDescriptor.CLASSID_VIDEO: {
                                    + Integer.toHexString(stream.getByte()));
                            Byte subtype = stream.getByte();
                            descriptor = UsbVCEndpoint.allocDescriptor(this, length, type);
                            if (DEBUG) {
                                Log.d(TAG, "UsbDescriptor.CLASSID_VIDEO type:0x"
                                        + Integer.toHexString(type));
                            }
                            descriptor = UsbVCEndpoint.allocDescriptor(this, length, type, subtype);
                        }
                            break;
                            break;


                        case UsbDescriptor.CLASSID_AUDIOVIDEO:
                        case UsbDescriptor.CLASSID_AUDIOVIDEO:
                            Log.d(TAG, "UsbDescriptor.CLASSID_AUDIOVIDEO subType:0x"
                            if (DEBUG) {
                                    + Integer.toHexString(stream.getByte()));
                                Log.d(TAG, "UsbDescriptor.CLASSID_AUDIOVIDEO type:0x"
                                        + Integer.toHexString(type));
                            }
                            break;
                            break;

                        default:
                        default:
                            Log.d(TAG, "  Unparsed Class-specific Endpoint:0x"
                            Log.w(TAG, "  Unparsed Class-specific Endpoint:0x"
                                    + Integer.toHexString(mCurInterfaceDescriptor.getUsbClass()));
                                    + Integer.toHexString(subClass));
                            break;
                            break;
                    }
                    }
                }
                }
@@ -552,6 +575,30 @@ public final class UsbDescriptorParser {
        return hasAudioTerminal(UsbACInterface.ACI_INPUT_TERMINAL);
        return hasAudioTerminal(UsbACInterface.ACI_INPUT_TERMINAL);
    }
    }


    /**
     * @hide
     */
    public boolean hasVideoCapture() {
        for (UsbDescriptor descriptor : mDescriptors) {
            if (descriptor instanceof UsbVCInputTerminal) {
                return true;
            }
        }
        return false;
    }

    /**
     * @hide
     */
    public boolean hasVideoPlayback() {
        for (UsbDescriptor descriptor : mDescriptors) {
            if (descriptor instanceof UsbVCOutputTerminal) {
                return true;
            }
        }
        return false;
    }

    /**
    /**
     * @hide
     * @hide
     */
     */
+2 −1
Original line number Original line Diff line number Diff line
@@ -160,7 +160,8 @@ public final class UsbDeviceDescriptor extends UsbDescriptor {
        return new UsbDevice.Builder(parser.getDeviceAddr(), mVendorID,
        return new UsbDevice.Builder(parser.getDeviceAddr(), mVendorID,
                mProductID, mDevClass, mDevSubClass, mProtocol, mfgName, prodName, versionString,
                mProductID, mDevClass, mDevSubClass, mProtocol, mfgName, prodName, versionString,
                configs, serialStr, parser.hasAudioPlayback(), parser.hasAudioCapture(),
                configs, serialStr, parser.hasAudioPlayback(), parser.hasAudioCapture(),
                parser.hasMIDIInterface());
                parser.hasMIDIInterface(),
                parser.hasVideoPlayback(), parser.hasVideoCapture());
    }
    }


    @Override
    @Override
+37 −24
Original line number Original line Diff line number Diff line
@@ -20,41 +20,54 @@ import android.util.Log;
/**
/**
 * @hide
 * @hide
 * A video class-specific Endpoint
 * A video class-specific Endpoint
 * see
 * see USB_Video_Class_1.1.pdf - 3.10 VideoStreaming Endpoint Descriptors
 */
 */
abstract class UsbVCEndpoint extends UsbDescriptor {
abstract class UsbVCEndpoint extends UsbDescriptor {
    private static final String TAG = "UsbVCEndpoint";
    private static final String TAG = "UsbVCEndpoint";


    UsbVCEndpoint(int length, byte type, int subclass) {

    public static final byte VCEP_UNDEFINED = 0x00;
    public static final byte VCEP_GENERAL   = 0x01;
    public static final byte VCEP_ENDPOINT  = 0x02;
    public static final byte VCEP_INTERRUPT = 0x03;

    UsbVCEndpoint(int length, byte type) {
        super(length, type);
        super(length, type);
        // mSubclass = subclass;
    }
    }


    public static UsbDescriptor allocDescriptor(UsbDescriptorParser parser,
    public static UsbDescriptor allocDescriptor(UsbDescriptorParser parser,
                                                int length, byte type) {
                                                int length, byte type, byte subtype) {
        UsbInterfaceDescriptor interfaceDesc = parser.getCurInterface();
        UsbInterfaceDescriptor interfaceDesc = parser.getCurInterface();
        int subClass = interfaceDesc.getUsbSubclass();

        switch (subClass) {
        // TODO - create classes for each specific subtype
//            case AUDIO_AUDIOCONTROL:
        //  (don't need it to answer if this device supports video
//                if (UsbDescriptorParser.DEBUG) {
        switch (subtype) {
//                    Log.i(TAG, "---> AUDIO_AUDIOCONTROL");
            case VCEP_UNDEFINED:
//                }
                if (UsbDescriptorParser.DEBUG) {
//                return new UsbACAudioControlEndpoint(length, type, subClass);
                    Log.d(TAG, "---> VCEP_UNDEFINED");
//
                }
//            case AUDIO_AUDIOSTREAMING:
                return null;
//                if (UsbDescriptorParser.DEBUG) {

//                    Log.i(TAG, "---> AUDIO_AUDIOSTREAMING");
            case VCEP_GENERAL:
//                }
                if (UsbDescriptorParser.DEBUG) {
//                return new UsbACAudioStreamEndpoint(length, type, subClass);
                    Log.d(TAG, "---> VCEP_GENERAL");
//
                }
//            case AUDIO_MIDISTREAMING:
                return null;
//                if (UsbDescriptorParser.DEBUG) {

//                    Log.i(TAG, "---> AUDIO_MIDISTREAMING");
            case VCEP_ENDPOINT:
//                }
                if (UsbDescriptorParser.DEBUG) {
//                return new UsbACMidiEndpoint(length, type, subClass);
                    Log.d(TAG, "---> VCEP_ENDPOINT");
                }
                return null;

            case VCEP_INTERRUPT:
                if (UsbDescriptorParser.DEBUG) {
                    Log.d(TAG, "---> VCEP_INTERRUPT");
                }
                return null;


            default:
            default:
                Log.w(TAG, "Unknown Video Class Endpoint id:0x" + Integer.toHexString(subClass));
                Log.w(TAG, "Unknown Video Class Endpoint id:0x" + Integer.toHexString(subtype));
                return null;
                return null;
        }
        }
    }
    }
Loading