BassBoost.java revision 1a5149e5d7f2dddc8b324f7695e69fd89af73c52
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 * Bass boost is an audio effect to boost or amplify low frequencies of the sound. It is comparable
34 * to a simple equalizer but limited to one band amplification in the low frequency range.
35 * <p>An application creates a BassBoost object to instantiate and control a bass boost engine in
36 * the audio framework.
37 * <p>The methods, parameter types and units exposed by the BassBoost implementation are directly
38 * mapping those defined by the OpenSL ES 1.0.1 Specification (http://www.khronos.org/opensles/)
39 * for the SLBassBoostItf interface. Please refer to this specification for more details.
40 * <p>To attach the BassBoost to a particular AudioTrack or MediaPlayer, specify the audio session
41 * ID of this AudioTrack or MediaPlayer when constructing the BassBoost.
42 * If the audio session ID 0 is specified, the BassBoost applies to the main audio output mix.
43 * <p>Creating a BassBoost on the output mix (audio session 0) requires permission
44 * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}
45 * <p>See {@link android.media.MediaPlayer#getAudioSessionId()} for details on audio sessions.
46 * <p>See {@link android.media.audiofx.AudioEffect} class for more details on
47 * controlling audio effects.
48 */
49
50public class BassBoost extends AudioEffect {
51
52    private final static String TAG = "BassBoost";
53
54    // These constants must be synchronized with those in
55    // frameworks/base/include/media/EffectBassBoostApi.h
56    /**
57     * Is strength parameter supported by bass boost engine. Parameter ID for getParameter().
58     */
59    public static final int PARAM_STRENGTH_SUPPORTED = 0;
60    /**
61     * Bass boost effect strength. Parameter ID for
62     * {@link android.media.audiofx.BassBoost.OnParameterChangeListener}
63     */
64    public static final int PARAM_STRENGTH = 1;
65
66    /**
67     * Indicates if strength parameter is supported by the bass boost 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 BassBoost
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. If audioSession
93     *  is not 0, the BassBoost will be attached to the MediaPlayer or AudioTrack in the
94     *  same audio session. Otherwise, the BassBoost will apply to the output mix.
95     *
96     * @throws java.lang.IllegalStateException
97     * @throws java.lang.IllegalArgumentException
98     * @throws java.lang.UnsupportedOperationException
99     * @throws java.lang.RuntimeException
100     */
101    public BassBoost(int priority, int audioSession)
102    throws IllegalStateException, IllegalArgumentException,
103           UnsupportedOperationException, RuntimeException {
104        super(EFFECT_TYPE_BASS_BOOST, EFFECT_TYPE_NULL, priority, audioSession);
105
106        int[] value = new int[1];
107        checkStatus(getParameter(PARAM_STRENGTH_SUPPORTED, value));
108        mStrengthSupported = (value[0] != 0);
109    }
110
111    /**
112     * Indicates whether setting strength is supported. If this method returns false, only one
113     * strength is supported and the setStrength() method always rounds to that value.
114     * @return true is strength parameter is supported, false otherwise
115     */
116    public boolean getStrengthSupported() {
117       return mStrengthSupported;
118    }
119
120    /**
121     * Sets the strength of the bass boost effect. If the implementation does not support per mille
122     * accuracy for setting the strength, it is allowed to round the given strength to the nearest
123     * supported value. You can use the {@link #getRoundedStrength()} method to query the
124     * (possibly rounded) value that was actually set.
125     * @param strength strength of the effect. The valid range for strength strength is [0, 1000],
126     * where 0 per mille designates the mildest effect and 1000 per mille designates the strongest.
127     * @throws IllegalStateException
128     * @throws IllegalArgumentException
129     * @throws UnsupportedOperationException
130     */
131    public void setStrength(short strength)
132    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
133        checkStatus(setParameter(PARAM_STRENGTH, strength));
134    }
135
136    /**
137     * Gets the current strength of the effect.
138     * @return the strength of the effect. The valid range for strength is [0, 1000], where 0 per
139     * mille designates the mildest effect and 1000 per mille the strongest
140     * @throws IllegalStateException
141     * @throws IllegalArgumentException
142     * @throws UnsupportedOperationException
143     */
144    public short getRoundedStrength()
145    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
146        short[] value = new short[1];
147        checkStatus(getParameter(PARAM_STRENGTH, value));
148        return value[0];
149    }
150
151    /**
152     * The OnParameterChangeListener interface defines a method called by the BassBoost when a
153     * parameter value has changed.
154     */
155    public interface OnParameterChangeListener  {
156        /**
157         * Method called when a parameter value has changed. The method is called only if the
158         * parameter was changed by another application having the control of the same
159         * BassBoost engine.
160         * @param effect the BassBoost on which the interface is registered.
161         * @param status status of the set parameter operation.
162         * @param param ID of the modified parameter. See {@link #PARAM_STRENGTH} ...
163         * @param value the new parameter value.
164         */
165        void onParameterChange(BassBoost effect, int status, int param, short value);
166    }
167
168    /**
169     * Listener used internally to receive unformatted parameter change events from AudioEffect
170     * super class.
171     */
172    private class BaseParameterListener implements AudioEffect.OnParameterChangeListener {
173        private BaseParameterListener() {
174
175        }
176        public void onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value) {
177            OnParameterChangeListener l = null;
178
179            synchronized (mParamListenerLock) {
180                if (mParamListener != null) {
181                    l = mParamListener;
182                }
183            }
184            if (l != null) {
185                int p = -1;
186                short v = -1;
187
188                if (param.length == 4) {
189                    p = byteArrayToInt(param, 0);
190                }
191                if (value.length == 2) {
192                    v = byteArrayToShort(value, 0);
193                }
194                if (p != -1 && v != -1) {
195                    l.onParameterChange(BassBoost.this, status, p, v);
196                }
197            }
198        }
199    }
200
201    /**
202     * Registers an OnParameterChangeListener interface.
203     * @param listener OnParameterChangeListener interface registered
204     */
205    public void setParameterListener(OnParameterChangeListener listener) {
206        synchronized (mParamListenerLock) {
207            if (mParamListener == null) {
208                mParamListener = listener;
209                mBaseParamListener = new BaseParameterListener();
210                super.setParameterListener(mBaseParamListener);
211            }
212        }
213    }
214
215    /**
216     * The Settings class regroups all bass boost parameters. It is used in
217     * conjuntion with getProperties() and setProperties() methods to backup and restore
218     * all parameters in a single call.
219     */
220    public static class Settings {
221        public short strength;
222
223        public Settings() {
224        }
225
226        /**
227         * Settings class constructor from a key=value; pairs formatted string. The string is
228         * typically returned by Settings.toString() method.
229         * @throws IllegalArgumentException if the string is not correctly formatted.
230         */
231        public Settings(String settings) {
232            StringTokenizer st = new StringTokenizer(settings, "=;");
233            int tokens = st.countTokens();
234            if (st.countTokens() != 3) {
235                throw new IllegalArgumentException("settings: " + settings);
236            }
237            String key = st.nextToken();
238            if (!key.equals("BassBoost")) {
239                throw new IllegalArgumentException(
240                        "invalid settings for BassBoost: " + key);
241            }
242            try {
243                key = st.nextToken();
244                if (!key.equals("strength")) {
245                    throw new IllegalArgumentException("invalid key name: " + key);
246                }
247                strength = Short.parseShort(st.nextToken());
248             } catch (NumberFormatException nfe) {
249                throw new IllegalArgumentException("invalid value for key: " + key);
250            }
251        }
252
253        @Override
254        public String toString() {
255            String str = new String (
256                    "BassBoost"+
257                    ";strength="+Short.toString(strength)
258                    );
259            return str;
260        }
261    };
262
263
264    /**
265     * Gets the bass boost properties. This method is useful when a snapshot of current
266     * bass boost settings must be saved by the application.
267     * @return a BassBoost.Settings object containing all current parameters values
268     * @throws IllegalStateException
269     * @throws IllegalArgumentException
270     * @throws UnsupportedOperationException
271     */
272    public BassBoost.Settings getProperties()
273    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
274        Settings settings = new Settings();
275        short[] value = new short[1];
276        checkStatus(getParameter(PARAM_STRENGTH, value));
277        settings.strength = value[0];
278        return settings;
279    }
280
281    /**
282     * Sets the bass boost properties. This method is useful when bass boost settings have to
283     * be applied from a previous backup.
284     * @param settings a BassBoost.Settings object containing the properties to apply
285     * @throws IllegalStateException
286     * @throws IllegalArgumentException
287     * @throws UnsupportedOperationException
288     */
289    public void setProperties(BassBoost.Settings settings)
290    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
291        checkStatus(setParameter(PARAM_STRENGTH, settings.strength));
292    }
293}
294