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