1/*
2 * Copyright (C) 2010-2011 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 com.android.musicfx;
18
19import android.content.Context;
20import android.content.SharedPreferences;
21import android.media.MediaPlayer;
22import android.media.audiofx.AudioEffect;
23import android.media.audiofx.BassBoost;
24import android.media.audiofx.Equalizer;
25import android.media.audiofx.PresetReverb;
26import android.media.audiofx.Virtualizer;
27import android.util.Log;
28
29import java.util.Arrays;
30import java.util.concurrent.ConcurrentHashMap;
31
32/**
33 * The Common class defines constants to be used by the control panels.
34 */
35public class ControlPanelEffect {
36
37    private final static String TAG = "MusicFXControlPanelEffect";
38
39    /**
40     * Audio session priority
41     */
42    private static final int PRIORITY = 0;
43
44    /**
45     * The control mode specifies if control panel updates effects and preferences or only
46     * preferences.
47     */
48    static enum ControlMode {
49        /**
50         * Control panel updates effects and preferences. Applicable when audio session is delivered
51         * by user.
52         */
53        CONTROL_EFFECTS,
54        /**
55         * Control panel only updates preferences. Applicable when there was no audio or invalid
56         * session provided by user.
57         */
58        CONTROL_PREFERENCES
59    }
60
61    static enum Key {
62        global_enabled, virt_enabled, virt_strength_supported, virt_strength, virt_type, bb_enabled,
63        bb_strength, te_enabled, te_strength, avl_enabled, lm_enabled, lm_strength, eq_enabled,
64        eq_num_bands, eq_level_range, eq_center_freq, eq_band_level, eq_num_presets, eq_preset_name,
65        eq_preset_user_band_level, eq_preset_user_band_level_default,
66        eq_preset_opensl_es_band_level, eq_preset_ci_extreme_band_level, eq_current_preset,
67        pr_enabled, pr_current_preset
68    }
69
70    // Effect/audio session Mappings
71    /**
72     * Hashmap initial capacity
73     */
74    private static final int HASHMAP_INITIAL_CAPACITY = 16;
75    /**
76     * Hashmap load factor
77     */
78    private static final float HASHMAP_LOAD_FACTOR = 0.75f;
79    /**
80     * ConcurrentHashMap concurrency level
81     */
82    private static final int HASHMAP_CONCURRENCY_LEVEL = 2;
83
84    /**
85     * Map containing the Virtualizer audio session, effect mappings.
86     */
87    private static final ConcurrentHashMap<Integer, Virtualizer> mVirtualizerInstances = new ConcurrentHashMap<Integer, Virtualizer>(
88            HASHMAP_INITIAL_CAPACITY, HASHMAP_LOAD_FACTOR, HASHMAP_CONCURRENCY_LEVEL);
89    /**
90     * Map containing the BB audio session, effect mappings.
91     */
92    private static final ConcurrentHashMap<Integer, BassBoost> mBassBoostInstances = new ConcurrentHashMap<Integer, BassBoost>(
93            HASHMAP_INITIAL_CAPACITY, HASHMAP_LOAD_FACTOR, HASHMAP_CONCURRENCY_LEVEL);
94    /**
95     * Map containing the EQ audio session, effect mappings.
96     */
97    private static final ConcurrentHashMap<Integer, Equalizer> mEQInstances = new ConcurrentHashMap<Integer, Equalizer>(
98            HASHMAP_INITIAL_CAPACITY, HASHMAP_LOAD_FACTOR, HASHMAP_CONCURRENCY_LEVEL);
99    /**
100     * Map containing the PR audio session, effect mappings.
101     */
102    private static final ConcurrentHashMap<Integer, PresetReverb> mPresetReverbInstances = new ConcurrentHashMap<Integer, PresetReverb>(
103            HASHMAP_INITIAL_CAPACITY, HASHMAP_LOAD_FACTOR, HASHMAP_CONCURRENCY_LEVEL);
104
105    /**
106     * Map containing the package name, audio session mappings.
107     */
108    private static final ConcurrentHashMap<String, Integer> mPackageSessions = new ConcurrentHashMap<String, Integer>(
109            HASHMAP_INITIAL_CAPACITY, HASHMAP_LOAD_FACTOR, HASHMAP_CONCURRENCY_LEVEL);
110
111    // Defaults
112    final static boolean GLOBAL_ENABLED_DEFAULT = false;
113    private final static boolean VIRTUALIZER_ENABLED_DEFAULT = true;
114    private final static int VIRTUALIZER_STRENGTH_DEFAULT = 1000;
115    private final static boolean BASS_BOOST_ENABLED_DEFAULT = true;
116    private final static int BASS_BOOST_STRENGTH_DEFAULT = 667;
117    private final static boolean PRESET_REVERB_ENABLED_DEFAULT = false;
118    private final static int PRESET_REVERB_CURRENT_PRESET_DEFAULT = 0; // None
119
120    // EQ defaults
121    private final static boolean EQUALIZER_ENABLED_DEFAULT = true;
122    private final static String EQUALIZER_PRESET_NAME_DEFAULT = "Preset";
123    private final static short EQUALIZER_NUMBER_BANDS_DEFAULT = 5;
124    private final static short EQUALIZER_NUMBER_PRESETS_DEFAULT = 0;
125    private final static short[] EQUALIZER_BAND_LEVEL_RANGE_DEFAULT = { -1500, 1500 };
126    private final static int[] EQUALIZER_CENTER_FREQ_DEFAULT = { 60000, 230000, 910000, 3600000,
127            14000000 };
128    private final static short[] EQUALIZER_PRESET_CIEXTREME_BAND_LEVEL = { 0, 800, 400, 100, 1000 };
129    private final static short[] EQUALIZER_PRESET_USER_BAND_LEVEL_DEFAULT = { 0, 0, 0, 0, 0 };
130    private final static short[][] EQUALIZER_PRESET_OPENSL_ES_BAND_LEVEL_DEFAULT = new short[EQUALIZER_NUMBER_PRESETS_DEFAULT][EQUALIZER_NUMBER_BANDS_DEFAULT];
131
132    // EQ effect properties which are invariable over all EQ effects sessions
133    private static short[] mEQBandLevelRange = EQUALIZER_BAND_LEVEL_RANGE_DEFAULT;
134    private static short mEQNumBands = EQUALIZER_NUMBER_BANDS_DEFAULT;
135    private static int[] mEQCenterFreq = EQUALIZER_CENTER_FREQ_DEFAULT;
136    private static short mEQNumPresets = EQUALIZER_NUMBER_PRESETS_DEFAULT;
137    private static short[][] mEQPresetOpenSLESBandLevel = EQUALIZER_PRESET_OPENSL_ES_BAND_LEVEL_DEFAULT;
138    private static String[] mEQPresetNames;
139    private static boolean mIsEQInitialized = false;
140    private final static Object mEQInitLock = new Object();
141
142    /**
143     * Default int argument used in methods to see that the arg is a dummy. Used for method
144     * overloading.
145     */
146    private final static int DUMMY_ARGUMENT = -1;
147
148    /**
149     * Inits effects preferences for the given context and package name in the control panel. If
150     * preferences for the given package name don't exist, they are created and initialized.
151     *
152     * @param context
153     * @param packageName
154     * @param audioSession
155     *            System wide unique audio session identifier.
156     */
157    public static void initEffectsPreferences(final Context context, final String packageName,
158            final int audioSession) {
159        final SharedPreferences prefs = context.getSharedPreferences(packageName,
160                Context.MODE_PRIVATE);
161        final SharedPreferences.Editor editor = prefs.edit();
162        final ControlMode controlMode = getControlMode(audioSession);
163
164        // init preferences
165        try {
166            // init global on/off switch
167            final boolean isGlobalEnabled = prefs.getBoolean(Key.global_enabled.toString(),
168                    GLOBAL_ENABLED_DEFAULT);
169            editor.putBoolean(Key.global_enabled.toString(), isGlobalEnabled);
170            Log.v(TAG, "isGlobalEnabled = " + isGlobalEnabled);
171
172            // Virtualizer
173            final boolean isVIEnabled = prefs.getBoolean(Key.virt_enabled.toString(),
174                    VIRTUALIZER_ENABLED_DEFAULT);
175            final Virtualizer virt = new Virtualizer(0, audioSession);
176            final int vIStrength = prefs.getInt(Key.virt_strength.toString(),
177                    virt.getRoundedStrength());
178            virt.release();
179            editor.putBoolean(Key.virt_enabled.toString(), isVIEnabled);
180            editor.putInt(Key.virt_strength.toString(), vIStrength);
181            {
182                final MediaPlayer mediaPlayer = new MediaPlayer();
183                final int session = mediaPlayer.getAudioSessionId();
184                Virtualizer virtualizerEffect = null;
185                try {
186                    virtualizerEffect = new Virtualizer(PRIORITY, session);
187                    editor.putBoolean(Key.virt_strength_supported.toString(),
188                            virtualizerEffect.getStrengthSupported());
189                } finally {
190                    if (virtualizerEffect != null) {
191                        Log.d(TAG, "Releasing dummy Virtualizer effect");
192                        virtualizerEffect.release();
193                    }
194                    mediaPlayer.release();
195                }
196            }
197
198            // BassBoost
199            final boolean isBBEnabled = prefs.getBoolean(Key.bb_enabled.toString(),
200                    BASS_BOOST_ENABLED_DEFAULT);
201            final int bBStrength = prefs.getInt(Key.bb_strength.toString(),
202                    BASS_BOOST_STRENGTH_DEFAULT);
203            editor.putBoolean(Key.bb_enabled.toString(), isBBEnabled);
204            editor.putInt(Key.bb_strength.toString(), bBStrength);
205
206            // Equalizer
207            synchronized (mEQInitLock) {
208                // If EQ is not initialized already create "dummy" audio session created by
209                // MediaPlayer and create effect on it to retrieve the invariable EQ properties
210                if (!mIsEQInitialized) {
211                    final MediaPlayer mediaPlayer = new MediaPlayer();
212                    final int session = mediaPlayer.getAudioSessionId();
213                    Equalizer equalizerEffect = null;
214                    try {
215                        Log.d(TAG, "Creating dummy EQ effect on session " + session);
216                        equalizerEffect = new Equalizer(PRIORITY, session);
217
218                        mEQBandLevelRange = equalizerEffect.getBandLevelRange();
219                        mEQNumBands = equalizerEffect.getNumberOfBands();
220                        mEQCenterFreq = new int[mEQNumBands];
221                        for (short band = 0; band < mEQNumBands; band++) {
222                            mEQCenterFreq[band] = equalizerEffect.getCenterFreq(band);
223                        }
224                        mEQNumPresets = equalizerEffect.getNumberOfPresets();
225                        mEQPresetNames = new String[mEQNumPresets];
226                        mEQPresetOpenSLESBandLevel = new short[mEQNumPresets][mEQNumBands];
227                        for (short preset = 0; preset < mEQNumPresets; preset++) {
228                            mEQPresetNames[preset] = equalizerEffect.getPresetName(preset);
229                            equalizerEffect.usePreset(preset);
230                            for (short band = 0; band < mEQNumBands; band++) {
231                                mEQPresetOpenSLESBandLevel[preset][band] = equalizerEffect
232                                        .getBandLevel(band);
233                            }
234                        }
235
236                        mIsEQInitialized = true;
237                    } catch (final IllegalStateException e) {
238                        Log.e(TAG, "Equalizer: " + e);
239                    } catch (final IllegalArgumentException e) {
240                        Log.e(TAG, "Equalizer: " + e);
241                    } catch (final UnsupportedOperationException e) {
242                        Log.e(TAG, "Equalizer: " + e);
243                    } catch (final RuntimeException e) {
244                        Log.e(TAG, "Equalizer: " + e);
245                    } finally {
246                        if (equalizerEffect != null) {
247                            Log.d(TAG, "Releasing dummy EQ effect");
248                            equalizerEffect.release();
249                        }
250                        mediaPlayer.release();
251
252                        // When there was a failure set some good defaults
253                        if (!mIsEQInitialized) {
254                            mEQPresetOpenSLESBandLevel = new short[mEQNumPresets][mEQNumBands];
255                            for (short preset = 0; preset < mEQNumPresets; preset++) {
256                                // Init preset names to a dummy name
257                                mEQPresetNames[preset] = prefs.getString(
258                                        Key.eq_preset_name.toString() + preset,
259                                        EQUALIZER_PRESET_NAME_DEFAULT + preset);
260                                if (preset < EQUALIZER_PRESET_OPENSL_ES_BAND_LEVEL_DEFAULT.length) {
261                                    mEQPresetOpenSLESBandLevel[preset] = Arrays.copyOf(
262                                            EQUALIZER_PRESET_OPENSL_ES_BAND_LEVEL_DEFAULT[preset],
263                                            mEQNumBands);
264                                }
265                            }
266                        }
267                    }
268                }
269                editor.putInt(Key.eq_level_range.toString() + 0, mEQBandLevelRange[0]);
270                editor.putInt(Key.eq_level_range.toString() + 1, mEQBandLevelRange[1]);
271                editor.putInt(Key.eq_num_bands.toString(), mEQNumBands);
272                editor.putInt(Key.eq_num_presets.toString(), mEQNumPresets);
273                // Resetting the EQ arrays depending on the real # bands with defaults if
274                // band < default size else 0 by copying default arrays over new ones
275                final short[] eQPresetCIExtremeBandLevel = Arrays.copyOf(
276                        EQUALIZER_PRESET_CIEXTREME_BAND_LEVEL, mEQNumBands);
277                final short[] eQPresetUserBandLevelDefault = Arrays.copyOf(
278                        EQUALIZER_PRESET_USER_BAND_LEVEL_DEFAULT, mEQNumBands);
279                // If no preset prefs set use CI EXTREME (= numPresets)
280                final short eQPreset = (short) prefs.getInt(Key.eq_current_preset.toString(),
281                        mEQNumPresets);
282                editor.putInt(Key.eq_current_preset.toString(), eQPreset);
283                final short[] bandLevel = new short[mEQNumBands];
284                for (short band = 0; band < mEQNumBands; band++) {
285                    if (controlMode == ControlMode.CONTROL_PREFERENCES) {
286                        if (eQPreset < mEQNumPresets) {
287                            // OpenSL ES effect presets
288                            bandLevel[band] = mEQPresetOpenSLESBandLevel[eQPreset][band];
289                        } else if (eQPreset == mEQNumPresets) {
290                            // CI EXTREME
291                            bandLevel[band] = eQPresetCIExtremeBandLevel[band];
292                        } else {
293                            // User
294                            bandLevel[band] = (short) prefs.getInt(
295                                    Key.eq_preset_user_band_level.toString() + band,
296                                    eQPresetUserBandLevelDefault[band]);
297                        }
298                        editor.putInt(Key.eq_band_level.toString() + band, bandLevel[band]);
299                    }
300                    editor.putInt(Key.eq_center_freq.toString() + band, mEQCenterFreq[band]);
301                    editor.putInt(Key.eq_preset_ci_extreme_band_level.toString() + band,
302                            eQPresetCIExtremeBandLevel[band]);
303                    editor.putInt(Key.eq_preset_user_band_level_default.toString() + band,
304                            eQPresetUserBandLevelDefault[band]);
305                }
306                for (short preset = 0; preset < mEQNumPresets; preset++) {
307                    editor.putString(Key.eq_preset_name.toString() + preset, mEQPresetNames[preset]);
308                    for (short band = 0; band < mEQNumBands; band++) {
309                        editor.putInt(Key.eq_preset_opensl_es_band_level.toString() + preset + "_"
310                                + band, mEQPresetOpenSLESBandLevel[preset][band]);
311                    }
312                }
313            }
314            final boolean isEQEnabled = prefs.getBoolean(Key.eq_enabled.toString(),
315                    EQUALIZER_ENABLED_DEFAULT);
316            editor.putBoolean(Key.eq_enabled.toString(), isEQEnabled);
317
318            // Preset reverb
319            final boolean isEnabledPR = prefs.getBoolean(Key.pr_enabled.toString(),
320                    PRESET_REVERB_ENABLED_DEFAULT);
321            final short presetPR = (short) prefs.getInt(Key.pr_current_preset.toString(),
322                    PRESET_REVERB_CURRENT_PRESET_DEFAULT);
323            editor.putBoolean(Key.pr_enabled.toString(), isEnabledPR);
324            editor.putInt(Key.pr_current_preset.toString(), presetPR);
325
326            editor.commit();
327        } catch (final RuntimeException e) {
328            Log.e(TAG, "initEffectsPreferences: processingEnabled: " + e);
329        }
330    }
331
332    /**
333     * Gets the effect control mode based on the given audio session in the control panel. Control
334     * mode defines if the control panel is controlling effects and/or preferences
335     *
336     * @param audioSession
337     *            System wide unique audio session identifier.
338     * @return effect control mode
339     */
340    public static ControlMode getControlMode(final int audioSession) {
341        if (audioSession == AudioEffect.ERROR_BAD_VALUE) {
342            return ControlMode.CONTROL_PREFERENCES;
343        }
344        return ControlMode.CONTROL_EFFECTS;
345    }
346
347    /**
348     * Sets boolean parameter to value for given key
349     *
350     * @param context
351     * @param packageName
352     * @param audioSession
353     *            System wide unique audio session identifier.
354     * @param key
355     * @param value
356     */
357    public static void setParameterBoolean(final Context context, final String packageName,
358            final int audioSession, final Key key, final boolean value) {
359        try {
360            final SharedPreferences prefs = context.getSharedPreferences(packageName,
361                    Context.MODE_PRIVATE);
362            final ControlMode controlMode = getControlMode(audioSession);
363            boolean enabled = value;
364
365            // Global on/off
366            if (key == Key.global_enabled) {
367                boolean processingEnabled = false;
368                if (value == true) {
369                    // enable all with respect to preferences
370                    if (controlMode == ControlMode.CONTROL_EFFECTS) {
371                        final Virtualizer virtualizerEffect = getVirtualizerEffect(audioSession);
372                        if (virtualizerEffect != null) {
373                            virtualizerEffect.setEnabled(prefs.getBoolean(
374                                    Key.virt_enabled.toString(), VIRTUALIZER_ENABLED_DEFAULT));
375                            int defaultstrength = virtualizerEffect.getRoundedStrength();
376                            final int vIStrength = prefs.getInt(Key.virt_strength.toString(),
377                                    defaultstrength);
378                            setParameterInt(context, packageName,
379                                    audioSession, Key.virt_strength, vIStrength);
380                        }
381                        final BassBoost bassBoostEffect = getBassBoostEffect(audioSession);
382                        if (bassBoostEffect != null) {
383                            bassBoostEffect.setEnabled(prefs.getBoolean(Key.bb_enabled.toString(),
384                                    BASS_BOOST_ENABLED_DEFAULT));
385                            final int bBStrength = prefs.getInt(Key.bb_strength.toString(),
386                                    BASS_BOOST_STRENGTH_DEFAULT);
387                            setParameterInt(context, packageName,
388                                    audioSession, Key.bb_strength, bBStrength);
389                        }
390                        final Equalizer equalizerEffect = getEqualizerEffect(audioSession);
391                        if (equalizerEffect != null) {
392                            equalizerEffect.setEnabled(prefs.getBoolean(Key.eq_enabled.toString(),
393                                    EQUALIZER_ENABLED_DEFAULT));
394                            final int[] bandLevels = getParameterIntArray(context,
395                                    packageName, audioSession, Key.eq_band_level);
396                            final int len = bandLevels.length;
397                            for (short band = 0; band < len; band++) {
398                                final int level = bandLevels[band];
399                                setParameterInt(context, packageName,
400                                        audioSession, Key.eq_band_level, level, band);
401                            }
402                        }
403                        // XXX: Preset Reverb not used for the moment, so commented out the effect
404                        // creation to not use MIPS
405                        // final PresetReverb presetReverbEffect =
406                        // getPresetReverbEffect(audioSession);
407                        // if (presetReverbEffect != null) {
408                        // presetReverbEffect.setEnabled(prefs.getBoolean(
409                        // Key.pr_enabled.toString(), PRESET_REVERB_ENABLED_DEFAULT));
410                        // }
411                    }
412
413                    processingEnabled = true;
414                    Log.v(TAG, "processingEnabled=" + processingEnabled);
415
416                } else {
417                    // disable all
418                    if (controlMode == ControlMode.CONTROL_EFFECTS) {
419                        final Virtualizer virtualizerEffect = getVirtualizerEffectNoCreate(audioSession);
420                        if (virtualizerEffect != null) {
421                            mVirtualizerInstances.remove(audioSession, virtualizerEffect);
422                            virtualizerEffect.setEnabled(false);
423                            virtualizerEffect.release();
424                        }
425                        final BassBoost bassBoostEffect = getBassBoostEffectNoCreate(audioSession);
426                        if (bassBoostEffect != null) {
427                            mBassBoostInstances.remove(audioSession, bassBoostEffect);
428                            bassBoostEffect.setEnabled(false);
429                            bassBoostEffect.release();
430                        }
431                        final Equalizer equalizerEffect = getEqualizerEffectNoCreate(audioSession);
432                        if (equalizerEffect != null) {
433                            mEQInstances.remove(audioSession, equalizerEffect);
434                            equalizerEffect.setEnabled(false);
435                            equalizerEffect.release();
436                        }
437                        // XXX: Preset Reverb not used for the moment, so commented out the effect
438                        // creation to not use MIPS
439                        // final PresetReverb presetReverbEffect =
440                        // getPresetReverbEffect(audioSession);
441                        // if (presetReverbEffect != null) {
442                        // presetReverbEffect.setEnabled(false);
443                        // }
444                    }
445
446                    processingEnabled = false;
447                    Log.v(TAG, "processingEnabled=" + processingEnabled);
448                }
449                enabled = processingEnabled;
450            } else if (controlMode == ControlMode.CONTROL_EFFECTS) {
451                final boolean isGlobalEnabled = prefs.getBoolean(Key.global_enabled.toString(),
452                        GLOBAL_ENABLED_DEFAULT);
453                if (isGlobalEnabled == true) {
454                    // Set effect parameters
455                    switch (key) {
456
457                    case global_enabled:
458                        // Global, already handled, to get out error free
459                        break;
460
461                    // Virtualizer
462                    case virt_enabled:
463                        final Virtualizer virtualizerEffect = getVirtualizerEffect(audioSession);
464                        if (virtualizerEffect != null) {
465                            virtualizerEffect.setEnabled(value);
466                            enabled = virtualizerEffect.getEnabled();
467                        }
468                        break;
469
470                    // BassBoost
471                    case bb_enabled:
472                        final BassBoost bassBoostEffect = getBassBoostEffect(audioSession);
473                        if (bassBoostEffect != null) {
474                            bassBoostEffect.setEnabled(value);
475                            enabled = bassBoostEffect.getEnabled();
476                        }
477                        break;
478
479                    // Equalizer
480                    case eq_enabled:
481                        final Equalizer equalizerEffect = getEqualizerEffect(audioSession);
482                        if (equalizerEffect != null) {
483                            equalizerEffect.setEnabled(value);
484                            enabled = equalizerEffect.getEnabled();
485                        }
486                        break;
487
488                    // PresetReverb
489                    case pr_enabled:
490                        // XXX: Preset Reverb not used for the moment, so commented out the effect
491                        // creation to not use MIPS
492                        // final PresetReverb presetReverbEffect =
493                        // getPresetReverbEffect(audioSession);
494                        // if (presetReverbEffect != null) {
495                        // presetReverbEffect.setEnabled(value);
496                        // enabled = presetReverbEffect.getEnabled();
497                        // }
498                        break;
499
500                    default:
501                        Log.e(TAG, "Unknown/unsupported key " + key);
502                        return;
503                    }
504                }
505
506            }
507
508            // Set preferences
509            final SharedPreferences.Editor editor = prefs.edit();
510            editor.putBoolean(key.toString(), enabled);
511            editor.commit();
512
513        } catch (final RuntimeException e) {
514            Log.e(TAG, "setParameterBoolean: " + key + "; " + value + "; " + e);
515        }
516    }
517
518    /**
519     * Gets boolean parameter for given key
520     *
521     * @param context
522     * @param packageName
523     * @param audioSession
524     *            System wide unique audio session identifier.
525     * @param key
526     * @return parameter value
527     */
528    public static Boolean getParameterBoolean(final Context context, final String packageName,
529            final int audioSession, final Key key) {
530        final SharedPreferences prefs = context.getSharedPreferences(packageName,
531                Context.MODE_PRIVATE);
532        boolean value = false;
533
534        try {
535            value = prefs.getBoolean(key.toString(), value);
536        } catch (final RuntimeException e) {
537            Log.e(TAG, "getParameterBoolean: " + key + "; " + value + "; " + e);
538        }
539
540        return value;
541
542    }
543
544    /**
545     * Sets int parameter for given key and value arg0, arg1
546     *
547     * @param context
548     * @param packageName
549     * @param audioSession
550     *            System wide unique audio session identifier.
551     * @param key
552     * @param arg0
553     * @param arg1
554     */
555    public static void setParameterInt(final Context context, final String packageName,
556            final int audioSession, final Key key, final int arg0, final int arg1) {
557        String strKey = key.toString();
558        int value = arg0;
559
560        try {
561            final SharedPreferences prefs = context.getSharedPreferences(packageName,
562                    Context.MODE_PRIVATE);
563            final SharedPreferences.Editor editor = prefs.edit();
564            final ControlMode controlMode = getControlMode(audioSession);
565
566            // Set effect parameters
567            if (controlMode == ControlMode.CONTROL_EFFECTS) {
568
569                switch (key) {
570
571                // Virtualizer
572                case virt_strength: {
573                    final Virtualizer virtualizerEffect = getVirtualizerEffect(audioSession);
574                    if (virtualizerEffect != null) {
575                        virtualizerEffect.setStrength((short) value);
576                        value = virtualizerEffect.getRoundedStrength();
577                    }
578                    break;
579                }
580                    // BassBoost
581                case bb_strength: {
582                    final BassBoost bassBoostEffect = getBassBoostEffect(audioSession);
583                    if (bassBoostEffect != null) {
584                        bassBoostEffect.setStrength((short) value);
585                        value = bassBoostEffect.getRoundedStrength();
586                    }
587                    break;
588                }
589                    // Equalizer
590                case eq_band_level: {
591                    if (arg1 == DUMMY_ARGUMENT) {
592                        throw new IllegalArgumentException("Dummy arg passed.");
593                    }
594                    final short band = (short) arg1;
595                    strKey = strKey + band;
596                    final Equalizer equalizerEffect = getEqualizerEffect(audioSession);
597                    if (equalizerEffect != null) {
598                        equalizerEffect.setBandLevel(band, (short) value);
599                        value = equalizerEffect.getBandLevel(band);
600                        // save band level in User preset
601                        editor.putInt(Key.eq_preset_user_band_level.toString() + band, value);
602                    }
603                    break;
604                }
605                case eq_current_preset: {
606                    final Equalizer equalizerEffect = getEqualizerEffect(audioSession);
607                    if (equalizerEffect != null) {
608                        final short preset = (short) value;
609                        final int numBands = prefs.getInt(Key.eq_num_bands.toString(),
610                                EQUALIZER_NUMBER_BANDS_DEFAULT);
611                        final int numPresets = prefs.getInt(Key.eq_num_presets.toString(),
612                                EQUALIZER_NUMBER_PRESETS_DEFAULT);
613
614                        if (preset < numPresets) {
615                            // OpenSL ES EQ Effect presets
616                            equalizerEffect.usePreset(preset);
617                            value = equalizerEffect.getCurrentPreset();
618                        } else {
619                            final short[] eQPresetCIExtremeBandLevelDefault = Arrays.copyOf(
620                                    EQUALIZER_PRESET_CIEXTREME_BAND_LEVEL, numBands);
621                            final short[] eQPresetUserBandLevelDefault = Arrays.copyOf(
622                                    EQUALIZER_PRESET_USER_BAND_LEVEL_DEFAULT, numBands);
623                            // Set the band levels manually for custom presets
624                            for (short band = 0; band < numBands; band++) {
625                                short bandLevel = 0;
626                                if (preset == numPresets) {
627                                    // CI EXTREME
628                                    bandLevel = (short) prefs.getInt(
629                                            Key.eq_preset_ci_extreme_band_level.toString() + band,
630                                            eQPresetCIExtremeBandLevelDefault[band]);
631                                } else {
632                                    // User
633                                    bandLevel = (short) prefs.getInt(
634                                            Key.eq_preset_user_band_level.toString() + band,
635                                            eQPresetUserBandLevelDefault[band]);
636                                }
637                                equalizerEffect.setBandLevel(band, bandLevel);
638                            }
639                        }
640
641                        // update band levels
642                        for (short band = 0; band < numBands; band++) {
643                            final short level = equalizerEffect.getBandLevel(band);
644                            editor.putInt(Key.eq_band_level.toString() + band, level);
645                        }
646                    }
647                    break;
648                }
649                case eq_preset_user_band_level:
650                    // Fall through
651                case eq_preset_user_band_level_default:
652                    // Fall through
653                case eq_preset_ci_extreme_band_level: {
654                    if (arg1 == DUMMY_ARGUMENT) {
655                        throw new IllegalArgumentException("Dummy arg passed.");
656                    }
657                    final short band = (short) arg1;
658                    strKey = strKey + band;
659                    break;
660                }
661                case pr_current_preset:
662                    // XXX: Preset Reverb not used for the moment, so commented out the effect
663                    // creation to not use MIPS
664                    // final PresetReverb presetReverbEffect = getPresetReverbEffect(audioSession);
665                    // if (presetReverbEffect != null) {
666                    // presetReverbEffect.setPreset((short) value);
667                    // value = presetReverbEffect.getPreset();
668                    // }
669                    break;
670                default:
671                    Log.e(TAG, "setParameterInt: Unknown/unsupported key " + key);
672                    return;
673                }
674            } else {
675                switch (key) {
676                // Virtualizer
677                case virt_strength:
678                    // Do nothing
679                    break;
680                case virt_type:
681                    // Do nothing
682                    break;
683
684                // BassBoost
685                case bb_strength:
686                    // Do nothing
687                    break;
688
689                // Equalizer
690                case eq_band_level: {
691                    if (arg1 == DUMMY_ARGUMENT) {
692                        throw new IllegalArgumentException("Dummy arg passed.");
693                    }
694                    final short band = (short) arg1;
695                    strKey = strKey + band;
696
697                    editor.putInt(Key.eq_preset_user_band_level.toString() + band, value);
698                    break;
699                }
700                case eq_current_preset: {
701                    final short preset = (short) value;
702                    final int numBands = prefs.getInt(Key.eq_num_bands.toString(),
703                            EQUALIZER_NUMBER_BANDS_DEFAULT);
704                    final int numPresets = prefs.getInt(Key.eq_num_presets.toString(),
705                            EQUALIZER_NUMBER_PRESETS_DEFAULT);
706
707                    final short[][] eQPresetOpenSLESBandLevelDefault = Arrays.copyOf(
708                            EQUALIZER_PRESET_OPENSL_ES_BAND_LEVEL_DEFAULT, numBands);
709                    final short[] eQPresetCIExtremeBandLevelDefault = Arrays.copyOf(
710                            EQUALIZER_PRESET_CIEXTREME_BAND_LEVEL, numBands);
711                    final short[] eQPresetUserBandLevelDefault = Arrays.copyOf(
712                            EQUALIZER_PRESET_USER_BAND_LEVEL_DEFAULT, numBands);
713                    for (short band = 0; band < numBands; band++) {
714                        short bandLevel = 0;
715                        if (preset < numPresets) {
716                            // OpenSL ES EQ Effect presets
717                            bandLevel = (short) prefs.getInt(
718                                    Key.eq_preset_opensl_es_band_level.toString() + preset + "_"
719                                            + band, eQPresetOpenSLESBandLevelDefault[preset][band]);
720                        } else if (preset == numPresets) {
721                            // CI EXTREME
722                            bandLevel = (short) prefs.getInt(
723                                    Key.eq_preset_ci_extreme_band_level.toString() + band,
724                                    eQPresetCIExtremeBandLevelDefault[band]);
725                        } else {
726                            // User
727                            bandLevel = (short) prefs.getInt(
728                                    Key.eq_preset_user_band_level.toString() + band,
729                                    eQPresetUserBandLevelDefault[band]);
730                        }
731                        editor.putInt(Key.eq_band_level.toString() + band, bandLevel);
732                    }
733                    break;
734                }
735                case eq_preset_user_band_level:
736                    // Fall through
737                case eq_preset_user_band_level_default:
738                    // Fall through
739                case eq_preset_ci_extreme_band_level: {
740                    if (arg1 == DUMMY_ARGUMENT) {
741                        throw new IllegalArgumentException("Dummy arg passed.");
742                    }
743                    final short band = (short) arg1;
744                    strKey = strKey + band;
745                    break;
746                }
747                case pr_current_preset:
748                    // Do nothing
749                    break;
750                default:
751                    Log.e(TAG, "setParameterInt: Unknown/unsupported key " + key);
752                    return;
753                }
754            }
755
756            // Set preferences
757            editor.putInt(strKey, value);
758            editor.apply();
759
760        } catch (final RuntimeException e) {
761            Log.e(TAG, "setParameterInt: " + key + "; " + arg0 + "; " + arg1 + "; " + e);
762        }
763
764    }
765
766    /**
767     * Sets int parameter for given key and value arg
768     *
769     * @param context
770     * @param packageName
771     * @param audioSession
772     *            System wide unique audio session identifier.
773     * @param key
774     * @param arg
775     */
776    public static void setParameterInt(final Context context, final String packageName,
777            final int audioSession, final Key key, final int arg) {
778        setParameterInt(context, packageName, audioSession, key, arg, DUMMY_ARGUMENT);
779    }
780
781    /**
782     * Gets int parameter given key
783     *
784     * @param context
785     * @param packageName
786     * @param audioSession
787     *            System wide unique audio session identifier.
788     * @param key
789     * @return parameter value
790     */
791    public static int getParameterInt(final Context context, final String packageName,
792            final int audioSession, final String key) {
793        int value = 0;
794
795        try {
796            final SharedPreferences prefs = context.getSharedPreferences(packageName,
797                    Context.MODE_PRIVATE);
798            value = prefs.getInt(key, value);
799        } catch (final RuntimeException e) {
800            Log.e(TAG, "getParameterInt: " + key + "; " + e);
801        }
802
803        return value;
804    }
805
806    /**
807     * Gets int parameter given key
808     *
809     * @param context
810     * @param packageName
811     * @param audioSession
812     *            System wide unique audio session identifier.
813     * @param key
814     * @return parameter value
815     */
816    public static int getParameterInt(final Context context, final String packageName,
817            final int audioSession, final Key key) {
818        return getParameterInt(context, packageName, audioSession, key.toString());
819    }
820
821    /**
822     * Gets int parameter given key and arg
823     *
824     * @param context
825     * @param packageName
826     * @param audioSession
827     *            System wide unique audio session identifier.
828     * @param audioSession
829     * @param key
830     * @param arg
831     * @return parameter value
832     */
833    public static int getParameterInt(final Context context, final String packageName,
834            final int audioSession, final Key key, final int arg) {
835        return getParameterInt(context, packageName, audioSession, key.toString() + arg);
836    }
837
838    /**
839     * Gets int parameter given key, arg0 and arg1
840     *
841     * @param context
842     * @param packageName
843     * @param audioSession
844     *            System wide unique audio session identifier.
845     * @param audioSession
846     * @param key
847     * @param arg0
848     * @param arg1
849     * @return parameter value
850     */
851    public static int getParameterInt(final Context context, final String packageName,
852            final int audioSession, final Key key, final int arg0, final int arg1) {
853        return getParameterInt(context, packageName, audioSession, key.toString() + arg0 + "_"
854                + arg1);
855    }
856
857    /**
858     * Gets integer array parameter given key. Returns null if not found.
859     *
860     * @param context
861     * @param packageName
862     * @param audioSession
863     *            System wide unique audio session identifier.
864     * @param key
865     * @return parameter value array
866     */
867    public static int[] getParameterIntArray(final Context context, final String packageName,
868            final int audioSession, final Key key) {
869        final SharedPreferences prefs = context.getSharedPreferences(packageName,
870                Context.MODE_PRIVATE);
871
872        int[] intArray = null;
873        try {
874            // Get effect parameters
875            switch (key) {
876            case eq_level_range: {
877                intArray = new int[2];
878                break;
879            }
880            case eq_center_freq:
881                // Fall through
882            case eq_band_level:
883                // Fall through
884            case eq_preset_user_band_level:
885                // Fall through
886            case eq_preset_user_band_level_default:
887                // Fall through
888            case eq_preset_ci_extreme_band_level: {
889                final int numBands = prefs.getInt(Key.eq_num_bands.toString(), 0);
890                intArray = new int[numBands];
891                break;
892            }
893            default:
894                Log.e(TAG, "getParameterIntArray: Unknown/unsupported key " + key);
895                return null;
896            }
897
898            for (int i = 0; i < intArray.length; i++) {
899                intArray[i] = prefs.getInt(key.toString() + i, 0);
900            }
901
902        } catch (final RuntimeException e) {
903            Log.e(TAG, "getParameterIntArray: " + key + "; " + e);
904        }
905
906        return intArray;
907    }
908
909    /**
910     * Gets string parameter given key. Returns empty string if not found.
911     *
912     * @param context
913     * @param packageName
914     * @param audioSession
915     *            System wide unique audio session identifier.
916     * @param key
917     * @return parameter value
918     */
919    public static String getParameterString(final Context context, final String packageName,
920            final int audioSession, final String key) {
921        String value = "";
922        try {
923            final SharedPreferences prefs = context.getSharedPreferences(packageName,
924                    Context.MODE_PRIVATE);
925
926            // Get effect parameters
927            value = prefs.getString(key, value);
928
929        } catch (final RuntimeException e) {
930            Log.e(TAG, "getParameterString: " + key + "; " + e);
931        }
932
933        return value;
934    }
935
936    /**
937     * Gets string parameter given key.
938     *
939     * @param context
940     * @param packageName
941     * @param audioSession
942     *            System wide unique audio session identifier.
943     * @param key
944     * @return parameter value
945     */
946    public static String getParameterString(final Context context, final String packageName,
947            final int audioSession, final Key key) {
948        return getParameterString(context, packageName, audioSession, key.toString());
949    }
950
951    /**
952     * Gets string parameter given key and arg.
953     *
954     * @param context
955     * @param packageName
956     * @param audioSession
957     *            System wide unique audio session identifier.
958     * @param args
959     * @return parameter value
960     */
961    public static String getParameterString(final Context context, final String packageName,
962            final int audioSession, final Key key, final int arg) {
963        return getParameterString(context, packageName, audioSession, key.toString() + arg);
964    }
965
966    /**
967     * Opens/initializes the effects session for the given audio session with preferences linked to
968     * the given package name and context.
969     *
970     * @param context
971     * @param packageName
972     * @param audioSession
973     *            System wide unique audio session identifier.
974     */
975    public static void openSession(final Context context, final String packageName,
976            final int audioSession) {
977        Log.v(TAG, "openSession(" + context + ", " + packageName + ", " + audioSession + ")");
978        final String methodTag = "openSession: ";
979
980        // init preferences
981        final SharedPreferences prefs = context.getSharedPreferences(packageName,
982                Context.MODE_PRIVATE);
983        final SharedPreferences.Editor editor = prefs.edit();
984
985        final boolean isGlobalEnabled = prefs.getBoolean(Key.global_enabled.toString(),
986                GLOBAL_ENABLED_DEFAULT);
987        editor.putBoolean(Key.global_enabled.toString(), isGlobalEnabled);
988
989        if (!isGlobalEnabled) {
990            return;
991        }
992
993        // Manage audioSession information
994
995        // Retrieve AudioSession Id from map
996        boolean isExistingAudioSession = false;
997
998        try {
999            final Integer currentAudioSession = mPackageSessions.putIfAbsent(packageName,
1000                    audioSession);
1001            if (currentAudioSession != null) {
1002                // Compare with passed argument
1003                if (currentAudioSession == audioSession) {
1004                    // FIXME: Normally, we should exit the function here
1005                    // BUT: we have to take care of the virtualizer because of
1006                    // a bug in the Android Effects Framework
1007                    // editor.commit();
1008                    // return;
1009                    isExistingAudioSession = true;
1010                } else {
1011                    closeSession(context, packageName, currentAudioSession);
1012                }
1013            }
1014        } catch (final NullPointerException e) {
1015            Log.e(TAG, methodTag + e);
1016            editor.commit();
1017            return;
1018        }
1019
1020        // Because the audioSession is new, get effects & settings from shared preferences
1021
1022        // Virtualizer
1023        // create effect
1024        final Virtualizer virtualizerEffect = getVirtualizerEffect(audioSession);
1025        {
1026            final String errorTag = methodTag + "Virtualizer error: ";
1027
1028            try {
1029                // read parameters
1030                final boolean isEnabled = prefs.getBoolean(Key.virt_enabled.toString(),
1031                        VIRTUALIZER_ENABLED_DEFAULT);
1032                int defaultstrength = isExistingAudioSession ? VIRTUALIZER_STRENGTH_DEFAULT :
1033                    virtualizerEffect.getRoundedStrength();
1034                final int strength = prefs.getInt(Key.virt_strength.toString(), defaultstrength);
1035                // init settings
1036                Virtualizer.Settings settings = new Virtualizer.Settings("Virtualizer;strength="
1037                        + strength);
1038
1039                virtualizerEffect.setProperties(settings);
1040
1041                // set parameters
1042                if (isGlobalEnabled == true) {
1043                    virtualizerEffect.setEnabled(isEnabled);
1044                } else {
1045                    virtualizerEffect.setEnabled(false);
1046                }
1047
1048                // get parameters
1049                settings = virtualizerEffect.getProperties();
1050                Log.v(TAG, "Parameters: " + settings.toString() + ";enabled=" + isEnabled);
1051
1052                // update preferences
1053                editor.putBoolean(Key.virt_enabled.toString(), isEnabled);
1054                editor.putInt(Key.virt_strength.toString(), settings.strength);
1055            } catch (final RuntimeException e) {
1056                Log.e(TAG, errorTag + e);
1057            }
1058        }
1059
1060        // In case of an existing audio session
1061        // Exit after the virtualizer has been re-enabled
1062
1063        if (isExistingAudioSession) {
1064            editor.apply();
1065            return;
1066        }
1067
1068        // BassBoost
1069        // create effect
1070        final BassBoost bassBoostEffect = getBassBoostEffect(audioSession);
1071        {
1072            final String errorTag = methodTag + "BassBoost error: ";
1073
1074            try {
1075                // read parameters
1076                final boolean isEnabled = prefs.getBoolean(Key.bb_enabled.toString(),
1077                        BASS_BOOST_ENABLED_DEFAULT);
1078                final int strength = prefs.getInt(Key.bb_strength.toString(),
1079                        BASS_BOOST_STRENGTH_DEFAULT);
1080
1081                // init settings
1082                BassBoost.Settings settings = new BassBoost.Settings("BassBoost;strength="
1083                        + strength);
1084
1085                bassBoostEffect.setProperties(settings);
1086
1087                // set parameters
1088                if (isGlobalEnabled == true) {
1089                    bassBoostEffect.setEnabled(isEnabled);
1090                } else {
1091                    bassBoostEffect.setEnabled(false);
1092                }
1093
1094                // get parameters
1095                settings = bassBoostEffect.getProperties();
1096                Log.v(TAG, "Parameters: " + settings.toString() + ";enabled=" + isEnabled);
1097
1098                // update preferences
1099                editor.putBoolean(Key.bb_enabled.toString(), isEnabled);
1100                editor.putInt(Key.bb_strength.toString(), settings.strength);
1101            } catch (final RuntimeException e) {
1102                Log.e(TAG, errorTag + e);
1103            }
1104        }
1105
1106        // Equalizer
1107        // create effect
1108        final Equalizer equalizerEffect = getEqualizerEffect(audioSession);
1109        {
1110            final String errorTag = methodTag + "Equalizer error: ";
1111
1112            try {
1113                final short eQNumBands;
1114                final short[] bandLevel;
1115                final int[] eQCenterFreq;
1116                final short eQNumPresets;
1117                final String[] eQPresetNames;
1118                short eQPreset;
1119                synchronized (mEQInitLock) {
1120                    // read parameters
1121                    mEQBandLevelRange = equalizerEffect.getBandLevelRange();
1122                    mEQNumBands = equalizerEffect.getNumberOfBands();
1123                    mEQCenterFreq = new int[mEQNumBands];
1124                    mEQNumPresets = equalizerEffect.getNumberOfPresets();
1125                    mEQPresetNames = new String[mEQNumPresets];
1126
1127                    for (short preset = 0; preset < mEQNumPresets; preset++) {
1128                        mEQPresetNames[preset] = equalizerEffect.getPresetName(preset);
1129                        editor.putString(Key.eq_preset_name.toString() + preset,
1130                                mEQPresetNames[preset]);
1131                    }
1132
1133                    editor.putInt(Key.eq_level_range.toString() + 0, mEQBandLevelRange[0]);
1134                    editor.putInt(Key.eq_level_range.toString() + 1, mEQBandLevelRange[1]);
1135                    editor.putInt(Key.eq_num_bands.toString(), mEQNumBands);
1136                    editor.putInt(Key.eq_num_presets.toString(), mEQNumPresets);
1137                    // Resetting the EQ arrays depending on the real # bands with defaults if band <
1138                    // default size else 0 by copying default arrays over new ones
1139                    final short[] eQPresetCIExtremeBandLevel = Arrays.copyOf(
1140                            EQUALIZER_PRESET_CIEXTREME_BAND_LEVEL, mEQNumBands);
1141                    final short[] eQPresetUserBandLevelDefault = Arrays.copyOf(
1142                            EQUALIZER_PRESET_USER_BAND_LEVEL_DEFAULT, mEQNumBands);
1143                    // If no preset prefs set use CI EXTREME (= numPresets)
1144                    eQPreset = (short) prefs
1145                            .getInt(Key.eq_current_preset.toString(), mEQNumPresets);
1146                    if (eQPreset < mEQNumPresets) {
1147                        // OpenSL ES effect presets
1148                        equalizerEffect.usePreset(eQPreset);
1149                        eQPreset = equalizerEffect.getCurrentPreset();
1150                    } else {
1151                        for (short band = 0; band < mEQNumBands; band++) {
1152                            short level = 0;
1153                            if (eQPreset == mEQNumPresets) {
1154                                // CI EXTREME
1155                                level = eQPresetCIExtremeBandLevel[band];
1156                            } else {
1157                                // User
1158                                level = (short) prefs.getInt(
1159                                        Key.eq_preset_user_band_level.toString() + band,
1160                                        eQPresetUserBandLevelDefault[band]);
1161                            }
1162                            equalizerEffect.setBandLevel(band, level);
1163                        }
1164                    }
1165                    editor.putInt(Key.eq_current_preset.toString(), eQPreset);
1166
1167                    bandLevel = new short[mEQNumBands];
1168                    for (short band = 0; band < mEQNumBands; band++) {
1169                        mEQCenterFreq[band] = equalizerEffect.getCenterFreq(band);
1170                        bandLevel[band] = equalizerEffect.getBandLevel(band);
1171
1172                        editor.putInt(Key.eq_band_level.toString() + band, bandLevel[band]);
1173                        editor.putInt(Key.eq_center_freq.toString() + band, mEQCenterFreq[band]);
1174                        editor.putInt(Key.eq_preset_ci_extreme_band_level.toString() + band,
1175                                eQPresetCIExtremeBandLevel[band]);
1176                        editor.putInt(Key.eq_preset_user_band_level_default.toString() + band,
1177                                eQPresetUserBandLevelDefault[band]);
1178                    }
1179
1180                    eQNumBands = mEQNumBands;
1181                    eQCenterFreq = mEQCenterFreq;
1182                    eQNumPresets = mEQNumPresets;
1183                    eQPresetNames = mEQPresetNames;
1184                }
1185
1186                final boolean isEnabled = prefs.getBoolean(Key.eq_enabled.toString(),
1187                        EQUALIZER_ENABLED_DEFAULT);
1188                editor.putBoolean(Key.eq_enabled.toString(), isEnabled);
1189                if (isGlobalEnabled == true) {
1190                    equalizerEffect.setEnabled(isEnabled);
1191                } else {
1192                    equalizerEffect.setEnabled(false);
1193                }
1194
1195                // dump
1196                Log.v(TAG, "Parameters: Equalizer");
1197                Log.v(TAG, "bands=" + eQNumBands);
1198                String str = "levels=";
1199                for (short band = 0; band < eQNumBands; band++) {
1200                    str = str + bandLevel[band] + "; ";
1201                }
1202                Log.v(TAG, str);
1203                str = "center=";
1204                for (short band = 0; band < eQNumBands; band++) {
1205                    str = str + eQCenterFreq[band] + "; ";
1206                }
1207                Log.v(TAG, str);
1208                str = "presets=";
1209                for (short preset = 0; preset < eQNumPresets; preset++) {
1210                    str = str + eQPresetNames[preset] + "; ";
1211                }
1212                Log.v(TAG, str);
1213                Log.v(TAG, "current=" + eQPreset);
1214            } catch (final RuntimeException e) {
1215                Log.e(TAG, errorTag + e);
1216            }
1217        }
1218
1219        // XXX: Preset Reverb not used for the moment, so commented out the effect creation to not
1220        // use MIPS left in the code for (future) reference.
1221        // Preset reverb
1222        // create effect
1223        // final PresetReverb presetReverbEffect = getPresetReverbEffect(audioSession);
1224        // {
1225        // final String errorTag = methodTag + "PresetReverb error: ";
1226        //
1227        // try {
1228        // // read parameters
1229        // final boolean isEnabled = prefs.getBoolean(Key.pr_enabled.toString(),
1230        // PRESET_REVERB_ENABLED_DEFAULT);
1231        // final short preset = (short) prefs.getInt(Key.pr_current_preset.toString(),
1232        // PRESET_REVERB_CURRENT_PRESET_DEFAULT);
1233        //
1234        // // init settings
1235        // PresetReverb.Settings settings = new PresetReverb.Settings("PresetReverb;preset="
1236        // + preset);
1237        //
1238        // // read/update preferences
1239        // presetReverbEffect.setProperties(settings);
1240        //
1241        // // set parameters
1242        // if (isGlobalEnabled == true) {
1243        // presetReverbEffect.setEnabled(isEnabled);
1244        // } else {
1245        // presetReverbEffect.setEnabled(false);
1246        // }
1247        //
1248        // // get parameters
1249        // settings = presetReverbEffect.getProperties();
1250        // Log.v(TAG, "Parameters: " + settings.toString() + ";enabled=" + isEnabled);
1251        //
1252        // // update preferences
1253        // editor.putBoolean(Key.pr_enabled.toString(), isEnabled);
1254        // editor.putInt(Key.pr_current_preset.toString(), settings.preset);
1255        // } catch (final RuntimeException e) {
1256        // Log.e(TAG, errorTag + e);
1257        // }
1258        // }
1259        editor.commit();
1260    }
1261
1262    /**
1263     * Closes the audio session (release effects) for the given session
1264     *
1265     * @param context
1266     * @param packageName
1267     * @param audioSession
1268     *            System wide unique audio session identifier.
1269     */
1270    public static void closeSession(final Context context, final String packageName,
1271            final int audioSession) {
1272        Log.v(TAG, "closeSession(" + context + ", " + packageName + ", " + audioSession + ")");
1273
1274        // PresetReverb
1275        final PresetReverb presetReverb = mPresetReverbInstances.remove(audioSession);
1276        if (presetReverb != null) {
1277            presetReverb.release();
1278        }
1279        // Equalizer
1280        final Equalizer equalizer = mEQInstances.remove(audioSession);
1281        if (equalizer != null) {
1282            equalizer.release();
1283        }
1284        // BassBoost
1285        final BassBoost bassBoost = mBassBoostInstances.remove(audioSession);
1286        if (bassBoost != null) {
1287            bassBoost.release();
1288        }
1289        // Virtualizer
1290        final Virtualizer virtualizer = mVirtualizerInstances.remove(audioSession);
1291        if (virtualizer != null) {
1292            virtualizer.release();
1293        }
1294
1295        mPackageSessions.remove(packageName);
1296    }
1297
1298    /**
1299     * Enables or disables all effects (global enable/disable) for a given context, package name and
1300     * audio session. It sets/inits the control mode and preferences and then sets the global
1301     * enabled parameter.
1302     *
1303     * @param context
1304     * @param packageName
1305     * @param audioSession
1306     *            System wide unique audio session identifier.
1307     * @param enabled
1308     */
1309    public static void setEnabledAll(final Context context, final String packageName,
1310            final int audioSession, final boolean enabled) {
1311        initEffectsPreferences(context, packageName, audioSession);
1312        setParameterBoolean(context, packageName, audioSession, Key.global_enabled, enabled);
1313    }
1314
1315    /**
1316     * Gets the virtualizer effect for the given audio session. If the effect on the session doesn't
1317     * exist yet, create it and add to collection.
1318     *
1319     * @param audioSession
1320     *            System wide unique audio session identifier.
1321     * @return virtualizerEffect
1322     */
1323    private static Virtualizer getVirtualizerEffectNoCreate(final int audioSession) {
1324        return mVirtualizerInstances.get(audioSession);
1325    }
1326    private static Virtualizer getVirtualizerEffect(final int audioSession) {
1327        Virtualizer virtualizerEffect = getVirtualizerEffectNoCreate(audioSession);
1328        if (virtualizerEffect == null) {
1329            try {
1330                final Virtualizer newVirtualizerEffect = new Virtualizer(PRIORITY, audioSession);
1331                virtualizerEffect = mVirtualizerInstances.putIfAbsent(audioSession,
1332                        newVirtualizerEffect);
1333                if (virtualizerEffect == null) {
1334                    // put succeeded, use new value
1335                    virtualizerEffect = newVirtualizerEffect;
1336                }
1337            } catch (final IllegalArgumentException e) {
1338                Log.e(TAG, "Virtualizer: " + e);
1339            } catch (final UnsupportedOperationException e) {
1340                Log.e(TAG, "Virtualizer: " + e);
1341            } catch (final RuntimeException e) {
1342                Log.e(TAG, "Virtualizer: " + e);
1343            }
1344        }
1345        return virtualizerEffect;
1346    }
1347
1348    /**
1349     * Gets the bass boost effect for the given audio session. If the effect on the session doesn't
1350     * exist yet, create it and add to collection.
1351     *
1352     * @param audioSession
1353     *            System wide unique audio session identifier.
1354     * @return bassBoostEffect
1355     */
1356    private static BassBoost getBassBoostEffectNoCreate(final int audioSession) {
1357        return mBassBoostInstances.get(audioSession);
1358    }
1359    private static BassBoost getBassBoostEffect(final int audioSession) {
1360
1361        BassBoost bassBoostEffect = getBassBoostEffectNoCreate(audioSession);
1362        if (bassBoostEffect == null) {
1363            try {
1364                final BassBoost newBassBoostEffect = new BassBoost(PRIORITY, audioSession);
1365                bassBoostEffect = mBassBoostInstances.putIfAbsent(audioSession, newBassBoostEffect);
1366                if (bassBoostEffect == null) {
1367                    // put succeeded, use new value
1368                    bassBoostEffect = newBassBoostEffect;
1369                }
1370            } catch (final IllegalArgumentException e) {
1371                Log.e(TAG, "BassBoost: " + e);
1372            } catch (final UnsupportedOperationException e) {
1373                Log.e(TAG, "BassBoost: " + e);
1374            } catch (final RuntimeException e) {
1375                Log.e(TAG, "BassBoost: " + e);
1376            }
1377        }
1378        return bassBoostEffect;
1379    }
1380
1381    /**
1382     * Gets the equalizer effect for the given audio session. If the effect on the session doesn't
1383     * exist yet, create it and add to collection.
1384     *
1385     * @param audioSession
1386     *            System wide unique audio session identifier.
1387     * @return equalizerEffect
1388     */
1389    private static Equalizer getEqualizerEffectNoCreate(final int audioSession) {
1390        return mEQInstances.get(audioSession);
1391    }
1392    private static Equalizer getEqualizerEffect(final int audioSession) {
1393        Equalizer equalizerEffect = getEqualizerEffectNoCreate(audioSession);
1394        if (equalizerEffect == null) {
1395            try {
1396                final Equalizer newEqualizerEffect = new Equalizer(PRIORITY, audioSession);
1397                equalizerEffect = mEQInstances.putIfAbsent(audioSession, newEqualizerEffect);
1398                if (equalizerEffect == null) {
1399                    // put succeeded, use new value
1400                    equalizerEffect = newEqualizerEffect;
1401                }
1402            } catch (final IllegalArgumentException e) {
1403                Log.e(TAG, "Equalizer: " + e);
1404            } catch (final UnsupportedOperationException e) {
1405                Log.e(TAG, "Equalizer: " + e);
1406            } catch (final RuntimeException e) {
1407                Log.e(TAG, "Equalizer: " + e);
1408            }
1409        }
1410        return equalizerEffect;
1411    }
1412
1413    // XXX: Preset Reverb not used for the moment, so commented out the effect creation to not
1414    // use MIPS
1415    // /**
1416    // * Gets the preset reverb effect for the given audio session. If the effect on the session
1417    // * doesn't exist yet, create it and add to collection.
1418    // *
1419    // * @param audioSession
1420    // * System wide unique audio session identifier.
1421    // * @return presetReverbEffect
1422    // */
1423    // private static PresetReverb getPresetReverbEffect(final int audioSession) {
1424    // PresetReverb presetReverbEffect = mPresetReverbInstances.get(audioSession);
1425    // if (presetReverbEffect == null) {
1426    // try {
1427    // final PresetReverb newPresetReverbEffect = new PresetReverb(PRIORITY, audioSession);
1428    // presetReverbEffect = mPresetReverbInstances.putIfAbsent(audioSession,
1429    // newPresetReverbEffect);
1430    // if (presetReverbEffect == null) {
1431    // // put succeeded, use new value
1432    // presetReverbEffect = newPresetReverbEffect;
1433    // }
1434    // } catch (final IllegalArgumentException e) {
1435    // Log.e(TAG, "PresetReverb: " + e);
1436    // } catch (final UnsupportedOperationException e) {
1437    // Log.e(TAG, "PresetReverb: " + e);
1438    // } catch (final RuntimeException e) {
1439    // Log.e(TAG, "PresetReverb: " + e);
1440    // }
1441    // }
1442    // return presetReverbEffect;
1443    // }
1444}
1445