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