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