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