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 19b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Triviimport android.annotation.IntDef; 20a33be211e768746745a0deeba71f8c6b65e72442Paul McLeanimport android.media.AudioDeviceInfo; 21d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Triviimport android.media.AudioFormat; 221a5149e5d7f2dddc8b324f7695e69fd89af73c52Eric Laurentimport android.media.audiofx.AudioEffect; 23fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurentimport android.util.Log; 24ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent 25b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Triviimport java.lang.annotation.Retention; 26b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Triviimport java.lang.annotation.RetentionPolicy; 27d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Triviimport java.nio.ByteBuffer; 28d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Triviimport java.nio.ByteOrder; 29ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurentimport java.util.StringTokenizer; 30fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent 31fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent 32fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent/** 33fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * An audio virtualizer is a general name for an effect to spatialize audio channels. The exact 34fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * behavior of this effect is dependent on the number of audio input channels and the types and 35fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * number of audio output channels of the device. For example, in the case of a stereo input and 36fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * stereo headphone output, a stereo widening effect is used when this effect is turned on. 37fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * <p>An application creates a Virtualizer object to instantiate and control a virtualizer engine 38fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * in the audio framework. 39fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * <p>The methods, parameter types and units exposed by the Virtualizer implementation are directly 40fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * mapping those defined by the OpenSL ES 1.0.1 Specification (http://www.khronos.org/opensles/) 41fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * for the SLVirtualizerItf interface. Please refer to this specification for more details. 42fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * <p>To attach the Virtualizer to a particular AudioTrack or MediaPlayer, specify the audio session 4362f3617f2f4016ad2f59635d5156d64872989880Eric Laurent * ID of this AudioTrack or MediaPlayer when constructing the Virtualizer. 4462f3617f2f4016ad2f59635d5156d64872989880Eric Laurent * <p>NOTE: attaching a Virtualizer to the global audio output mix by use of session 0 is 4562f3617f2f4016ad2f59635d5156d64872989880Eric Laurent * deprecated. 461a5149e5d7f2dddc8b324f7695e69fd89af73c52Eric Laurent * <p>See {@link android.media.MediaPlayer#getAudioSessionId()} for details on audio sessions. 471a5149e5d7f2dddc8b324f7695e69fd89af73c52Eric Laurent * <p>See {@link android.media.audiofx.AudioEffect} class for more details on controlling 481a5149e5d7f2dddc8b324f7695e69fd89af73c52Eric Laurent * audio effects. 49fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent */ 50fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent 51fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurentpublic class Virtualizer extends AudioEffect { 52fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent 53fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent private final static String TAG = "Virtualizer"; 54d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi private final static boolean DEBUG = false; 55fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent 56d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi // These constants must be synchronized with those in 57d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi // system/media/audio_effects/include/audio_effects/effect_virtualizer.h 58fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent /** 59fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * Is strength parameter supported by virtualizer engine. Parameter ID for getParameter(). 60fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent */ 61fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent public static final int PARAM_STRENGTH_SUPPORTED = 0; 62fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent /** 63fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * Virtualizer effect strength. Parameter ID for 641a5149e5d7f2dddc8b324f7695e69fd89af73c52Eric Laurent * {@link android.media.audiofx.Virtualizer.OnParameterChangeListener} 65fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent */ 66fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent public static final int PARAM_STRENGTH = 1; 67d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi /** 68d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @hide 69d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * Parameter ID to query the virtual speaker angles for a channel mask / device configuration. 70d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi */ 71d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi public static final int PARAM_VIRTUAL_SPEAKER_ANGLES = 2; 72d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi /** 73d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @hide 74d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * Parameter ID to force the virtualization mode to be that of a specific device 75d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi */ 76d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi public static final int PARAM_FORCE_VIRTUALIZATION_MODE = 3; 77d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi /** 78d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @hide 79d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * Parameter ID to query the current virtualization mode. 80d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi */ 81d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi public static final int PARAM_VIRTUALIZATION_MODE = 4; 82fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent 83fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent /** 84fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * Indicates if strength parameter is supported by the virtualizer engine 85fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent */ 86fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent private boolean mStrengthSupported = false; 87fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent 88fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent /** 89fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * Registered listener for parameter changes. 90fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent */ 91fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent private OnParameterChangeListener mParamListener = null; 92fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent 93fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent /** 94fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * Listener used internally to to receive raw parameter change event from AudioEffect super class 95fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent */ 96fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent private BaseParameterListener mBaseParamListener = null; 97fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent 98fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent /** 99fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * Lock for access to mParamListener 100fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent */ 101fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent private final Object mParamListenerLock = new Object(); 102fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent 103fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent /** 104fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * Class constructor. 105fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * @param priority the priority level requested by the application for controlling the Virtualizer 106fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * engine. As the same engine can be shared by several applications, this parameter indicates 107fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * how much the requesting application needs control of effect parameters. The normal priority 108fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * is 0, above normal is a positive number, below normal a negative number. 10962f3617f2f4016ad2f59635d5156d64872989880Eric Laurent * @param audioSession system wide unique audio session identifier. The Virtualizer will 11062f3617f2f4016ad2f59635d5156d64872989880Eric Laurent * be attached to the MediaPlayer or AudioTrack in the same audio session. 111fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * 112fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * @throws java.lang.IllegalStateException 113fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * @throws java.lang.IllegalArgumentException 114fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * @throws java.lang.UnsupportedOperationException 115fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * @throws java.lang.RuntimeException 116fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent */ 117fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent public Virtualizer(int priority, int audioSession) 118fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent throws IllegalStateException, IllegalArgumentException, 119fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent UnsupportedOperationException, RuntimeException { 120fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent super(EFFECT_TYPE_VIRTUALIZER, EFFECT_TYPE_NULL, priority, audioSession); 121fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent 12262f3617f2f4016ad2f59635d5156d64872989880Eric Laurent if (audioSession == 0) { 12362f3617f2f4016ad2f59635d5156d64872989880Eric Laurent Log.w(TAG, "WARNING: attaching a Virtualizer to global output mix is deprecated!"); 12462f3617f2f4016ad2f59635d5156d64872989880Eric Laurent } 12562f3617f2f4016ad2f59635d5156d64872989880Eric Laurent 126ba8da2e61b1d9ebb7a4758f1f7849ff8440bd20cEric Laurent int[] value = new int[1]; 127fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent checkStatus(getParameter(PARAM_STRENGTH_SUPPORTED, value)); 128fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent mStrengthSupported = (value[0] != 0); 129fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent } 130fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent 131fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent /** 132fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * Indicates whether setting strength is supported. If this method returns false, only one 133fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * strength is supported and the setStrength() method always rounds to that value. 134fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * @return true is strength parameter is supported, false otherwise 135fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent */ 136fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent public boolean getStrengthSupported() { 137fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent return mStrengthSupported; 138fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent } 139fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent 140fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent /** 141fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * Sets the strength of the virtualizer effect. If the implementation does not support per mille 142fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * accuracy for setting the strength, it is allowed to round the given strength to the nearest 143fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * supported value. You can use the {@link #getRoundedStrength()} method to query the 144fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * (possibly rounded) value that was actually set. 14517cb280e7f1ac3556eac90ab08263712e0348cb9Eric Laurent * @param strength strength of the effect. The valid range for strength strength is [0, 1000], 146fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * where 0 per mille designates the mildest effect and 1000 per mille designates the strongest. 147fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * @throws IllegalStateException 148fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * @throws IllegalArgumentException 149fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * @throws UnsupportedOperationException 150fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent */ 151fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent public void setStrength(short strength) 152fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 153fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent checkStatus(setParameter(PARAM_STRENGTH, strength)); 154fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent } 155fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent 156fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent /** 157fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * Gets the current strength of the effect. 15817cb280e7f1ac3556eac90ab08263712e0348cb9Eric Laurent * @return the strength of the effect. The valid range for strength is [0, 1000], where 0 per 159fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * mille designates the mildest effect and 1000 per mille the strongest 160fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * @throws IllegalStateException 161fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * @throws IllegalArgumentException 162fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * @throws UnsupportedOperationException 163fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent */ 164fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent public short getRoundedStrength() 165fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 166fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent short[] value = new short[1]; 167fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent checkStatus(getParameter(PARAM_STRENGTH, value)); 168fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent return value[0]; 169fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent } 170fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent 171fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent /** 172d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * Checks if a configuration is supported, and query the virtual speaker angles. 173d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @param inputChannelMask 174d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @param deviceType 175d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @param angles if non-null: array in which the angles will be written. If null, no angles 176d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * are returned 177d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @return true if the combination of channel mask and output device type is supported, false 178d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * otherwise 179d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @throws IllegalStateException 180d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @throws IllegalArgumentException 181d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @throws UnsupportedOperationException 182d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi */ 183d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi private boolean getAnglesInt(int inputChannelMask, int deviceType, int[] angles) 184d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 185d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi // parameter check 186d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi if (inputChannelMask == AudioFormat.CHANNEL_INVALID) { 187d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi throw (new IllegalArgumentException( 188d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi "Virtualizer: illegal CHANNEL_INVALID channel mask")); 189d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi } 190d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi int channelMask = inputChannelMask == AudioFormat.CHANNEL_OUT_DEFAULT ? 191d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi AudioFormat.CHANNEL_OUT_STEREO : inputChannelMask; 192d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi int nbChannels = AudioFormat.channelCountFromOutChannelMask(channelMask); 193d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi if ((angles != null) && (angles.length < (nbChannels * 3))) { 194d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi Log.e(TAG, "Size of array for angles cannot accomodate number of channels in mask (" 195d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi + nbChannels + ")"); 196d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi throw (new IllegalArgumentException( 197d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi "Virtualizer: array for channel / angle pairs is too small: is " + angles.length 198d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi + ", should be " + (nbChannels * 3))); 199d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi } 200d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi 201d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi ByteBuffer paramsConverter = ByteBuffer.allocate(3 /* param + mask + device*/ * 4); 202d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi paramsConverter.order(ByteOrder.nativeOrder()); 203d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi paramsConverter.putInt(PARAM_VIRTUAL_SPEAKER_ANGLES); 204d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi // convert channel mask to internal native representation 205d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi paramsConverter.putInt(AudioFormat.convertChannelOutMaskToNativeMask(channelMask)); 206d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi // convert Java device type to internal representation 207a33be211e768746745a0deeba71f8c6b65e72442Paul McLean paramsConverter.putInt(AudioDeviceInfo.convertDeviceTypeToInternalDevice(deviceType)); 208d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi // allocate an array to store the results 209d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi byte[] result = new byte[nbChannels * 4/*int to byte*/ * 3/*for mask, azimuth, elevation*/]; 210d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi 211d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi // call into the effect framework 212d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi int status = getParameter(paramsConverter.array(), result); 213d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi if (DEBUG) { 214d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi Log.v(TAG, "getAngles(0x" + Integer.toHexString(inputChannelMask) + ", 0x" 215d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi + Integer.toHexString(deviceType) + ") returns " + status); 216d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi } 217d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi 218d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi if (status >= 0) { 219d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi if (angles != null) { 220d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi // convert and copy the results 221d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi ByteBuffer resultConverter = ByteBuffer.wrap(result); 222d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi resultConverter.order(ByteOrder.nativeOrder()); 223d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi for (int i = 0 ; i < nbChannels ; i++) { 224d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi // write the channel mask 225d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi angles[3 * i] = AudioFormat.convertNativeChannelMaskToOutMask( 226d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi resultConverter.getInt((i * 4 * 3))); 227d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi // write the azimuth 228d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi angles[3 * i + 1] = resultConverter.getInt(i * 4 * 3 + 4); 229d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi // write the elevation 230d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi angles[3 * i + 2] = resultConverter.getInt(i * 4 * 3 + 8); 231d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi if (DEBUG) { 232d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi Log.v(TAG, "channel 0x" + Integer.toHexString(angles[3*i]).toUpperCase() 233d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi + " at az=" + angles[3*i+1] + "deg" 234d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi + " elev=" + angles[3*i+2] + "deg"); 235d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi } 236d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi } 237d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi } 238d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi return true; 239d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi } else if (status == AudioEffect.ERROR_BAD_VALUE) { 240d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi // a BAD_VALUE return from getParameter indicates the configuration is not supported 241d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi // don't throw an exception, just return false 242d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi return false; 243d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi } else { 244d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi // something wrong may have happened 245d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi checkStatus(status); 246d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi } 247d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi // unexpected virtualizer behavior 248d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi Log.e(TAG, "unexpected status code " + status 249d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi + " after getParameter(PARAM_VIRTUAL_SPEAKER_ANGLES)"); 250d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi return false; 251d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi } 252d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi 253d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi /** 254b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi * A virtualization mode indicating virtualization processing is not active. 255b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi * See {@link #getVirtualizationMode()} as one of the possible return value. 256b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi */ 257b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi public static final int VIRTUALIZATION_MODE_OFF = 0; 258b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi 259b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi /** 260b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi * A virtualization mode used to indicate the virtualizer effect must stop forcing the 261b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi * processing to a particular mode in {@link #forceVirtualizationMode(int)}. 262b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi */ 263b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi public static final int VIRTUALIZATION_MODE_AUTO = 1; 264b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi /** 265b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi * A virtualization mode typically used over headphones. 266b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi * Binaural virtualization describes an audio processing configuration for virtualization 267b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi * where the left and right channels are respectively reaching the left and right ear of the 268b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi * user, without also feeding the opposite ear (as is the case when listening over speakers). 269b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi * <p>Such a mode is therefore meant to be used when audio is playing over stereo wired 270b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi * headphones or headsets, but also stereo headphones through a wireless A2DP Bluetooth link. 271b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi * <p>See {@link #canVirtualize(int, int)} to verify this mode is supported by this Virtualizer. 272b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi */ 273b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi public final static int VIRTUALIZATION_MODE_BINAURAL = 2; 274b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi 275b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi /** 276b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi * A virtualization mode typically used over speakers. 277b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi * Transaural virtualization describes an audio processing configuration that differs from 278b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi * binaural (as described in {@link #VIRTUALIZATION_MODE_BINAURAL} in that cross-talk is 279b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi * present, i.e. audio played from the left channel also reaches the right ear of the user, 280b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi * and vice-versa. 281b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi * <p>When supported, such a mode is therefore meant to be used when audio is playing over the 282b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi * built-in stereo speakers of a device, if they are featured. 283b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi * <p>See {@link #canVirtualize(int, int)} to verify this mode is supported by this Virtualizer. 284b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi */ 285b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi public final static int VIRTUALIZATION_MODE_TRANSAURAL = 3; 286b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi 287b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi /** @hide */ 288b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi @IntDef( { 289b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi VIRTUALIZATION_MODE_BINAURAL, 290b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi VIRTUALIZATION_MODE_TRANSAURAL 291b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi }) 292b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi @Retention(RetentionPolicy.SOURCE) 293b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi public @interface VirtualizationMode {} 294b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi 295b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi /** @hide */ 296b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi @IntDef( { 297b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi VIRTUALIZATION_MODE_AUTO, 298b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi VIRTUALIZATION_MODE_BINAURAL, 299b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi VIRTUALIZATION_MODE_TRANSAURAL 300b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi }) 301b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi @Retention(RetentionPolicy.SOURCE) 302b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi public @interface ForceVirtualizationMode {} 303b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi 304b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi private static int getDeviceForModeQuery(@VirtualizationMode int virtualizationMode) 305b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi throws IllegalArgumentException { 306b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi switch (virtualizationMode) { 307b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi case VIRTUALIZATION_MODE_BINAURAL: 308a33be211e768746745a0deeba71f8c6b65e72442Paul McLean return AudioDeviceInfo.TYPE_WIRED_HEADPHONES; 309b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi case VIRTUALIZATION_MODE_TRANSAURAL: 310a33be211e768746745a0deeba71f8c6b65e72442Paul McLean return AudioDeviceInfo.TYPE_BUILTIN_SPEAKER; 311b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi default: 312b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi throw (new IllegalArgumentException( 313b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi "Virtualizer: illegal virtualization mode " + virtualizationMode)); 314b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi } 315b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi } 316b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi 317b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi private static int getDeviceForModeForce(@ForceVirtualizationMode int virtualizationMode) 318b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi throws IllegalArgumentException { 319b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi if (virtualizationMode == VIRTUALIZATION_MODE_AUTO) { 320a33be211e768746745a0deeba71f8c6b65e72442Paul McLean return AudioDeviceInfo.TYPE_UNKNOWN; 321b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi } else { 322b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi return getDeviceForModeQuery(virtualizationMode); 323b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi } 324b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi } 325b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi 326b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi private static int deviceToMode(int deviceType) { 327b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi switch (deviceType) { 328a33be211e768746745a0deeba71f8c6b65e72442Paul McLean case AudioDeviceInfo.TYPE_WIRED_HEADSET: 329a33be211e768746745a0deeba71f8c6b65e72442Paul McLean case AudioDeviceInfo.TYPE_WIRED_HEADPHONES: 330a33be211e768746745a0deeba71f8c6b65e72442Paul McLean case AudioDeviceInfo.TYPE_BLUETOOTH_SCO: 331a33be211e768746745a0deeba71f8c6b65e72442Paul McLean case AudioDeviceInfo.TYPE_BUILTIN_EARPIECE: 332b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi return VIRTUALIZATION_MODE_BINAURAL; 333a33be211e768746745a0deeba71f8c6b65e72442Paul McLean case AudioDeviceInfo.TYPE_BUILTIN_SPEAKER: 334a33be211e768746745a0deeba71f8c6b65e72442Paul McLean case AudioDeviceInfo.TYPE_LINE_ANALOG: 335a33be211e768746745a0deeba71f8c6b65e72442Paul McLean case AudioDeviceInfo.TYPE_LINE_DIGITAL: 336a33be211e768746745a0deeba71f8c6b65e72442Paul McLean case AudioDeviceInfo.TYPE_BLUETOOTH_A2DP: 337a33be211e768746745a0deeba71f8c6b65e72442Paul McLean case AudioDeviceInfo.TYPE_HDMI: 338a33be211e768746745a0deeba71f8c6b65e72442Paul McLean case AudioDeviceInfo.TYPE_HDMI_ARC: 339a33be211e768746745a0deeba71f8c6b65e72442Paul McLean case AudioDeviceInfo.TYPE_USB_DEVICE: 340a33be211e768746745a0deeba71f8c6b65e72442Paul McLean case AudioDeviceInfo.TYPE_USB_ACCESSORY: 341a33be211e768746745a0deeba71f8c6b65e72442Paul McLean case AudioDeviceInfo.TYPE_DOCK: 342a33be211e768746745a0deeba71f8c6b65e72442Paul McLean case AudioDeviceInfo.TYPE_FM: 343a33be211e768746745a0deeba71f8c6b65e72442Paul McLean case AudioDeviceInfo.TYPE_AUX_LINE: 344b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi return VIRTUALIZATION_MODE_TRANSAURAL; 345a33be211e768746745a0deeba71f8c6b65e72442Paul McLean case AudioDeviceInfo.TYPE_UNKNOWN: 346b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi default: 347b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi return VIRTUALIZATION_MODE_OFF; 348b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi } 349b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi } 350b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi 351b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi /** 352b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi * Checks if the combination of a channel mask and virtualization mode is supported by this 353b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi * virtualizer. 354d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * Some virtualizer implementations may only support binaural processing (i.e. only support 355b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi * headphone output, see {@link #VIRTUALIZATION_MODE_BINAURAL}), some may support transaural 356b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi * processing (i.e. for speaker output, see {@link #VIRTUALIZATION_MODE_TRANSAURAL}) for the 357d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * built-in speakers. Use this method to query the virtualizer implementation capabilities. 358d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @param inputChannelMask the channel mask of the content to virtualize. 359b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi * @param virtualizationMode the mode for which virtualization processing is to be performed, 360b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi * one of {@link #VIRTUALIZATION_MODE_BINAURAL}, {@link #VIRTUALIZATION_MODE_TRANSAURAL}. 361b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi * @return true if the combination of channel mask and virtualization mode is supported, false 362d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * otherwise. 363d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * <br>An indication that a certain channel mask is not supported doesn't necessarily mean 364d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * you cannot play content with that channel mask, it more likely implies the content will 365d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * be downmixed before being virtualized. For instance a virtualizer that only supports a 366d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * mask such as {@link AudioFormat#CHANNEL_OUT_STEREO} 367d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * will still be able to process content with a mask of 368d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * {@link AudioFormat#CHANNEL_OUT_5POINT1}, but will downmix the content to stereo first, and 369d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * then will virtualize, as opposed to virtualizing each channel individually. 370d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @throws IllegalStateException 371d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @throws IllegalArgumentException 372d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @throws UnsupportedOperationException 373d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi */ 374b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi public boolean canVirtualize(int inputChannelMask, @VirtualizationMode int virtualizationMode) 375d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 376b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi return getAnglesInt(inputChannelMask, getDeviceForModeQuery(virtualizationMode), null); 377d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi } 378d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi 379d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi /** 380d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * Queries the virtual speaker angles (azimuth and elevation) for a combination of a channel 381b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi * mask and virtualization mode. 382b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi * If the virtualization configuration (mask and mode) is supported (see 383d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * {@link #canVirtualize(int, int)}, the array angles will contain upon return the 384d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * definition of each virtual speaker and its azimuth and elevation angles relative to the 385d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * listener. 386d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * <br>Note that in some virtualizer implementations, the angles may be strength-dependent. 387d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @param inputChannelMask the channel mask of the content to virtualize. 388b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi * @param virtualizationMode the mode for which virtualization processing is to be performed, 389b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi * one of {@link #VIRTUALIZATION_MODE_BINAURAL}, {@link #VIRTUALIZATION_MODE_TRANSAURAL}. 390d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @param angles a non-null array whose length is 3 times the number of channels in the channel 391d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * mask. 392d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * If the method indicates the configuration is supported, the array will contain upon return 393d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * triplets of values: for each channel <code>i</code> among the channels of the mask: 394d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * <ul> 395d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * <li>the element at index <code>3*i</code> in the array contains the speaker 396d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * identification (e.g. {@link AudioFormat#CHANNEL_OUT_FRONT_LEFT}),</li> 397d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * <li>the element at index <code>3*i+1</code> contains its corresponding azimuth angle 398d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * expressed in degrees, where 0 is the direction the listener faces, 180 is behind 399d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * the listener, and -90 is to her/his left,</li> 400d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * <li>the element at index <code>3*i+2</code> contains its corresponding elevation angle 401d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * where +90 is directly above the listener, 0 is the horizontal plane, and -90 is 402d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * directly below the listener.</li> 403b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi * @return true if the combination of channel mask and virtualization mode is supported, false 404d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * otherwise. 405d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @throws IllegalStateException 406d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @throws IllegalArgumentException 407d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @throws UnsupportedOperationException 408d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi */ 409b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi public boolean getSpeakerAngles(int inputChannelMask, 410b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi @VirtualizationMode int virtualizationMode, int[] angles) 411d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 412d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi if (angles == null) { 413d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi throw (new IllegalArgumentException( 414d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi "Virtualizer: illegal null channel / angle array")); 415d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi } 416d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi 417b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi return getAnglesInt(inputChannelMask, getDeviceForModeQuery(virtualizationMode), angles); 418d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi } 419d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi 420d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi /** 421b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi * Forces the virtualizer effect to use the given processing mode. 422d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * The effect must be enabled for the forced mode to be applied. 423b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi * @param virtualizationMode one of {@link #VIRTUALIZATION_MODE_BINAURAL}, 424b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi * {@link #VIRTUALIZATION_MODE_TRANSAURAL} to force a particular processing mode, or 425b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi * {@value #VIRTUALIZATION_MODE_AUTO} to stop forcing a mode. 426b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi * @return true if the processing mode is supported, and it is successfully set, or 427b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi * forcing was successfully disabled, false otherwise. 428d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @throws IllegalStateException 429d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @throws IllegalArgumentException 430d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi * @throws UnsupportedOperationException 431d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi */ 432b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi public boolean forceVirtualizationMode(@ForceVirtualizationMode int virtualizationMode) 433d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 434d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi // convert Java device type to internal representation 435b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi int deviceType = getDeviceForModeForce(virtualizationMode); 436a33be211e768746745a0deeba71f8c6b65e72442Paul McLean int internalDevice = AudioDeviceInfo.convertDeviceTypeToInternalDevice(deviceType); 437d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi 438d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi int status = setParameter(PARAM_FORCE_VIRTUALIZATION_MODE, internalDevice); 439d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi 440d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi if (status >= 0) { 441d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi return true; 442d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi } else if (status == AudioEffect.ERROR_BAD_VALUE) { 443b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi // a BAD_VALUE return from setParameter indicates the mode can't be forced 444b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi // don't throw an exception, just return false 445d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi return false; 446d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi } else { 447d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi // something wrong may have happened 448d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi checkStatus(status); 449d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi } 450d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi // unexpected virtualizer behavior 451d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi Log.e(TAG, "unexpected status code " + status 452d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi + " after setParameter(PARAM_FORCE_VIRTUALIZATION_MODE)"); 453d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi return false; 454d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi } 455d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi 456d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi /** 457b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi * Return the virtualization mode being used, if any. 458b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi * @return the virtualization mode being used. 459b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi * If virtualization is not active, the virtualization mode will be 460b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi * {@link #VIRTUALIZATION_MODE_OFF}. Otherwise the value will be 461b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi * {@link #VIRTUALIZATION_MODE_BINAURAL} or {@link #VIRTUALIZATION_MODE_TRANSAURAL}. 462b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi * Virtualization may not be active either because the effect is not enabled or 463b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi * because the current output device is not compatible with this virtualization 464b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi * implementation. 465a3ee6642d8325f621f267c951c6a524220646610Jean-Michel Trivi * @throws IllegalStateException 466a3ee6642d8325f621f267c951c6a524220646610Jean-Michel Trivi * @throws UnsupportedOperationException 467d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi */ 468a3ee6642d8325f621f267c951c6a524220646610Jean-Michel Trivi public int getVirtualizationMode() 469b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi throws IllegalStateException, UnsupportedOperationException { 470d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi int[] value = new int[1]; 471d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi int status = getParameter(PARAM_VIRTUALIZATION_MODE, value); 472d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi if (status >= 0) { 473a33be211e768746745a0deeba71f8c6b65e72442Paul McLean return deviceToMode(AudioDeviceInfo.convertInternalDeviceToDeviceType(value[0])); 474d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi } else if (status == AudioEffect.ERROR_BAD_VALUE) { 475b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi return VIRTUALIZATION_MODE_OFF; 476d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi } else { 477d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi // something wrong may have happened 478d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi checkStatus(status); 479d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi } 480d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi // unexpected virtualizer behavior 481d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi Log.e(TAG, "unexpected status code " + status 482d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi + " after getParameter(PARAM_VIRTUALIZATION_MODE)"); 483b3bf7d487afdba540b1ce0f5abc57f060a159d0eJean-Michel Trivi return VIRTUALIZATION_MODE_OFF; 484d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi } 485d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi 486d2bebb3ab86177c0d27664af86b30b7dce2c9bcbJean-Michel Trivi /** 487fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * The OnParameterChangeListener interface defines a method called by the Virtualizer when a 488fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * parameter value has changed. 489fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent */ 490fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent public interface OnParameterChangeListener { 491fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent /** 492fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * Method called when a parameter value has changed. The method is called only if the 493fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * parameter was changed by another application having the control of the same 494fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * Virtualizer engine. 495fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * @param effect the Virtualizer on which the interface is registered. 496fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * @param status status of the set parameter operation. 497fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * @param param ID of the modified parameter. See {@link #PARAM_STRENGTH} ... 498fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * @param value the new parameter value. 499fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent */ 500fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent void onParameterChange(Virtualizer effect, int status, int param, short value); 501fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent } 502fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent 503fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent /** 504fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * Listener used internally to receive unformatted parameter change events from AudioEffect 505fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * super class. 506fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent */ 507fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent private class BaseParameterListener implements AudioEffect.OnParameterChangeListener { 508fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent private BaseParameterListener() { 509fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent 510fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent } 511fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent public void onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value) { 512fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent OnParameterChangeListener l = null; 513fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent 514fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent synchronized (mParamListenerLock) { 515fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent if (mParamListener != null) { 516fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent l = mParamListener; 517fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent } 518fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent } 519fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent if (l != null) { 520fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent int p = -1; 521fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent short v = -1; 522fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent 523fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent if (param.length == 4) { 524fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent p = byteArrayToInt(param, 0); 525fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent } 526fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent if (value.length == 2) { 527fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent v = byteArrayToShort(value, 0); 528fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent } 529fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent if (p != -1 && v != -1) { 530fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent l.onParameterChange(Virtualizer.this, status, p, v); 531fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent } 532fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent } 533fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent } 534fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent } 535fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent 536fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent /** 537fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * Registers an OnParameterChangeListener interface. 538fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent * @param listener OnParameterChangeListener interface registered 539fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent */ 540fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent public void setParameterListener(OnParameterChangeListener listener) { 541fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent synchronized (mParamListenerLock) { 542fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent if (mParamListener == null) { 543fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent mParamListener = listener; 544fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent mBaseParamListener = new BaseParameterListener(); 545fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent super.setParameterListener(mBaseParamListener); 546fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent } 547fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent } 548fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent } 549ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent 550ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent /** 551ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent * The Settings class regroups all virtualizer parameters. It is used in 552ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent * conjuntion with getProperties() and setProperties() methods to backup and restore 553ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent * all parameters in a single call. 554ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent */ 555ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent public static class Settings { 556ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent public short strength; 557ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent 558ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent public Settings() { 559ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent } 560ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent 561ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent /** 562ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent * Settings class constructor from a key=value; pairs formatted string. The string is 563ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent * typically returned by Settings.toString() method. 564ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent * @throws IllegalArgumentException if the string is not correctly formatted. 565ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent */ 566ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent public Settings(String settings) { 567ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent StringTokenizer st = new StringTokenizer(settings, "=;"); 568ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent int tokens = st.countTokens(); 569ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent if (st.countTokens() != 3) { 570ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent throw new IllegalArgumentException("settings: " + settings); 571ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent } 572ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent String key = st.nextToken(); 573ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent if (!key.equals("Virtualizer")) { 574ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent throw new IllegalArgumentException( 575ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent "invalid settings for Virtualizer: " + key); 576ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent } 577ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent try { 578ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent key = st.nextToken(); 579ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent if (!key.equals("strength")) { 580ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent throw new IllegalArgumentException("invalid key name: " + key); 581ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent } 582ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent strength = Short.parseShort(st.nextToken()); 583ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent } catch (NumberFormatException nfe) { 584ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent throw new IllegalArgumentException("invalid value for key: " + key); 585ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent } 586ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent } 587ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent 588ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent @Override 589ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent public String toString() { 590ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent String str = new String ( 591ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent "Virtualizer"+ 592ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent ";strength="+Short.toString(strength) 593ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent ); 594ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent return str; 595ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent } 596ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent }; 597ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent 598ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent 599ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent /** 600ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent * Gets the virtualizer properties. This method is useful when a snapshot of current 601ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent * virtualizer settings must be saved by the application. 602ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent * @return a Virtualizer.Settings object containing all current parameters values 603ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent * @throws IllegalStateException 604ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent * @throws IllegalArgumentException 605ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent * @throws UnsupportedOperationException 606ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent */ 607ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent public Virtualizer.Settings getProperties() 608ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 609ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent Settings settings = new Settings(); 610ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent short[] value = new short[1]; 611ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent checkStatus(getParameter(PARAM_STRENGTH, value)); 612ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent settings.strength = value[0]; 613ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent return settings; 614ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent } 615ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent 616ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent /** 617ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent * Sets the virtualizer properties. This method is useful when virtualizer settings have to 618ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent * be applied from a previous backup. 61917cb280e7f1ac3556eac90ab08263712e0348cb9Eric Laurent * @param settings a Virtualizer.Settings object containing the properties to apply 620ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent * @throws IllegalStateException 621ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent * @throws IllegalArgumentException 622ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent * @throws UnsupportedOperationException 623ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent */ 624ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent public void setProperties(Virtualizer.Settings settings) 625ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 626ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent checkStatus(setParameter(PARAM_STRENGTH, settings.strength)); 627ca57d1cc89d65dfbd59c749c5736574cd08c7bd3Eric Laurent } 628fd84f97af4b44d54bba53bb85b31a6dbce07f6e2Eric Laurent} 629