1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.media.audiofx; 18 19import android.app.Activity; 20import android.content.Context; 21import android.content.Intent; 22import android.media.audiofx.AudioEffect; 23import android.os.Bundle; 24import android.util.Log; 25 26import java.nio.ByteOrder; 27import java.nio.ByteBuffer; 28import java.nio.CharBuffer; 29import java.util.StringTokenizer; 30 31 32/** 33 * An audio virtualizer is a general name for an effect to spatialize audio channels. The exact 34 * behavior of this effect is dependent on the number of audio input channels and the types and 35 * number of audio output channels of the device. For example, in the case of a stereo input and 36 * stereo headphone output, a stereo widening effect is used when this effect is turned on. 37 * <p>An application creates a Virtualizer object to instantiate and control a virtualizer engine 38 * in the audio framework. 39 * <p>The methods, parameter types and units exposed by the Virtualizer implementation are directly 40 * mapping those defined by the OpenSL ES 1.0.1 Specification (http://www.khronos.org/opensles/) 41 * for the SLVirtualizerItf interface. Please refer to this specification for more details. 42 * <p>To attach the Virtualizer to a particular AudioTrack or MediaPlayer, specify the audio session 43 * ID of this AudioTrack or MediaPlayer when constructing the Virtualizer. 44 * <p>NOTE: attaching a Virtualizer to the global audio output mix by use of session 0 is 45 * deprecated. 46 * <p>See {@link android.media.MediaPlayer#getAudioSessionId()} for details on audio sessions. 47 * <p>See {@link android.media.audiofx.AudioEffect} class for more details on controlling 48 * audio effects. 49 */ 50 51public class Virtualizer extends AudioEffect { 52 53 private final static String TAG = "Virtualizer"; 54 55 // These constants must be synchronized with those in frameworks/base/include/media/EffectVirtualizerApi.h 56 /** 57 * Is strength parameter supported by virtualizer engine. Parameter ID for getParameter(). 58 */ 59 public static final int PARAM_STRENGTH_SUPPORTED = 0; 60 /** 61 * Virtualizer effect strength. Parameter ID for 62 * {@link android.media.audiofx.Virtualizer.OnParameterChangeListener} 63 */ 64 public static final int PARAM_STRENGTH = 1; 65 66 /** 67 * Indicates if strength parameter is supported by the virtualizer engine 68 */ 69 private boolean mStrengthSupported = false; 70 71 /** 72 * Registered listener for parameter changes. 73 */ 74 private OnParameterChangeListener mParamListener = null; 75 76 /** 77 * Listener used internally to to receive raw parameter change event from AudioEffect super class 78 */ 79 private BaseParameterListener mBaseParamListener = null; 80 81 /** 82 * Lock for access to mParamListener 83 */ 84 private final Object mParamListenerLock = new Object(); 85 86 /** 87 * Class constructor. 88 * @param priority the priority level requested by the application for controlling the Virtualizer 89 * engine. As the same engine can be shared by several applications, this parameter indicates 90 * how much the requesting application needs control of effect parameters. The normal priority 91 * is 0, above normal is a positive number, below normal a negative number. 92 * @param audioSession system wide unique audio session identifier. The Virtualizer will 93 * be attached to the MediaPlayer or AudioTrack in the same audio session. 94 * 95 * @throws java.lang.IllegalStateException 96 * @throws java.lang.IllegalArgumentException 97 * @throws java.lang.UnsupportedOperationException 98 * @throws java.lang.RuntimeException 99 */ 100 public Virtualizer(int priority, int audioSession) 101 throws IllegalStateException, IllegalArgumentException, 102 UnsupportedOperationException, RuntimeException { 103 super(EFFECT_TYPE_VIRTUALIZER, EFFECT_TYPE_NULL, priority, audioSession); 104 105 if (audioSession == 0) { 106 Log.w(TAG, "WARNING: attaching a Virtualizer to global output mix is deprecated!"); 107 } 108 109 int[] value = new int[1]; 110 checkStatus(getParameter(PARAM_STRENGTH_SUPPORTED, value)); 111 mStrengthSupported = (value[0] != 0); 112 } 113 114 /** 115 * Indicates whether setting strength is supported. If this method returns false, only one 116 * strength is supported and the setStrength() method always rounds to that value. 117 * @return true is strength parameter is supported, false otherwise 118 */ 119 public boolean getStrengthSupported() { 120 return mStrengthSupported; 121 } 122 123 /** 124 * Sets the strength of the virtualizer effect. If the implementation does not support per mille 125 * accuracy for setting the strength, it is allowed to round the given strength to the nearest 126 * supported value. You can use the {@link #getRoundedStrength()} method to query the 127 * (possibly rounded) value that was actually set. 128 * @param strength strength of the effect. The valid range for strength strength is [0, 1000], 129 * where 0 per mille designates the mildest effect and 1000 per mille designates the strongest. 130 * @throws IllegalStateException 131 * @throws IllegalArgumentException 132 * @throws UnsupportedOperationException 133 */ 134 public void setStrength(short strength) 135 throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 136 checkStatus(setParameter(PARAM_STRENGTH, strength)); 137 } 138 139 /** 140 * Gets the current strength of the effect. 141 * @return the strength of the effect. The valid range for strength is [0, 1000], where 0 per 142 * mille designates the mildest effect and 1000 per mille the strongest 143 * @throws IllegalStateException 144 * @throws IllegalArgumentException 145 * @throws UnsupportedOperationException 146 */ 147 public short getRoundedStrength() 148 throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 149 short[] value = new short[1]; 150 checkStatus(getParameter(PARAM_STRENGTH, value)); 151 return value[0]; 152 } 153 154 /** 155 * The OnParameterChangeListener interface defines a method called by the Virtualizer when a 156 * parameter value has changed. 157 */ 158 public interface OnParameterChangeListener { 159 /** 160 * Method called when a parameter value has changed. The method is called only if the 161 * parameter was changed by another application having the control of the same 162 * Virtualizer engine. 163 * @param effect the Virtualizer on which the interface is registered. 164 * @param status status of the set parameter operation. 165 * @param param ID of the modified parameter. See {@link #PARAM_STRENGTH} ... 166 * @param value the new parameter value. 167 */ 168 void onParameterChange(Virtualizer effect, int status, int param, short value); 169 } 170 171 /** 172 * Listener used internally to receive unformatted parameter change events from AudioEffect 173 * super class. 174 */ 175 private class BaseParameterListener implements AudioEffect.OnParameterChangeListener { 176 private BaseParameterListener() { 177 178 } 179 public void onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value) { 180 OnParameterChangeListener l = null; 181 182 synchronized (mParamListenerLock) { 183 if (mParamListener != null) { 184 l = mParamListener; 185 } 186 } 187 if (l != null) { 188 int p = -1; 189 short v = -1; 190 191 if (param.length == 4) { 192 p = byteArrayToInt(param, 0); 193 } 194 if (value.length == 2) { 195 v = byteArrayToShort(value, 0); 196 } 197 if (p != -1 && v != -1) { 198 l.onParameterChange(Virtualizer.this, status, p, v); 199 } 200 } 201 } 202 } 203 204 /** 205 * Registers an OnParameterChangeListener interface. 206 * @param listener OnParameterChangeListener interface registered 207 */ 208 public void setParameterListener(OnParameterChangeListener listener) { 209 synchronized (mParamListenerLock) { 210 if (mParamListener == null) { 211 mParamListener = listener; 212 mBaseParamListener = new BaseParameterListener(); 213 super.setParameterListener(mBaseParamListener); 214 } 215 } 216 } 217 218 /** 219 * The Settings class regroups all virtualizer parameters. It is used in 220 * conjuntion with getProperties() and setProperties() methods to backup and restore 221 * all parameters in a single call. 222 */ 223 public static class Settings { 224 public short strength; 225 226 public Settings() { 227 } 228 229 /** 230 * Settings class constructor from a key=value; pairs formatted string. The string is 231 * typically returned by Settings.toString() method. 232 * @throws IllegalArgumentException if the string is not correctly formatted. 233 */ 234 public Settings(String settings) { 235 StringTokenizer st = new StringTokenizer(settings, "=;"); 236 int tokens = st.countTokens(); 237 if (st.countTokens() != 3) { 238 throw new IllegalArgumentException("settings: " + settings); 239 } 240 String key = st.nextToken(); 241 if (!key.equals("Virtualizer")) { 242 throw new IllegalArgumentException( 243 "invalid settings for Virtualizer: " + key); 244 } 245 try { 246 key = st.nextToken(); 247 if (!key.equals("strength")) { 248 throw new IllegalArgumentException("invalid key name: " + key); 249 } 250 strength = Short.parseShort(st.nextToken()); 251 } catch (NumberFormatException nfe) { 252 throw new IllegalArgumentException("invalid value for key: " + key); 253 } 254 } 255 256 @Override 257 public String toString() { 258 String str = new String ( 259 "Virtualizer"+ 260 ";strength="+Short.toString(strength) 261 ); 262 return str; 263 } 264 }; 265 266 267 /** 268 * Gets the virtualizer properties. This method is useful when a snapshot of current 269 * virtualizer settings must be saved by the application. 270 * @return a Virtualizer.Settings object containing all current parameters values 271 * @throws IllegalStateException 272 * @throws IllegalArgumentException 273 * @throws UnsupportedOperationException 274 */ 275 public Virtualizer.Settings getProperties() 276 throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 277 Settings settings = new Settings(); 278 short[] value = new short[1]; 279 checkStatus(getParameter(PARAM_STRENGTH, value)); 280 settings.strength = value[0]; 281 return settings; 282 } 283 284 /** 285 * Sets the virtualizer properties. This method is useful when virtualizer settings have to 286 * be applied from a previous backup. 287 * @param settings a Virtualizer.Settings object containing the properties to apply 288 * @throws IllegalStateException 289 * @throws IllegalArgumentException 290 * @throws UnsupportedOperationException 291 */ 292 public void setProperties(Virtualizer.Settings settings) 293 throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException { 294 checkStatus(setParameter(PARAM_STRENGTH, settings.strength)); 295 } 296} 297