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