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.AudioDeviceAttributes; 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 stream or device 360 */ 361 public static final String EFFECT_PRE_PROCESSING = "Pre Processing"; 362 /** 363 * Effect connection mode is post processing. 364 * The audio post processing effects are attached to an audio output stream or device 365 */ 366 public static final String EFFECT_POST_PROCESSING = "Post Processing"; 367 368 // -------------------------------------------------------------------------- 369 // Member variables 370 // -------------------- 371 /** 372 * Indicates the state of the AudioEffect instance 373 */ 374 private int mState = STATE_UNINITIALIZED; 375 /** 376 * Lock to synchronize access to mState 377 */ 378 private final Object mStateLock = new Object(); 379 /** 380 * System wide unique effect ID 381 */ 382 private int mId; 383 384 // accessed by native methods 385 private long mNativeAudioEffect; 386 private long mJniData; 387 388 /** 389 * Effect descriptor 390 */ 391 private Descriptor mDescriptor; 392 393 /** 394 * Listener for effect engine state change notifications. 395 * 396 * @see #setEnableStatusListener(OnEnableStatusChangeListener) 397 */ 398 private OnEnableStatusChangeListener mEnableStatusChangeListener = null; 399 /** 400 * Listener for effect engine control ownership change notifications. 401 * 402 * @see #setControlStatusListener(OnControlStatusChangeListener) 403 */ 404 private OnControlStatusChangeListener mControlChangeStatusListener = null; 405 /** 406 * Listener for effect engine control ownership change notifications. 407 * 408 * @see #setParameterListener(OnParameterChangeListener) 409 */ 410 private OnParameterChangeListener mParameterChangeListener = null; 411 /** 412 * Lock to protect listeners updates against event notifications 413 * @hide 414 */ 415 public final Object mListenerLock = new Object(); 416 /** 417 * Handler for events coming from the native code 418 * @hide 419 */ 420 public NativeEventHandler mNativeEventHandler = null; 421 422 // -------------------------------------------------------------------------- 423 // Constructor, Finalize 424 // -------------------- 425 /** 426 * Class constructor. 427 * 428 * @param type type of effect engine created. See {@link #EFFECT_TYPE_ENV_REVERB}, 429 * {@link #EFFECT_TYPE_EQUALIZER} ... Types corresponding to 430 * built-in effects are defined by AudioEffect class. Other types 431 * can be specified provided they correspond an existing OpenSL 432 * ES interface ID and the corresponsing effect is available on 433 * the platform. If an unspecified effect type is requested, the 434 * constructor with throw the IllegalArgumentException. This 435 * parameter can be set to {@link #EFFECT_TYPE_NULL} in which 436 * case only the uuid will be used to select the effect. 437 * @param uuid unique identifier of a particular effect implementation. 438 * Must be specified if the caller wants to use a particular 439 * implementation of an effect type. This parameter can be set to 440 * {@link #EFFECT_TYPE_NULL} in which case only the type will 441 * be used to select the effect. 442 * @param priority the priority level requested by the application for 443 * controlling the effect engine. As the same effect engine can 444 * be shared by several applications, this parameter indicates 445 * how much the requesting application needs control of effect 446 * parameters. The normal priority is 0, above normal is a 447 * positive number, below normal a negative number. 448 * @param audioSession system wide unique audio session identifier. 449 * The effect will be attached to the MediaPlayer or AudioTrack in 450 * the same audio session. 451 * 452 * @throws java.lang.IllegalArgumentException 453 * @throws java.lang.UnsupportedOperationException 454 * @throws java.lang.RuntimeException 455 * @hide 456 */ 457 458 @UnsupportedAppUsage AudioEffect(UUID type, UUID uuid, int priority, int audioSession)459 public AudioEffect(UUID type, UUID uuid, int priority, int audioSession) 460 throws IllegalArgumentException, UnsupportedOperationException, 461 RuntimeException { 462 this(type, uuid, priority, audioSession, null); 463 } 464 465 /** 466 * Constructs an AudioEffect attached to a particular audio device. 467 * The device does not have to be attached when the effect is created. The effect will only 468 * be applied when the device is actually selected for playback or capture. 469 * @param uuid unique identifier of a particular effect implementation. 470 * @param device the device the effect must be attached to. 471 * 472 * @throws java.lang.IllegalArgumentException 473 * @throws java.lang.UnsupportedOperationException 474 * @throws java.lang.RuntimeException 475 * @hide 476 */ 477 @SystemApi 478 @RequiresPermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS) AudioEffect(@onNull UUID uuid, @NonNull AudioDeviceAttributes device)479 public AudioEffect(@NonNull UUID uuid, @NonNull AudioDeviceAttributes device) { 480 this(EFFECT_TYPE_NULL, Objects.requireNonNull(uuid), 481 0, -2, Objects.requireNonNull(device)); 482 } 483 AudioEffect(UUID type, UUID uuid, int priority, int audioSession, @Nullable AudioDeviceAttributes device)484 private AudioEffect(UUID type, UUID uuid, int priority, 485 int audioSession, @Nullable AudioDeviceAttributes device) 486 throws IllegalArgumentException, UnsupportedOperationException, 487 RuntimeException { 488 this(type, uuid, priority, audioSession, device, false); 489 } 490 AudioEffect(UUID type, UUID uuid, int priority, int audioSession, @Nullable AudioDeviceAttributes device, boolean probe)491 private AudioEffect(UUID type, UUID uuid, int priority, 492 int audioSession, @Nullable AudioDeviceAttributes device, boolean probe) 493 throws IllegalArgumentException, UnsupportedOperationException, 494 RuntimeException { 495 int[] id = new int[1]; 496 Descriptor[] desc = new Descriptor[1]; 497 498 int deviceType = AudioSystem.DEVICE_NONE; 499 String deviceAddress = ""; 500 if (device != null) { 501 deviceType = AudioDeviceInfo.convertDeviceTypeToInternalDevice(device.getType()); 502 deviceAddress = device.getAddress(); 503 } 504 505 // native initialization 506 int initResult = native_setup(new WeakReference<AudioEffect>(this), 507 type.toString(), uuid.toString(), priority, audioSession, 508 deviceType, deviceAddress, 509 id, desc, ActivityThread.currentOpPackageName(), probe); 510 if (initResult != SUCCESS && initResult != ALREADY_EXISTS) { 511 Log.e(TAG, "Error code " + initResult 512 + " when initializing AudioEffect."); 513 switch (initResult) { 514 case ERROR_BAD_VALUE: 515 throw (new IllegalArgumentException("Effect type: " + type 516 + " not supported.")); 517 case ERROR_INVALID_OPERATION: 518 throw (new UnsupportedOperationException( 519 "Effect library not loaded")); 520 default: 521 throw (new RuntimeException( 522 "Cannot initialize effect engine for type: " + type 523 + " Error: " + initResult)); 524 } 525 } 526 mId = id[0]; 527 mDescriptor = desc[0]; 528 if (!probe) { 529 synchronized (mStateLock) { 530 mState = STATE_INITIALIZED; 531 } 532 } 533 } 534 535 /** 536 * Checks if an AudioEffect identified by the supplied uuid can be attached 537 * to an audio device described by the supplied AudioDeviceAttributes. 538 * @param uuid unique identifier of a particular effect implementation. 539 * @param device the device the effect would be attached to. 540 * @return true if possible, false otherwise. 541 * @hide 542 */ 543 @SystemApi 544 @RequiresPermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS) isEffectSupportedForDevice( @onNull UUID uuid, @NonNull AudioDeviceAttributes device)545 public static boolean isEffectSupportedForDevice( 546 @NonNull UUID uuid, @NonNull AudioDeviceAttributes device) { 547 try { 548 AudioEffect fx = new AudioEffect( 549 EFFECT_TYPE_NULL, Objects.requireNonNull(uuid), 550 0, -2, Objects.requireNonNull(device), true); 551 fx.release(); 552 return true; 553 } catch (Exception e) { 554 return false; 555 } 556 } 557 558 /** 559 * Releases the native AudioEffect resources. It is a good practice to 560 * release the effect engine when not in use as control can be returned to 561 * other applications or the native resources released. 562 */ release()563 public void release() { 564 synchronized (mStateLock) { 565 native_release(); 566 mState = STATE_UNINITIALIZED; 567 } 568 } 569 570 @Override finalize()571 protected void finalize() { 572 native_finalize(); 573 } 574 575 /** 576 * Get the effect descriptor. 577 * 578 * @see android.media.audiofx.AudioEffect.Descriptor 579 * @throws IllegalStateException 580 */ getDescriptor()581 public Descriptor getDescriptor() throws IllegalStateException { 582 checkState("getDescriptor()"); 583 return mDescriptor; 584 } 585 586 // -------------------------------------------------------------------------- 587 // Effects Enumeration 588 // -------------------- 589 590 /** 591 * Query all effects available on the platform. Returns an array of 592 * {@link android.media.audiofx.AudioEffect.Descriptor} objects 593 * 594 * @throws IllegalStateException 595 */ 596 queryEffects()597 static public Descriptor[] queryEffects() { 598 return (Descriptor[]) native_query_effects(); 599 } 600 601 /** 602 * Query all audio pre-processing effects applied to the AudioRecord with the supplied 603 * audio session ID. Returns an array of {@link android.media.audiofx.AudioEffect.Descriptor} 604 * objects. 605 * @param audioSession system wide unique audio session identifier. 606 * @throws IllegalStateException 607 * @hide 608 */ 609 queryPreProcessings(int audioSession)610 static public Descriptor[] queryPreProcessings(int audioSession) { 611 return (Descriptor[]) native_query_pre_processing(audioSession); 612 } 613 614 /** 615 * Checks if the device implements the specified effect type. 616 * @param type the requested effect type. 617 * @return true if the device implements the specified effect type, false otherwise. 618 * @hide 619 */ 620 @TestApi isEffectTypeAvailable(UUID type)621 public static boolean isEffectTypeAvailable(UUID type) { 622 AudioEffect.Descriptor[] desc = AudioEffect.queryEffects(); 623 if (desc == null) { 624 return false; 625 } 626 627 for (int i = 0; i < desc.length; i++) { 628 if (desc[i].type.equals(type)) { 629 return true; 630 } 631 } 632 return false; 633 } 634 635 // -------------------------------------------------------------------------- 636 // Control methods 637 // -------------------- 638 639 /** 640 * Enable or disable the effect. 641 * Creating an audio effect does not automatically apply this effect on the audio source. It 642 * creates the resources necessary to process this effect but the audio signal is still bypassed 643 * through the effect engine. Calling this method will make that the effect is actually applied 644 * or not to the audio content being played in the corresponding audio session. 645 * 646 * @param enabled the requested enable state 647 * @return {@link #SUCCESS} in case of success, {@link #ERROR_INVALID_OPERATION} 648 * or {@link #ERROR_DEAD_OBJECT} in case of failure. 649 * @throws IllegalStateException 650 */ setEnabled(boolean enabled)651 public int setEnabled(boolean enabled) throws IllegalStateException { 652 checkState("setEnabled()"); 653 return native_setEnabled(enabled); 654 } 655 656 /** 657 * Set effect parameter. The setParameter method is provided in several 658 * forms addressing most common parameter formats. This form is the most 659 * generic one where the parameter and its value are both specified as an 660 * array of bytes. The parameter and value type and length are therefore 661 * totally free. For standard effect defined by OpenSL ES, the parameter 662 * format and values must match the definitions in the corresponding OpenSL 663 * ES interface. 664 * 665 * @param param the identifier of the parameter to set 666 * @param value the new value for the specified parameter 667 * @return {@link #SUCCESS} in case of success, {@link #ERROR_BAD_VALUE}, 668 * {@link #ERROR_NO_MEMORY}, {@link #ERROR_INVALID_OPERATION} or 669 * {@link #ERROR_DEAD_OBJECT} in case of failure 670 * @throws IllegalStateException 671 * @hide 672 */ 673 @TestApi setParameter(byte[] param, byte[] value)674 public int setParameter(byte[] param, byte[] value) 675 throws IllegalStateException { 676 checkState("setParameter()"); 677 return native_setParameter(param.length, param, value.length, value); 678 } 679 680 /** 681 * Set effect parameter. The parameter and its value are integers. 682 * 683 * @see #setParameter(byte[], byte[]) 684 * @hide 685 */ 686 @TestApi setParameter(int param, int value)687 public int setParameter(int param, int value) throws IllegalStateException { 688 byte[] p = intToByteArray(param); 689 byte[] v = intToByteArray(value); 690 return setParameter(p, v); 691 } 692 693 /** 694 * Set effect parameter. The parameter is an integer and the value is a 695 * short integer. 696 * 697 * @see #setParameter(byte[], byte[]) 698 * @hide 699 */ 700 @TestApi setParameter(int param, short value)701 public int setParameter(int param, short value) 702 throws IllegalStateException { 703 byte[] p = intToByteArray(param); 704 byte[] v = shortToByteArray(value); 705 return setParameter(p, v); 706 } 707 708 /** 709 * Set effect parameter. The parameter is an integer and the value is an 710 * array of bytes. 711 * 712 * @see #setParameter(byte[], byte[]) 713 * @hide 714 */ 715 @TestApi setParameter(int param, byte[] value)716 public int setParameter(int param, byte[] value) 717 throws IllegalStateException { 718 byte[] p = intToByteArray(param); 719 return setParameter(p, value); 720 } 721 722 /** 723 * Set effect parameter. The parameter is an array of 1 or 2 integers and 724 * the value is also an array of 1 or 2 integers 725 * 726 * @see #setParameter(byte[], byte[]) 727 * @hide 728 */ 729 @TestApi setParameter(int[] param, int[] value)730 public int setParameter(int[] param, int[] value) 731 throws IllegalStateException { 732 if (param.length > 2 || value.length > 2) { 733 return ERROR_BAD_VALUE; 734 } 735 byte[] p = intToByteArray(param[0]); 736 if (param.length > 1) { 737 byte[] p2 = intToByteArray(param[1]); 738 p = concatArrays(p, p2); 739 } 740 byte[] v = intToByteArray(value[0]); 741 if (value.length > 1) { 742 byte[] v2 = intToByteArray(value[1]); 743 v = concatArrays(v, v2); 744 } 745 return setParameter(p, v); 746 } 747 748 /** 749 * Set effect parameter. The parameter is an array of 1 or 2 integers and 750 * the value is an array of 1 or 2 short integers 751 * 752 * @see #setParameter(byte[], byte[]) 753 * @hide 754 */ 755 @UnsupportedAppUsage setParameter(int[] param, short[] value)756 public int setParameter(int[] param, short[] value) 757 throws IllegalStateException { 758 if (param.length > 2 || value.length > 2) { 759 return ERROR_BAD_VALUE; 760 } 761 byte[] p = intToByteArray(param[0]); 762 if (param.length > 1) { 763 byte[] p2 = intToByteArray(param[1]); 764 p = concatArrays(p, p2); 765 } 766 767 byte[] v = shortToByteArray(value[0]); 768 if (value.length > 1) { 769 byte[] v2 = shortToByteArray(value[1]); 770 v = concatArrays(v, v2); 771 } 772 return setParameter(p, v); 773 } 774 775 /** 776 * Set effect parameter. The parameter is an array of 1 or 2 integers and 777 * the value is an array of bytes 778 * 779 * @see #setParameter(byte[], byte[]) 780 * @hide 781 */ 782 @TestApi setParameter(int[] param, byte[] value)783 public int setParameter(int[] param, byte[] value) 784 throws IllegalStateException { 785 if (param.length > 2) { 786 return ERROR_BAD_VALUE; 787 } 788 byte[] p = intToByteArray(param[0]); 789 if (param.length > 1) { 790 byte[] p2 = intToByteArray(param[1]); 791 p = concatArrays(p, p2); 792 } 793 return setParameter(p, value); 794 } 795 796 /** 797 * Get effect parameter. The getParameter method is provided in several 798 * forms addressing most common parameter formats. This form is the most 799 * generic one where the parameter and its value are both specified as an 800 * array of bytes. The parameter and value type and length are therefore 801 * totally free. 802 * 803 * @param param the identifier of the parameter to set 804 * @param value the new value for the specified parameter 805 * @return the number of meaningful bytes in value array in case of success or 806 * {@link #ERROR_BAD_VALUE}, {@link #ERROR_NO_MEMORY}, {@link #ERROR_INVALID_OPERATION} 807 * or {@link #ERROR_DEAD_OBJECT} in case of failure. 808 * @throws IllegalStateException 809 * @hide 810 */ 811 @TestApi getParameter(byte[] param, byte[] value)812 public int getParameter(byte[] param, byte[] value) 813 throws IllegalStateException { 814 checkState("getParameter()"); 815 return native_getParameter(param.length, param, value.length, value); 816 } 817 818 /** 819 * Get effect parameter. The parameter is an integer and the value is an 820 * array of bytes. 821 * 822 * @see #getParameter(byte[], byte[]) 823 * @hide 824 */ 825 @TestApi getParameter(int param, byte[] value)826 public int getParameter(int param, byte[] value) 827 throws IllegalStateException { 828 byte[] p = intToByteArray(param); 829 830 return getParameter(p, value); 831 } 832 833 /** 834 * Get effect parameter. The parameter is an integer and the value is an 835 * array of 1 or 2 integers 836 * 837 * @see #getParameter(byte[], byte[]) 838 * In case of success, returns the number of meaningful integers in value array. 839 * @hide 840 */ 841 @TestApi getParameter(int param, int[] value)842 public int getParameter(int param, int[] value) 843 throws IllegalStateException { 844 if (value.length > 2) { 845 return ERROR_BAD_VALUE; 846 } 847 byte[] p = intToByteArray(param); 848 849 byte[] v = new byte[value.length * 4]; 850 851 int status = getParameter(p, v); 852 853 if (status == 4 || status == 8) { 854 value[0] = byteArrayToInt(v); 855 if (status == 8) { 856 value[1] = byteArrayToInt(v, 4); 857 } 858 status /= 4; 859 } else { 860 status = ERROR; 861 } 862 return status; 863 } 864 865 /** 866 * Get effect parameter. The parameter is an integer and the value is an 867 * array of 1 or 2 short integers 868 * 869 * @see #getParameter(byte[], byte[]) 870 * In case of success, returns the number of meaningful short integers in value array. 871 * @hide 872 */ 873 @TestApi getParameter(int param, short[] value)874 public int getParameter(int param, short[] value) 875 throws IllegalStateException { 876 if (value.length > 2) { 877 return ERROR_BAD_VALUE; 878 } 879 byte[] p = intToByteArray(param); 880 881 byte[] v = new byte[value.length * 2]; 882 883 int status = getParameter(p, v); 884 885 if (status == 2 || status == 4) { 886 value[0] = byteArrayToShort(v); 887 if (status == 4) { 888 value[1] = byteArrayToShort(v, 2); 889 } 890 status /= 2; 891 } else { 892 status = ERROR; 893 } 894 return status; 895 } 896 897 /** 898 * Get effect parameter. The parameter is an array of 1 or 2 integers and 899 * the value is also an array of 1 or 2 integers 900 * 901 * @see #getParameter(byte[], byte[]) 902 * In case of success, the returns the number of meaningful integers in value array. 903 * @hide 904 */ 905 @UnsupportedAppUsage getParameter(int[] param, int[] value)906 public int getParameter(int[] param, int[] value) 907 throws IllegalStateException { 908 if (param.length > 2 || value.length > 2) { 909 return ERROR_BAD_VALUE; 910 } 911 byte[] p = intToByteArray(param[0]); 912 if (param.length > 1) { 913 byte[] p2 = intToByteArray(param[1]); 914 p = concatArrays(p, p2); 915 } 916 byte[] v = new byte[value.length * 4]; 917 918 int status = getParameter(p, v); 919 920 if (status == 4 || status == 8) { 921 value[0] = byteArrayToInt(v); 922 if (status == 8) { 923 value[1] = byteArrayToInt(v, 4); 924 } 925 status /= 4; 926 } else { 927 status = ERROR; 928 } 929 return status; 930 } 931 932 /** 933 * Get effect parameter. The parameter is an array of 1 or 2 integers and 934 * the value is an array of 1 or 2 short integers 935 * 936 * @see #getParameter(byte[], byte[]) 937 * In case of success, returns the number of meaningful short integers in value array. 938 * @hide 939 */ 940 @TestApi getParameter(int[] param, short[] value)941 public int getParameter(int[] param, short[] value) 942 throws IllegalStateException { 943 if (param.length > 2 || value.length > 2) { 944 return ERROR_BAD_VALUE; 945 } 946 byte[] p = intToByteArray(param[0]); 947 if (param.length > 1) { 948 byte[] p2 = intToByteArray(param[1]); 949 p = concatArrays(p, p2); 950 } 951 byte[] v = new byte[value.length * 2]; 952 953 int status = getParameter(p, v); 954 955 if (status == 2 || status == 4) { 956 value[0] = byteArrayToShort(v); 957 if (status == 4) { 958 value[1] = byteArrayToShort(v, 2); 959 } 960 status /= 2; 961 } else { 962 status = ERROR; 963 } 964 return status; 965 } 966 967 /** 968 * Get effect parameter. The parameter is an array of 1 or 2 integers and 969 * the value is an array of bytes 970 * 971 * @see #getParameter(byte[], byte[]) 972 * @hide 973 */ 974 @UnsupportedAppUsage getParameter(int[] param, byte[] value)975 public int getParameter(int[] param, byte[] value) 976 throws IllegalStateException { 977 if (param.length > 2) { 978 return ERROR_BAD_VALUE; 979 } 980 byte[] p = intToByteArray(param[0]); 981 if (param.length > 1) { 982 byte[] p2 = intToByteArray(param[1]); 983 p = concatArrays(p, p2); 984 } 985 986 return getParameter(p, value); 987 } 988 989 /** 990 * Send a command to the effect engine. This method is intended to send 991 * proprietary commands to a particular effect implementation. 992 * In case of success, returns the number of meaningful bytes in reply array. 993 * In case of failure, the returned value is negative and implementation specific. 994 * @hide 995 */ 996 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) command(int cmdCode, byte[] command, byte[] reply)997 public int command(int cmdCode, byte[] command, byte[] reply) 998 throws IllegalStateException { 999 checkState("command()"); 1000 return native_command(cmdCode, command.length, command, reply.length, reply); 1001 } 1002 1003 // -------------------------------------------------------------------------- 1004 // Getters 1005 // -------------------- 1006 1007 /** 1008 * Returns effect unique identifier. This system wide unique identifier can 1009 * be used to attach this effect to a MediaPlayer or an AudioTrack when the 1010 * effect is an auxiliary effect (Reverb) 1011 * 1012 * @return the effect identifier. 1013 * @throws IllegalStateException 1014 */ getId()1015 public int getId() throws IllegalStateException { 1016 checkState("getId()"); 1017 return mId; 1018 } 1019 1020 /** 1021 * Returns effect enabled state 1022 * 1023 * @return true if the effect is enabled, false otherwise. 1024 * @throws IllegalStateException 1025 */ getEnabled()1026 public boolean getEnabled() throws IllegalStateException { 1027 checkState("getEnabled()"); 1028 return native_getEnabled(); 1029 } 1030 1031 /** 1032 * Checks if this AudioEffect object is controlling the effect engine. 1033 * 1034 * @return true if this instance has control of effect engine, false 1035 * otherwise. 1036 * @throws IllegalStateException 1037 */ hasControl()1038 public boolean hasControl() throws IllegalStateException { 1039 checkState("hasControl()"); 1040 return native_hasControl(); 1041 } 1042 1043 // -------------------------------------------------------------------------- 1044 // Initialization / configuration 1045 // -------------------- 1046 /** 1047 * Sets the listener AudioEffect notifies when the effect engine is enabled 1048 * or disabled. 1049 * 1050 * @param listener 1051 */ setEnableStatusListener(OnEnableStatusChangeListener listener)1052 public void setEnableStatusListener(OnEnableStatusChangeListener listener) { 1053 synchronized (mListenerLock) { 1054 mEnableStatusChangeListener = listener; 1055 } 1056 if ((listener != null) && (mNativeEventHandler == null)) { 1057 createNativeEventHandler(); 1058 } 1059 } 1060 1061 /** 1062 * Sets the listener AudioEffect notifies when the effect engine control is 1063 * taken or returned. 1064 * 1065 * @param listener 1066 */ setControlStatusListener(OnControlStatusChangeListener listener)1067 public void setControlStatusListener(OnControlStatusChangeListener listener) { 1068 synchronized (mListenerLock) { 1069 mControlChangeStatusListener = listener; 1070 } 1071 if ((listener != null) && (mNativeEventHandler == null)) { 1072 createNativeEventHandler(); 1073 } 1074 } 1075 1076 /** 1077 * Sets the listener AudioEffect notifies when a parameter is changed. 1078 * 1079 * @param listener 1080 * @hide 1081 */ 1082 @TestApi setParameterListener(OnParameterChangeListener listener)1083 public void setParameterListener(OnParameterChangeListener listener) { 1084 synchronized (mListenerLock) { 1085 mParameterChangeListener = listener; 1086 } 1087 if ((listener != null) && (mNativeEventHandler == null)) { 1088 createNativeEventHandler(); 1089 } 1090 } 1091 1092 // Convenience method for the creation of the native event handler 1093 // It is called only when a non-null event listener is set. 1094 // precondition: 1095 // mNativeEventHandler is null createNativeEventHandler()1096 private void createNativeEventHandler() { 1097 Looper looper; 1098 if ((looper = Looper.myLooper()) != null) { 1099 mNativeEventHandler = new NativeEventHandler(this, looper); 1100 } else if ((looper = Looper.getMainLooper()) != null) { 1101 mNativeEventHandler = new NativeEventHandler(this, looper); 1102 } else { 1103 mNativeEventHandler = null; 1104 } 1105 } 1106 1107 // --------------------------------------------------------- 1108 // Interface definitions 1109 // -------------------- 1110 /** 1111 * The OnEnableStatusChangeListener interface defines a method called by the AudioEffect 1112 * when the enabled state of the effect engine was changed by the controlling application. 1113 */ 1114 public interface OnEnableStatusChangeListener { 1115 /** 1116 * Called on the listener to notify it that the effect engine has been 1117 * enabled or disabled. 1118 * @param effect the effect on which the interface is registered. 1119 * @param enabled new effect state. 1120 */ onEnableStatusChange(AudioEffect effect, boolean enabled)1121 void onEnableStatusChange(AudioEffect effect, boolean enabled); 1122 } 1123 1124 /** 1125 * The OnControlStatusChangeListener interface defines a method called by the AudioEffect 1126 * when control of the effect engine is gained or lost by the application 1127 */ 1128 public interface OnControlStatusChangeListener { 1129 /** 1130 * Called on the listener to notify it that the effect engine control 1131 * has been taken or returned. 1132 * @param effect the effect on which the interface is registered. 1133 * @param controlGranted true if the application has been granted control of the effect 1134 * engine, false otherwise. 1135 */ onControlStatusChange(AudioEffect effect, boolean controlGranted)1136 void onControlStatusChange(AudioEffect effect, boolean controlGranted); 1137 } 1138 1139 /** 1140 * The OnParameterChangeListener interface defines a method called by the AudioEffect 1141 * when a parameter is changed in the effect engine by the controlling application. 1142 * @hide 1143 */ 1144 @TestApi 1145 public interface OnParameterChangeListener { 1146 /** 1147 * Called on the listener to notify it that a parameter value has changed. 1148 * @param effect the effect on which the interface is registered. 1149 * @param status status of the set parameter operation. 1150 * @param param ID of the modified parameter. 1151 * @param value the new parameter value. 1152 */ onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value)1153 void onParameterChange(AudioEffect effect, int status, byte[] param, 1154 byte[] value); 1155 } 1156 1157 1158 // ------------------------------------------------------------------------- 1159 // Audio Effect Control panel intents 1160 // ------------------------------------------------------------------------- 1161 1162 /** 1163 * Intent to launch an audio effect control panel UI. 1164 * <p>The goal of this intent is to enable separate implementations of music/media player 1165 * applications and audio effect control application or services. 1166 * This will allow platform vendors to offer more advanced control options for standard effects 1167 * or control for platform specific effects. 1168 * <p>The intent carries a number of extras used by the player application to communicate 1169 * necessary pieces of information to the control panel application. 1170 * <p>The calling application must use the 1171 * {@link android.app.Activity#startActivityForResult(Intent, int)} method to launch the 1172 * control panel so that its package name is indicated and used by the control panel 1173 * application to keep track of changes for this particular application. 1174 * <p>The {@link #EXTRA_AUDIO_SESSION} extra will indicate an audio session to which the 1175 * audio effects should be applied. If no audio session is specified, either one of the 1176 * follownig will happen: 1177 * <p>- If an audio session was previously opened by the calling application with 1178 * {@link #ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION} intent, the effect changes will 1179 * be applied to that session. 1180 * <p>- If no audio session is opened, the changes will be stored in the package specific 1181 * storage area and applied whenever a new audio session is opened by this application. 1182 * <p>The {@link #EXTRA_CONTENT_TYPE} extra will help the control panel application 1183 * customize both the UI layout and the default audio effect settings if none are already 1184 * stored for the calling application. 1185 */ 1186 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 1187 public static final String ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL = 1188 "android.media.action.DISPLAY_AUDIO_EFFECT_CONTROL_PANEL"; 1189 1190 /** 1191 * Intent to signal to the effect control application or service that a new audio session 1192 * is opened and requires audio effects to be applied. 1193 * <p>This is different from {@link #ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL} in that no 1194 * UI should be displayed in this case. Music player applications can broadcast this intent 1195 * before starting playback to make sure that any audio effect settings previously selected 1196 * by the user are applied. 1197 * <p>The effect control application receiving this intent will look for previously stored 1198 * settings for the calling application, create all required audio effects and apply the 1199 * effect settings to the specified audio session. 1200 * <p>The calling package name is indicated by the {@link #EXTRA_PACKAGE_NAME} extra and the 1201 * audio session ID by the {@link #EXTRA_AUDIO_SESSION} extra. Both extras are mandatory. 1202 * <p>If no stored settings are found for the calling application, default settings for the 1203 * content type indicated by {@link #EXTRA_CONTENT_TYPE} will be applied. The default settings 1204 * for a given content type are platform specific. 1205 */ 1206 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 1207 public static final String ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION = 1208 "android.media.action.OPEN_AUDIO_EFFECT_CONTROL_SESSION"; 1209 1210 /** 1211 * Intent to signal to the effect control application or service that an audio session 1212 * is closed and that effects should not be applied anymore. 1213 * <p>The effect control application receiving this intent will delete all effects on 1214 * this session and store current settings in package specific storage. 1215 * <p>The calling package name is indicated by the {@link #EXTRA_PACKAGE_NAME} extra and the 1216 * audio session ID by the {@link #EXTRA_AUDIO_SESSION} extra. Both extras are mandatory. 1217 * <p>It is good practice for applications to broadcast this intent when music playback stops 1218 * and/or when exiting to free system resources consumed by audio effect engines. 1219 */ 1220 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 1221 public static final String ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION = 1222 "android.media.action.CLOSE_AUDIO_EFFECT_CONTROL_SESSION"; 1223 1224 /** 1225 * Contains the ID of the audio session the effects should be applied to. 1226 * <p>This extra is for use with {@link #ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL}, 1227 * {@link #ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION} and 1228 * {@link #ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION} intents. 1229 * <p>The extra value is of type int and is the audio session ID. 1230 * @see android.media.MediaPlayer#getAudioSessionId() for details on audio sessions. 1231 */ 1232 public static final String EXTRA_AUDIO_SESSION = "android.media.extra.AUDIO_SESSION"; 1233 1234 /** 1235 * Contains the package name of the calling application. 1236 * <p>This extra is for use with {@link #ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION} and 1237 * {@link #ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION} intents. 1238 * <p>The extra value is a string containing the full package name. 1239 */ 1240 public static final String EXTRA_PACKAGE_NAME = "android.media.extra.PACKAGE_NAME"; 1241 1242 /** 1243 * Indicates which type of content is played by the application. 1244 * <p>This extra is for use with {@link #ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL} and 1245 * {@link #ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION} intents. 1246 * <p>This information is used by the effect control application to customize UI and select 1247 * appropriate default effect settings. The content type is one of the following: 1248 * <ul> 1249 * <li>{@link #CONTENT_TYPE_MUSIC}</li> 1250 * <li>{@link #CONTENT_TYPE_MOVIE}</li> 1251 * <li>{@link #CONTENT_TYPE_GAME}</li> 1252 * <li>{@link #CONTENT_TYPE_VOICE}</li> 1253 * </ul> 1254 * If omitted, the content type defaults to {@link #CONTENT_TYPE_MUSIC}. 1255 */ 1256 public static final String EXTRA_CONTENT_TYPE = "android.media.extra.CONTENT_TYPE"; 1257 1258 /** 1259 * Value for {@link #EXTRA_CONTENT_TYPE} when the type of content played is music 1260 */ 1261 public static final int CONTENT_TYPE_MUSIC = 0; 1262 /** 1263 * Value for {@link #EXTRA_CONTENT_TYPE} when the type of content played is video or movie 1264 */ 1265 public static final int CONTENT_TYPE_MOVIE = 1; 1266 /** 1267 * Value for {@link #EXTRA_CONTENT_TYPE} when the type of content played is game audio 1268 */ 1269 public static final int CONTENT_TYPE_GAME = 2; 1270 /** 1271 * Value for {@link #EXTRA_CONTENT_TYPE} when the type of content played is voice audio 1272 */ 1273 public static final int CONTENT_TYPE_VOICE = 3; 1274 1275 1276 // --------------------------------------------------------- 1277 // Inner classes 1278 // -------------------- 1279 /** 1280 * Helper class to handle the forwarding of native events to the appropriate 1281 * listeners 1282 */ 1283 private class NativeEventHandler extends Handler { 1284 private AudioEffect mAudioEffect; 1285 NativeEventHandler(AudioEffect ae, Looper looper)1286 public NativeEventHandler(AudioEffect ae, Looper looper) { 1287 super(looper); 1288 mAudioEffect = ae; 1289 } 1290 1291 @Override handleMessage(Message msg)1292 public void handleMessage(Message msg) { 1293 if (mAudioEffect == null) { 1294 return; 1295 } 1296 switch (msg.what) { 1297 case NATIVE_EVENT_ENABLED_STATUS: 1298 OnEnableStatusChangeListener enableStatusChangeListener = null; 1299 synchronized (mListenerLock) { 1300 enableStatusChangeListener = mAudioEffect.mEnableStatusChangeListener; 1301 } 1302 if (enableStatusChangeListener != null) { 1303 enableStatusChangeListener.onEnableStatusChange( 1304 mAudioEffect, (boolean) (msg.arg1 != 0)); 1305 } 1306 break; 1307 case NATIVE_EVENT_CONTROL_STATUS: 1308 OnControlStatusChangeListener controlStatusChangeListener = null; 1309 synchronized (mListenerLock) { 1310 controlStatusChangeListener = mAudioEffect.mControlChangeStatusListener; 1311 } 1312 if (controlStatusChangeListener != null) { 1313 controlStatusChangeListener.onControlStatusChange( 1314 mAudioEffect, (boolean) (msg.arg1 != 0)); 1315 } 1316 break; 1317 case NATIVE_EVENT_PARAMETER_CHANGED: 1318 OnParameterChangeListener parameterChangeListener = null; 1319 synchronized (mListenerLock) { 1320 parameterChangeListener = mAudioEffect.mParameterChangeListener; 1321 } 1322 if (parameterChangeListener != null) { 1323 // arg1 contains offset of parameter value from start of 1324 // byte array 1325 int vOffset = msg.arg1; 1326 byte[] p = (byte[]) msg.obj; 1327 // See effect_param_t in EffectApi.h for psize and vsize 1328 // fields offsets 1329 int status = byteArrayToInt(p, 0); 1330 int psize = byteArrayToInt(p, 4); 1331 int vsize = byteArrayToInt(p, 8); 1332 byte[] param = new byte[psize]; 1333 byte[] value = new byte[vsize]; 1334 System.arraycopy(p, 12, param, 0, psize); 1335 System.arraycopy(p, vOffset, value, 0, vsize); 1336 1337 parameterChangeListener.onParameterChange(mAudioEffect, 1338 status, param, value); 1339 } 1340 break; 1341 1342 default: 1343 Log.e(TAG, "handleMessage() Unknown event type: " + msg.what); 1344 break; 1345 } 1346 } 1347 } 1348 1349 // --------------------------------------------------------- 1350 // Java methods called from the native side 1351 // -------------------- 1352 @SuppressWarnings("unused") postEventFromNative(Object effect_ref, int what, int arg1, int arg2, Object obj)1353 private static void postEventFromNative(Object effect_ref, int what, 1354 int arg1, int arg2, Object obj) { 1355 AudioEffect effect = (AudioEffect) ((WeakReference) effect_ref).get(); 1356 if (effect == null) { 1357 return; 1358 } 1359 if (effect.mNativeEventHandler != null) { 1360 Message m = effect.mNativeEventHandler.obtainMessage(what, arg1, 1361 arg2, obj); 1362 effect.mNativeEventHandler.sendMessage(m); 1363 } 1364 1365 } 1366 1367 // --------------------------------------------------------- 1368 // Native methods called from the Java side 1369 // -------------------- 1370 native_init()1371 private static native final void native_init(); 1372 native_setup(Object audioeffect_this, String type, String uuid, int priority, int audioSession, int deviceType, String deviceAddress, int[] id, Object[] desc, String opPackageName, boolean probe)1373 private native final int native_setup(Object audioeffect_this, String type, 1374 String uuid, int priority, int audioSession, 1375 int deviceType, String deviceAddress, int[] id, Object[] desc, 1376 String opPackageName, boolean probe); 1377 native_finalize()1378 private native final void native_finalize(); 1379 native_release()1380 private native final void native_release(); 1381 native_setEnabled(boolean enabled)1382 private native final int native_setEnabled(boolean enabled); 1383 native_getEnabled()1384 private native final boolean native_getEnabled(); 1385 native_hasControl()1386 private native final boolean native_hasControl(); 1387 native_setParameter(int psize, byte[] param, int vsize, byte[] value)1388 private native final int native_setParameter(int psize, byte[] param, 1389 int vsize, byte[] value); 1390 native_getParameter(int psize, byte[] param, int vsize, byte[] value)1391 private native final int native_getParameter(int psize, byte[] param, 1392 int vsize, byte[] value); 1393 native_command(int cmdCode, int cmdSize, byte[] cmdData, int repSize, byte[] repData)1394 private native final int native_command(int cmdCode, int cmdSize, 1395 byte[] cmdData, int repSize, byte[] repData); 1396 native_query_effects()1397 private static native Object[] native_query_effects(); 1398 native_query_pre_processing(int audioSession)1399 private static native Object[] native_query_pre_processing(int audioSession); 1400 1401 // --------------------------------------------------------- 1402 // Utility methods 1403 // ------------------ 1404 1405 /** 1406 * @hide 1407 */ 1408 @UnsupportedAppUsage checkState(String methodName)1409 public void checkState(String methodName) throws IllegalStateException { 1410 synchronized (mStateLock) { 1411 if (mState != STATE_INITIALIZED) { 1412 throw (new IllegalStateException(methodName 1413 + " called on uninitialized AudioEffect.")); 1414 } 1415 } 1416 } 1417 1418 /** 1419 * @hide 1420 */ checkStatus(int status)1421 public void checkStatus(int status) { 1422 if (isError(status)) { 1423 switch (status) { 1424 case AudioEffect.ERROR_BAD_VALUE: 1425 throw (new IllegalArgumentException( 1426 "AudioEffect: bad parameter value")); 1427 case AudioEffect.ERROR_INVALID_OPERATION: 1428 throw (new UnsupportedOperationException( 1429 "AudioEffect: invalid parameter operation")); 1430 default: 1431 throw (new RuntimeException("AudioEffect: set/get parameter error")); 1432 } 1433 } 1434 } 1435 1436 /** 1437 * @hide 1438 */ 1439 @TestApi isError(int status)1440 public static boolean isError(int status) { 1441 return (status < 0); 1442 } 1443 1444 /** 1445 * @hide 1446 */ 1447 @TestApi byteArrayToInt(byte[] valueBuf)1448 public static int byteArrayToInt(byte[] valueBuf) { 1449 return byteArrayToInt(valueBuf, 0); 1450 1451 } 1452 1453 /** 1454 * @hide 1455 */ byteArrayToInt(byte[] valueBuf, int offset)1456 public static int byteArrayToInt(byte[] valueBuf, int offset) { 1457 ByteBuffer converter = ByteBuffer.wrap(valueBuf); 1458 converter.order(ByteOrder.nativeOrder()); 1459 return converter.getInt(offset); 1460 1461 } 1462 1463 /** 1464 * @hide 1465 */ 1466 @TestApi intToByteArray(int value)1467 public static byte[] intToByteArray(int value) { 1468 ByteBuffer converter = ByteBuffer.allocate(4); 1469 converter.order(ByteOrder.nativeOrder()); 1470 converter.putInt(value); 1471 return converter.array(); 1472 } 1473 1474 /** 1475 * @hide 1476 */ 1477 @TestApi byteArrayToShort(byte[] valueBuf)1478 public static short byteArrayToShort(byte[] valueBuf) { 1479 return byteArrayToShort(valueBuf, 0); 1480 } 1481 1482 /** 1483 * @hide 1484 */ byteArrayToShort(byte[] valueBuf, int offset)1485 public static short byteArrayToShort(byte[] valueBuf, int offset) { 1486 ByteBuffer converter = ByteBuffer.wrap(valueBuf); 1487 converter.order(ByteOrder.nativeOrder()); 1488 return converter.getShort(offset); 1489 1490 } 1491 1492 /** 1493 * @hide 1494 */ 1495 @TestApi shortToByteArray(short value)1496 public static byte[] shortToByteArray(short value) { 1497 ByteBuffer converter = ByteBuffer.allocate(2); 1498 converter.order(ByteOrder.nativeOrder()); 1499 short sValue = (short) value; 1500 converter.putShort(sValue); 1501 return converter.array(); 1502 } 1503 1504 /** 1505 * @hide 1506 */ byteArrayToFloat(byte[] valueBuf)1507 public static float byteArrayToFloat(byte[] valueBuf) { 1508 return byteArrayToFloat(valueBuf, 0); 1509 1510 } 1511 1512 /** 1513 * @hide 1514 */ byteArrayToFloat(byte[] valueBuf, int offset)1515 public static float byteArrayToFloat(byte[] valueBuf, int offset) { 1516 ByteBuffer converter = ByteBuffer.wrap(valueBuf); 1517 converter.order(ByteOrder.nativeOrder()); 1518 return converter.getFloat(offset); 1519 1520 } 1521 1522 /** 1523 * @hide 1524 */ floatToByteArray(float value)1525 public static byte[] floatToByteArray(float value) { 1526 ByteBuffer converter = ByteBuffer.allocate(4); 1527 converter.order(ByteOrder.nativeOrder()); 1528 converter.putFloat(value); 1529 return converter.array(); 1530 } 1531 1532 /** 1533 * @hide 1534 */ concatArrays(byte[]... arrays)1535 public static byte[] concatArrays(byte[]... arrays) { 1536 int len = 0; 1537 for (byte[] a : arrays) { 1538 len += a.length; 1539 } 1540 byte[] b = new byte[len]; 1541 1542 int offs = 0; 1543 for (byte[] a : arrays) { 1544 System.arraycopy(a, 0, b, offs, a.length); 1545 offs += a.length; 1546 } 1547 return b; 1548 } 1549 } 1550