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                 if (UsbDescriptorParser.DEBUG) {
104                     Log.d(TAG, " ---> ACI_HEADER");
105                 }
106                 int acInterfaceSpec = stream.unpackUsbShort();
107                 parser.setACInterfaceSpec(acInterfaceSpec);
108                 if (UsbDescriptorParser.DEBUG) {
109                     Log.d(TAG, "  acInterfaceSpec:0x" + Integer.toHexString(acInterfaceSpec));
110                 }
111                 if (acInterfaceSpec == UsbDeviceDescriptor.USBSPEC_2_0) {
112                     return new Usb20ACHeader(length, type, subtype, subClass, acInterfaceSpec);
113                 } else {
114                     return new Usb10ACHeader(length, type, subtype, subClass, acInterfaceSpec);
115                 }
116             }
117 
118             case ACI_INPUT_TERMINAL:
119             {
120                 if (UsbDescriptorParser.DEBUG) {
121                     Log.d(TAG, " ---> ACI_INPUT_TERMINAL");
122                 }
123                 int acInterfaceSpec = parser.getACInterfaceSpec();
124                 if (UsbDescriptorParser.DEBUG) {
125                     Log.d(TAG, "  acInterfaceSpec:0x" + Integer.toHexString(acInterfaceSpec));
126                 }
127                 if (acInterfaceSpec == UsbDeviceDescriptor.USBSPEC_2_0) {
128                     return new Usb20ACInputTerminal(length, type, subtype, subClass);
129                 } else {
130                     return new Usb10ACInputTerminal(length, type, subtype, subClass);
131                 }
132             }
133 
134             case ACI_OUTPUT_TERMINAL:
135             {
136                 if (UsbDescriptorParser.DEBUG) {
137                     Log.d(TAG, " ---> ACI_OUTPUT_TERMINAL");
138                 }
139                 int acInterfaceSpec = parser.getACInterfaceSpec();
140                 if (UsbDescriptorParser.DEBUG) {
141                     Log.d(TAG, "  acInterfaceSpec:0x" + Integer.toHexString(acInterfaceSpec));
142                 }
143                 if (acInterfaceSpec == UsbDeviceDescriptor.USBSPEC_2_0) {
144                     return new Usb20ACOutputTerminal(length, type, subtype, subClass);
145                 } else {
146                     return new Usb10ACOutputTerminal(length, type, subtype, subClass);
147                 }
148             }
149 
150             case ACI_SELECTOR_UNIT:
151                 if (UsbDescriptorParser.DEBUG) {
152                     Log.d(TAG, " ---> ACI_SELECTOR_UNIT");
153                 }
154                 return new UsbACSelectorUnit(length, type, subtype, subClass);
155 
156             case ACI_FEATURE_UNIT:
157                 if (UsbDescriptorParser.DEBUG) {
158                     Log.d(TAG, " ---> ACI_FEATURE_UNIT");
159                 }
160                 return new UsbACFeatureUnit(length, type, subtype, subClass);
161 
162             case ACI_MIXER_UNIT:
163             {
164                 if (UsbDescriptorParser.DEBUG) {
165                     Log.d(TAG, " ---> ACI_MIXER_UNIT");
166                 }
167                 int acInterfaceSpec = parser.getACInterfaceSpec();
168                 if (UsbDescriptorParser.DEBUG) {
169                     Log.d(TAG, "  acInterfaceSpec:0x" + Integer.toHexString(acInterfaceSpec));
170                 }
171                 if (acInterfaceSpec == UsbDeviceDescriptor.USBSPEC_2_0) {
172                     return new Usb20ACMixerUnit(length, type, subtype, subClass);
173                 } else {
174                     return new Usb10ACMixerUnit(length, type, subtype, subClass);
175                 }
176             }
177 
178             case ACI_PROCESSING_UNIT:
179             case ACI_EXTENSION_UNIT:
180             case ACI_UNDEFINED:
181                 // break; Fall through until we implement this descriptor
182             default:
183                 Log.w(TAG, "Unknown Audio Class Interface subtype:0x"
184                         + Integer.toHexString(subtype));
185                 return new UsbACInterfaceUnparsed(length, type, subtype, subClass);
186         }
187     }
188 
allocAudioStreamingDescriptor(UsbDescriptorParser parser, ByteStream stream, int length, byte type, byte subtype, int subClass)189     private static UsbDescriptor allocAudioStreamingDescriptor(UsbDescriptorParser parser,
190             ByteStream stream, int length, byte type, byte subtype, int subClass) {
191         //int spec = parser.getUsbSpec();
192         int acInterfaceSpec = parser.getACInterfaceSpec();
193         switch (subtype) {
194             case ASI_GENERAL:
195                 if (acInterfaceSpec == UsbDeviceDescriptor.USBSPEC_2_0) {
196                     return new Usb20ASGeneral(length, type, subtype, subClass);
197                 } else {
198                     return new Usb10ASGeneral(length, type, subtype, subClass);
199                 }
200 
201             case ASI_FORMAT_TYPE:
202                 return UsbASFormat.allocDescriptor(parser, stream, length, type, subtype, subClass);
203 
204             case ASI_FORMAT_SPECIFIC:
205             case ASI_UNDEFINED:
206                 // break; Fall through until we implement this descriptor
207             default:
208                 Log.w(TAG, "Unknown Audio Streaming Interface subtype:0x"
209                         + Integer.toHexString(subtype));
210                 return null;
211         }
212     }
213 
allocMidiStreamingDescriptor(int length, byte type, byte subtype, int subClass)214     private static UsbDescriptor allocMidiStreamingDescriptor(int length, byte type,
215             byte subtype, int subClass) {
216         switch (subtype) {
217             case MSI_HEADER:
218                 return new UsbMSMidiHeader(length, type, subtype, subClass);
219 
220             case MSI_IN_JACK:
221                 return new UsbMSMidiInputJack(length, type, subtype, subClass);
222 
223             case MSI_OUT_JACK:
224                 return new UsbMSMidiOutputJack(length, type, subtype, subClass);
225 
226             case MSI_ELEMENT:
227                 // break;
228                 // Fall through until we implement that descriptor
229 
230             case MSI_UNDEFINED:
231             default:
232                 Log.w(TAG, "Unknown MIDI Streaming Interface subtype:0x"
233                         + Integer.toHexString(subtype));
234                 return null;
235         }
236     }
237 
238     /**
239      * Allocates an audio class interface subtype based on subtype and subclass.
240      */
allocDescriptor(UsbDescriptorParser parser, ByteStream stream, int length, byte type)241     public static UsbDescriptor allocDescriptor(UsbDescriptorParser parser, ByteStream stream,
242             int length, byte type) {
243         byte subtype = stream.getByte();
244         UsbInterfaceDescriptor interfaceDesc = parser.getCurInterface();
245         int subClass = interfaceDesc.getUsbSubclass();
246         switch (subClass) {
247             case AUDIO_AUDIOCONTROL:
248                 if (UsbDescriptorParser.DEBUG) {
249                     Log.d(TAG, "  AUDIO_AUDIOCONTROL");
250                 }
251                 return allocAudioControlDescriptor(
252                         parser, stream, length, type, subtype, subClass);
253 
254             case AUDIO_AUDIOSTREAMING:
255                 if (UsbDescriptorParser.DEBUG) {
256                     Log.d(TAG, "  AUDIO_AUDIOSTREAMING");
257                 }
258                 return allocAudioStreamingDescriptor(
259                         parser, stream, length, type, subtype, subClass);
260 
261             case AUDIO_MIDISTREAMING:
262                 if (UsbDescriptorParser.DEBUG) {
263                     Log.d(TAG, "  AUDIO_MIDISTREAMING");
264                 }
265                 return allocMidiStreamingDescriptor(length, type, subtype, subClass);
266 
267             default:
268                 Log.w(TAG, "Unknown Audio Class Interface Subclass: 0x"
269                         + Integer.toHexString(subClass));
270                 return null;
271         }
272     }
273 
274     @Override
report(ReportCanvas canvas)275     public void report(ReportCanvas canvas) {
276         super.report(canvas);
277 
278         int subClass = getSubclass();
279         String subClassName = UsbStrings.getACInterfaceSubclassName(subClass);
280 
281         byte subtype = getSubtype();
282         String subTypeName = UsbStrings.getACControlInterfaceName(subtype);
283 
284         canvas.openList();
285         canvas.writeListItem("Subclass: " + ReportCanvas.getHexString(subClass)
286                 + " " + subClassName);
287         canvas.writeListItem("Subtype: " + ReportCanvas.getHexString(subtype) + " " + subTypeName);
288         canvas.closeList();
289     }
290 }
291