1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.server.usb.descriptors;
17 
18 import android.util.Log;
19 
20 import com.android.server.usb.descriptors.report.ReportCanvas;
21 import com.android.server.usb.descriptors.report.UsbStrings;
22 
23 /**
24  * @hide
25  * An audio class-specific Interface.
26  * see audio10.pdf section 4.3.2
27  */
28 public abstract class UsbACInterface extends UsbDescriptor {
29     private static final String TAG = "UsbACInterface";
30 
31     // Audio Control Subtypes
32     public static final byte ACI_UNDEFINED = 0;
33     public static final byte ACI_HEADER = 1;
34     public static final byte ACI_INPUT_TERMINAL = 2;
35     public static final byte ACI_OUTPUT_TERMINAL = 3;
36     public static final byte ACI_MIXER_UNIT = 4;
37     public static final byte ACI_SELECTOR_UNIT = 5;
38     public static final byte ACI_FEATURE_UNIT = 6;
39     public static final byte ACI_PROCESSING_UNIT = 7;
40     public static final byte ACI_EXTENSION_UNIT = 8;
41     // Not handled yet
42     public static final byte ACI_CLOCK_SOURCE = 0x0A;
43     public static final byte ACI_CLOCK_SELECTOR = 0x0B;
44     public static final byte ACI_CLOCK_MULTIPLIER = 0x0C;
45     public static final byte ACI_SAMPLE_RATE_CONVERTER =  0x0D;
46 
47     // Audio Streaming Subtypes
48     public static final byte ASI_UNDEFINED = 0;
49     public static final byte ASI_GENERAL = 1;
50     public static final byte ASI_FORMAT_TYPE = 2;
51     public static final byte ASI_FORMAT_SPECIFIC = 3;
52 
53     // MIDI Streaming Subtypes
54     public static final byte MSI_UNDEFINED = 0;
55     public static final byte MSI_HEADER = 1;
56     public static final byte MSI_IN_JACK = 2;
57     public static final byte MSI_OUT_JACK = 3;
58     public static final byte MSI_ELEMENT = 4;
59 
60     // Sample format IDs (encodings)
61     // FORMAT_I
62     public static final int FORMAT_I_UNDEFINED     = 0x0000;
63     public static final int FORMAT_I_PCM           = 0x0001;
64     public static final int FORMAT_I_PCM8          = 0x0002;
65     public static final int FORMAT_I_IEEE_FLOAT    = 0x0003;
66     public static final int FORMAT_I_ALAW          = 0x0004;
67     public static final int FORMAT_I_MULAW         = 0x0005;
68     // FORMAT_II
69     public static final int FORMAT_II_UNDEFINED    = 0x1000;
70     public static final int FORMAT_II_MPEG         = 0x1001;
71     public static final int FORMAT_II_AC3          = 0x1002;
72     // FORMAT_III
73     public static final int FORMAT_III_UNDEFINED              = 0x2000;
74     public static final int FORMAT_III_IEC1937AC3             = 0x2001;
75     public static final int FORMAT_III_IEC1937_MPEG1_Layer1   = 0x2002;
76     public static final int FORMAT_III_IEC1937_MPEG1_Layer2   = 0x2003;
77     public static final int FORMAT_III_IEC1937_MPEG2_EXT      = 0x2004;
78     public static final int FORMAT_III_IEC1937_MPEG2_Layer1LS = 0x2005;
79 
80     protected final byte mSubtype;  // 2:1 HEADER descriptor subtype
81     protected final int mSubclass;  // from the mSubclass member of the
82                                     // "enclosing" Interface Descriptor
83 
UsbACInterface(int length, byte type, byte subtype, int subclass)84     public UsbACInterface(int length, byte type, byte subtype, int subclass) {
85         super(length, type);
86         mSubtype = subtype;
87         mSubclass = subclass;
88     }
89 
getSubtype()90     public byte getSubtype() {
91         return mSubtype;
92     }
93 
getSubclass()94     public int getSubclass() {
95         return mSubclass;
96     }
97 
allocAudioControlDescriptor(UsbDescriptorParser parser, ByteStream stream, int length, byte type, byte subtype, int subClass)98     private static UsbDescriptor allocAudioControlDescriptor(UsbDescriptorParser parser,
99             ByteStream stream, int length, byte type, byte subtype, int subClass) {
100         switch (subtype) {
101             case ACI_HEADER:
102             {
103                 int acInterfaceSpec = stream.unpackUsbShort();
104                 parser.setACInterfaceSpec(acInterfaceSpec);
105                 if (acInterfaceSpec == UsbDeviceDescriptor.USBSPEC_2_0) {
106                     return new Usb20ACHeader(length, type, subtype, subClass, acInterfaceSpec);
107                 } else {
108                     return new Usb10ACHeader(length, type, subtype, subClass, acInterfaceSpec);
109                 }
110             }
111 
112             case ACI_INPUT_TERMINAL:
113             {
114                 int acInterfaceSpec = parser.getACInterfaceSpec();
115                 if (acInterfaceSpec == UsbDeviceDescriptor.USBSPEC_2_0) {
116                     return new Usb20ACInputTerminal(length, type, subtype, subClass);
117                 } else {
118                     return new Usb10ACInputTerminal(length, type, subtype, subClass);
119                 }
120             }
121 
122             case ACI_OUTPUT_TERMINAL:
123             {
124                 int acInterfaceSpec = parser.getACInterfaceSpec();
125                 if (acInterfaceSpec == UsbDeviceDescriptor.USBSPEC_2_0) {
126                     return new Usb20ACOutputTerminal(length, type, subtype, subClass);
127                 } else {
128                     return new Usb10ACOutputTerminal(length, type, subtype, subClass);
129                 }
130             }
131 
132             case ACI_SELECTOR_UNIT:
133                 return new UsbACSelectorUnit(length, type, subtype, subClass);
134 
135             case ACI_FEATURE_UNIT:
136                 return new UsbACFeatureUnit(length, type, subtype, subClass);
137 
138             case ACI_MIXER_UNIT:
139             {
140                 int acInterfaceSpec = parser.getACInterfaceSpec();
141                 if (acInterfaceSpec == UsbDeviceDescriptor.USBSPEC_2_0) {
142                     return new Usb20ACMixerUnit(length, type, subtype, subClass);
143                 } else {
144                     return new Usb10ACMixerUnit(length, type, subtype, subClass);
145                 }
146             }
147 
148             case ACI_PROCESSING_UNIT:
149             case ACI_EXTENSION_UNIT:
150             case ACI_UNDEFINED:
151                 // break; Fall through until we implement this descriptor
152             default:
153                 Log.w(TAG, "Unknown Audio Class Interface subtype:0x"
154                         + Integer.toHexString(subtype));
155                 return new UsbACInterfaceUnparsed(length, type, subtype, subClass);
156         }
157     }
158 
allocAudioStreamingDescriptor(UsbDescriptorParser parser, ByteStream stream, int length, byte type, byte subtype, int subClass)159     private static UsbDescriptor allocAudioStreamingDescriptor(UsbDescriptorParser parser,
160             ByteStream stream, int length, byte type, byte subtype, int subClass) {
161         //int spec = parser.getUsbSpec();
162         int acInterfaceSpec = parser.getACInterfaceSpec();
163         switch (subtype) {
164             case ASI_GENERAL:
165                 if (acInterfaceSpec == UsbDeviceDescriptor.USBSPEC_2_0) {
166                     return new Usb20ASGeneral(length, type, subtype, subClass);
167                 } else {
168                     return new Usb10ASGeneral(length, type, subtype, subClass);
169                 }
170 
171             case ASI_FORMAT_TYPE:
172                 return UsbASFormat.allocDescriptor(parser, stream, length, type, subtype, subClass);
173 
174             case ASI_FORMAT_SPECIFIC:
175             case ASI_UNDEFINED:
176                 // break; Fall through until we implement this descriptor
177             default:
178                 Log.w(TAG, "Unknown Audio Streaming Interface subtype:0x"
179                         + Integer.toHexString(subtype));
180                 return null;
181         }
182     }
183 
allocMidiStreamingDescriptor(int length, byte type, byte subtype, int subClass)184     private static UsbDescriptor allocMidiStreamingDescriptor(int length, byte type,
185             byte subtype, int subClass) {
186         switch (subtype) {
187             case MSI_HEADER:
188                 return new UsbMSMidiHeader(length, type, subtype, subClass);
189 
190             case MSI_IN_JACK:
191                 return new UsbMSMidiInputJack(length, type, subtype, subClass);
192 
193             case MSI_OUT_JACK:
194                 return new UsbMSMidiOutputJack(length, type, subtype, subClass);
195 
196             case MSI_ELEMENT:
197                 // break;
198                 // Fall through until we implement that descriptor
199 
200             case MSI_UNDEFINED:
201             default:
202                 Log.w(TAG, "Unknown MIDI Streaming Interface subtype:0x"
203                         + Integer.toHexString(subtype));
204                 return null;
205         }
206     }
207 
208     /**
209      * Allocates an audio class interface subtype based on subtype and subclass.
210      */
allocDescriptor(UsbDescriptorParser parser, ByteStream stream, int length, byte type)211     public static UsbDescriptor allocDescriptor(UsbDescriptorParser parser, ByteStream stream,
212             int length, byte type) {
213         byte subtype = stream.getByte();
214         UsbInterfaceDescriptor interfaceDesc = parser.getCurInterface();
215         int subClass = interfaceDesc.getUsbSubclass();
216         switch (subClass) {
217             case AUDIO_AUDIOCONTROL:
218                 return allocAudioControlDescriptor(
219                         parser, stream, length, type, subtype, subClass);
220 
221             case AUDIO_AUDIOSTREAMING:
222                 return allocAudioStreamingDescriptor(
223                         parser, stream, length, type, subtype, subClass);
224 
225             case AUDIO_MIDISTREAMING:
226                 return allocMidiStreamingDescriptor(length, type, subtype, subClass);
227 
228             default:
229                 Log.w(TAG, "Unknown Audio Class Interface Subclass: 0x"
230                         + Integer.toHexString(subClass));
231                 return null;
232         }
233     }
234 
235     @Override
report(ReportCanvas canvas)236     public void report(ReportCanvas canvas) {
237         super.report(canvas);
238 
239         int subClass = getSubclass();
240         String subClassName = UsbStrings.getACInterfaceSubclassName(subClass);
241 
242         byte subtype = getSubtype();
243         String subTypeName = UsbStrings.getACControlInterfaceName(subtype);
244 
245         canvas.openList();
246         canvas.writeListItem("Subclass: " + ReportCanvas.getHexString(subClass)
247                 + " " + subClassName);
248         canvas.writeListItem("Subtype: " + ReportCanvas.getHexString(subtype) + " " + subTypeName);
249         canvas.closeList();
250     }
251 }
252