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