blob: db46c3ee51d730d7925d6a5386c64437e47c59c8 [file] [log] [blame]
/*
* Copyright (C) 2010-2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.musicfx;
import android.content.Context;
import android.content.SharedPreferences;
import android.media.MediaPlayer;
import android.media.audiofx.AudioEffect;
import android.media.audiofx.BassBoost;
import android.media.audiofx.Equalizer;
import android.media.audiofx.PresetReverb;
import android.media.audiofx.Virtualizer;
import android.util.Log;
import java.util.Arrays;
import java.util.concurrent.ConcurrentHashMap;
/**
* The Common class defines constants to be used by the control panels.
*/
public class ControlPanelEffect {
private final static String TAG = "MusicFXControlPanelEffect";
/**
* Audio session priority
*/
private static final int PRIORITY = 0;
/**
* The control mode specifies if control panel updates effects and preferences or only
* preferences.
*/
static enum ControlMode {
/**
* Control panel updates effects and preferences. Applicable when audio session is delivered
* by user.
*/
CONTROL_EFFECTS,
/**
* Control panel only updates preferences. Applicable when there was no audio or invalid
* session provided by user.
*/
CONTROL_PREFERENCES
}
static enum Key {
global_enabled, virt_enabled, virt_strength, virt_type, bb_enabled, bb_strength, te_enabled, te_strength, avl_enabled, lm_enabled, lm_strength, eq_enabled, eq_num_bands, eq_level_range, eq_center_freq, eq_band_level, eq_num_presets, eq_preset_name, eq_preset_user_band_level, eq_preset_user_band_level_default, eq_preset_opensl_es_band_level, eq_preset_ci_extreme_band_level, eq_current_preset, pr_enabled, pr_current_preset
}
// Effect/audio session Mappings
/**
* Hashmap initial capacity
*/
private static final int HASHMAP_INITIAL_CAPACITY = 16;
/**
* Hashmap load factor
*/
private static final float HASHMAP_LOAD_FACTOR = 0.75f;
/**
* ConcurrentHashMap concurrency level
*/
private static final int HASHMAP_CONCURRENCY_LEVEL = 2;
/**
* Map containing the Virtualizer audio session, effect mappings.
*/
private static final ConcurrentHashMap<Integer, Virtualizer> mVirtualizerInstances = new ConcurrentHashMap<Integer, Virtualizer>(
HASHMAP_INITIAL_CAPACITY, HASHMAP_LOAD_FACTOR, HASHMAP_CONCURRENCY_LEVEL);
/**
* Map containing the BB audio session, effect mappings.
*/
private static final ConcurrentHashMap<Integer, BassBoost> mBassBoostInstances = new ConcurrentHashMap<Integer, BassBoost>(
HASHMAP_INITIAL_CAPACITY, HASHMAP_LOAD_FACTOR, HASHMAP_CONCURRENCY_LEVEL);
/**
* Map containing the EQ audio session, effect mappings.
*/
private static final ConcurrentHashMap<Integer, Equalizer> mEQInstances = new ConcurrentHashMap<Integer, Equalizer>(
HASHMAP_INITIAL_CAPACITY, HASHMAP_LOAD_FACTOR, HASHMAP_CONCURRENCY_LEVEL);
/**
* Map containing the PR audio session, effect mappings.
*/
private static final ConcurrentHashMap<Integer, PresetReverb> mPresetReverbInstances = new ConcurrentHashMap<Integer, PresetReverb>(
HASHMAP_INITIAL_CAPACITY, HASHMAP_LOAD_FACTOR, HASHMAP_CONCURRENCY_LEVEL);
/**
* Map containing the package name, audio session mappings.
*/
private static final ConcurrentHashMap<String, Integer> mPackageSessions = new ConcurrentHashMap<String, Integer>(
HASHMAP_INITIAL_CAPACITY, HASHMAP_LOAD_FACTOR, HASHMAP_CONCURRENCY_LEVEL);
// Defaults
final static boolean GLOBAL_ENABLED_DEFAULT = false;
private final static boolean VIRTUALIZER_ENABLED_DEFAULT = true;
private final static int VIRTUALIZER_STRENGTH_DEFAULT = 1000;
private final static boolean BASS_BOOST_ENABLED_DEFAULT = true;
private final static int BASS_BOOST_STRENGTH_DEFAULT = 667;
private final static boolean PRESET_REVERB_ENABLED_DEFAULT = false;
private final static int PRESET_REVERB_CURRENT_PRESET_DEFAULT = 0; // None
// EQ defaults
private final static boolean EQUALIZER_ENABLED_DEFAULT = true;
private final static String EQUALIZER_PRESET_NAME_DEFAULT = "Preset";
private final static short EQUALIZER_NUMBER_BANDS_DEFAULT = 5;
private final static short EQUALIZER_NUMBER_PRESETS_DEFAULT = 0;
private final static short[] EQUALIZER_BAND_LEVEL_RANGE_DEFAULT = { -1500, 1500 };
private final static int[] EQUALIZER_CENTER_FREQ_DEFAULT = { 60000, 230000, 910000, 3600000,
14000000 };
private final static short[] EQUALIZER_PRESET_CIEXTREME_BAND_LEVEL = { 0, 800, 400, 100, 1000 };
private final static short[] EQUALIZER_PRESET_USER_BAND_LEVEL_DEFAULT = { 0, 0, 0, 0, 0 };
private final static short[][] EQUALIZER_PRESET_OPENSL_ES_BAND_LEVEL_DEFAULT = new short[EQUALIZER_NUMBER_PRESETS_DEFAULT][EQUALIZER_NUMBER_BANDS_DEFAULT];
// EQ effect properties which are invariable over all EQ effects sessions
private static short[] mEQBandLevelRange = EQUALIZER_BAND_LEVEL_RANGE_DEFAULT;
private static short mEQNumBands = EQUALIZER_NUMBER_BANDS_DEFAULT;
private static int[] mEQCenterFreq = EQUALIZER_CENTER_FREQ_DEFAULT;
private static short mEQNumPresets = EQUALIZER_NUMBER_PRESETS_DEFAULT;
private static short[][] mEQPresetOpenSLESBandLevel = EQUALIZER_PRESET_OPENSL_ES_BAND_LEVEL_DEFAULT;
private static String[] mEQPresetNames;
private static boolean mIsEQInitialized = false;
private final static Object mEQInitLock = new Object();
/**
* Default int argument used in methods to see that the arg is a dummy. Used for method
* overloading.
*/
private final static int DUMMY_ARGUMENT = -1;
/**
* Inits effects preferences for the given context and package name in the control panel. If
* preferences for the given package name don't exist, they are created and initialized.
*
* @param context
* @param packageName
* @param audioSession
* System wide unique audio session identifier.
*/
public static void initEffectsPreferences(final Context context, final String packageName,
final int audioSession) {
final SharedPreferences prefs = context.getSharedPreferences(packageName,
Context.MODE_PRIVATE);
final SharedPreferences.Editor editor = prefs.edit();
final ControlMode controlMode = getControlMode(audioSession);
// init preferences
try {
// init global on/off switch
final boolean isGlobalEnabled = prefs.getBoolean(Key.global_enabled.toString(),
GLOBAL_ENABLED_DEFAULT);
editor.putBoolean(Key.global_enabled.toString(), isGlobalEnabled);
Log.v(TAG, "isGlobalEnabled = " + isGlobalEnabled);
// Virtualizer
final boolean isVIEnabled = prefs.getBoolean(Key.virt_enabled.toString(),
VIRTUALIZER_ENABLED_DEFAULT);
final int vIStrength = prefs.getInt(Key.virt_strength.toString(),
VIRTUALIZER_STRENGTH_DEFAULT);
editor.putBoolean(Key.virt_enabled.toString(), isVIEnabled);
editor.putInt(Key.virt_strength.toString(), vIStrength);
// BassBoost
final boolean isBBEnabled = prefs.getBoolean(Key.bb_enabled.toString(),
BASS_BOOST_ENABLED_DEFAULT);
final int bBStrength = prefs.getInt(Key.bb_strength.toString(),
BASS_BOOST_STRENGTH_DEFAULT);
editor.putBoolean(Key.bb_enabled.toString(), isBBEnabled);
editor.putInt(Key.bb_strength.toString(), bBStrength);
// Equalizer
synchronized (mEQInitLock) {
// If EQ is not initialized already create "dummy" audio session created by
// MediaPlayer and create effect on it to retrieve the invariable EQ properties
if (!mIsEQInitialized) {
final MediaPlayer mediaPlayer = new MediaPlayer();
final int session = mediaPlayer.getAudioSessionId();
Equalizer equalizerEffect = null;
try {
Log.d(TAG, "Creating dummy EQ effect on session " + session);
equalizerEffect = new Equalizer(PRIORITY, session);
mEQBandLevelRange = equalizerEffect.getBandLevelRange();
mEQNumBands = equalizerEffect.getNumberOfBands();
mEQCenterFreq = new int[mEQNumBands];
for (short band = 0; band < mEQNumBands; band++) {
mEQCenterFreq[band] = equalizerEffect.getCenterFreq(band);
}
mEQNumPresets = equalizerEffect.getNumberOfPresets();
mEQPresetNames = new String[mEQNumPresets];
mEQPresetOpenSLESBandLevel = new short[mEQNumPresets][mEQNumBands];
for (short preset = 0; preset < mEQNumPresets; preset++) {
mEQPresetNames[preset] = equalizerEffect.getPresetName(preset);
equalizerEffect.usePreset(preset);
for (short band = 0; band < mEQNumBands; band++) {
mEQPresetOpenSLESBandLevel[preset][band] = equalizerEffect
.getBandLevel(band);
}
}
mIsEQInitialized = true;
} catch (final IllegalStateException e) {
Log.e(TAG, "Equalizer: " + e);
} catch (final IllegalArgumentException e) {
Log.e(TAG, "Equalizer: " + e);
} catch (final UnsupportedOperationException e) {
Log.e(TAG, "Equalizer: " + e);
} catch (final RuntimeException e) {
Log.e(TAG, "Equalizer: " + e);
} finally {
if (equalizerEffect != null) {
Log.d(TAG, "Releasing dummy EQ effect");
equalizerEffect.release();
}
mediaPlayer.release();
// When there was a failure set some good defaults
if (!mIsEQInitialized) {
mEQPresetOpenSLESBandLevel = new short[mEQNumPresets][mEQNumBands];
for (short preset = 0; preset < mEQNumPresets; preset++) {
// Init preset names to a dummy name
mEQPresetNames[preset] = prefs.getString(
Key.eq_preset_name.toString() + preset,
EQUALIZER_PRESET_NAME_DEFAULT + preset);
if (preset < EQUALIZER_PRESET_OPENSL_ES_BAND_LEVEL_DEFAULT.length) {
mEQPresetOpenSLESBandLevel[preset] = Arrays.copyOf(
EQUALIZER_PRESET_OPENSL_ES_BAND_LEVEL_DEFAULT[preset],
mEQNumBands);
}
}
}
}
}
editor.putInt(Key.eq_level_range.toString() + 0, mEQBandLevelRange[0]);
editor.putInt(Key.eq_level_range.toString() + 1, mEQBandLevelRange[1]);
editor.putInt(Key.eq_num_bands.toString(), mEQNumBands);
editor.putInt(Key.eq_num_presets.toString(), mEQNumPresets);
// Resetting the EQ arrays depending on the real # bands with defaults if
// band < default size else 0 by copying default arrays over new ones
final short[] eQPresetCIExtremeBandLevel = Arrays.copyOf(
EQUALIZER_PRESET_CIEXTREME_BAND_LEVEL, mEQNumBands);
final short[] eQPresetUserBandLevelDefault = Arrays.copyOf(
EQUALIZER_PRESET_USER_BAND_LEVEL_DEFAULT, mEQNumBands);
// If no preset prefs set use CI EXTREME (= numPresets)
final short eQPreset = (short) prefs.getInt(Key.eq_current_preset.toString(),
mEQNumPresets);
editor.putInt(Key.eq_current_preset.toString(), eQPreset);
final short[] bandLevel = new short[mEQNumBands];
for (short band = 0; band < mEQNumBands; band++) {
if (controlMode == ControlMode.CONTROL_PREFERENCES) {
if (eQPreset < mEQNumPresets) {
// OpenSL ES effect presets
bandLevel[band] = mEQPresetOpenSLESBandLevel[eQPreset][band];
} else if (eQPreset == mEQNumPresets) {
// CI EXTREME
bandLevel[band] = eQPresetCIExtremeBandLevel[band];
} else {
// User
bandLevel[band] = (short) prefs.getInt(
Key.eq_preset_user_band_level.toString() + band,
eQPresetUserBandLevelDefault[band]);
}
editor.putInt(Key.eq_band_level.toString() + band, bandLevel[band]);
}
editor.putInt(Key.eq_center_freq.toString() + band, mEQCenterFreq[band]);
editor.putInt(Key.eq_preset_ci_extreme_band_level.toString() + band,
eQPresetCIExtremeBandLevel[band]);
editor.putInt(Key.eq_preset_user_band_level_default.toString() + band,
eQPresetUserBandLevelDefault[band]);
}
for (short preset = 0; preset < mEQNumPresets; preset++) {
editor.putString(Key.eq_preset_name.toString() + preset, mEQPresetNames[preset]);
for (short band = 0; band < mEQNumBands; band++) {
editor.putInt(Key.eq_preset_opensl_es_band_level.toString() + preset + "_"
+ band, mEQPresetOpenSLESBandLevel[preset][band]);
}
}
}
final boolean isEQEnabled = prefs.getBoolean(Key.eq_enabled.toString(),
EQUALIZER_ENABLED_DEFAULT);
editor.putBoolean(Key.eq_enabled.toString(), isEQEnabled);
// Preset reverb
final boolean isEnabledPR = prefs.getBoolean(Key.pr_enabled.toString(),
PRESET_REVERB_ENABLED_DEFAULT);
final short presetPR = (short) prefs.getInt(Key.pr_current_preset.toString(),
PRESET_REVERB_CURRENT_PRESET_DEFAULT);
editor.putBoolean(Key.pr_enabled.toString(), isEnabledPR);
editor.putInt(Key.pr_current_preset.toString(), presetPR);
editor.commit();
} catch (final RuntimeException e) {
Log.e(TAG, "initEffectsPreferences: processingEnabled: " + e);
}
}
/**
* Gets the effect control mode based on the given audio session in the control panel. Control
* mode defines if the control panel is controlling effects and/or preferences
*
* @param audioSession
* System wide unique audio session identifier.
* @return effect control mode
*/
public static ControlMode getControlMode(final int audioSession) {
if (audioSession == AudioEffect.ERROR_BAD_VALUE) {
return ControlMode.CONTROL_PREFERENCES;
}
return ControlMode.CONTROL_EFFECTS;
}
/**
* Sets boolean parameter to value for given key
*
* @param context
* @param packageName
* @param audioSession
* System wide unique audio session identifier.
* @param key
* @param value
*/
public static void setParameterBoolean(final Context context, final String packageName,
final int audioSession, final Key key, final boolean value) {
try {
final SharedPreferences prefs = context.getSharedPreferences(packageName,
Context.MODE_PRIVATE);
final ControlMode controlMode = getControlMode(audioSession);
boolean enabled = value;
// Global on/off
if (key == Key.global_enabled) {
boolean processingEnabled = false;
if (value == true) {
// enable all with respect to preferences
if (controlMode == ControlMode.CONTROL_EFFECTS) {
final Virtualizer virtualizerEffect = getVirtualizerEffect(audioSession);
if (virtualizerEffect != null) {
virtualizerEffect.setEnabled(prefs.getBoolean(
Key.virt_enabled.toString(), VIRTUALIZER_ENABLED_DEFAULT));
final int vIStrength = prefs.getInt(Key.virt_strength.toString(),
VIRTUALIZER_STRENGTH_DEFAULT);
setParameterInt(context, packageName,
audioSession, Key.virt_strength, vIStrength);
}
final BassBoost bassBoostEffect = getBassBoostEffect(audioSession);
if (bassBoostEffect != null) {
bassBoostEffect.setEnabled(prefs.getBoolean(Key.bb_enabled.toString(),
BASS_BOOST_ENABLED_DEFAULT));
final int bBStrength = prefs.getInt(Key.bb_strength.toString(),
BASS_BOOST_STRENGTH_DEFAULT);
setParameterInt(context, packageName,
audioSession, Key.bb_strength, bBStrength);
}
final Equalizer equalizerEffect = getEqualizerEffect(audioSession);
if (equalizerEffect != null) {
equalizerEffect.setEnabled(prefs.getBoolean(Key.eq_enabled.toString(),
EQUALIZER_ENABLED_DEFAULT));
final int[] bandLevels = getParameterIntArray(context,
packageName, audioSession, Key.eq_band_level);
final int len = bandLevels.length;
for (short band = 0; band < len; band++) {
final int level = bandLevels[band];
setParameterInt(context, packageName,
audioSession, Key.eq_band_level, level, band);
}
}
// XXX: Preset Reverb not used for the moment, so commented out the effect
// creation to not use MIPS
// final PresetReverb presetReverbEffect =
// getPresetReverbEffect(audioSession);
// if (presetReverbEffect != null) {
// presetReverbEffect.setEnabled(prefs.getBoolean(
// Key.pr_enabled.toString(), PRESET_REVERB_ENABLED_DEFAULT));
// }
}
processingEnabled = true;
Log.v(TAG, "processingEnabled=" + processingEnabled);
} else {
// disable all
if (controlMode == ControlMode.CONTROL_EFFECTS) {
final Virtualizer virtualizerEffect = getVirtualizerEffectNoCreate(audioSession);
if (virtualizerEffect != null) {
mVirtualizerInstances.remove(audioSession, virtualizerEffect);
virtualizerEffect.setEnabled(false);
virtualizerEffect.release();
}
final BassBoost bassBoostEffect = getBassBoostEffectNoCreate(audioSession);
if (bassBoostEffect != null) {
mBassBoostInstances.remove(audioSession, bassBoostEffect);
bassBoostEffect.setEnabled(false);
bassBoostEffect.release();
}
final Equalizer equalizerEffect = getEqualizerEffectNoCreate(audioSession);
if (equalizerEffect != null) {
mEQInstances.remove(audioSession, equalizerEffect);
equalizerEffect.setEnabled(false);
equalizerEffect.release();
}
// XXX: Preset Reverb not used for the moment, so commented out the effect
// creation to not use MIPS
// final PresetReverb presetReverbEffect =
// getPresetReverbEffect(audioSession);
// if (presetReverbEffect != null) {
// presetReverbEffect.setEnabled(false);
// }
}
processingEnabled = false;
Log.v(TAG, "processingEnabled=" + processingEnabled);
}
enabled = processingEnabled;
} else if (controlMode == ControlMode.CONTROL_EFFECTS) {
final boolean isGlobalEnabled = prefs.getBoolean(Key.global_enabled.toString(),
GLOBAL_ENABLED_DEFAULT);
if (isGlobalEnabled == true) {
// Set effect parameters
switch (key) {
case global_enabled:
// Global, already handled, to get out error free
break;
// Virtualizer
case virt_enabled:
final Virtualizer virtualizerEffect = getVirtualizerEffect(audioSession);
if (virtualizerEffect != null) {
virtualizerEffect.setEnabled(value);
enabled = virtualizerEffect.getEnabled();
}
break;
// BassBoost
case bb_enabled:
final BassBoost bassBoostEffect = getBassBoostEffect(audioSession);
if (bassBoostEffect != null) {
bassBoostEffect.setEnabled(value);
enabled = bassBoostEffect.getEnabled();
}
break;
// Equalizer
case eq_enabled:
final Equalizer equalizerEffect = getEqualizerEffect(audioSession);
if (equalizerEffect != null) {
equalizerEffect.setEnabled(value);
enabled = equalizerEffect.getEnabled();
}
break;
// PresetReverb
case pr_enabled:
// XXX: Preset Reverb not used for the moment, so commented out the effect
// creation to not use MIPS
// final PresetReverb presetReverbEffect =
// getPresetReverbEffect(audioSession);
// if (presetReverbEffect != null) {
// presetReverbEffect.setEnabled(value);
// enabled = presetReverbEffect.getEnabled();
// }
break;
default:
Log.e(TAG, "Unknown/unsupported key " + key);
return;
}
}
}
// Set preferences
final SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean(key.toString(), enabled);
editor.commit();
} catch (final RuntimeException e) {
Log.e(TAG, "setParameterBoolean: " + key + "; " + value + "; " + e);
}
}
/**
* Gets boolean parameter for given key
*
* @param context
* @param packageName
* @param audioSession
* System wide unique audio session identifier.
* @param key
* @return parameter value
*/
public static Boolean getParameterBoolean(final Context context, final String packageName,
final int audioSession, final Key key) {
final SharedPreferences prefs = context.getSharedPreferences(packageName,
Context.MODE_PRIVATE);
boolean value = false;
try {
value = prefs.getBoolean(key.toString(), value);
} catch (final RuntimeException e) {
Log.e(TAG, "getParameterBoolean: " + key + "; " + value + "; " + e);
}
return value;
}
/**
* Sets int parameter for given key and value arg0, arg1
*
* @param context
* @param packageName
* @param audioSession
* System wide unique audio session identifier.
* @param key
* @param arg0
* @param arg1
*/
public static void setParameterInt(final Context context, final String packageName,
final int audioSession, final Key key, final int arg0, final int arg1) {
String strKey = key.toString();
int value = arg0;
try {
final SharedPreferences prefs = context.getSharedPreferences(packageName,
Context.MODE_PRIVATE);
final SharedPreferences.Editor editor = prefs.edit();
final ControlMode controlMode = getControlMode(audioSession);
// Set effect parameters
if (controlMode == ControlMode.CONTROL_EFFECTS) {
switch (key) {
// Virtualizer
case virt_strength: {
final Virtualizer virtualizerEffect = getVirtualizerEffect(audioSession);
if (virtualizerEffect != null) {
virtualizerEffect.setStrength((short) value);
value = virtualizerEffect.getRoundedStrength();
}
break;
}
// BassBoost
case bb_strength: {
final BassBoost bassBoostEffect = getBassBoostEffect(audioSession);
if (bassBoostEffect != null) {
bassBoostEffect.setStrength((short) value);
value = bassBoostEffect.getRoundedStrength();
}
break;
}
// Equalizer
case eq_band_level: {
if (arg1 == DUMMY_ARGUMENT) {
throw new IllegalArgumentException("Dummy arg passed.");
}
final short band = (short) arg1;
strKey = strKey + band;
final Equalizer equalizerEffect = getEqualizerEffect(audioSession);
if (equalizerEffect != null) {
equalizerEffect.setBandLevel(band, (short) value);
value = equalizerEffect.getBandLevel(band);
// save band level in User preset
editor.putInt(Key.eq_preset_user_band_level.toString() + band, value);
}
break;
}
case eq_current_preset: {
final Equalizer equalizerEffect = getEqualizerEffect(audioSession);
if (equalizerEffect != null) {
final short preset = (short) value;
final int numBands = prefs.getInt(Key.eq_num_bands.toString(),
EQUALIZER_NUMBER_BANDS_DEFAULT);
final int numPresets = prefs.getInt(Key.eq_num_presets.toString(),
EQUALIZER_NUMBER_PRESETS_DEFAULT);
if (preset < numPresets) {
// OpenSL ES EQ Effect presets
equalizerEffect.usePreset(preset);
value = equalizerEffect.getCurrentPreset();
} else {
final short[] eQPresetCIExtremeBandLevelDefault = Arrays.copyOf(
EQUALIZER_PRESET_CIEXTREME_BAND_LEVEL, numBands);
final short[] eQPresetUserBandLevelDefault = Arrays.copyOf(
EQUALIZER_PRESET_USER_BAND_LEVEL_DEFAULT, numBands);
// Set the band levels manually for custom presets
for (short band = 0; band < numBands; band++) {
short bandLevel = 0;
if (preset == numPresets) {
// CI EXTREME
bandLevel = (short) prefs.getInt(
Key.eq_preset_ci_extreme_band_level.toString() + band,
eQPresetCIExtremeBandLevelDefault[band]);
} else {
// User
bandLevel = (short) prefs.getInt(
Key.eq_preset_user_band_level.toString() + band,
eQPresetUserBandLevelDefault[band]);
}
equalizerEffect.setBandLevel(band, bandLevel);
}
}
// update band levels
for (short band = 0; band < numBands; band++) {
final short level = equalizerEffect.getBandLevel(band);
editor.putInt(Key.eq_band_level.toString() + band, level);
}
}
break;
}
case eq_preset_user_band_level:
// Fall through
case eq_preset_user_band_level_default:
// Fall through
case eq_preset_ci_extreme_band_level: {
if (arg1 == DUMMY_ARGUMENT) {
throw new IllegalArgumentException("Dummy arg passed.");
}
final short band = (short) arg1;
strKey = strKey + band;
break;
}
case pr_current_preset:
// XXX: Preset Reverb not used for the moment, so commented out the effect
// creation to not use MIPS
// final PresetReverb presetReverbEffect = getPresetReverbEffect(audioSession);
// if (presetReverbEffect != null) {
// presetReverbEffect.setPreset((short) value);
// value = presetReverbEffect.getPreset();
// }
break;
default:
Log.e(TAG, "setParameterInt: Unknown/unsupported key " + key);
return;
}
} else {
switch (key) {
// Virtualizer
case virt_strength:
// Do nothing
break;
case virt_type:
// Do nothing
break;
// BassBoost
case bb_strength:
// Do nothing
break;
// Equalizer
case eq_band_level: {
if (arg1 == DUMMY_ARGUMENT) {
throw new IllegalArgumentException("Dummy arg passed.");
}
final short band = (short) arg1;
strKey = strKey + band;
editor.putInt(Key.eq_preset_user_band_level.toString() + band, value);
break;
}
case eq_current_preset: {
final short preset = (short) value;
final int numBands = prefs.getInt(Key.eq_num_bands.toString(),
EQUALIZER_NUMBER_BANDS_DEFAULT);
final int numPresets = prefs.getInt(Key.eq_num_presets.toString(),
EQUALIZER_NUMBER_PRESETS_DEFAULT);
final short[][] eQPresetOpenSLESBandLevelDefault = Arrays.copyOf(
EQUALIZER_PRESET_OPENSL_ES_BAND_LEVEL_DEFAULT, numBands);
final short[] eQPresetCIExtremeBandLevelDefault = Arrays.copyOf(
EQUALIZER_PRESET_CIEXTREME_BAND_LEVEL, numBands);
final short[] eQPresetUserBandLevelDefault = Arrays.copyOf(
EQUALIZER_PRESET_USER_BAND_LEVEL_DEFAULT, numBands);
for (short band = 0; band < numBands; band++) {
short bandLevel = 0;
if (preset < numPresets) {
// OpenSL ES EQ Effect presets
bandLevel = (short) prefs.getInt(
Key.eq_preset_opensl_es_band_level.toString() + preset + "_"
+ band, eQPresetOpenSLESBandLevelDefault[preset][band]);
} else if (preset == numPresets) {
// CI EXTREME
bandLevel = (short) prefs.getInt(
Key.eq_preset_ci_extreme_band_level.toString() + band,
eQPresetCIExtremeBandLevelDefault[band]);
} else {
// User
bandLevel = (short) prefs.getInt(
Key.eq_preset_user_band_level.toString() + band,
eQPresetUserBandLevelDefault[band]);
}
editor.putInt(Key.eq_band_level.toString() + band, bandLevel);
}
break;
}
case eq_preset_user_band_level:
// Fall through
case eq_preset_user_band_level_default:
// Fall through
case eq_preset_ci_extreme_band_level: {
if (arg1 == DUMMY_ARGUMENT) {
throw new IllegalArgumentException("Dummy arg passed.");
}
final short band = (short) arg1;
strKey = strKey + band;
break;
}
case pr_current_preset:
// Do nothing
break;
default:
Log.e(TAG, "setParameterInt: Unknown/unsupported key " + key);
return;
}
}
// Set preferences
editor.putInt(strKey, value);
editor.apply();
} catch (final RuntimeException e) {
Log.e(TAG, "setParameterInt: " + key + "; " + arg0 + "; " + arg1 + "; " + e);
}
}
/**
* Sets int parameter for given key and value arg
*
* @param context
* @param packageName
* @param audioSession
* System wide unique audio session identifier.
* @param key
* @param arg
*/
public static void setParameterInt(final Context context, final String packageName,
final int audioSession, final Key key, final int arg) {
setParameterInt(context, packageName, audioSession, key, arg, DUMMY_ARGUMENT);
}
/**
* Gets int parameter given key
*
* @param context
* @param packageName
* @param audioSession
* System wide unique audio session identifier.
* @param key
* @return parameter value
*/
public static int getParameterInt(final Context context, final String packageName,
final int audioSession, final String key) {
int value = 0;
try {
final SharedPreferences prefs = context.getSharedPreferences(packageName,
Context.MODE_PRIVATE);
value = prefs.getInt(key, value);
} catch (final RuntimeException e) {
Log.e(TAG, "getParameterInt: " + key + "; " + e);
}
return value;
}
/**
* Gets int parameter given key
*
* @param context
* @param packageName
* @param audioSession
* System wide unique audio session identifier.
* @param key
* @return parameter value
*/
public static int getParameterInt(final Context context, final String packageName,
final int audioSession, final Key key) {
return getParameterInt(context, packageName, audioSession, key.toString());
}
/**
* Gets int parameter given key and arg
*
* @param context
* @param packageName
* @param audioSession
* System wide unique audio session identifier.
* @param audioSession
* @param key
* @param arg
* @return parameter value
*/
public static int getParameterInt(final Context context, final String packageName,
final int audioSession, final Key key, final int arg) {
return getParameterInt(context, packageName, audioSession, key.toString() + arg);
}
/**
* Gets int parameter given key, arg0 and arg1
*
* @param context
* @param packageName
* @param audioSession
* System wide unique audio session identifier.
* @param audioSession
* @param key
* @param arg0
* @param arg1
* @return parameter value
*/
public static int getParameterInt(final Context context, final String packageName,
final int audioSession, final Key key, final int arg0, final int arg1) {
return getParameterInt(context, packageName, audioSession, key.toString() + arg0 + "_"
+ arg1);
}
/**
* Gets integer array parameter given key. Returns null if not found.
*
* @param context
* @param packageName
* @param audioSession
* System wide unique audio session identifier.
* @param key
* @return parameter value array
*/
public static int[] getParameterIntArray(final Context context, final String packageName,
final int audioSession, final Key key) {
final SharedPreferences prefs = context.getSharedPreferences(packageName,
Context.MODE_PRIVATE);
int[] intArray = null;
try {
// Get effect parameters
switch (key) {
case eq_level_range: {
intArray = new int[2];
break;
}
case eq_center_freq:
// Fall through
case eq_band_level:
// Fall through
case eq_preset_user_band_level:
// Fall through
case eq_preset_user_band_level_default:
// Fall through
case eq_preset_ci_extreme_band_level: {
final int numBands = prefs.getInt(Key.eq_num_bands.toString(), 0);
intArray = new int[numBands];
break;
}
default:
Log.e(TAG, "getParameterIntArray: Unknown/unsupported key " + key);
return null;
}
for (int i = 0; i < intArray.length; i++) {
intArray[i] = prefs.getInt(key.toString() + i, 0);
}
} catch (final RuntimeException e) {
Log.e(TAG, "getParameterIntArray: " + key + "; " + e);
}
return intArray;
}
/**
* Gets string parameter given key. Returns empty string if not found.
*
* @param context
* @param packageName
* @param audioSession
* System wide unique audio session identifier.
* @param key
* @return parameter value
*/
public static String getParameterString(final Context context, final String packageName,
final int audioSession, final String key) {
String value = "";
try {
final SharedPreferences prefs = context.getSharedPreferences(packageName,
Context.MODE_PRIVATE);
// Get effect parameters
value = prefs.getString(key, value);
} catch (final RuntimeException e) {
Log.e(TAG, "getParameterString: " + key + "; " + e);
}
return value;
}
/**
* Gets string parameter given key.
*
* @param context
* @param packageName
* @param audioSession
* System wide unique audio session identifier.
* @param key
* @return parameter value
*/
public static String getParameterString(final Context context, final String packageName,
final int audioSession, final Key key) {
return getParameterString(context, packageName, audioSession, key.toString());
}
/**
* Gets string parameter given key and arg.
*
* @param context
* @param packageName
* @param audioSession
* System wide unique audio session identifier.
* @param args
* @return parameter value
*/
public static String getParameterString(final Context context, final String packageName,
final int audioSession, final Key key, final int arg) {
return getParameterString(context, packageName, audioSession, key.toString() + arg);
}
/**
* Opens/initializes the effects session for the given audio session with preferences linked to
* the given package name and context.
*
* @param context
* @param packageName
* @param audioSession
* System wide unique audio session identifier.
*/
public static void openSession(final Context context, final String packageName,
final int audioSession) {
Log.v(TAG, "openSession(" + context + ", " + packageName + ", " + audioSession + ")");
final String methodTag = "openSession: ";
// init preferences
final SharedPreferences prefs = context.getSharedPreferences(packageName,
Context.MODE_PRIVATE);
final SharedPreferences.Editor editor = prefs.edit();
final boolean isGlobalEnabled = prefs.getBoolean(Key.global_enabled.toString(),
GLOBAL_ENABLED_DEFAULT);
editor.putBoolean(Key.global_enabled.toString(), isGlobalEnabled);
if (!isGlobalEnabled) {
return;
}
// Manage audioSession information
// Retrieve AudioSession Id from map
boolean isExistingAudioSession = false;
try {
final Integer currentAudioSession = mPackageSessions.putIfAbsent(packageName,
audioSession);
if (currentAudioSession != null) {
// Compare with passed argument
if (currentAudioSession == audioSession) {
// FIXME: Normally, we should exit the function here
// BUT: we have to take care of the virtualizer because of
// a bug in the Android Effects Framework
// editor.commit();
// return;
isExistingAudioSession = true;
} else {
closeSession(context, packageName, currentAudioSession);
}
}
} catch (final NullPointerException e) {
Log.e(TAG, methodTag + e);
editor.commit();
return;
}
// Because the audioSession is new, get effects & settings from shared preferences
// Virtualizer
// create effect
final Virtualizer virtualizerEffect = getVirtualizerEffect(audioSession);
{
final String errorTag = methodTag + "Virtualizer error: ";
try {
// read parameters
final boolean isEnabled = prefs.getBoolean(Key.virt_enabled.toString(),
VIRTUALIZER_ENABLED_DEFAULT);
final int strength = prefs.getInt(Key.virt_strength.toString(),
VIRTUALIZER_STRENGTH_DEFAULT);
// init settings
Virtualizer.Settings settings = new Virtualizer.Settings("Virtualizer;strength="
+ strength);
virtualizerEffect.setProperties(settings);
// set parameters
if (isGlobalEnabled == true) {
virtualizerEffect.setEnabled(isEnabled);
} else {
virtualizerEffect.setEnabled(false);
}
// get parameters
settings = virtualizerEffect.getProperties();
Log.v(TAG, "Parameters: " + settings.toString() + ";enabled=" + isEnabled);
// update preferences
editor.putBoolean(Key.virt_enabled.toString(), isEnabled);
editor.putInt(Key.virt_strength.toString(), settings.strength);
} catch (final RuntimeException e) {
Log.e(TAG, errorTag + e);
}
}
// In case of an existing audio session
// Exit after the virtualizer has been re-enabled
if (isExistingAudioSession) {
editor.apply();
return;
}
// BassBoost
// create effect
final BassBoost bassBoostEffect = getBassBoostEffect(audioSession);
{
final String errorTag = methodTag + "BassBoost error: ";
try {
// read parameters
final boolean isEnabled = prefs.getBoolean(Key.bb_enabled.toString(),
BASS_BOOST_ENABLED_DEFAULT);
final int strength = prefs.getInt(Key.bb_strength.toString(),
BASS_BOOST_STRENGTH_DEFAULT);
// init settings
BassBoost.Settings settings = new BassBoost.Settings("BassBoost;strength="
+ strength);
bassBoostEffect.setProperties(settings);
// set parameters
if (isGlobalEnabled == true) {
bassBoostEffect.setEnabled(isEnabled);
} else {
bassBoostEffect.setEnabled(false);
}
// get parameters
settings = bassBoostEffect.getProperties();
Log.v(TAG, "Parameters: " + settings.toString() + ";enabled=" + isEnabled);
// update preferences
editor.putBoolean(Key.bb_enabled.toString(), isEnabled);
editor.putInt(Key.bb_strength.toString(), settings.strength);
} catch (final RuntimeException e) {
Log.e(TAG, errorTag + e);
}
}
// Equalizer
// create effect
final Equalizer equalizerEffect = getEqualizerEffect(audioSession);
{
final String errorTag = methodTag + "Equalizer error: ";
try {
final short eQNumBands;
final short[] bandLevel;
final int[] eQCenterFreq;
final short eQNumPresets;
final String[] eQPresetNames;
short eQPreset;
synchronized (mEQInitLock) {
// read parameters
mEQBandLevelRange = equalizerEffect.getBandLevelRange();
mEQNumBands = equalizerEffect.getNumberOfBands();
mEQCenterFreq = new int[mEQNumBands];
mEQNumPresets = equalizerEffect.getNumberOfPresets();
mEQPresetNames = new String[mEQNumPresets];
for (short preset = 0; preset < mEQNumPresets; preset++) {
mEQPresetNames[preset] = equalizerEffect.getPresetName(preset);
editor.putString(Key.eq_preset_name.toString() + preset,
mEQPresetNames[preset]);
}
editor.putInt(Key.eq_level_range.toString() + 0, mEQBandLevelRange[0]);
editor.putInt(Key.eq_level_range.toString() + 1, mEQBandLevelRange[1]);
editor.putInt(Key.eq_num_bands.toString(), mEQNumBands);
editor.putInt(Key.eq_num_presets.toString(), mEQNumPresets);
// Resetting the EQ arrays depending on the real # bands with defaults if band <
// default size else 0 by copying default arrays over new ones
final short[] eQPresetCIExtremeBandLevel = Arrays.copyOf(
EQUALIZER_PRESET_CIEXTREME_BAND_LEVEL, mEQNumBands);
final short[] eQPresetUserBandLevelDefault = Arrays.copyOf(
EQUALIZER_PRESET_USER_BAND_LEVEL_DEFAULT, mEQNumBands);
// If no preset prefs set use CI EXTREME (= numPresets)
eQPreset = (short) prefs
.getInt(Key.eq_current_preset.toString(), mEQNumPresets);
if (eQPreset < mEQNumPresets) {
// OpenSL ES effect presets
equalizerEffect.usePreset(eQPreset);
eQPreset = equalizerEffect.getCurrentPreset();
} else {
for (short band = 0; band < mEQNumBands; band++) {
short level = 0;
if (eQPreset == mEQNumPresets) {
// CI EXTREME
level = eQPresetCIExtremeBandLevel[band];
} else {
// User
level = (short) prefs.getInt(
Key.eq_preset_user_band_level.toString() + band,
eQPresetUserBandLevelDefault[band]);
}
equalizerEffect.setBandLevel(band, level);
}
}
editor.putInt(Key.eq_current_preset.toString(), eQPreset);
bandLevel = new short[mEQNumBands];
for (short band = 0; band < mEQNumBands; band++) {
mEQCenterFreq[band] = equalizerEffect.getCenterFreq(band);
bandLevel[band] = equalizerEffect.getBandLevel(band);
editor.putInt(Key.eq_band_level.toString() + band, bandLevel[band]);
editor.putInt(Key.eq_center_freq.toString() + band, mEQCenterFreq[band]);
editor.putInt(Key.eq_preset_ci_extreme_band_level.toString() + band,
eQPresetCIExtremeBandLevel[band]);
editor.putInt(Key.eq_preset_user_band_level_default.toString() + band,
eQPresetUserBandLevelDefault[band]);
}
eQNumBands = mEQNumBands;
eQCenterFreq = mEQCenterFreq;
eQNumPresets = mEQNumPresets;
eQPresetNames = mEQPresetNames;
}
final boolean isEnabled = prefs.getBoolean(Key.eq_enabled.toString(),
EQUALIZER_ENABLED_DEFAULT);
editor.putBoolean(Key.eq_enabled.toString(), isEnabled);
if (isGlobalEnabled == true) {
equalizerEffect.setEnabled(isEnabled);
} else {
equalizerEffect.setEnabled(false);
}
// dump
Log.v(TAG, "Parameters: Equalizer");
Log.v(TAG, "bands=" + eQNumBands);
String str = "levels=";
for (short band = 0; band < eQNumBands; band++) {
str = str + bandLevel[band] + "; ";
}
Log.v(TAG, str);
str = "center=";
for (short band = 0; band < eQNumBands; band++) {
str = str + eQCenterFreq[band] + "; ";
}
Log.v(TAG, str);
str = "presets=";
for (short preset = 0; preset < eQNumPresets; preset++) {
str = str + eQPresetNames[preset] + "; ";
}
Log.v(TAG, str);
Log.v(TAG, "current=" + eQPreset);
} catch (final RuntimeException e) {
Log.e(TAG, errorTag + e);
}
}
// XXX: Preset Reverb not used for the moment, so commented out the effect creation to not
// use MIPS left in the code for (future) reference.
// Preset reverb
// create effect
// final PresetReverb presetReverbEffect = getPresetReverbEffect(audioSession);
// {
// final String errorTag = methodTag + "PresetReverb error: ";
//
// try {
// // read parameters
// final boolean isEnabled = prefs.getBoolean(Key.pr_enabled.toString(),
// PRESET_REVERB_ENABLED_DEFAULT);
// final short preset = (short) prefs.getInt(Key.pr_current_preset.toString(),
// PRESET_REVERB_CURRENT_PRESET_DEFAULT);
//
// // init settings
// PresetReverb.Settings settings = new PresetReverb.Settings("PresetReverb;preset="
// + preset);
//
// // read/update preferences
// presetReverbEffect.setProperties(settings);
//
// // set parameters
// if (isGlobalEnabled == true) {
// presetReverbEffect.setEnabled(isEnabled);
// } else {
// presetReverbEffect.setEnabled(false);
// }
//
// // get parameters
// settings = presetReverbEffect.getProperties();
// Log.v(TAG, "Parameters: " + settings.toString() + ";enabled=" + isEnabled);
//
// // update preferences
// editor.putBoolean(Key.pr_enabled.toString(), isEnabled);
// editor.putInt(Key.pr_current_preset.toString(), settings.preset);
// } catch (final RuntimeException e) {
// Log.e(TAG, errorTag + e);
// }
// }
editor.commit();
}
/**
* Closes the audio session (release effects) for the given session
*
* @param context
* @param packageName
* @param audioSession
* System wide unique audio session identifier.
*/
public static void closeSession(final Context context, final String packageName,
final int audioSession) {
Log.v(TAG, "closeSession(" + context + ", " + packageName + ", " + audioSession + ")");
// PresetReverb
final PresetReverb presetReverb = mPresetReverbInstances.remove(audioSession);
if (presetReverb != null) {
presetReverb.release();
}
// Equalizer
final Equalizer equalizer = mEQInstances.remove(audioSession);
if (equalizer != null) {
equalizer.release();
}
// BassBoost
final BassBoost bassBoost = mBassBoostInstances.remove(audioSession);
if (bassBoost != null) {
bassBoost.release();
}
// Virtualizer
final Virtualizer virtualizer = mVirtualizerInstances.remove(audioSession);
if (virtualizer != null) {
virtualizer.release();
}
mPackageSessions.remove(packageName);
}
/**
* Enables or disables all effects (global enable/disable) for a given context, package name and
* audio session. It sets/inits the control mode and preferences and then sets the global
* enabled parameter.
*
* @param context
* @param packageName
* @param audioSession
* System wide unique audio session identifier.
* @param enabled
*/
public static void setEnabledAll(final Context context, final String packageName,
final int audioSession, final boolean enabled) {
initEffectsPreferences(context, packageName, audioSession);
setParameterBoolean(context, packageName, audioSession, Key.global_enabled, enabled);
}
/**
* Gets the virtualizer effect for the given audio session. If the effect on the session doesn't
* exist yet, create it and add to collection.
*
* @param audioSession
* System wide unique audio session identifier.
* @return virtualizerEffect
*/
private static Virtualizer getVirtualizerEffectNoCreate(final int audioSession) {
return mVirtualizerInstances.get(audioSession);
}
private static Virtualizer getVirtualizerEffect(final int audioSession) {
Virtualizer virtualizerEffect = getVirtualizerEffectNoCreate(audioSession);
if (virtualizerEffect == null) {
try {
final Virtualizer newVirtualizerEffect = new Virtualizer(PRIORITY, audioSession);
virtualizerEffect = mVirtualizerInstances.putIfAbsent(audioSession,
newVirtualizerEffect);
if (virtualizerEffect == null) {
// put succeeded, use new value
virtualizerEffect = newVirtualizerEffect;
}
} catch (final IllegalArgumentException e) {
Log.e(TAG, "Virtualizer: " + e);
} catch (final UnsupportedOperationException e) {
Log.e(TAG, "Virtualizer: " + e);
} catch (final RuntimeException e) {
Log.e(TAG, "Virtualizer: " + e);
}
}
return virtualizerEffect;
}
/**
* Gets the bass boost effect for the given audio session. If the effect on the session doesn't
* exist yet, create it and add to collection.
*
* @param audioSession
* System wide unique audio session identifier.
* @return bassBoostEffect
*/
private static BassBoost getBassBoostEffectNoCreate(final int audioSession) {
return mBassBoostInstances.get(audioSession);
}
private static BassBoost getBassBoostEffect(final int audioSession) {
BassBoost bassBoostEffect = getBassBoostEffectNoCreate(audioSession);
if (bassBoostEffect == null) {
try {
final BassBoost newBassBoostEffect = new BassBoost(PRIORITY, audioSession);
bassBoostEffect = mBassBoostInstances.putIfAbsent(audioSession, newBassBoostEffect);
if (bassBoostEffect == null) {
// put succeeded, use new value
bassBoostEffect = newBassBoostEffect;
}
} catch (final IllegalArgumentException e) {
Log.e(TAG, "BassBoost: " + e);
} catch (final UnsupportedOperationException e) {
Log.e(TAG, "BassBoost: " + e);
} catch (final RuntimeException e) {
Log.e(TAG, "BassBoost: " + e);
}
}
return bassBoostEffect;
}
/**
* Gets the equalizer effect for the given audio session. If the effect on the session doesn't
* exist yet, create it and add to collection.
*
* @param audioSession
* System wide unique audio session identifier.
* @return equalizerEffect
*/
private static Equalizer getEqualizerEffectNoCreate(final int audioSession) {
return mEQInstances.get(audioSession);
}
private static Equalizer getEqualizerEffect(final int audioSession) {
Equalizer equalizerEffect = getEqualizerEffectNoCreate(audioSession);
if (equalizerEffect == null) {
try {
final Equalizer newEqualizerEffect = new Equalizer(PRIORITY, audioSession);
equalizerEffect = mEQInstances.putIfAbsent(audioSession, newEqualizerEffect);
if (equalizerEffect == null) {
// put succeeded, use new value
equalizerEffect = newEqualizerEffect;
}
} catch (final IllegalArgumentException e) {
Log.e(TAG, "Equalizer: " + e);
} catch (final UnsupportedOperationException e) {
Log.e(TAG, "Equalizer: " + e);
} catch (final RuntimeException e) {
Log.e(TAG, "Equalizer: " + e);
}
}
return equalizerEffect;
}
// XXX: Preset Reverb not used for the moment, so commented out the effect creation to not
// use MIPS
// /**
// * Gets the preset reverb effect for the given audio session. If the effect on the session
// * doesn't exist yet, create it and add to collection.
// *
// * @param audioSession
// * System wide unique audio session identifier.
// * @return presetReverbEffect
// */
// private static PresetReverb getPresetReverbEffect(final int audioSession) {
// PresetReverb presetReverbEffect = mPresetReverbInstances.get(audioSession);
// if (presetReverbEffect == null) {
// try {
// final PresetReverb newPresetReverbEffect = new PresetReverb(PRIORITY, audioSession);
// presetReverbEffect = mPresetReverbInstances.putIfAbsent(audioSession,
// newPresetReverbEffect);
// if (presetReverbEffect == null) {
// // put succeeded, use new value
// presetReverbEffect = newPresetReverbEffect;
// }
// } catch (final IllegalArgumentException e) {
// Log.e(TAG, "PresetReverb: " + e);
// } catch (final UnsupportedOperationException e) {
// Log.e(TAG, "PresetReverb: " + e);
// } catch (final RuntimeException e) {
// Log.e(TAG, "PresetReverb: " + e);
// }
// }
// return presetReverbEffect;
// }
}