1 /* 2 * Copyright (C) 2010 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.audiofx; 18 19 import android.annotation.SdkConstant; 20 import android.annotation.SdkConstant.SdkConstantType; 21 import android.app.ActivityThread; 22 import android.os.Handler; 23 import android.os.Looper; 24 import android.os.Message; 25 import android.util.Log; 26 import java.lang.ref.WeakReference; 27 import java.nio.ByteOrder; 28 import java.nio.ByteBuffer; 29 import java.util.UUID; 30 31 /** 32 * AudioEffect is the base class for controlling audio effects provided by the android audio 33 * framework. 34 * <p>Applications should not use the AudioEffect class directly but one of its derived classes to 35 * control specific effects: 36 * <ul> 37 * <li> {@link android.media.audiofx.Equalizer}</li> 38 * <li> {@link android.media.audiofx.Virtualizer}</li> 39 * <li> {@link android.media.audiofx.BassBoost}</li> 40 * <li> {@link android.media.audiofx.PresetReverb}</li> 41 * <li> {@link android.media.audiofx.EnvironmentalReverb}</li> 42 * </ul> 43 * <p>To apply the audio effect to a specific AudioTrack or MediaPlayer instance, 44 * the application must specify the audio session ID of that instance when creating the AudioEffect. 45 * (see {@link android.media.MediaPlayer#getAudioSessionId()} for details on audio sessions). 46 * <p>NOTE: attaching insert effects (equalizer, bass boost, virtualizer) to the global audio output 47 * mix by use of session 0 is deprecated. 48 * <p>Creating an AudioEffect object will create the corresponding effect engine in the audio 49 * framework if no instance of the same effect type exists in the specified audio session. 50 * If one exists, this instance will be used. 51 * <p>The application creating the AudioEffect object (or a derived class) will either receive 52 * control of the effect engine or not depending on the priority parameter. If priority is higher 53 * than the priority used by the current effect engine owner, the control will be transfered to the 54 * new object. Otherwise control will remain with the previous object. In this case, the new 55 * application will be notified of changes in effect engine state or control ownership by the 56 * appropiate listener. 57 */ 58 59 public class AudioEffect { 60 static { 61 System.loadLibrary("audioeffect_jni"); native_init()62 native_init(); 63 } 64 65 private final static String TAG = "AudioEffect-JAVA"; 66 67 // effect type UUIDs are taken from hardware/libhardware/include/hardware/audio_effect.h 68 69 /** 70 * The following UUIDs define effect types corresponding to standard audio 71 * effects whose implementation and interface conform to the OpenSL ES 72 * specification. The definitions match the corresponding interface IDs in 73 * OpenSLES_IID.h 74 */ 75 /** 76 * UUID for environmental reverberation effect 77 */ 78 public static final UUID EFFECT_TYPE_ENV_REVERB = UUID 79 .fromString("c2e5d5f0-94bd-4763-9cac-4e234d06839e"); 80 /** 81 * UUID for preset reverberation effect 82 */ 83 public static final UUID EFFECT_TYPE_PRESET_REVERB = UUID 84 .fromString("47382d60-ddd8-11db-bf3a-0002a5d5c51b"); 85 /** 86 * UUID for equalizer effect 87 */ 88 public static final UUID EFFECT_TYPE_EQUALIZER = UUID 89 .fromString("0bed4300-ddd6-11db-8f34-0002a5d5c51b"); 90 /** 91 * UUID for bass boost effect 92 */ 93 public static final UUID EFFECT_TYPE_BASS_BOOST = UUID 94 .fromString("0634f220-ddd4-11db-a0fc-0002a5d5c51b"); 95 /** 96 * UUID for virtualizer effect 97 */ 98 public static final UUID EFFECT_TYPE_VIRTUALIZER = UUID 99 .fromString("37cc2c00-dddd-11db-8577-0002a5d5c51b"); 100 101 /** 102 * UUIDs for effect types not covered by OpenSL ES. 103 */ 104 /** 105 * UUID for Automatic Gain Control (AGC) 106 */ 107 public static final UUID EFFECT_TYPE_AGC = UUID 108 .fromString("0a8abfe0-654c-11e0-ba26-0002a5d5c51b"); 109 110 /** 111 * UUID for Acoustic Echo Canceler (AEC) 112 */ 113 public static final UUID EFFECT_TYPE_AEC = UUID 114 .fromString("7b491460-8d4d-11e0-bd61-0002a5d5c51b"); 115 116 /** 117 * UUID for Noise Suppressor (NS) 118 */ 119 public static final UUID EFFECT_TYPE_NS = UUID 120 .fromString("58b4b260-8e06-11e0-aa8e-0002a5d5c51b"); 121 122 /** 123 * UUID for Loudness Enhancer 124 */ 125 public static final UUID EFFECT_TYPE_LOUDNESS_ENHANCER = UUID 126 .fromString("fe3199be-aed0-413f-87bb-11260eb63cf1"); 127 128 /** 129 * Null effect UUID. Used when the UUID for effect type of 130 * @hide 131 */ 132 public static final UUID EFFECT_TYPE_NULL = UUID 133 .fromString("ec7178ec-e5e1-4432-a3f4-4657e6795210"); 134 135 /** 136 * State of an AudioEffect object that was not successfully initialized upon 137 * creation 138 * @hide 139 */ 140 public static final int STATE_UNINITIALIZED = 0; 141 /** 142 * State of an AudioEffect object that is ready to be used. 143 * @hide 144 */ 145 public static final int STATE_INITIALIZED = 1; 146 147 // to keep in sync with 148 // frameworks/base/include/media/AudioEffect.h 149 /** 150 * Event id for engine control ownership change notification. 151 * @hide 152 */ 153 public static final int NATIVE_EVENT_CONTROL_STATUS = 0; 154 /** 155 * Event id for engine state change notification. 156 * @hide 157 */ 158 public static final int NATIVE_EVENT_ENABLED_STATUS = 1; 159 /** 160 * Event id for engine parameter change notification. 161 * @hide 162 */ 163 public static final int NATIVE_EVENT_PARAMETER_CHANGED = 2; 164 165 /** 166 * Successful operation. 167 */ 168 public static final int SUCCESS = 0; 169 /** 170 * Unspecified error. 171 */ 172 public static final int ERROR = -1; 173 /** 174 * Internal operation status. Not returned by any method. 175 */ 176 public static final int ALREADY_EXISTS = -2; 177 /** 178 * Operation failed due to bad object initialization. 179 */ 180 public static final int ERROR_NO_INIT = -3; 181 /** 182 * Operation failed due to bad parameter value. 183 */ 184 public static final int ERROR_BAD_VALUE = -4; 185 /** 186 * Operation failed because it was requested in wrong state. 187 */ 188 public static final int ERROR_INVALID_OPERATION = -5; 189 /** 190 * Operation failed due to lack of memory. 191 */ 192 public static final int ERROR_NO_MEMORY = -6; 193 /** 194 * Operation failed due to dead remote object. 195 */ 196 public static final int ERROR_DEAD_OBJECT = -7; 197 198 /** 199 * The effect descriptor contains information on a particular effect implemented in the 200 * audio framework:<br> 201 * <ul> 202 * <li>type: UUID identifying the effect type. May be one of: 203 * {@link AudioEffect#EFFECT_TYPE_AEC}, {@link AudioEffect#EFFECT_TYPE_AGC}, 204 * {@link AudioEffect#EFFECT_TYPE_BASS_BOOST}, {@link AudioEffect#EFFECT_TYPE_ENV_REVERB}, 205 * {@link AudioEffect#EFFECT_TYPE_EQUALIZER}, {@link AudioEffect#EFFECT_TYPE_NS}, 206 * {@link AudioEffect#EFFECT_TYPE_PRESET_REVERB}, {@link AudioEffect#EFFECT_TYPE_VIRTUALIZER}. 207 * </li> 208 * <li>uuid: UUID for this particular implementation</li> 209 * <li>connectMode: {@link #EFFECT_INSERT} or {@link #EFFECT_AUXILIARY}</li> 210 * <li>name: human readable effect name</li> 211 * <li>implementor: human readable effect implementor name</li> 212 * </ul> 213 * The method {@link #queryEffects()} returns an array of Descriptors to facilitate effects 214 * enumeration. 215 */ 216 public static class Descriptor { 217 Descriptor()218 public Descriptor() { 219 } 220 221 /** 222 * @param type UUID identifying the effect type. May be one of: 223 * {@link AudioEffect#EFFECT_TYPE_AEC}, {@link AudioEffect#EFFECT_TYPE_AGC}, 224 * {@link AudioEffect#EFFECT_TYPE_BASS_BOOST}, {@link AudioEffect#EFFECT_TYPE_ENV_REVERB}, 225 * {@link AudioEffect#EFFECT_TYPE_EQUALIZER}, {@link AudioEffect#EFFECT_TYPE_NS}, 226 * {@link AudioEffect#EFFECT_TYPE_PRESET_REVERB}, 227 * {@link AudioEffect#EFFECT_TYPE_VIRTUALIZER}. 228 * @param uuid UUID for this particular implementation 229 * @param connectMode {@link #EFFECT_INSERT} or {@link #EFFECT_AUXILIARY} 230 * @param name human readable effect name 231 * @param implementor human readable effect implementor name 232 * 233 */ Descriptor(String type, String uuid, String connectMode, String name, String implementor)234 public Descriptor(String type, String uuid, String connectMode, 235 String name, String implementor) { 236 this.type = UUID.fromString(type); 237 this.uuid = UUID.fromString(uuid); 238 this.connectMode = connectMode; 239 this.name = name; 240 this.implementor = implementor; 241 } 242 243 /** 244 * Indicates the generic type of the effect (Equalizer, Bass boost ...). 245 * One of {@link AudioEffect#EFFECT_TYPE_AEC}, 246 * {@link AudioEffect#EFFECT_TYPE_AGC}, {@link AudioEffect#EFFECT_TYPE_BASS_BOOST}, 247 * {@link AudioEffect#EFFECT_TYPE_ENV_REVERB}, {@link AudioEffect#EFFECT_TYPE_EQUALIZER}, 248 * {@link AudioEffect#EFFECT_TYPE_NS}, {@link AudioEffect#EFFECT_TYPE_PRESET_REVERB} 249 * or {@link AudioEffect#EFFECT_TYPE_VIRTUALIZER}.<br> 250 * For reverberation, bass boost, EQ and virtualizer, the UUID 251 * corresponds to the OpenSL ES Interface ID. 252 */ 253 public UUID type; 254 /** 255 * Indicates the particular implementation of the effect in that type. Several effects 256 * can have the same type but this uuid is unique to a given implementation. 257 */ 258 public UUID uuid; 259 /** 260 * Indicates if the effect is of insert category {@link #EFFECT_INSERT} or auxiliary 261 * category {@link #EFFECT_AUXILIARY}. 262 * Insert effects (typically an {@link Equalizer}) are applied 263 * to the entire audio source and usually not shared by several sources. Auxiliary effects 264 * (typically a reverberator) are applied to part of the signal (wet) and the effect output 265 * is added to the original signal (dry). 266 * Audio pre processing are applied to audio captured on a particular 267 * {@link android.media.AudioRecord}. 268 */ 269 public String connectMode; 270 /** 271 * Human readable effect name 272 */ 273 public String name; 274 /** 275 * Human readable effect implementor name 276 */ 277 public String implementor; 278 }; 279 280 /** 281 * Effect connection mode is insert. Specifying an audio session ID when creating the effect 282 * will insert this effect after all players in the same audio session. 283 */ 284 public static final String EFFECT_INSERT = "Insert"; 285 /** 286 * Effect connection mode is auxiliary. 287 * <p>Auxiliary effects must be created on session 0 (global output mix). In order for a 288 * MediaPlayer or AudioTrack to be fed into this effect, they must be explicitely attached to 289 * this effect and a send level must be specified. 290 * <p>Use the effect ID returned by {@link #getId()} to designate this particular effect when 291 * attaching it to the MediaPlayer or AudioTrack. 292 */ 293 public static final String EFFECT_AUXILIARY = "Auxiliary"; 294 /** 295 * Effect connection mode is pre processing. 296 * The audio pre processing effects are attached to an audio input (AudioRecord). 297 * @hide 298 */ 299 public static final String EFFECT_PRE_PROCESSING = "Pre Processing"; 300 301 // -------------------------------------------------------------------------- 302 // Member variables 303 // -------------------- 304 /** 305 * Indicates the state of the AudioEffect instance 306 */ 307 private int mState = STATE_UNINITIALIZED; 308 /** 309 * Lock to synchronize access to mState 310 */ 311 private final Object mStateLock = new Object(); 312 /** 313 * System wide unique effect ID 314 */ 315 private int mId; 316 317 // accessed by native methods 318 private long mNativeAudioEffect; 319 private long mJniData; 320 321 /** 322 * Effect descriptor 323 */ 324 private Descriptor mDescriptor; 325 326 /** 327 * Listener for effect engine state change notifications. 328 * 329 * @see #setEnableStatusListener(OnEnableStatusChangeListener) 330 */ 331 private OnEnableStatusChangeListener mEnableStatusChangeListener = null; 332 /** 333 * Listener for effect engine control ownership change notifications. 334 * 335 * @see #setControlStatusListener(OnControlStatusChangeListener) 336 */ 337 private OnControlStatusChangeListener mControlChangeStatusListener = null; 338 /** 339 * Listener for effect engine control ownership change notifications. 340 * 341 * @see #setParameterListener(OnParameterChangeListener) 342 */ 343 private OnParameterChangeListener mParameterChangeListener = null; 344 /** 345 * Lock to protect listeners updates against event notifications 346 * @hide 347 */ 348 public final Object mListenerLock = new Object(); 349 /** 350 * Handler for events coming from the native code 351 * @hide 352 */ 353 public NativeEventHandler mNativeEventHandler = null; 354 355 // -------------------------------------------------------------------------- 356 // Constructor, Finalize 357 // -------------------- 358 /** 359 * Class constructor. 360 * 361 * @param type type of effect engine created. See {@link #EFFECT_TYPE_ENV_REVERB}, 362 * {@link #EFFECT_TYPE_EQUALIZER} ... Types corresponding to 363 * built-in effects are defined by AudioEffect class. Other types 364 * can be specified provided they correspond an existing OpenSL 365 * ES interface ID and the corresponsing effect is available on 366 * the platform. If an unspecified effect type is requested, the 367 * constructor with throw the IllegalArgumentException. This 368 * parameter can be set to {@link #EFFECT_TYPE_NULL} in which 369 * case only the uuid will be used to select the effect. 370 * @param uuid unique identifier of a particular effect implementation. 371 * Must be specified if the caller wants to use a particular 372 * implementation of an effect type. This parameter can be set to 373 * {@link #EFFECT_TYPE_NULL} in which case only the type will 374 * be used to select the effect. 375 * @param priority the priority level requested by the application for 376 * controlling the effect engine. As the same effect engine can 377 * be shared by several applications, this parameter indicates 378 * how much the requesting application needs control of effect 379 * parameters. The normal priority is 0, above normal is a 380 * positive number, below normal a negative number. 381 * @param audioSession system wide unique audio session identifier. 382 * The effect will be attached to the MediaPlayer or AudioTrack in 383 * the same audio session. 384 * 385 * @throws java.lang.IllegalArgumentException 386 * @throws java.lang.UnsupportedOperationException 387 * @throws java.lang.RuntimeException 388 * @hide 389 */ 390 AudioEffect(UUID type, UUID uuid, int priority, int audioSession)391 public AudioEffect(UUID type, UUID uuid, int priority, int audioSession) 392 throws IllegalArgumentException, UnsupportedOperationException, 393 RuntimeException { 394 int[] id = new int[1]; 395 Descriptor[] desc = new Descriptor[1]; 396 // native initialization 397 int initResult = native_setup(new WeakReference<AudioEffect>(this), 398 type.toString(), uuid.toString(), priority, audioSession, id, 399 desc, ActivityThread.currentOpPackageName()); 400 if (initResult != SUCCESS && initResult != ALREADY_EXISTS) { 401 Log.e(TAG, "Error code " + initResult 402 + " when initializing AudioEffect."); 403 switch (initResult) { 404 case ERROR_BAD_VALUE: 405 throw (new IllegalArgumentException("Effect type: " + type 406 + " not supported.")); 407 case ERROR_INVALID_OPERATION: 408 throw (new UnsupportedOperationException( 409 "Effect library not loaded")); 410 default: 411 throw (new RuntimeException( 412 "Cannot initialize effect engine for type: " + type 413 + " Error: " + initResult)); 414 } 415 } 416 mId = id[0]; 417 mDescriptor = desc[0]; 418 synchronized (mStateLock) { 419 mState = STATE_INITIALIZED; 420 } 421 } 422 423 /** 424 * Releases the native AudioEffect resources. It is a good practice to 425 * release the effect engine when not in use as control can be returned to 426 * other applications or the native resources released. 427 */ release()428 public void release() { 429 synchronized (mStateLock) { 430 native_release(); 431 mState = STATE_UNINITIALIZED; 432 } 433 } 434 435 @Override finalize()436 protected void finalize() { 437 native_finalize(); 438 } 439 440 /** 441 * Get the effect descriptor. 442 * 443 * @see android.media.audiofx.AudioEffect.Descriptor 444 * @throws IllegalStateException 445 */ getDescriptor()446 public Descriptor getDescriptor() throws IllegalStateException { 447 checkState("getDescriptor()"); 448 return mDescriptor; 449 } 450 451 // -------------------------------------------------------------------------- 452 // Effects Enumeration 453 // -------------------- 454 455 /** 456 * Query all effects available on the platform. Returns an array of 457 * {@link android.media.audiofx.AudioEffect.Descriptor} objects 458 * 459 * @throws IllegalStateException 460 */ 461 queryEffects()462 static public Descriptor[] queryEffects() { 463 return (Descriptor[]) native_query_effects(); 464 } 465 466 /** 467 * Query all audio pre-processing effects applied to the AudioRecord with the supplied 468 * audio session ID. Returns an array of {@link android.media.audiofx.AudioEffect.Descriptor} 469 * objects. 470 * @param audioSession system wide unique audio session identifier. 471 * @throws IllegalStateException 472 * @hide 473 */ 474 queryPreProcessings(int audioSession)475 static public Descriptor[] queryPreProcessings(int audioSession) { 476 return (Descriptor[]) native_query_pre_processing(audioSession); 477 } 478 479 /** 480 * Checks if the device implements the specified effect type. 481 * @param type the requested effect type. 482 * @return true if the device implements the specified effect type, false otherwise. 483 * @hide 484 */ isEffectTypeAvailable(UUID type)485 public static boolean isEffectTypeAvailable(UUID type) { 486 AudioEffect.Descriptor[] desc = AudioEffect.queryEffects(); 487 if (desc == null) { 488 return false; 489 } 490 491 for (int i = 0; i < desc.length; i++) { 492 if (desc[i].type.equals(type)) { 493 return true; 494 } 495 } 496 return false; 497 } 498 499 // -------------------------------------------------------------------------- 500 // Control methods 501 // -------------------- 502 503 /** 504 * Enable or disable the effect. 505 * Creating an audio effect does not automatically apply this effect on the audio source. It 506 * creates the resources necessary to process this effect but the audio signal is still bypassed 507 * through the effect engine. Calling this method will make that the effect is actually applied 508 * or not to the audio content being played in the corresponding audio session. 509 * 510 * @param enabled the requested enable state 511 * @return {@link #SUCCESS} in case of success, {@link #ERROR_INVALID_OPERATION} 512 * or {@link #ERROR_DEAD_OBJECT} in case of failure. 513 * @throws IllegalStateException 514 */ setEnabled(boolean enabled)515 public int setEnabled(boolean enabled) throws IllegalStateException { 516 checkState("setEnabled()"); 517 return native_setEnabled(enabled); 518 } 519 520 /** 521 * Set effect parameter. The setParameter method is provided in several 522 * forms addressing most common parameter formats. This form is the most 523 * generic one where the parameter and its value are both specified as an 524 * array of bytes. The parameter and value type and length are therefore 525 * totally free. For standard effect defined by OpenSL ES, the parameter 526 * format and values must match the definitions in the corresponding OpenSL 527 * ES interface. 528 * 529 * @param param the identifier of the parameter to set 530 * @param value the new value for the specified parameter 531 * @return {@link #SUCCESS} in case of success, {@link #ERROR_BAD_VALUE}, 532 * {@link #ERROR_NO_MEMORY}, {@link #ERROR_INVALID_OPERATION} or 533 * {@link #ERROR_DEAD_OBJECT} in case of failure 534 * @throws IllegalStateException 535 * @hide 536 */ setParameter(byte[] param, byte[] value)537 public int setParameter(byte[] param, byte[] value) 538 throws IllegalStateException { 539 checkState("setParameter()"); 540 return native_setParameter(param.length, param, value.length, value); 541 } 542 543 /** 544 * Set effect parameter. The parameter and its value are integers. 545 * 546 * @see #setParameter(byte[], byte[]) 547 * @hide 548 */ setParameter(int param, int value)549 public int setParameter(int param, int value) throws IllegalStateException { 550 byte[] p = intToByteArray(param); 551 byte[] v = intToByteArray(value); 552 return setParameter(p, v); 553 } 554 555 /** 556 * Set effect parameter. The parameter is an integer and the value is a 557 * short integer. 558 * 559 * @see #setParameter(byte[], byte[]) 560 * @hide 561 */ setParameter(int param, short value)562 public int setParameter(int param, short value) 563 throws IllegalStateException { 564 byte[] p = intToByteArray(param); 565 byte[] v = shortToByteArray(value); 566 return setParameter(p, v); 567 } 568 569 /** 570 * Set effect parameter. The parameter is an integer and the value is an 571 * array of bytes. 572 * 573 * @see #setParameter(byte[], byte[]) 574 * @hide 575 */ setParameter(int param, byte[] value)576 public int setParameter(int param, byte[] value) 577 throws IllegalStateException { 578 byte[] p = intToByteArray(param); 579 return setParameter(p, value); 580 } 581 582 /** 583 * Set effect parameter. The parameter is an array of 1 or 2 integers and 584 * the value is also an array of 1 or 2 integers 585 * 586 * @see #setParameter(byte[], byte[]) 587 * @hide 588 */ setParameter(int[] param, int[] value)589 public int setParameter(int[] param, int[] value) 590 throws IllegalStateException { 591 if (param.length > 2 || value.length > 2) { 592 return ERROR_BAD_VALUE; 593 } 594 byte[] p = intToByteArray(param[0]); 595 if (param.length > 1) { 596 byte[] p2 = intToByteArray(param[1]); 597 p = concatArrays(p, p2); 598 } 599 byte[] v = intToByteArray(value[0]); 600 if (value.length > 1) { 601 byte[] v2 = intToByteArray(value[1]); 602 v = concatArrays(v, v2); 603 } 604 return setParameter(p, v); 605 } 606 607 /** 608 * Set effect parameter. The parameter is an array of 1 or 2 integers and 609 * the value is an array of 1 or 2 short integers 610 * 611 * @see #setParameter(byte[], byte[]) 612 * @hide 613 */ setParameter(int[] param, short[] value)614 public int setParameter(int[] param, short[] value) 615 throws IllegalStateException { 616 if (param.length > 2 || value.length > 2) { 617 return ERROR_BAD_VALUE; 618 } 619 byte[] p = intToByteArray(param[0]); 620 if (param.length > 1) { 621 byte[] p2 = intToByteArray(param[1]); 622 p = concatArrays(p, p2); 623 } 624 625 byte[] v = shortToByteArray(value[0]); 626 if (value.length > 1) { 627 byte[] v2 = shortToByteArray(value[1]); 628 v = concatArrays(v, v2); 629 } 630 return setParameter(p, v); 631 } 632 633 /** 634 * Set effect parameter. The parameter is an array of 1 or 2 integers and 635 * the value is an array of bytes 636 * 637 * @see #setParameter(byte[], byte[]) 638 * @hide 639 */ setParameter(int[] param, byte[] value)640 public int setParameter(int[] param, byte[] value) 641 throws IllegalStateException { 642 if (param.length > 2) { 643 return ERROR_BAD_VALUE; 644 } 645 byte[] p = intToByteArray(param[0]); 646 if (param.length > 1) { 647 byte[] p2 = intToByteArray(param[1]); 648 p = concatArrays(p, p2); 649 } 650 return setParameter(p, value); 651 } 652 653 /** 654 * Get effect parameter. The getParameter method is provided in several 655 * forms addressing most common parameter formats. This form is the most 656 * generic one where the parameter and its value are both specified as an 657 * array of bytes. The parameter and value type and length are therefore 658 * totally free. 659 * 660 * @param param the identifier of the parameter to set 661 * @param value the new value for the specified parameter 662 * @return the number of meaningful bytes in value array in case of success or 663 * {@link #ERROR_BAD_VALUE}, {@link #ERROR_NO_MEMORY}, {@link #ERROR_INVALID_OPERATION} 664 * or {@link #ERROR_DEAD_OBJECT} in case of failure. 665 * @throws IllegalStateException 666 * @hide 667 */ getParameter(byte[] param, byte[] value)668 public int getParameter(byte[] param, byte[] value) 669 throws IllegalStateException { 670 checkState("getParameter()"); 671 return native_getParameter(param.length, param, value.length, value); 672 } 673 674 /** 675 * Get effect parameter. The parameter is an integer and the value is an 676 * array of bytes. 677 * 678 * @see #getParameter(byte[], byte[]) 679 * @hide 680 */ getParameter(int param, byte[] value)681 public int getParameter(int param, byte[] value) 682 throws IllegalStateException { 683 byte[] p = intToByteArray(param); 684 685 return getParameter(p, value); 686 } 687 688 /** 689 * Get effect parameter. The parameter is an integer and the value is an 690 * array of 1 or 2 integers 691 * 692 * @see #getParameter(byte[], byte[]) 693 * In case of success, returns the number of meaningful integers in value array. 694 * @hide 695 */ getParameter(int param, int[] value)696 public int getParameter(int param, int[] value) 697 throws IllegalStateException { 698 if (value.length > 2) { 699 return ERROR_BAD_VALUE; 700 } 701 byte[] p = intToByteArray(param); 702 703 byte[] v = new byte[value.length * 4]; 704 705 int status = getParameter(p, v); 706 707 if (status == 4 || status == 8) { 708 value[0] = byteArrayToInt(v); 709 if (status == 8) { 710 value[1] = byteArrayToInt(v, 4); 711 } 712 status /= 4; 713 } else { 714 status = ERROR; 715 } 716 return status; 717 } 718 719 /** 720 * Get effect parameter. The parameter is an integer and the value is an 721 * array of 1 or 2 short integers 722 * 723 * @see #getParameter(byte[], byte[]) 724 * In case of success, returns the number of meaningful short integers in value array. 725 * @hide 726 */ getParameter(int param, short[] value)727 public int getParameter(int param, short[] value) 728 throws IllegalStateException { 729 if (value.length > 2) { 730 return ERROR_BAD_VALUE; 731 } 732 byte[] p = intToByteArray(param); 733 734 byte[] v = new byte[value.length * 2]; 735 736 int status = getParameter(p, v); 737 738 if (status == 2 || status == 4) { 739 value[0] = byteArrayToShort(v); 740 if (status == 4) { 741 value[1] = byteArrayToShort(v, 2); 742 } 743 status /= 2; 744 } else { 745 status = ERROR; 746 } 747 return status; 748 } 749 750 /** 751 * Get effect parameter. The parameter is an array of 1 or 2 integers and 752 * the value is also an array of 1 or 2 integers 753 * 754 * @see #getParameter(byte[], byte[]) 755 * In case of success, the returns the number of meaningful integers in value array. 756 * @hide 757 */ getParameter(int[] param, int[] value)758 public int getParameter(int[] param, int[] value) 759 throws IllegalStateException { 760 if (param.length > 2 || value.length > 2) { 761 return ERROR_BAD_VALUE; 762 } 763 byte[] p = intToByteArray(param[0]); 764 if (param.length > 1) { 765 byte[] p2 = intToByteArray(param[1]); 766 p = concatArrays(p, p2); 767 } 768 byte[] v = new byte[value.length * 4]; 769 770 int status = getParameter(p, v); 771 772 if (status == 4 || status == 8) { 773 value[0] = byteArrayToInt(v); 774 if (status == 8) { 775 value[1] = byteArrayToInt(v, 4); 776 } 777 status /= 4; 778 } else { 779 status = ERROR; 780 } 781 return status; 782 } 783 784 /** 785 * Get effect parameter. The parameter is an array of 1 or 2 integers and 786 * the value is an array of 1 or 2 short integers 787 * 788 * @see #getParameter(byte[], byte[]) 789 * In case of success, returns the number of meaningful short integers in value array. 790 * @hide 791 */ getParameter(int[] param, short[] value)792 public int getParameter(int[] param, short[] value) 793 throws IllegalStateException { 794 if (param.length > 2 || value.length > 2) { 795 return ERROR_BAD_VALUE; 796 } 797 byte[] p = intToByteArray(param[0]); 798 if (param.length > 1) { 799 byte[] p2 = intToByteArray(param[1]); 800 p = concatArrays(p, p2); 801 } 802 byte[] v = new byte[value.length * 2]; 803 804 int status = getParameter(p, v); 805 806 if (status == 2 || status == 4) { 807 value[0] = byteArrayToShort(v); 808 if (status == 4) { 809 value[1] = byteArrayToShort(v, 2); 810 } 811 status /= 2; 812 } else { 813 status = ERROR; 814 } 815 return status; 816 } 817 818 /** 819 * Get effect parameter. The parameter is an array of 1 or 2 integers and 820 * the value is an array of bytes 821 * 822 * @see #getParameter(byte[], byte[]) 823 * @hide 824 */ getParameter(int[] param, byte[] value)825 public int getParameter(int[] param, byte[] value) 826 throws IllegalStateException { 827 if (param.length > 2) { 828 return ERROR_BAD_VALUE; 829 } 830 byte[] p = intToByteArray(param[0]); 831 if (param.length > 1) { 832 byte[] p2 = intToByteArray(param[1]); 833 p = concatArrays(p, p2); 834 } 835 836 return getParameter(p, value); 837 } 838 839 /** 840 * Send a command to the effect engine. This method is intended to send 841 * proprietary commands to a particular effect implementation. 842 * In case of success, returns the number of meaningful bytes in reply array. 843 * In case of failure, the returned value is negative and implementation specific. 844 * @hide 845 */ command(int cmdCode, byte[] command, byte[] reply)846 public int command(int cmdCode, byte[] command, byte[] reply) 847 throws IllegalStateException { 848 checkState("command()"); 849 return native_command(cmdCode, command.length, command, reply.length, reply); 850 } 851 852 // -------------------------------------------------------------------------- 853 // Getters 854 // -------------------- 855 856 /** 857 * Returns effect unique identifier. This system wide unique identifier can 858 * be used to attach this effect to a MediaPlayer or an AudioTrack when the 859 * effect is an auxiliary effect (Reverb) 860 * 861 * @return the effect identifier. 862 * @throws IllegalStateException 863 */ getId()864 public int getId() throws IllegalStateException { 865 checkState("getId()"); 866 return mId; 867 } 868 869 /** 870 * Returns effect enabled state 871 * 872 * @return true if the effect is enabled, false otherwise. 873 * @throws IllegalStateException 874 */ getEnabled()875 public boolean getEnabled() throws IllegalStateException { 876 checkState("getEnabled()"); 877 return native_getEnabled(); 878 } 879 880 /** 881 * Checks if this AudioEffect object is controlling the effect engine. 882 * 883 * @return true if this instance has control of effect engine, false 884 * otherwise. 885 * @throws IllegalStateException 886 */ hasControl()887 public boolean hasControl() throws IllegalStateException { 888 checkState("hasControl()"); 889 return native_hasControl(); 890 } 891 892 // -------------------------------------------------------------------------- 893 // Initialization / configuration 894 // -------------------- 895 /** 896 * Sets the listener AudioEffect notifies when the effect engine is enabled 897 * or disabled. 898 * 899 * @param listener 900 */ setEnableStatusListener(OnEnableStatusChangeListener listener)901 public void setEnableStatusListener(OnEnableStatusChangeListener listener) { 902 synchronized (mListenerLock) { 903 mEnableStatusChangeListener = listener; 904 } 905 if ((listener != null) && (mNativeEventHandler == null)) { 906 createNativeEventHandler(); 907 } 908 } 909 910 /** 911 * Sets the listener AudioEffect notifies when the effect engine control is 912 * taken or returned. 913 * 914 * @param listener 915 */ setControlStatusListener(OnControlStatusChangeListener listener)916 public void setControlStatusListener(OnControlStatusChangeListener listener) { 917 synchronized (mListenerLock) { 918 mControlChangeStatusListener = listener; 919 } 920 if ((listener != null) && (mNativeEventHandler == null)) { 921 createNativeEventHandler(); 922 } 923 } 924 925 /** 926 * Sets the listener AudioEffect notifies when a parameter is changed. 927 * 928 * @param listener 929 * @hide 930 */ setParameterListener(OnParameterChangeListener listener)931 public void setParameterListener(OnParameterChangeListener listener) { 932 synchronized (mListenerLock) { 933 mParameterChangeListener = listener; 934 } 935 if ((listener != null) && (mNativeEventHandler == null)) { 936 createNativeEventHandler(); 937 } 938 } 939 940 // Convenience method for the creation of the native event handler 941 // It is called only when a non-null event listener is set. 942 // precondition: 943 // mNativeEventHandler is null createNativeEventHandler()944 private void createNativeEventHandler() { 945 Looper looper; 946 if ((looper = Looper.myLooper()) != null) { 947 mNativeEventHandler = new NativeEventHandler(this, looper); 948 } else if ((looper = Looper.getMainLooper()) != null) { 949 mNativeEventHandler = new NativeEventHandler(this, looper); 950 } else { 951 mNativeEventHandler = null; 952 } 953 } 954 955 // --------------------------------------------------------- 956 // Interface definitions 957 // -------------------- 958 /** 959 * The OnEnableStatusChangeListener interface defines a method called by the AudioEffect 960 * when a the enabled state of the effect engine was changed by the controlling application. 961 */ 962 public interface OnEnableStatusChangeListener { 963 /** 964 * Called on the listener to notify it that the effect engine has been 965 * enabled or disabled. 966 * @param effect the effect on which the interface is registered. 967 * @param enabled new effect state. 968 */ onEnableStatusChange(AudioEffect effect, boolean enabled)969 void onEnableStatusChange(AudioEffect effect, boolean enabled); 970 } 971 972 /** 973 * The OnControlStatusChangeListener interface defines a method called by the AudioEffect 974 * when a the control of the effect engine is gained or lost by the application 975 */ 976 public interface OnControlStatusChangeListener { 977 /** 978 * Called on the listener to notify it that the effect engine control 979 * has been taken or returned. 980 * @param effect the effect on which the interface is registered. 981 * @param controlGranted true if the application has been granted control of the effect 982 * engine, false otherwise. 983 */ onControlStatusChange(AudioEffect effect, boolean controlGranted)984 void onControlStatusChange(AudioEffect effect, boolean controlGranted); 985 } 986 987 /** 988 * The OnParameterChangeListener interface defines a method called by the AudioEffect 989 * when a parameter is changed in the effect engine by the controlling application. 990 * @hide 991 */ 992 public interface OnParameterChangeListener { 993 /** 994 * Called on the listener to notify it that a parameter value has changed. 995 * @param effect the effect on which the interface is registered. 996 * @param status status of the set parameter operation. 997 * @param param ID of the modified parameter. 998 * @param value the new parameter value. 999 */ onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value)1000 void onParameterChange(AudioEffect effect, int status, byte[] param, 1001 byte[] value); 1002 } 1003 1004 1005 // ------------------------------------------------------------------------- 1006 // Audio Effect Control panel intents 1007 // ------------------------------------------------------------------------- 1008 1009 /** 1010 * Intent to launch an audio effect control panel UI. 1011 * <p>The goal of this intent is to enable separate implementations of music/media player 1012 * applications and audio effect control application or services. 1013 * This will allow platform vendors to offer more advanced control options for standard effects 1014 * or control for platform specific effects. 1015 * <p>The intent carries a number of extras used by the player application to communicate 1016 * necessary pieces of information to the control panel application. 1017 * <p>The calling application must use the 1018 * {@link android.app.Activity#startActivityForResult(Intent, int)} method to launch the 1019 * control panel so that its package name is indicated and used by the control panel 1020 * application to keep track of changes for this particular application. 1021 * <p>The {@link #EXTRA_AUDIO_SESSION} extra will indicate an audio session to which the 1022 * audio effects should be applied. If no audio session is specified, either one of the 1023 * follownig will happen: 1024 * <p>- If an audio session was previously opened by the calling application with 1025 * {@link #ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION} intent, the effect changes will 1026 * be applied to that session. 1027 * <p>- If no audio session is opened, the changes will be stored in the package specific 1028 * storage area and applied whenever a new audio session is opened by this application. 1029 * <p>The {@link #EXTRA_CONTENT_TYPE} extra will help the control panel application 1030 * customize both the UI layout and the default audio effect settings if none are already 1031 * stored for the calling application. 1032 */ 1033 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 1034 public static final String ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL = 1035 "android.media.action.DISPLAY_AUDIO_EFFECT_CONTROL_PANEL"; 1036 1037 /** 1038 * Intent to signal to the effect control application or service that a new audio session 1039 * is opened and requires audio effects to be applied. 1040 * <p>This is different from {@link #ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL} in that no 1041 * UI should be displayed in this case. Music player applications can broadcast this intent 1042 * before starting playback to make sure that any audio effect settings previously selected 1043 * by the user are applied. 1044 * <p>The effect control application receiving this intent will look for previously stored 1045 * settings for the calling application, create all required audio effects and apply the 1046 * effect settings to the specified audio session. 1047 * <p>The calling package name is indicated by the {@link #EXTRA_PACKAGE_NAME} extra and the 1048 * audio session ID by the {@link #EXTRA_AUDIO_SESSION} extra. Both extras are mandatory. 1049 * <p>If no stored settings are found for the calling application, default settings for the 1050 * content type indicated by {@link #EXTRA_CONTENT_TYPE} will be applied. The default settings 1051 * for a given content type are platform specific. 1052 */ 1053 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 1054 public static final String ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION = 1055 "android.media.action.OPEN_AUDIO_EFFECT_CONTROL_SESSION"; 1056 1057 /** 1058 * Intent to signal to the effect control application or service that an audio session 1059 * is closed and that effects should not be applied anymore. 1060 * <p>The effect control application receiving this intent will delete all effects on 1061 * this session and store current settings in package specific storage. 1062 * <p>The calling package name is indicated by the {@link #EXTRA_PACKAGE_NAME} extra and the 1063 * audio session ID by the {@link #EXTRA_AUDIO_SESSION} extra. Both extras are mandatory. 1064 * <p>It is good practice for applications to broadcast this intent when music playback stops 1065 * and/or when exiting to free system resources consumed by audio effect engines. 1066 */ 1067 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 1068 public static final String ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION = 1069 "android.media.action.CLOSE_AUDIO_EFFECT_CONTROL_SESSION"; 1070 1071 /** 1072 * Contains the ID of the audio session the effects should be applied to. 1073 * <p>This extra is for use with {@link #ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL}, 1074 * {@link #ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION} and 1075 * {@link #ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION} intents. 1076 * <p>The extra value is of type int and is the audio session ID. 1077 * @see android.media.MediaPlayer#getAudioSessionId() for details on audio sessions. 1078 */ 1079 public static final String EXTRA_AUDIO_SESSION = "android.media.extra.AUDIO_SESSION"; 1080 1081 /** 1082 * Contains the package name of the calling application. 1083 * <p>This extra is for use with {@link #ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION} and 1084 * {@link #ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION} intents. 1085 * <p>The extra value is a string containing the full package name. 1086 */ 1087 public static final String EXTRA_PACKAGE_NAME = "android.media.extra.PACKAGE_NAME"; 1088 1089 /** 1090 * Indicates which type of content is played by the application. 1091 * <p>This extra is for use with {@link #ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL} and 1092 * {@link #ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION} intents. 1093 * <p>This information is used by the effect control application to customize UI and select 1094 * appropriate default effect settings. The content type is one of the following: 1095 * <ul> 1096 * <li>{@link #CONTENT_TYPE_MUSIC}</li> 1097 * <li>{@link #CONTENT_TYPE_MOVIE}</li> 1098 * <li>{@link #CONTENT_TYPE_GAME}</li> 1099 * <li>{@link #CONTENT_TYPE_VOICE}</li> 1100 * </ul> 1101 * If omitted, the content type defaults to {@link #CONTENT_TYPE_MUSIC}. 1102 */ 1103 public static final String EXTRA_CONTENT_TYPE = "android.media.extra.CONTENT_TYPE"; 1104 1105 /** 1106 * Value for {@link #EXTRA_CONTENT_TYPE} when the type of content played is music 1107 */ 1108 public static final int CONTENT_TYPE_MUSIC = 0; 1109 /** 1110 * Value for {@link #EXTRA_CONTENT_TYPE} when the type of content played is video or movie 1111 */ 1112 public static final int CONTENT_TYPE_MOVIE = 1; 1113 /** 1114 * Value for {@link #EXTRA_CONTENT_TYPE} when the type of content played is game audio 1115 */ 1116 public static final int CONTENT_TYPE_GAME = 2; 1117 /** 1118 * Value for {@link #EXTRA_CONTENT_TYPE} when the type of content played is voice audio 1119 */ 1120 public static final int CONTENT_TYPE_VOICE = 3; 1121 1122 1123 // --------------------------------------------------------- 1124 // Inner classes 1125 // -------------------- 1126 /** 1127 * Helper class to handle the forwarding of native events to the appropriate 1128 * listeners 1129 */ 1130 private class NativeEventHandler extends Handler { 1131 private AudioEffect mAudioEffect; 1132 NativeEventHandler(AudioEffect ae, Looper looper)1133 public NativeEventHandler(AudioEffect ae, Looper looper) { 1134 super(looper); 1135 mAudioEffect = ae; 1136 } 1137 1138 @Override handleMessage(Message msg)1139 public void handleMessage(Message msg) { 1140 if (mAudioEffect == null) { 1141 return; 1142 } 1143 switch (msg.what) { 1144 case NATIVE_EVENT_ENABLED_STATUS: 1145 OnEnableStatusChangeListener enableStatusChangeListener = null; 1146 synchronized (mListenerLock) { 1147 enableStatusChangeListener = mAudioEffect.mEnableStatusChangeListener; 1148 } 1149 if (enableStatusChangeListener != null) { 1150 enableStatusChangeListener.onEnableStatusChange( 1151 mAudioEffect, (boolean) (msg.arg1 != 0)); 1152 } 1153 break; 1154 case NATIVE_EVENT_CONTROL_STATUS: 1155 OnControlStatusChangeListener controlStatusChangeListener = null; 1156 synchronized (mListenerLock) { 1157 controlStatusChangeListener = mAudioEffect.mControlChangeStatusListener; 1158 } 1159 if (controlStatusChangeListener != null) { 1160 controlStatusChangeListener.onControlStatusChange( 1161 mAudioEffect, (boolean) (msg.arg1 != 0)); 1162 } 1163 break; 1164 case NATIVE_EVENT_PARAMETER_CHANGED: 1165 OnParameterChangeListener parameterChangeListener = null; 1166 synchronized (mListenerLock) { 1167 parameterChangeListener = mAudioEffect.mParameterChangeListener; 1168 } 1169 if (parameterChangeListener != null) { 1170 // arg1 contains offset of parameter value from start of 1171 // byte array 1172 int vOffset = msg.arg1; 1173 byte[] p = (byte[]) msg.obj; 1174 // See effect_param_t in EffectApi.h for psize and vsize 1175 // fields offsets 1176 int status = byteArrayToInt(p, 0); 1177 int psize = byteArrayToInt(p, 4); 1178 int vsize = byteArrayToInt(p, 8); 1179 byte[] param = new byte[psize]; 1180 byte[] value = new byte[vsize]; 1181 System.arraycopy(p, 12, param, 0, psize); 1182 System.arraycopy(p, vOffset, value, 0, vsize); 1183 1184 parameterChangeListener.onParameterChange(mAudioEffect, 1185 status, param, value); 1186 } 1187 break; 1188 1189 default: 1190 Log.e(TAG, "handleMessage() Unknown event type: " + msg.what); 1191 break; 1192 } 1193 } 1194 } 1195 1196 // --------------------------------------------------------- 1197 // Java methods called from the native side 1198 // -------------------- 1199 @SuppressWarnings("unused") postEventFromNative(Object effect_ref, int what, int arg1, int arg2, Object obj)1200 private static void postEventFromNative(Object effect_ref, int what, 1201 int arg1, int arg2, Object obj) { 1202 AudioEffect effect = (AudioEffect) ((WeakReference) effect_ref).get(); 1203 if (effect == null) { 1204 return; 1205 } 1206 if (effect.mNativeEventHandler != null) { 1207 Message m = effect.mNativeEventHandler.obtainMessage(what, arg1, 1208 arg2, obj); 1209 effect.mNativeEventHandler.sendMessage(m); 1210 } 1211 1212 } 1213 1214 // --------------------------------------------------------- 1215 // Native methods called from the Java side 1216 // -------------------- 1217 native_init()1218 private static native final void native_init(); 1219 native_setup(Object audioeffect_this, String type, String uuid, int priority, int audioSession, int[] id, Object[] desc, String opPackageName)1220 private native final int native_setup(Object audioeffect_this, String type, 1221 String uuid, int priority, int audioSession, int[] id, Object[] desc, 1222 String opPackageName); 1223 native_finalize()1224 private native final void native_finalize(); 1225 native_release()1226 private native final void native_release(); 1227 native_setEnabled(boolean enabled)1228 private native final int native_setEnabled(boolean enabled); 1229 native_getEnabled()1230 private native final boolean native_getEnabled(); 1231 native_hasControl()1232 private native final boolean native_hasControl(); 1233 native_setParameter(int psize, byte[] param, int vsize, byte[] value)1234 private native final int native_setParameter(int psize, byte[] param, 1235 int vsize, byte[] value); 1236 native_getParameter(int psize, byte[] param, int vsize, byte[] value)1237 private native final int native_getParameter(int psize, byte[] param, 1238 int vsize, byte[] value); 1239 native_command(int cmdCode, int cmdSize, byte[] cmdData, int repSize, byte[] repData)1240 private native final int native_command(int cmdCode, int cmdSize, 1241 byte[] cmdData, int repSize, byte[] repData); 1242 native_query_effects()1243 private static native Object[] native_query_effects(); 1244 native_query_pre_processing(int audioSession)1245 private static native Object[] native_query_pre_processing(int audioSession); 1246 1247 // --------------------------------------------------------- 1248 // Utility methods 1249 // ------------------ 1250 1251 /** 1252 * @hide 1253 */ checkState(String methodName)1254 public void checkState(String methodName) throws IllegalStateException { 1255 synchronized (mStateLock) { 1256 if (mState != STATE_INITIALIZED) { 1257 throw (new IllegalStateException(methodName 1258 + " called on uninitialized AudioEffect.")); 1259 } 1260 } 1261 } 1262 1263 /** 1264 * @hide 1265 */ checkStatus(int status)1266 public void checkStatus(int status) { 1267 if (isError(status)) { 1268 switch (status) { 1269 case AudioEffect.ERROR_BAD_VALUE: 1270 throw (new IllegalArgumentException( 1271 "AudioEffect: bad parameter value")); 1272 case AudioEffect.ERROR_INVALID_OPERATION: 1273 throw (new UnsupportedOperationException( 1274 "AudioEffect: invalid parameter operation")); 1275 default: 1276 throw (new RuntimeException("AudioEffect: set/get parameter error")); 1277 } 1278 } 1279 } 1280 1281 /** 1282 * @hide 1283 */ isError(int status)1284 public static boolean isError(int status) { 1285 return (status < 0); 1286 } 1287 1288 /** 1289 * @hide 1290 */ byteArrayToInt(byte[] valueBuf)1291 public static int byteArrayToInt(byte[] valueBuf) { 1292 return byteArrayToInt(valueBuf, 0); 1293 1294 } 1295 1296 /** 1297 * @hide 1298 */ byteArrayToInt(byte[] valueBuf, int offset)1299 public static int byteArrayToInt(byte[] valueBuf, int offset) { 1300 ByteBuffer converter = ByteBuffer.wrap(valueBuf); 1301 converter.order(ByteOrder.nativeOrder()); 1302 return converter.getInt(offset); 1303 1304 } 1305 1306 /** 1307 * @hide 1308 */ intToByteArray(int value)1309 public static byte[] intToByteArray(int value) { 1310 ByteBuffer converter = ByteBuffer.allocate(4); 1311 converter.order(ByteOrder.nativeOrder()); 1312 converter.putInt(value); 1313 return converter.array(); 1314 } 1315 1316 /** 1317 * @hide 1318 */ byteArrayToShort(byte[] valueBuf)1319 public static short byteArrayToShort(byte[] valueBuf) { 1320 return byteArrayToShort(valueBuf, 0); 1321 } 1322 1323 /** 1324 * @hide 1325 */ byteArrayToShort(byte[] valueBuf, int offset)1326 public static short byteArrayToShort(byte[] valueBuf, int offset) { 1327 ByteBuffer converter = ByteBuffer.wrap(valueBuf); 1328 converter.order(ByteOrder.nativeOrder()); 1329 return converter.getShort(offset); 1330 1331 } 1332 1333 /** 1334 * @hide 1335 */ shortToByteArray(short value)1336 public static byte[] shortToByteArray(short value) { 1337 ByteBuffer converter = ByteBuffer.allocate(2); 1338 converter.order(ByteOrder.nativeOrder()); 1339 short sValue = (short) value; 1340 converter.putShort(sValue); 1341 return converter.array(); 1342 } 1343 1344 /** 1345 * @hide 1346 */ concatArrays(byte[]... arrays)1347 public static byte[] concatArrays(byte[]... arrays) { 1348 int len = 0; 1349 for (byte[] a : arrays) { 1350 len += a.length; 1351 } 1352 byte[] b = new byte[len]; 1353 1354 int offs = 0; 1355 for (byte[] a : arrays) { 1356 System.arraycopy(a, 0, b, offs, a.length); 1357 offs += a.length; 1358 } 1359 return b; 1360 } 1361 } 1362