• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 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 
17 package android.media.midi;
18 
19 import android.annotation.IntDef;
20 import android.os.Bundle;
21 import android.os.Parcel;
22 import android.os.Parcelable;
23 import android.util.Log;
24 
25 import java.lang.annotation.Retention;
26 import java.lang.annotation.RetentionPolicy;
27 
28 /**
29  * This class contains information to describe a MIDI device.
30  * For now we only have information that can be retrieved easily for USB devices,
31  * but we will probably expand this in the future.
32  *
33  * This class is just an immutable object to encapsulate the MIDI device description.
34  * Use the MidiDevice class to actually communicate with devices.
35  */
36 public final class MidiDeviceInfo implements Parcelable {
37 
38     private static final String TAG = "MidiDeviceInfo";
39 
40     /*
41      * Please note that constants and (un)marshalling code need to be kept in sync
42      * with the native implementation (MidiDeviceInfo.h|cpp)
43      */
44 
45     /**
46      * Constant representing USB MIDI devices for {@link #getType}
47      */
48     public static final int TYPE_USB = 1;
49 
50     /**
51      * Constant representing virtual (software based) MIDI devices for {@link #getType}
52      */
53     public static final int TYPE_VIRTUAL = 2;
54 
55     /**
56      * Constant representing Bluetooth MIDI devices for {@link #getType}
57      */
58     public static final int TYPE_BLUETOOTH = 3;
59 
60     /**
61      * Constant representing a default protocol with Universal MIDI Packets (UMP).
62      * UMP is defined in "Universal MIDI Packet (UMP) Format and MIDI 2.0 Protocol" spec.
63      * All UMP data should be a multiple of 4 bytes.
64      * Use UMP to negotiate with the device with MIDI-CI.
65      * MIDI-CI is defined in "MIDI Capability Inquiry (MIDI-CI)" spec.
66      * Call {@link MidiManager#getDevicesForTransport} with parameter
67      * {@link MidiManager#TRANSPORT_UNIVERSAL_MIDI_PACKETS} to get devices with this transport.
68      * @see MidiDeviceInfo#getDefaultProtocol
69      */
70     public static final int PROTOCOL_UMP_USE_MIDI_CI = 0;
71 
72     /**
73      * Constant representing a default protocol with Universal MIDI Packets (UMP).
74      * UMP is defined in "Universal MIDI Packet (UMP) Format and MIDI 2.0 Protocol" spec.
75      * All UMP data should be a multiple of 4 bytes.
76      * Use MIDI 1.0 through UMP with packet sizes up to 64 bits.
77      * Call {@link MidiManager#getDevicesForTransport} with parameter
78      * {@link MidiManager#TRANSPORT_UNIVERSAL_MIDI_PACKETS} to get devices with this transport.
79      * @see MidiDeviceInfo#getDefaultProtocol
80      */
81     public static final int PROTOCOL_UMP_MIDI_1_0_UP_TO_64_BITS = 1;
82 
83     /**
84      * Constant representing a default protocol with Universal MIDI Packets (UMP).
85      * UMP is defined in "Universal MIDI Packet (UMP) Format and MIDI 2.0 Protocol" spec.
86      * All UMP data should be a multiple of 4 bytes.
87      * Use MIDI 1.0 through UMP with packet sizes up to 64 bits and jitter reduction timestamps.
88      * Call {@link MidiManager#getDevicesForTransport} with parameter
89      * {@link MidiManager#TRANSPORT_UNIVERSAL_MIDI_PACKETS} to get devices with this transport.
90      * @see MidiDeviceInfo#getDefaultProtocol
91      */
92     public static final int PROTOCOL_UMP_MIDI_1_0_UP_TO_64_BITS_AND_JRTS = 2;
93 
94     /**
95      * Constant representing a default protocol with Universal MIDI Packets (UMP).
96      * UMP is defined in "Universal MIDI Packet (UMP) Format and MIDI 2.0 Protocol" spec.
97      * All UMP data should be a multiple of 4 bytes.
98      * Use MIDI 1.0 through UMP with packet sizes up to 128 bits.
99      * Call {@link MidiManager#getDevicesForTransport} with parameter
100      * {@link MidiManager#TRANSPORT_UNIVERSAL_MIDI_PACKETS} to get devices with this transport.
101      * @see MidiDeviceInfo#getDefaultProtocol
102      */
103     public static final int PROTOCOL_UMP_MIDI_1_0_UP_TO_128_BITS = 3;
104 
105     /**
106      * Constant representing a default protocol with Universal MIDI Packets (UMP).
107      * UMP is defined in "Universal MIDI Packet (UMP) Format and MIDI 2.0 Protocol" spec.
108      * All UMP data should be a multiple of 4 bytes.
109      * Use MIDI 1.0 through UMP with packet sizes up to 128 bits and jitter reduction timestamps.
110      * Call {@link MidiManager#getDevicesForTransport} with parameter
111      * {@link MidiManager#TRANSPORT_UNIVERSAL_MIDI_PACKETS} to get devices with this transport.
112      * @see MidiDeviceInfo#getDefaultProtocol
113      */
114     public static final int PROTOCOL_UMP_MIDI_1_0_UP_TO_128_BITS_AND_JRTS = 4;
115 
116     /**
117      * Constant representing a default protocol with Universal MIDI Packets (UMP).
118      * UMP is defined in "Universal MIDI Packet (UMP) Format and MIDI 2.0 Protocol" spec.
119      * All UMP data should be a multiple of 4 bytes.
120      * Use MIDI 2.0 through UMP.
121      * Call {@link MidiManager#getDevicesForTransport} with parameter
122      * {@link MidiManager#TRANSPORT_UNIVERSAL_MIDI_PACKETS} to get devices with this transport.
123      * @see MidiDeviceInfo#getDefaultProtocol
124      */
125     public static final int PROTOCOL_UMP_MIDI_2_0 = 17;
126 
127      /**
128      * Constant representing a default protocol with Universal MIDI Packets (UMP).
129      * UMP is defined in "Universal MIDI Packet (UMP) Format and MIDI 2.0 Protocol" spec.
130      * All UMP data should be a multiple of 4 bytes.
131      * Use MIDI 2.0 through UMP and jitter reduction timestamps.
132      * Call {@link MidiManager#getDevicesForTransport} with parameter
133      * {@link MidiManager#TRANSPORT_UNIVERSAL_MIDI_PACKETS} to get devices with this transport.
134      * @see MidiDeviceInfo#getDefaultProtocol
135      */
136     public static final int PROTOCOL_UMP_MIDI_2_0_AND_JRTS = 18;
137 
138     /**
139      * Constant representing a device with an unknown default protocol.
140      * If Universal MIDI Packets (UMP) are needed, use MIDI-CI through MIDI 1.0.
141      * UMP is defined in "Universal MIDI Packet (UMP) Format and MIDI 2.0 Protocol" spec.
142      * MIDI-CI is defined in "MIDI Capability Inquiry (MIDI-CI)" spec.
143      * @see MidiDeviceInfo#getDefaultProtocol
144      */
145     public static final int PROTOCOL_UNKNOWN = -1;
146 
147     /**
148      * @see MidiDeviceInfo#getDefaultProtocol
149      * @hide
150      */
151     @IntDef(prefix = { "PROTOCOL_" }, value = {
152             PROTOCOL_UMP_USE_MIDI_CI,
153             PROTOCOL_UMP_MIDI_1_0_UP_TO_64_BITS,
154             PROTOCOL_UMP_MIDI_1_0_UP_TO_64_BITS_AND_JRTS,
155             PROTOCOL_UMP_MIDI_1_0_UP_TO_128_BITS,
156             PROTOCOL_UMP_MIDI_1_0_UP_TO_128_BITS_AND_JRTS,
157             PROTOCOL_UMP_MIDI_2_0,
158             PROTOCOL_UMP_MIDI_2_0_AND_JRTS,
159             PROTOCOL_UNKNOWN
160     })
161     @Retention(RetentionPolicy.SOURCE)
162     public @interface Protocol {}
163 
164     /**
165      * Bundle key for the device's user visible name property.
166      * The value for this property is of type {@link java.lang.String}.
167      * Used with the {@link android.os.Bundle} returned by {@link #getProperties}.
168      * For USB devices, this is a concatenation of the manufacturer and product names.
169      */
170     public static final String PROPERTY_NAME = "name";
171 
172     /**
173      * Bundle key for the device's manufacturer name property.
174      * The value for this property is of type {@link java.lang.String}.
175      * Used with the {@link android.os.Bundle} returned by {@link #getProperties}.
176      * Matches the USB device manufacturer name string for USB MIDI devices.
177      */
178     public static final String PROPERTY_MANUFACTURER = "manufacturer";
179 
180     /**
181      * Bundle key for the device's product name property.
182      * The value for this property is of type {@link java.lang.String}.
183      * Used with the {@link android.os.Bundle} returned by {@link #getProperties}
184      * Matches the USB device product name string for USB MIDI devices.
185      */
186     public static final String PROPERTY_PRODUCT = "product";
187 
188     /**
189      * Bundle key for the device's version property.
190      * The value for this property is of type {@link java.lang.String}.
191      * Used with the {@link android.os.Bundle} returned by {@link #getProperties}
192      * Matches the USB device version number for USB MIDI devices.
193      */
194     public static final String PROPERTY_VERSION = "version";
195 
196     /**
197      * Bundle key for the device's serial number property.
198      * The value for this property is of type {@link java.lang.String}.
199      * Used with the {@link android.os.Bundle} returned by {@link #getProperties}
200      * Matches the USB device serial number for USB MIDI devices.
201      */
202     public static final String PROPERTY_SERIAL_NUMBER = "serial_number";
203 
204     /**
205      * Bundle key for the device's corresponding USB device.
206      * The value for this property is of type {@link android.hardware.usb.UsbDevice}.
207      * Only set for USB MIDI devices.
208      * Used with the {@link android.os.Bundle} returned by {@link #getProperties}
209      */
210     public static final String PROPERTY_USB_DEVICE = "usb_device";
211 
212     /**
213      * Bundle key for the device's corresponding Bluetooth device.
214      * The value for this property is of type {@link android.bluetooth.BluetoothDevice}.
215      * Only set for Bluetooth MIDI devices.
216      * Used with the {@link android.os.Bundle} returned by {@link #getProperties}
217      */
218     public static final String PROPERTY_BLUETOOTH_DEVICE = "bluetooth_device";
219 
220     /**
221      * Bundle key for the device's ALSA card number.
222      * The value for this property is an integer.
223      * Only set for USB MIDI devices.
224      * Used with the {@link android.os.Bundle} returned by {@link #getProperties}
225      *
226      * @hide
227      */
228     public static final String PROPERTY_ALSA_CARD = "alsa_card";
229 
230     /**
231      * Bundle key for the device's ALSA device number.
232      * The value for this property is an integer.
233      * Only set for USB MIDI devices.
234      * Used with the {@link android.os.Bundle} returned by {@link #getProperties}
235      *
236      * @hide
237      */
238     public static final String PROPERTY_ALSA_DEVICE = "alsa_device";
239 
240     /**
241      * ServiceInfo for the service hosting the device implementation.
242      * The value for this property is of type {@link android.content.pm.ServiceInfo}.
243      * Only set for Virtual MIDI devices.
244      * Used with the {@link android.os.Bundle} returned by {@link #getProperties}
245      *
246      * @hide
247      */
248     public static final String PROPERTY_SERVICE_INFO = "service_info";
249 
250     /**
251      * Contains information about an input or output port.
252      */
253     public static final class PortInfo {
254         /**
255          * Port type for input ports
256          */
257         public static final int TYPE_INPUT = 1;
258 
259         /**
260          * Port type for output ports
261          */
262         public static final int TYPE_OUTPUT = 2;
263 
264         private final int mPortType;
265         private final int mPortNumber;
266         private final String mName;
267 
PortInfo(int type, int portNumber, String name)268         PortInfo(int type, int portNumber, String name) {
269             mPortType = type;
270             mPortNumber = portNumber;
271             mName = (name == null ? "" : name);
272         }
273 
274         /**
275          * Returns the port type of the port (either {@link #TYPE_INPUT} or {@link #TYPE_OUTPUT})
276          * @return the port type
277          */
getType()278         public int getType() {
279             return mPortType;
280         }
281 
282         /**
283          * Returns the port number of the port
284          * @return the port number
285          */
getPortNumber()286         public int getPortNumber() {
287             return mPortNumber;
288         }
289 
290         /**
291          * Returns the name of the port, or empty string if the port has no name
292          * @return the port name
293          */
getName()294         public String getName() {
295             return mName;
296         }
297     }
298 
299     private final int mType;    // USB or virtual
300     private final int mId;      // unique ID generated by MidiService. Accessed from native code.
301     private final int mInputPortCount;
302     private final int mOutputPortCount;
303     private final String[] mInputPortNames;
304     private final String[] mOutputPortNames;
305     private final Bundle mProperties;
306     private final boolean mIsPrivate;
307     private final int mDefaultProtocol;
308 
309     /**
310      * MidiDeviceInfo should only be instantiated by MidiService implementation
311      * @hide
312      */
MidiDeviceInfo(int type, int id, int numInputPorts, int numOutputPorts, String[] inputPortNames, String[] outputPortNames, Bundle properties, boolean isPrivate, int defaultProtocol)313     public MidiDeviceInfo(int type, int id, int numInputPorts, int numOutputPorts,
314             String[] inputPortNames, String[] outputPortNames, Bundle properties,
315             boolean isPrivate, int defaultProtocol) {
316         // Check num ports for out-of-range values. Typical values will be
317         // between zero and three. More than 16 would be very unlikely
318         // because the port index field in the USB packet is only 4 bits.
319         // This check is mainly just to prevent OutOfMemoryErrors when
320         // fuzz testing.
321         final int maxPorts = 256; // arbitrary and very high
322         if (numInputPorts < 0 || numInputPorts > maxPorts) {
323             throw new IllegalArgumentException("numInputPorts out of range = "
324                     + numInputPorts);
325         }
326         if (numOutputPorts < 0 || numOutputPorts > maxPorts) {
327             throw new IllegalArgumentException("numOutputPorts out of range = "
328                     + numOutputPorts);
329         }
330         mType = type;
331         mId = id;
332         mInputPortCount = numInputPorts;
333         mOutputPortCount = numOutputPorts;
334         if (inputPortNames == null) {
335             mInputPortNames = new String[numInputPorts];
336         } else {
337             mInputPortNames = inputPortNames;
338         }
339         if (outputPortNames == null) {
340             mOutputPortNames = new String[numOutputPorts];
341         } else {
342             mOutputPortNames = outputPortNames;
343         }
344         mProperties = properties;
345         mIsPrivate = isPrivate;
346         mDefaultProtocol = defaultProtocol;
347     }
348 
349     /**
350      * Returns the type of the device.
351      *
352      * @return the device's type
353      */
getType()354     public int getType() {
355         return mType;
356     }
357 
358     /**
359      * Returns the ID of the device.
360      * This ID is generated by the MIDI service and is not persistent across device unplugs.
361      *
362      * @return the device's ID
363      */
getId()364     public int getId() {
365         return mId;
366     }
367 
368     /**
369      * Returns the device's number of input ports.
370      *
371      * @return the number of input ports
372      */
getInputPortCount()373     public int getInputPortCount() {
374         return mInputPortCount;
375     }
376 
377     /**
378      * Returns the device's number of output ports.
379      *
380      * @return the number of output ports
381      */
getOutputPortCount()382     public int getOutputPortCount() {
383         return mOutputPortCount;
384     }
385 
386     /**
387      * Returns information about the device's ports.
388      * The ports are in unspecified order.
389      *
390      * @return array of {@link PortInfo}
391      */
getPorts()392     public PortInfo[] getPorts() {
393         PortInfo[] ports = new PortInfo[mInputPortCount + mOutputPortCount];
394 
395         int index = 0;
396         for (int i = 0; i < mInputPortCount; i++) {
397             ports[index++] = new PortInfo(PortInfo.TYPE_INPUT, i, mInputPortNames[i]);
398         }
399         for (int i = 0; i < mOutputPortCount; i++) {
400             ports[index++] = new PortInfo(PortInfo.TYPE_OUTPUT, i, mOutputPortNames[i]);
401         }
402 
403         return ports;
404     }
405 
406     /**
407      * Returns the {@link android.os.Bundle} containing the device's properties.
408      *
409      * @return the device's properties
410      */
getProperties()411     public Bundle getProperties() {
412         return mProperties;
413     }
414 
415     /**
416      * Returns true if the device is private.  Private devices are only visible and accessible
417      * to clients with the same UID as the application that is hosting the device.
418      *
419      * @return true if the device is private
420      */
isPrivate()421     public boolean isPrivate() {
422         return mIsPrivate;
423     }
424 
425     /**
426      * Returns the default protocol. For most devices, this will be {@link #PROTOCOL_UNKNOWN}.
427      * Returning {@link #PROTOCOL_UNKNOWN} is not an error; the device just doesn't support
428      * Universal MIDI Packets by default.
429      *
430      * @return the device's default protocol.
431      */
432     @Protocol
getDefaultProtocol()433     public int getDefaultProtocol() {
434         return mDefaultProtocol;
435     }
436 
437     @Override
equals(Object o)438     public boolean equals(Object o) {
439         if (o instanceof MidiDeviceInfo) {
440             return (((MidiDeviceInfo)o).mId == mId);
441         } else {
442             return false;
443         }
444     }
445 
446     @Override
hashCode()447     public int hashCode() {
448         return mId;
449     }
450 
451     @Override
toString()452     public String toString() {
453         // This is a hack to force the mProperties Bundle to unparcel so we can
454         // print all the names and values.
455         mProperties.getString(PROPERTY_NAME);
456         return ("MidiDeviceInfo[mType=" + mType
457                 + ",mInputPortCount=" + mInputPortCount
458                 + ",mOutputPortCount=" + mOutputPortCount
459                 + ",mProperties=" + mProperties
460                 + ",mIsPrivate=" + mIsPrivate
461                 + ",mDefaultProtocol=" + mDefaultProtocol);
462     }
463 
464     public static final @android.annotation.NonNull Parcelable.Creator<MidiDeviceInfo> CREATOR =
465         new Parcelable.Creator<MidiDeviceInfo>() {
466         public MidiDeviceInfo createFromParcel(Parcel in) {
467             // Needs to be kept in sync with code in MidiDeviceInfo.cpp
468             int type = in.readInt();
469             int id = in.readInt();
470             int inputPortCount = in.readInt();
471             int outputPortCount = in.readInt();
472             String[] inputPortNames = in.createStringArray();
473             String[] outputPortNames = in.createStringArray();
474             boolean isPrivate = (in.readInt() == 1);
475             int defaultProtocol = in.readInt();
476             Bundle basicPropertiesIgnored = in.readBundle();
477             Bundle properties = in.readBundle();
478             return new MidiDeviceInfo(type, id, inputPortCount, outputPortCount,
479                     inputPortNames, outputPortNames, properties, isPrivate,
480                     defaultProtocol);
481         }
482 
483         public MidiDeviceInfo[] newArray(int size) {
484             return new MidiDeviceInfo[size];
485         }
486     };
487 
describeContents()488     public int describeContents() {
489         return 0;
490     }
491 
getBasicProperties(String[] keys)492     private Bundle getBasicProperties(String[] keys) {
493         Bundle basicProperties = new Bundle();
494         for (String key : keys) {
495             Object val = mProperties.get(key);
496             if (val != null) {
497                 if (val instanceof String) {
498                     basicProperties.putString(key, (String) val);
499                 } else if (val instanceof Integer) {
500                     basicProperties.putInt(key, (Integer) val);
501                 } else {
502                     Log.w(TAG, "Unsupported property type: " + val.getClass().getName());
503                 }
504             }
505         }
506         return basicProperties;
507     }
508 
writeToParcel(Parcel parcel, int flags)509     public void writeToParcel(Parcel parcel, int flags) {
510         // Needs to be kept in sync with code in MidiDeviceInfo.cpp
511         parcel.writeInt(mType);
512         parcel.writeInt(mId);
513         parcel.writeInt(mInputPortCount);
514         parcel.writeInt(mOutputPortCount);
515         parcel.writeStringArray(mInputPortNames);
516         parcel.writeStringArray(mOutputPortNames);
517         parcel.writeInt(mIsPrivate ? 1 : 0);
518         parcel.writeInt(mDefaultProtocol);
519         // "Basic" properties only contain properties of primitive types
520         // and thus can be read back by native code. "Extra" properties is
521         // a superset that contains all properties.
522         parcel.writeBundle(getBasicProperties(new String[] {
523             PROPERTY_NAME, PROPERTY_MANUFACTURER, PROPERTY_PRODUCT, PROPERTY_VERSION,
524             PROPERTY_SERIAL_NUMBER, PROPERTY_ALSA_CARD, PROPERTY_ALSA_DEVICE
525         }));
526         // Must be serialized last so native code can safely ignore it.
527         parcel.writeBundle(mProperties);
528    }
529 }
530