Virtualizer.java revision d2bebb3ab86177c0d27664af86b30b7dce2c9bcb
1fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent/* 217cb280e7f1ac3556eac90ab08263712e0348cb9Eric Laurent * Copyright (C) 2010 The Android Open Source Project 3fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * 4fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * Licensed under the Apache License, Version 2.0 (the "License"); 5fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * you may not use this file except in compliance with the License. 6fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * You may obtain a copy of the License at 7fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * 8fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * http://www.apache.org/licenses/LICENSE-2.0 9fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * 10fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * Unless required by applicable law or agreed to in writing, software 11fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * distributed under the License is distributed on an "AS IS" BASIS, 12fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * See the License for the specific language governing permissions and 14fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * limitations under the License. 15fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent */ 16fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent 171a5149e5d7f2dddc8b324f7695e69fd89af73c52Eric Laurentpackage android.media.audiofx; 18fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent 19d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Triviimport android.media.AudioDevice; 20d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Triviimport android.media.AudioFormat; 211a5149e5d7f2dddc8b324f7695e69fd89af73c52Eric Laurentimport android.media.audiofx.AudioEffect; 22fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurentimport android.util.Log; 23ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent 24d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Triviimport java.nio.ByteBuffer; 25d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Triviimport java.nio.ByteOrder; 26ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurentimport java.util.StringTokenizer; 27fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent 28fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent 29fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent/** 30fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * An audio virtualizer is a general name for an effect to spatialize audio channels. The exact 31fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * behavior of this effect is dependent on the number of audio input channels and the types and 32fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * number of audio output channels of the device. For example, in the case of a stereo input and 33fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * stereo headphone output, a stereo widening effect is used when this effect is turned on. 34fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * <p>An application creates a Virtualizer object to instantiate and control a virtualizer engine 35fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * in the audio framework. 36fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * <p>The methods, parameter types and units exposed by the Virtualizer implementation are directly 37fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * mapping those defined by the OpenSL ES 1.0.1 Specification (http://www.khronos.org/opensles/) 38fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * for the SLVirtualizerItf interface. Please refer to this specification for more details. 39fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * <p>To attach the Virtualizer to a particular AudioTrack or MediaPlayer, specify the audio session 4062f3617f2f4016ad2f59635d5156d64872989880Eric Laurent * ID of this AudioTrack or MediaPlayer when constructing the Virtualizer. 4162f3617f2f4016ad2f59635d5156d64872989880Eric Laurent * <p>NOTE: attaching a Virtualizer to the global audio output mix by use of session 0 is 4262f3617f2f4016ad2f59635d5156d64872989880Eric Laurent * deprecated. 431a5149e5d7f2dddc8b324f7695e69fd89af73c52Eric Laurent * <p>See {@link android.media.MediaPlayer#getAudioSessionId()} for details on audio sessions. 441a5149e5d7f2dddc8b324f7695e69fd89af73c52Eric Laurent * <p>See {@link android.media.audiofx.AudioEffect} class for more details on controlling 451a5149e5d7f2dddc8b324f7695e69fd89af73c52Eric Laurent * audio effects. 46fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent */ 47fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent 48fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurentpublic class Virtualizer extends AudioEffect { 49fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent 50fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent private final static String TAG = "Virtualizer"; 51d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi private final static boolean DEBUG = false; 52fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent 53d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi // These constants must be synchronized with those in 54d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi // system/media/audio_effects/include/audio_effects/effect_virtualizer.h 55fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent /** 56fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * Is strength parameter supported by virtualizer engine. Parameter ID for getParameter(). 57fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent */ 58fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent public static final int PARAM_STRENGTH_SUPPORTED = 0; 59fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent /** 60fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * Virtualizer effect strength. Parameter ID for 611a5149e5d7f2dddc8b324f7695e69fd89af73c52Eric Laurent * {@link android.media.audiofx.Virtualizer.OnParameterChangeListener} 62fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent */ 63fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent public static final int PARAM_STRENGTH = 1; 64d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi /** 65d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @hide 66d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * Parameter ID to query the virtual speaker angles for a channel mask / device configuration. 67d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi */ 68d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi public static final int PARAM_VIRTUAL_SPEAKER_ANGLES = 2; 69d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi /** 70d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @hide 71d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * Parameter ID to force the virtualization mode to be that of a specific device 72d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi */ 73d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi public static final int PARAM_FORCE_VIRTUALIZATION_MODE = 3; 74d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi /** 75d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @hide 76d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * Parameter ID to query the current virtualization mode. 77d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi */ 78d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi public static final int PARAM_VIRTUALIZATION_MODE = 4; 79fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent 80fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent /** 81fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * Indicates if strength parameter is supported by the virtualizer engine 82fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent */ 83fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent private boolean mStrengthSupported = false; 84fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent 85fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent /** 86fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * Registered listener for parameter changes. 87fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent */ 88fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent private OnParameterChangeListener mParamListener = null; 89fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent 90fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent /** 91fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * Listener used internally to to receive raw parameter change event from AudioEffect super class 92fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent */ 93fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent private BaseParameterListener mBaseParamListener = null; 94fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent 95fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent /** 96fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * Lock for access to mParamListener 97fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent */ 98fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent private final Object mParamListenerLock = new Object(); 99fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent 100fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent /** 101fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * Class constructor. 102fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * @param priority the priority level requested by the application for controlling the Virtualizer 103fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * engine. As the same engine can be shared by several applications, this parameter indicates 104fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * how much the requesting application needs control of effect parameters. The normal priority 105fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * is 0, above normal is a positive number, below normal a negative number. 10662f3617f2f4016ad2f59635d5156d64872989880Eric Laurent * @param audioSession system wide unique audio session identifier. The Virtualizer will 10762f3617f2f4016ad2f59635d5156d64872989880Eric Laurent * be attached to the MediaPlayer or AudioTrack in the same audio session. 108fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * 109fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * @throws java.lang.IllegalStateException 110fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * @throws java.lang.IllegalArgumentException 111fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * @throws java.lang.UnsupportedOperationException 112fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * @throws java.lang.RuntimeException 113fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent */ 114fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent public Virtualizer(int priority, int audioSession) 115fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent throws IllegalStateException, IllegalArgumentException, 116fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent UnsupportedOperationException, RuntimeException { 117fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent super(EFFECT_TYPE_VIRTUALIZER, EFFECT_TYPE_NULL, priority, audioSession); 118fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent 11962f3617f2f4016ad2f59635d5156d64872989880Eric Laurent if (audioSession == 0) { 12062f3617f2f4016ad2f59635d5156d64872989880Eric Laurent Log.w(TAG, "WARNING: attaching a Virtualizer to global output mix is deprecated!"); 12162f3617f2f4016ad2f59635d5156d64872989880Eric Laurent } 12262f3617f2f4016ad2f59635d5156d64872989880Eric Laurent 123ba8da2e61b1d9ebb7a4758f1f7849ff8440bd20cEric Laurent int[] value = new int[1]; 124fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent checkStatus(getParameter(PARAM_STRENGTH_SUPPORTED, value)); 125fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent mStrengthSupported = (value[0] != 0); 126fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent } 127fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent 128fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent /** 129fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * Indicates whether setting strength is supported. If this method returns false, only one 130fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * strength is supported and the setStrength() method always rounds to that value. 131fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * @return true is strength parameter is supported, false otherwise 132fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent */ 133fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent public boolean getStrengthSupported() { 134fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent return mStrengthSupported; 135fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent } 136fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent 137fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent /** 138fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * Sets the strength of the virtualizer effect. If the implementation does not support per mille 139fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * accuracy for setting the strength, it is allowed to round the given strength to the nearest 140fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * supported value. You can use the {@link #getRoundedStrength()} method to query the 141fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * (possibly rounded) value that was actually set. 14217cb280e7f1ac3556eac90ab08263712e0348cb9Eric Laurent * @param strength strength of the effect. The valid range for strength strength is [0, 1000], 143fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * where 0 per mille designates the mildest effect and 1000 per mille designates the strongest. 144fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * @throws IllegalStateException 145fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * @throws IllegalArgumentException 146fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * @throws UnsupportedOperationException 147fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent */ 148fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent public void setStrength(short strength) 149fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 150fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent checkStatus(setParameter(PARAM_STRENGTH, strength)); 151fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent } 152fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent 153fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent /** 154fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * Gets the current strength of the effect. 15517cb280e7f1ac3556eac90ab08263712e0348cb9Eric Laurent * @return the strength of the effect. The valid range for strength is [0, 1000], where 0 per 156fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * mille designates the mildest effect and 1000 per mille the strongest 157fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * @throws IllegalStateException 158fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * @throws IllegalArgumentException 159fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * @throws UnsupportedOperationException 160fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent */ 161fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent public short getRoundedStrength() 162fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 163fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent short[] value = new short[1]; 164fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent checkStatus(getParameter(PARAM_STRENGTH, value)); 165fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent return value[0]; 166fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent } 167fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent 168fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent /** 169d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * Checks if a configuration is supported, and query the virtual speaker angles. 170d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @param inputChannelMask 171d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @param deviceType 172d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @param angles if non-null: array in which the angles will be written. If null, no angles 173d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * are returned 174d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @return true if the combination of channel mask and output device type is supported, false 175d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * otherwise 176d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @throws IllegalStateException 177d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @throws IllegalArgumentException 178d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @throws UnsupportedOperationException 179d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi */ 180d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi private boolean getAnglesInt(int inputChannelMask, int deviceType, int[] angles) 181d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 182d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi // parameter check 183d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi if (inputChannelMask == AudioFormat.CHANNEL_INVALID) { 184d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi throw (new IllegalArgumentException( 185d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi "Virtualizer: illegal CHANNEL_INVALID channel mask")); 186d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi } 187d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi int channelMask = inputChannelMask == AudioFormat.CHANNEL_OUT_DEFAULT ? 188d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi AudioFormat.CHANNEL_OUT_STEREO : inputChannelMask; 189d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi int nbChannels = AudioFormat.channelCountFromOutChannelMask(channelMask); 190d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi if ((angles != null) && (angles.length < (nbChannels * 3))) { 191d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi Log.e(TAG, "Size of array for angles cannot accomodate number of channels in mask (" 192d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi + nbChannels + ")"); 193d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi throw (new IllegalArgumentException( 194d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi "Virtualizer: array for channel / angle pairs is too small: is " + angles.length 195d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi + ", should be " + (nbChannels * 3))); 196d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi } 197d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi 198d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi ByteBuffer paramsConverter = ByteBuffer.allocate(3 /* param + mask + device*/ * 4); 199d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi paramsConverter.order(ByteOrder.nativeOrder()); 200d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi paramsConverter.putInt(PARAM_VIRTUAL_SPEAKER_ANGLES); 201d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi // convert channel mask to internal native representation 202d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi paramsConverter.putInt(AudioFormat.convertChannelOutMaskToNativeMask(channelMask)); 203d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi // convert Java device type to internal representation 204d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi paramsConverter.putInt(AudioDevice.convertDeviceTypeToInternalDevice(deviceType)); 205d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi // allocate an array to store the results 206d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi byte[] result = new byte[nbChannels * 4/*int to byte*/ * 3/*for mask, azimuth, elevation*/]; 207d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi 208d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi // call into the effect framework 209d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi int status = getParameter(paramsConverter.array(), result); 210d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi if (DEBUG) { 211d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi Log.v(TAG, "getAngles(0x" + Integer.toHexString(inputChannelMask) + ", 0x" 212d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi + Integer.toHexString(deviceType) + ") returns " + status); 213d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi } 214d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi 215d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi if (status >= 0) { 216d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi if (angles != null) { 217d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi // convert and copy the results 218d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi ByteBuffer resultConverter = ByteBuffer.wrap(result); 219d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi resultConverter.order(ByteOrder.nativeOrder()); 220d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi for (int i = 0 ; i < nbChannels ; i++) { 221d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi // write the channel mask 222d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi angles[3 * i] = AudioFormat.convertNativeChannelMaskToOutMask( 223d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi resultConverter.getInt((i * 4 * 3))); 224d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi // write the azimuth 225d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi angles[3 * i + 1] = resultConverter.getInt(i * 4 * 3 + 4); 226d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi // write the elevation 227d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi angles[3 * i + 2] = resultConverter.getInt(i * 4 * 3 + 8); 228d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi if (DEBUG) { 229d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi Log.v(TAG, "channel 0x" + Integer.toHexString(angles[3*i]).toUpperCase() 230d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi + " at az=" + angles[3*i+1] + "deg" 231d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi + " elev=" + angles[3*i+2] + "deg"); 232d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi } 233d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi } 234d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi } 235d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi return true; 236d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi } else if (status == AudioEffect.ERROR_BAD_VALUE) { 237d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi // a BAD_VALUE return from getParameter indicates the configuration is not supported 238d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi // don't throw an exception, just return false 239d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi return false; 240d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi } else { 241d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi // something wrong may have happened 242d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi checkStatus(status); 243d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi } 244d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi // unexpected virtualizer behavior 245d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi Log.e(TAG, "unexpected status code " + status 246d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi + " after getParameter(PARAM_VIRTUAL_SPEAKER_ANGLES)"); 247d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi return false; 248d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi } 249d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi 250d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi /** 251d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @hide 252d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * CANDIDATE FOR PUBLIC API 253d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * Checks if the combination of a channel mask and device type is supported by this virtualizer. 254d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * Some virtualizer implementations may only support binaural processing (i.e. only support 255d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * headphone output), some may support transaural processing (i.e. for speaker output) for the 256d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * built-in speakers. Use this method to query the virtualizer implementation capabilities. 257d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @param inputChannelMask the channel mask of the content to virtualize. 258d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @param deviceType the device type for which virtualization processing is to be performed. 259d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * Valid values are the device types defined in {@link AudioDevice}. 260d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @return true if the combination of channel mask and output device type is supported, false 261d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * otherwise. 262d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * <br>An indication that a certain channel mask is not supported doesn't necessarily mean 263d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * you cannot play content with that channel mask, it more likely implies the content will 264d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * be downmixed before being virtualized. For instance a virtualizer that only supports a 265d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * mask such as {@link AudioFormat#CHANNEL_OUT_STEREO} 266d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * will still be able to process content with a mask of 267d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * {@link AudioFormat#CHANNEL_OUT_5POINT1}, but will downmix the content to stereo first, and 268d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * then will virtualize, as opposed to virtualizing each channel individually. 269d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @throws IllegalStateException 270d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @throws IllegalArgumentException 271d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @throws UnsupportedOperationException 272d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi */ 273d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi public boolean canVirtualize(int inputChannelMask, int deviceType) 274d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 275d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi return getAnglesInt(inputChannelMask, deviceType, null); 276d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi } 277d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi 278d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi /** 279d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @hide 280d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * CANDIDATE FOR PUBLIC API 281d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * Queries the virtual speaker angles (azimuth and elevation) for a combination of a channel 282d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * mask and device type. 283d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * If the virtualization configuration (mask and device) is supported (see 284d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * {@link #canVirtualize(int, int)}, the array angles will contain upon return the 285d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * definition of each virtual speaker and its azimuth and elevation angles relative to the 286d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * listener. 287d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * <br>Note that in some virtualizer implementations, the angles may be strength-dependent. 288d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @param inputChannelMask the channel mask of the content to virtualize. 289d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @param deviceType the device type for which virtualization processing is to be performed. 290d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * Valid values are the device types defined in {@link AudioDevice}. 291d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @param angles a non-null array whose length is 3 times the number of channels in the channel 292d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * mask. 293d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * If the method indicates the configuration is supported, the array will contain upon return 294d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * triplets of values: for each channel <code>i</code> among the channels of the mask: 295d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * <ul> 296d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * <li>the element at index <code>3*i</code> in the array contains the speaker 297d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * identification (e.g. {@link AudioFormat#CHANNEL_OUT_FRONT_LEFT}),</li> 298d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * <li>the element at index <code>3*i+1</code> contains its corresponding azimuth angle 299d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * expressed in degrees, where 0 is the direction the listener faces, 180 is behind 300d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * the listener, and -90 is to her/his left,</li> 301d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * <li>the element at index <code>3*i+2</code> contains its corresponding elevation angle 302d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * where +90 is directly above the listener, 0 is the horizontal plane, and -90 is 303d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * directly below the listener.</li> 304d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @return true if the combination of channel mask and output device type is supported, false 305d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * otherwise. 306d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @throws IllegalStateException 307d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @throws IllegalArgumentException 308d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @throws UnsupportedOperationException 309d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi */ 310d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi public boolean getSpeakerAngles(int inputChannelMask, int deviceType, int[] angles) 311d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 312d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi if (angles == null) { 313d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi throw (new IllegalArgumentException( 314d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi "Virtualizer: illegal null channel / angle array")); 315d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi } 316d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi 317d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi return getAnglesInt(inputChannelMask, deviceType, angles); 318d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi } 319d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi 320d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi /** 321d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @hide 322d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * CANDIDATE FOR PUBLIC API 323d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * Forces the virtualizer effect to use the processing mode used for the given device type. 324d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * The effect must be enabled for the forced mode to be applied. 325d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @param deviceType one of the device types defined in {@link AudioDevice}. 326d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * Use {@link AudioDevice#DEVICE_TYPE_UNKNOWN} to return to the non-forced mode. 327d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @return true if the processing mode for the device type is supported, and it is successfully 328d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * set, or forcing was successfully disabled with {@link AudioDevice#DEVICE_TYPE_UNKNOWN}, 329d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * false otherwise. 330d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @throws IllegalStateException 331d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @throws IllegalArgumentException 332d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @throws UnsupportedOperationException 333d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi */ 334d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi public boolean forceVirtualizationMode(int deviceType) 335d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 336d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi // convert Java device type to internal representation 337d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi int internalDevice = AudioDevice.convertDeviceTypeToInternalDevice(deviceType); 338d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi 339d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi int status = setParameter(PARAM_FORCE_VIRTUALIZATION_MODE, internalDevice); 340d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi 341d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi if (status >= 0) { 342d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi return true; 343d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi } else if (status == AudioEffect.ERROR_BAD_VALUE) { 344d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi // a BAD_VALUE return from setParameter indicates the mode can't be forced to that 345d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi // of this device, don't throw an exception, just return false 346d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi return false; 347d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi } else { 348d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi // something wrong may have happened 349d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi checkStatus(status); 350d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi } 351d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi // unexpected virtualizer behavior 352d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi Log.e(TAG, "unexpected status code " + status 353d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi + " after setParameter(PARAM_FORCE_VIRTUALIZATION_MODE)"); 354d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi return false; 355d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi } 356d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi 357d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi /** 358d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @hide 359d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * CANDIDATE FOR PUBLIC API 360d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * Return the device type which reflects the virtualization mode being used, if any. 361d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @return a device type (as defined in {@link AudioDevice}) which reflects the virtualization 362d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * mode being used. 363d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * If virtualization is not active, the device type will be 364d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * {@link AudioDevice#DEVICE_TYPE_UNKNOWN}. Virtualization may not be active either because 365d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * the effect is not enabled or because the current output device is not compatible with 366d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * this virtualization implementation. 367d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi */ 368d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi public int getVirtualizationMode() { 369d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi int[] value = new int[1]; 370d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi int status = getParameter(PARAM_VIRTUALIZATION_MODE, value); 371d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi if (status >= 0) { 372d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi return AudioDevice.convertInternalDeviceToDeviceType(value[0]); 373d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi } else if (status == AudioEffect.ERROR_BAD_VALUE) { 374d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi return AudioDevice.DEVICE_TYPE_UNKNOWN; 375d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi } else { 376d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi // something wrong may have happened 377d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi checkStatus(status); 378d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi } 379d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi // unexpected virtualizer behavior 380d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi Log.e(TAG, "unexpected status code " + status 381d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi + " after getParameter(PARAM_VIRTUALIZATION_MODE)"); 382d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi return AudioDevice.DEVICE_TYPE_UNKNOWN; 383d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi } 384d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi 385d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi /** 386fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * The OnParameterChangeListener interface defines a method called by the Virtualizer when a 387fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * parameter value has changed. 388fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent */ 389fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent public interface OnParameterChangeListener { 390fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent /** 391fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * Method called when a parameter value has changed. The method is called only if the 392fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * parameter was changed by another application having the control of the same 393fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * Virtualizer engine. 394fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * @param effect the Virtualizer on which the interface is registered. 395fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * @param status status of the set parameter operation. 396fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * @param param ID of the modified parameter. See {@link #PARAM_STRENGTH} ... 397fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * @param value the new parameter value. 398fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent */ 399fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent void onParameterChange(Virtualizer effect, int status, int param, short value); 400fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent } 401fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent 402fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent /** 403fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * Listener used internally to receive unformatted parameter change events from AudioEffect 404fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * super class. 405fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent */ 406fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent private class BaseParameterListener implements AudioEffect.OnParameterChangeListener { 407fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent private BaseParameterListener() { 408fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent 409fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent } 410fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent public void onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value) { 411fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent OnParameterChangeListener l = null; 412fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent 413fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent synchronized (mParamListenerLock) { 414fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent if (mParamListener != null) { 415fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent l = mParamListener; 416fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent } 417fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent } 418fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent if (l != null) { 419fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent int p = -1; 420fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent short v = -1; 421fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent 422fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent if (param.length == 4) { 423fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent p = byteArrayToInt(param, 0); 424fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent } 425fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent if (value.length == 2) { 426fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent v = byteArrayToShort(value, 0); 427fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent } 428fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent if (p != -1 && v != -1) { 429fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent l.onParameterChange(Virtualizer.this, status, p, v); 430fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent } 431fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent } 432fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent } 433fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent } 434fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent 435fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent /** 436fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * Registers an OnParameterChangeListener interface. 437fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * @param listener OnParameterChangeListener interface registered 438fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent */ 439fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent public void setParameterListener(OnParameterChangeListener listener) { 440fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent synchronized (mParamListenerLock) { 441fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent if (mParamListener == null) { 442fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent mParamListener = listener; 443fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent mBaseParamListener = new BaseParameterListener(); 444fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent super.setParameterListener(mBaseParamListener); 445fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent } 446fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent } 447fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent } 448ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent 449ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent /** 450ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent * The Settings class regroups all virtualizer parameters. It is used in 451ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent * conjuntion with getProperties() and setProperties() methods to backup and restore 452ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent * all parameters in a single call. 453ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent */ 454ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent public static class Settings { 455ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent public short strength; 456ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent 457ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent public Settings() { 458ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent } 459ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent 460ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent /** 461ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent * Settings class constructor from a key=value; pairs formatted string. The string is 462ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent * typically returned by Settings.toString() method. 463ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent * @throws IllegalArgumentException if the string is not correctly formatted. 464ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent */ 465ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent public Settings(String settings) { 466ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent StringTokenizer st = new StringTokenizer(settings, "=;"); 467ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent int tokens = st.countTokens(); 468ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent if (st.countTokens() != 3) { 469ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent throw new IllegalArgumentException("settings: " + settings); 470ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent } 471ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent String key = st.nextToken(); 472ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent if (!key.equals("Virtualizer")) { 473ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent throw new IllegalArgumentException( 474ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent "invalid settings for Virtualizer: " + key); 475ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent } 476ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent try { 477ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent key = st.nextToken(); 478ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent if (!key.equals("strength")) { 479ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent throw new IllegalArgumentException("invalid key name: " + key); 480ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent } 481ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent strength = Short.parseShort(st.nextToken()); 482ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent } catch (NumberFormatException nfe) { 483ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent throw new IllegalArgumentException("invalid value for key: " + key); 484ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent } 485ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent } 486ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent 487ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent @Override 488ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent public String toString() { 489ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent String str = new String ( 490ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent "Virtualizer"+ 491ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent ";strength="+Short.toString(strength) 492ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent ); 493ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent return str; 494ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent } 495ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent }; 496ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent 497ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent 498ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent /** 499ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent * Gets the virtualizer properties. This method is useful when a snapshot of current 500ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent * virtualizer settings must be saved by the application. 501ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent * @return a Virtualizer.Settings object containing all current parameters values 502ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent * @throws IllegalStateException 503ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent * @throws IllegalArgumentException 504ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent * @throws UnsupportedOperationException 505ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent */ 506ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent public Virtualizer.Settings getProperties() 507ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 508ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent Settings settings = new Settings(); 509ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent short[] value = new short[1]; 510ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent checkStatus(getParameter(PARAM_STRENGTH, value)); 511ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent settings.strength = value[0]; 512ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent return settings; 513ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent } 514ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent 515ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent /** 516ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent * Sets the virtualizer properties. This method is useful when virtualizer settings have to 517ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent * be applied from a previous backup. 51817cb280e7f1ac3556eac90ab08263712e0348cb9Eric Laurent * @param settings a Virtualizer.Settings object containing the properties to apply 519ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent * @throws IllegalStateException 520ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent * @throws IllegalArgumentException 521ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent * @throws UnsupportedOperationException 522ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent */ 523ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent public void setProperties(Virtualizer.Settings settings) 524ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 525ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent checkStatus(setParameter(PARAM_STRENGTH, settings.strength)); 526ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent } 527fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent} 528