diff options
author | Steve Kondik <steve@cyngn.com> | 2016-04-01 21:06:58 -0700 |
---|---|---|
committer | Roman Birg <roman@cyngn.com> | 2016-04-05 20:38:37 +0000 |
commit | 672ccc8e0f4427bd6a3a19b5db0c9a056bfbf3bc (patch) | |
tree | f8aa685d4e5888dbabfe12402ac667c69e00477b /src | |
parent | 70f9b012d9200faf044395570f7fea9b06b0e306 (diff) | |
download | android_packages_apps_AudioFX-672ccc8e0f4427bd6a3a19b5db0c9a056bfbf3bc.tar.gz android_packages_apps_AudioFX-672ccc8e0f4427bd6a3a19b5db0c9a056bfbf3bc.tar.bz2 android_packages_apps_AudioFX-672ccc8e0f4427bd6a3a19b5db0c9a056bfbf3bc.zip |
audiofx: A big pile of fixes.
* Fix MaxxAudio device selection. Use WAVESFX commands to do
this ourselves.
* Ditch parameter caching. It's overkill.
* Clean up locking across the board.
* Fix lost messages in the queue.
* Make parameter setting transactional.
* Add device changed and lifecycle callbacks to the backend.
* Turn the Waves effect on all the time and add some defaults.
Change-Id: Ia3e6bfd4010840189169db9037cb925811a6cbc4
Diffstat (limited to 'src')
-rw-r--r-- | src/com/cyngn/audiofx/Constants.java | 5 | ||||
-rw-r--r-- | src/com/cyngn/audiofx/activity/MasterConfigControl.java | 13 | ||||
-rw-r--r-- | src/com/cyngn/audiofx/backends/AndroidEffects.java | 60 | ||||
-rw-r--r-- | src/com/cyngn/audiofx/backends/EffectSet.java | 131 | ||||
-rw-r--r-- | src/com/cyngn/audiofx/backends/EffectSetWithAndroidEq.java | 58 | ||||
-rw-r--r-- | src/com/cyngn/audiofx/backends/EffectsFactory.java | 10 | ||||
-rw-r--r-- | src/com/cyngn/audiofx/service/AudioFxService.java | 305 |
7 files changed, 362 insertions, 220 deletions
diff --git a/src/com/cyngn/audiofx/Constants.java b/src/com/cyngn/audiofx/Constants.java index 61d53cc..bf9d6ba 100644 --- a/src/com/cyngn/audiofx/Constants.java +++ b/src/com/cyngn/audiofx/Constants.java @@ -28,7 +28,12 @@ public class Constants { // global settings public static final String AUDIOFX_GLOBAL_FILE = "global"; + public static final String DEVICE_SPEAKER = "speaker"; + public static final String DEVICE_HEADSET = "headset"; + public static final String DEVICE_USB = "usb"; + public static final String DEVICE_CAST = "wireless"; + public static final String DEVICE_BLUETOOTH = "bluetooth"; public static final String SAVED_DEFAULTS = "saved_defaults"; diff --git a/src/com/cyngn/audiofx/activity/MasterConfigControl.java b/src/com/cyngn/audiofx/activity/MasterConfigControl.java index fc67dbc..7f0806f 100644 --- a/src/com/cyngn/audiofx/activity/MasterConfigControl.java +++ b/src/com/cyngn/audiofx/activity/MasterConfigControl.java @@ -328,22 +328,23 @@ public class MasterConfigControl { switch (type) { case TYPE_WIRED_HEADSET: case TYPE_WIRED_HEADPHONES: - return "headset"; + return Constants.DEVICE_HEADSET; case TYPE_LINE_ANALOG: case TYPE_LINE_DIGITAL: // FIXME: support line-out - return "headset"; + return Constants.DEVICE_HEADSET; case TYPE_BLUETOOTH_SCO: case TYPE_BLUETOOTH_A2DP: - return "bluetooth"; + // FIXME: include dev info + return Constants.DEVICE_BLUETOOTH; case TYPE_USB_DEVICE: case TYPE_USB_ACCESSORY: case TYPE_DOCK: - return "usb"; + return Constants.DEVICE_USB; case TYPE_IP: - return "wireless"; + return Constants.DEVICE_CAST; default: - return "speaker"; + return Constants.DEVICE_SPEAKER; } } diff --git a/src/com/cyngn/audiofx/backends/AndroidEffects.java b/src/com/cyngn/audiofx/backends/AndroidEffects.java index 7e2811c..780bd63 100644 --- a/src/com/cyngn/audiofx/backends/AndroidEffects.java +++ b/src/com/cyngn/audiofx/backends/AndroidEffects.java @@ -1,19 +1,17 @@ package com.cyngn.audiofx.backends; +import android.media.AudioDeviceInfo; import android.media.audiofx.AudioEffect; import android.media.audiofx.BassBoost; import android.media.audiofx.PresetReverb; import android.media.audiofx.Virtualizer; import android.util.Log; -import android.util.SparseArray; /** * EffectSet which comprises standard Android effects */ class AndroidEffects extends EffectSetWithAndroidEq { - private final SparseArray<Short> mCache = new SparseArray<Short>(); - /** * Session-specific bassboost */ @@ -29,15 +27,13 @@ class AndroidEffects extends EffectSetWithAndroidEq { */ private final PresetReverb mPresetReverb; - public AndroidEffects(int sessionId) { - super(sessionId); + public AndroidEffects(int sessionId, AudioDeviceInfo deviceInfo) { + super(sessionId, deviceInfo); try { mBassBoost = new BassBoost(1000, sessionId); mVirtualizer = new Virtualizer(1000, sessionId); mPresetReverb = new PresetReverb(1000, sessionId); - - addEffects(mBassBoost, mVirtualizer, mPresetReverb); } catch (Exception e) { release(); throw e; @@ -45,6 +41,40 @@ class AndroidEffects extends EffectSetWithAndroidEq { } @Override + public void release() { + super.release(); + mBassBoost.release(); + mVirtualizer.release(); + mPresetReverb.release(); + } + + @Override + public void setGlobalEnabled(boolean globalEnabled) { + if (globalEnabled != isGlobalEnabled()) { + if (!globalEnabled) { + // disable everything. it will get explictly enabled + // individually when necessary. + try { + mVirtualizer.setEnabled(false); + } catch (Exception e) { + Log.e(TAG, "Unable to disable virtualizer!", e); + } + try { + mBassBoost.setEnabled(false); + } catch (Exception e) { + Log.e(TAG, "Unable to disable bass boost!", e); + } + try { + mPresetReverb.setEnabled(false); + } catch (Exception e) { + Log.e(TAG, "Unable to disable reverb!", e); + } + } + } + super.setGlobalEnabled(globalEnabled); + } + + @Override public boolean hasVirtualizer() { return mVirtualizer.getStrengthSupported(); } @@ -56,9 +86,6 @@ class AndroidEffects extends EffectSetWithAndroidEq { @Override public void enableBassBoost(boolean enable) { - if (enable == mBassBoost.getEnabled()) { - return; - } try { mBassBoost.setEnabled(enable); } catch (Exception e) { @@ -73,9 +100,6 @@ class AndroidEffects extends EffectSetWithAndroidEq { @Override public void enableVirtualizer(boolean enable) { - if (enable == mVirtualizer.getEnabled()) { - return; - } try { mVirtualizer.setEnabled(enable); } catch (Exception e) { @@ -90,14 +114,12 @@ class AndroidEffects extends EffectSetWithAndroidEq { @Override public void enableReverb(boolean enable) { - if (enable == mPresetReverb.getEnabled()) { - return; - } try { mPresetReverb.setEnabled(enable); } catch (Exception e) { Log.e(TAG, "Unable to " + (enable ? "enable" : "disable") + " preset reverb!", e); } + } @Override @@ -110,16 +132,12 @@ class AndroidEffects extends EffectSetWithAndroidEq { return EffectsFactory.ANDROID; } - private synchronized void setParameterSafe(AudioEffect e, int p, short v) { - if (mCache.indexOfKey(p) >= 0 && v == mCache.get(p)) { - return; - } + private void setParameterSafe(AudioEffect e, int p, short v) { if (!e.hasControl()) { return; } try { e.setParameter(p, v); - mCache.put(p, v); } catch (Exception ex) { Log.e(TAG, "Failed to set param " + p + " for effect " + e.getDescriptor().name, ex); } diff --git a/src/com/cyngn/audiofx/backends/EffectSet.java b/src/com/cyngn/audiofx/backends/EffectSet.java index 248dc01..a999819 100644 --- a/src/com/cyngn/audiofx/backends/EffectSet.java +++ b/src/com/cyngn/audiofx/backends/EffectSet.java @@ -1,10 +1,6 @@ package com.cyngn.audiofx.backends; -import android.media.audiofx.AudioEffect; -import android.util.Log; - -import java.util.ArrayList; -import java.util.Arrays; +import android.media.AudioDeviceInfo; /** * Helper class representing the full complement of effects attached to one @@ -16,12 +12,98 @@ public abstract class EffectSet { protected final int mSessionId; - protected final ArrayList<AudioEffect> mEffects = new ArrayList<AudioEffect>(); + protected boolean mGlobalEnabled; + + private AudioDeviceInfo mDeviceInfo; - public EffectSet(int sessionId) { + public EffectSet(int sessionId, AudioDeviceInfo deviceInfo) { mSessionId = sessionId; + mDeviceInfo = deviceInfo; + onCreate(); + } + + /** + * Called to do subclass-first initialization in case + * an implementation has ordering restrictions. + */ + protected void onCreate() { } + + /** + * Destroy all effects in this set. + * + * Attempting to use this object after calling release is + * undefined behavior. + */ + public void release() { } + + /** + * Returns the enumerated brand of this implementation + * @return brandId + */ + public abstract int getBrand(); + + /** + * Called when the user toggles the engine on or off. If the + * implementation has a built-in bypass mode, this is where + * to use it. + * + * @param globalEnabled + */ + public void setGlobalEnabled(boolean globalEnabled) { + mGlobalEnabled = globalEnabled; + } + + public boolean isGlobalEnabled() { + return mGlobalEnabled; + } + + /** + * Called when the output device has changed. All cached + * data should be cleared at this point. + * + * @param deviceInfo + */ + public void setDevice(AudioDeviceInfo deviceInfo) { + mDeviceInfo = deviceInfo; } + /** + * Return the current active output device + * @return deviceInfo + */ + public AudioDeviceInfo getDevice() { + return mDeviceInfo; + } + + /** + * Begin bulk-update of parameters. This can be used if the + * implementation supports operation in a transactional/atomic + * manner. Parameter changes will immediately follow this call + * and should be committed to the backend when the subsequent + * commitUpdate() is called. + * + * Optional. + * + * @return status - false on failure + */ + public boolean beginUpdate() { return true; } + + /** + * Commit accumulated updates to the backend. See above. + * + * begin/commit are used when a large number of parameters need + * to be sent to the backend, such as in the case of a device + * switch or preset change. This can increase performance and + * reduce click/pop issues. + * + * Optional. + * + * @return status - false on failure + */ + public boolean commitUpdate() { return true; } + + /* ---- Top level effects begin here ---- */ + // required effects public abstract boolean hasVirtualizer(); @@ -110,39 +192,4 @@ public abstract class EffectSet { public void enableVolumeBoost(boolean enable) { return; } - - public synchronized void release() { - for (AudioEffect e : mEffects) { - Log.d(TAG, "releasing effect: " + e.getDescriptor().name); - try { - e.release(); - } catch (Exception ex) { - Log.e(TAG, ex.getMessage(), ex); - } - } - mEffects.clear(); - } - - public boolean isActive() { - return mEffects.size() > 0; - } - - public abstract int getBrand(); - - public void setGlobalEnabled(boolean globalEnabled) { - if (globalEnabled) { - return; - } - for (AudioEffect e : mEffects) { - try { - e.setEnabled(false); - } catch (Exception ex) { - Log.e(TAG, ex.getMessage(), ex); - } - } - } - - protected void addEffects(AudioEffect... effects) { - mEffects.addAll(Arrays.asList(effects)); - } } diff --git a/src/com/cyngn/audiofx/backends/EffectSetWithAndroidEq.java b/src/com/cyngn/audiofx/backends/EffectSetWithAndroidEq.java index b1248b2..330b544 100644 --- a/src/com/cyngn/audiofx/backends/EffectSetWithAndroidEq.java +++ b/src/com/cyngn/audiofx/backends/EffectSetWithAndroidEq.java @@ -1,8 +1,8 @@ package com.cyngn.audiofx.backends; +import android.media.AudioDeviceInfo; import android.media.audiofx.Equalizer; import android.util.Log; -import android.util.SparseArray; import com.cyngn.audiofx.eq.EqUtils; @@ -13,30 +13,45 @@ public abstract class EffectSetWithAndroidEq extends EffectSet { /** * Session-specific equalizer */ - private final Equalizer mEqualizer; + private Equalizer mEqualizer; private short mEqNumPresets = -1; private short mEqNumBands = -1; - private final SparseArray<Short> mLevelCache = new SparseArray<Short>(); + public EffectSetWithAndroidEq(int sessionId, AudioDeviceInfo deviceInfo) { + super(sessionId, deviceInfo); + } - public EffectSetWithAndroidEq(int sessionId) { - super(sessionId); - try { - mEqualizer = new Equalizer(1000, sessionId); + @Override + protected void onCreate() { + mEqualizer = new Equalizer(1000, mSessionId); + super.onCreate(); - addEffects(mEqualizer); - } catch (Exception e) { - release(); - throw e; + } + + @Override + public synchronized void release() { + super.release(); + if (mEqualizer != null) { + mEqualizer.release(); + mEqualizer = null; } } + @Override + public void setGlobalEnabled(boolean globalEnabled) { + if (isGlobalEnabled() != globalEnabled) { + // disable it if needed. it will be explicitly enabled + // in a subsequent call if necessary. + if (!globalEnabled) { + mEqualizer.setEnabled(false); + } + } + super.setGlobalEnabled(globalEnabled); + } + @Override public void enableEqualizer(boolean enable) { - if (enable == mEqualizer.getEnabled()) { - return; - } try { mEqualizer.setEnabled(enable); } catch (Exception e) { @@ -52,6 +67,7 @@ public abstract class EffectSetWithAndroidEq extends EffectSet { } } + @Override public short getNumEqualizerBands() { if (mEqNumBands < 0) { mEqNumBands = mEqualizer.getNumberOfBands(); @@ -64,42 +80,42 @@ public abstract class EffectSetWithAndroidEq extends EffectSet { setBandLevelSafe(band, (short)level); } + @Override public int getEqualizerBandLevel(short band) { return mEqualizer.getBandLevel(band); } + @Override public String getEqualizerPresetName(short preset) { return mEqualizer.getPresetName(preset); } + @Override public void useEqualizerPreset(short preset) { mEqualizer.usePreset(preset); } + @Override public short getNumEqualizerPresets() { if (mEqNumPresets < 0) { mEqNumPresets = mEqualizer.getNumberOfPresets(); } return mEqNumPresets; } + + @Override public short[] getEqualizerBandLevelRange() { return mEqualizer.getBandLevelRange(); } + @Override public int getCenterFrequency(short band) { return mEqualizer.getCenterFreq(band); } private synchronized void setBandLevelSafe(short band, short level) { - if (!mEqualizer.hasControl()) { - return; - } - if (mLevelCache.indexOfKey((int)band) >= 0 && level == mLevelCache.get((int)band)) { - return; - } try { mEqualizer.setBandLevel(band, level); - mLevelCache.put((int)band, level); } catch (Exception e) { Log.e(TAG, "Unable to set eq band=" + band + " level=" + level, e); } diff --git a/src/com/cyngn/audiofx/backends/EffectsFactory.java b/src/com/cyngn/audiofx/backends/EffectsFactory.java index 6534e83..90e601d 100644 --- a/src/com/cyngn/audiofx/backends/EffectsFactory.java +++ b/src/com/cyngn/audiofx/backends/EffectsFactory.java @@ -1,6 +1,7 @@ package com.cyngn.audiofx.backends; import android.content.Context; +import android.media.AudioDeviceInfo; import android.util.Log; import java.io.File; @@ -20,7 +21,8 @@ public class EffectsFactory { public static final int DTS = 3; - public static EffectSet createEffectSet(Context context, int sessionId) { + public static EffectSet createEffectSet(Context context, int sessionId, + AudioDeviceInfo deviceInfo) { EffectSet effects = null; int brand = getBrand(); @@ -28,7 +30,7 @@ public class EffectsFactory { // dts? if (brand == DTS) { try { - effects = new DtsEffects(context, sessionId); + effects = new DtsEffects(context, sessionId, deviceInfo); } catch (Exception e) { Log.e(TAG, "Unable to create DTS effects!", e); effects = null; @@ -36,7 +38,7 @@ public class EffectsFactory { } else if (brand == MAXXAUDIO) { // try MaxxAudio next, this will throw an exception if unavailable try { - effects = new MaxxAudioEffects(sessionId); + effects = new MaxxAudioEffects(sessionId, deviceInfo); } catch (Exception e) { Log.e(TAG, "Unable to create MaxxAudio effects!", e); effects = null; @@ -47,7 +49,7 @@ public class EffectsFactory { // if this throws, we're screwed, don't bother to recover. these // are the standard effects that every android device must have, // and if they don't exist we have bigger problems. - effects = new AndroidEffects(sessionId); + effects = new AndroidEffects(sessionId, deviceInfo); } return effects; diff --git a/src/com/cyngn/audiofx/service/AudioFxService.java b/src/com/cyngn/audiofx/service/AudioFxService.java index 3e0b959..7688f3e 100644 --- a/src/com/cyngn/audiofx/service/AudioFxService.java +++ b/src/com/cyngn/audiofx/service/AudioFxService.java @@ -36,6 +36,7 @@ import static com.cyngn.audiofx.Constants.DEVICE_AUDIOFX_TREBLE_STRENGTH; import static com.cyngn.audiofx.Constants.DEVICE_AUDIOFX_VIRTUALIZER_ENABLE; import static com.cyngn.audiofx.Constants.DEVICE_AUDIOFX_VIRTUALIZER_STRENGTH; import static com.cyngn.audiofx.Constants.DEVICE_DEFAULT_GLOBAL_ENABLE; +import static com.cyngn.audiofx.Constants.DEVICE_HEADSET; import static com.cyngn.audiofx.Constants.DEVICE_SPEAKER; import static com.cyngn.audiofx.Constants.EQUALIZER_BAND_LEVEL_RANGE; import static com.cyngn.audiofx.Constants.EQUALIZER_CENTER_FREQS; @@ -63,6 +64,7 @@ import android.os.Looper; import android.os.Message; import android.os.Process; import android.support.v4.content.LocalBroadcastManager; +import android.text.TextUtils; import android.util.Log; import android.util.SparseArray; @@ -79,6 +81,7 @@ import cyanogenmod.app.CustomTile; import java.lang.ref.WeakReference; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Locale; @@ -224,11 +227,9 @@ public class AudioFxService extends Service { @Override public void onSessionAdded(int stream, int sessionId) { - if (stream == AudioManager.STREAM_MUSIC) { - if (DEBUG) { - Log.i(TAG, String.format("New audio session: %d", sessionId)); - } - + if (stream == AudioManager.STREAM_MUSIC && + !mHandler.hasMessages(MSG_ADD_SESSION, sessionId)) { + if (DEBUG) Log.i(TAG, String.format("New audio session: %d", sessionId)); mHandler.sendMessageAtFrontOfQueue(Message.obtain(mHandler, MSG_ADD_SESSION, sessionId)); } @@ -236,13 +237,12 @@ public class AudioFxService extends Service { @Override public void onSessionRemoved(int stream, int sessionId) { - if (stream == AudioManager.STREAM_MUSIC) { - if (DEBUG) { - Log.i(TAG, String.format("Audio session queued for removal: %d", sessionId)); - } + if (stream == AudioManager.STREAM_MUSIC && + !mHandler.hasMessages(MSG_REMOVE_SESSION, sessionId)) { + if (DEBUG) Log.i(TAG, String.format("Audio session queued for removal: %d", sessionId)); - mHandler.sendMessageDelayed(Message.obtain(mHandler, MSG_REMOVE_SESSION, sessionId), - REMOVE_SESSIONS_DELAY); + mHandler.sendMessageDelayed(Message.obtain(mHandler, + MSG_REMOVE_SESSION, sessionId), REMOVE_SESSIONS_DELAY); } } } @@ -251,33 +251,36 @@ public class AudioFxService extends Service { @Override public boolean handleMessage(Message msg) { - EffectSet session; - Integer sessionId; + EffectSet session = null; + Integer sessionId = 0; + int flags = 0; + switch (msg.what) { case MSG_ADD_SESSION: /** * msg.obj = sessionId */ sessionId = (Integer) msg.obj; - if (sessionId == 0) { + if (sessionId <= 0) { break; } + + // Do the whole thing inside the lock when creating a new session so + // it's ready to go as fast as possible synchronized (mAudioSessionsL) { - mHandler.removeMessages(MSG_REMOVE_SESSION, sessionId); - mHandler.removeMessages(MSG_UPDATE_FOR_SESSION, sessionId); if (mAudioSessionsL.indexOfKey(sessionId) < 0) { + mHandler.removeMessages(MSG_REMOVE_SESSION, sessionId); try { - session = EffectsFactory.createEffectSet(getApplicationContext(), sessionId); + session = EffectsFactory.createEffectSet(getApplicationContext(), + sessionId, mCurrentDevice); } catch (Exception e) { - Log.e(TAG, "couldn't create effects for session id: " + sessionId, - e); + Log.e(TAG, "couldn't create effects for session id: " + sessionId, e); break; } mAudioSessionsL.put(sessionId, session); if (DEBUG) Log.w(TAG, "added new EffectSet for sessionId=" + sessionId); } - mHandler.sendMessageAtFrontOfQueue(Message.obtain(mHandler, MSG_UPDATE_FOR_SESSION, - ALL_CHANGED, 0, sessionId)); + updateBackend(ALL_CHANGED, getSharedPreferences(getCurrentDeviceIdentifier(), 0), session); } break; @@ -286,38 +289,39 @@ public class AudioFxService extends Service { * msg.obj = sessionId */ sessionId = (Integer) msg.obj; - if (sessionId == 0) { + if (sessionId <= 0) { break; } synchronized (mAudioSessionsL) { mHandler.removeMessages(MSG_UPDATE_FOR_SESSION, sessionId); + if (mAudioSessionsL.indexOfKey(sessionId) > -1) { - final EffectSet effectSet = mAudioSessionsL.removeReturnOld(sessionId); - if (effectSet != null && effectSet.isActive()) { - effectSet.release(); - if (DEBUG) Log.w(TAG, "removed and released sessionId=" + sessionId); - } + session = mAudioSessionsL.removeReturnOld(sessionId); } } + if (session != null) { + session.release(); + if (DEBUG) Log.w(TAG, "removed and released sessionId=" + sessionId); + } + break; case MSG_UPDATE_DSP: /** * msg.arg1 = update what flags */ + flags = msg.arg1; + final String mode = getCurrentDeviceIdentifier(); if (DEBUG) Log.i(TAG, "Updating to configuration: " + mode); // cancel updates for other effects, let them go through on the last call synchronized (mAudioSessionsL) { - mHandler.removeMessages(MSG_UPDATE_FOR_SESSION); final int N = mAudioSessionsL.size(); for (int i = 0; i < N; i++) { - final int sessionIdKey = mAudioSessionsL.keyAt(i); - if (!mHandler.hasMessages(MSG_REMOVE_SESSION, sessionIdKey)) { - Message.obtain(mHandler, MSG_UPDATE_FOR_SESSION, msg.arg1, 0, sessionIdKey) - .sendToTarget(); - } + sessionId = mAudioSessionsL.keyAt(i); + Message.obtain(mHandler, MSG_UPDATE_FOR_SESSION, flags, 0, sessionId) + .sendToTarget(); } } break; @@ -328,23 +332,29 @@ public class AudioFxService extends Service { * msg.arg2 = unused * msg.obj = session id integer (for consistency) */ - String device = getCurrentDeviceIdentifier(); sessionId = (Integer) msg.obj; - if (DEBUG) { - Log.i(TAG, "updating DSP for sessionId=" + sessionId + ", device=" + device); + flags = msg.arg1; + + if (sessionId <= 0) { + break; } + + String device = getCurrentDeviceIdentifier(); + if (DEBUG) Log.i(TAG, "updating DSP for sessionId=" + sessionId + + ", device=" + device + " flags=" + flags); + synchronized (mAudioSessionsL) { session = mAudioSessionsL.get(sessionId); - - if (!mHandler.hasMessages(MSG_REMOVE_SESSION, sessionId)) { - updateDsp(msg.arg1, getSharedPreferences(device, 0), session); + if (session != null) { + updateBackend(flags, getSharedPreferences(device, 0), session); } } break; case MSG_SELF_DESTRUCT: - mHandler.removeMessages(MSG_SELF_DESTRUCT); synchronized (mAudioSessionsL) { + mHandler.removeMessages(MSG_SELF_DESTRUCT); + if (mAudioSessionsL.size() == 0) { stopSelf(); Log.w(TAG, "self destructing, no sessions active and nothing to do."); @@ -365,7 +375,23 @@ public class AudioFxService extends Service { mPreviousDevice = mCurrentDevice; mCurrentDevice = outputDevice; - update(ALL_CHANGED); + synchronized (mAudioSessionsL) { + // Update all the sessions for this output which are moving + final int N = mAudioSessionsL.size(); + for (int i = 0; i < N; i++) { + sessionId = mAudioSessionsL.keyAt(i); + session = mAudioSessionsL.valueAt(i); + if (DEBUG) Log.d(TAG, "UPDATE_DEVICE prev=" + + (mPreviousDevice == null ? "none" : mPreviousDevice.getType()) + + " new=" + (mCurrentDevice == null ? "none" : mCurrentDevice.getType() + + " session=" + sessionId + " session-device=" + + (session.getDevice() == null ? "none" : session.getDevice().getType()))); + + session.setDevice(mCurrentDevice); + updateBackend(ALL_CHANGED, getSharedPreferences(getCurrentDeviceIdentifier(), 0), session); + } + } + Intent intent = new Intent(ACTION_DEVICE_OUTPUT_CHANGED); intent.putExtra("device", mCurrentDevice.getId()); LocalBroadcastManager.getInstance(AudioFxService.this).sendBroadcast(intent); @@ -557,7 +583,7 @@ public class AudioFxService extends Service { // ======== DSP UPDATE METHODS BELOW ============= // /** - * Temporarily override a band level. {@link #updateDsp(int flags, SharedPreferences, EffectSet)} will take + * Temporarily override a band level. {@link #updateBackend(int flags, SharedPreferences, EffectSet)} will take * care of overriding the preset value when a preset is selected */ private void updateEqBand(short band, float level, EffectSet effectSet) { @@ -573,18 +599,16 @@ public class AudioFxService extends Service { if (mHandler == null) { return; } - if (!mHandler.hasMessages(MSG_UPDATE_DSP)) { - mHandler.sendMessage(Message.obtain(mHandler, MSG_UPDATE_DSP, flags, 0)); + mHandler.sendMessage(Message.obtain(mHandler, MSG_UPDATE_DSP, flags, 0)); - } if ((flags & ALL_CHANGED) == ALL_CHANGED) { updateQsTile(); } } - private void updateDsp(int flags, SharedPreferences prefs, EffectSet session) { + private synchronized void updateBackend(int flags, SharedPreferences prefs, EffectSet session) { if (DEBUG) { - Log.i(TAG, "updateDsp() called with " + "prefs = [" + prefs + Log.i(TAG, "updateBackend() called with " + "prefs = [" + prefs + "], session = [" + session + "]"); } if (session == null) { @@ -593,15 +617,35 @@ public class AudioFxService extends Service { final boolean globalEnabled = prefs.getBoolean(DEVICE_AUDIOFX_GLOBAL_ENABLE, DEVICE_DEFAULT_GLOBAL_ENABLE); + + // global bypass toggle session.setGlobalEnabled(globalEnabled); + // if we're bypassed, we can gtfo + if (!globalEnabled) { + return; + } + + // tell the backend it's time to party + session.beginUpdate(); + + // Volume boost extended effect first + try { + if ((flags & VOLUME_BOOST_CHANGED) > 0 && session.hasVolumeBoost()) { + // maxx volume + session.enableVolumeBoost(prefs.getBoolean(DEVICE_AUDIOFX_MAXXVOLUME_ENABLE, false)); + } + } catch (Exception e) { + Log.e(TAG, "Error enabling volume boost!", e); + } + // bass try { if ((flags & BASS_BOOST_CHANGED) > 0) { - session.enableBassBoost(globalEnabled - && prefs.getBoolean(DEVICE_AUDIOFX_BASS_ENABLE, false)); + boolean enable = prefs.getBoolean(DEVICE_AUDIOFX_BASS_ENABLE, false); + session.enableBassBoost(enable); session.setBassBoostStrength(Short.valueOf(prefs - .getString(DEVICE_AUDIOFX_BASS_STRENGTH, "0"))); + .getString(DEVICE_AUDIOFX_BASS_STRENGTH, "0"))); } } catch (Exception e) { Log.e(TAG, "Error enabling bass boost!", e); @@ -612,7 +656,7 @@ public class AudioFxService extends Service { if ((flags & REVERB_CHANGED) > 0) { short preset = Short.decode(prefs.getString(DEVICE_AUDIOFX_REVERB_PRESET, String.valueOf(PresetReverb.PRESET_NONE))); - session.enableReverb(globalEnabled && (preset > 0)); + session.enableReverb(preset > 0); session.setReverbPreset(preset); } } catch (Exception e) { @@ -622,8 +666,8 @@ public class AudioFxService extends Service { try { if ((flags & EQ_CHANGED) > 0) { - session.enableEqualizer(globalEnabled); - + // equalizer is always on unless bypassed + session.enableEqualizer(true); String savedPreset = prefs.getString(DEVICE_AUDIOFX_EQ_PRESET_LEVELS, null); if (savedPreset != null) { session.setEqualizerLevelsDecibels(EqUtils.stringBandsToFloats(savedPreset)); @@ -635,8 +679,8 @@ public class AudioFxService extends Service { try { if ((flags & VIRTUALIZER_CHANGED) > 0) { - session.enableVirtualizer(globalEnabled - && prefs.getBoolean(DEVICE_AUDIOFX_VIRTUALIZER_ENABLE, false)); + boolean enable = prefs.getBoolean(DEVICE_AUDIOFX_VIRTUALIZER_ENABLE, false); + session.enableVirtualizer(enable); session.setVirtualizerStrength(Short.valueOf(prefs.getString( DEVICE_AUDIOFX_VIRTUALIZER_STRENGTH, "0"))); } @@ -648,8 +692,8 @@ public class AudioFxService extends Service { try { if ((flags & TREBLE_BOOST_CHANGED) > 0 && session.hasTrebleBoost()) { // treble - session.enableTrebleBoost( - globalEnabled && prefs.getBoolean(DEVICE_AUDIOFX_TREBLE_ENABLE, false)); + boolean enable = prefs.getBoolean(DEVICE_AUDIOFX_TREBLE_ENABLE, false); + session.enableTrebleBoost(enable); session.setTrebleBoostStrength(Short.valueOf( prefs.getString(DEVICE_AUDIOFX_TREBLE_STRENGTH, "0"))); } @@ -657,15 +701,8 @@ public class AudioFxService extends Service { Log.e(TAG, "Error enabling treble boost!", e); } - try { - if ((flags & VOLUME_BOOST_CHANGED) > 0 && session.hasVolumeBoost()) { - // maxx volume - session.enableVolumeBoost( - globalEnabled && prefs.getBoolean(DEVICE_AUDIOFX_MAXXVOLUME_ENABLE, false)); - } - } catch (Exception e) { - Log.e(TAG, "Error enabling volume boost!", e); - } + // mic drop + session.commitUpdate(); } /** @@ -696,7 +733,7 @@ public class AudioFxService extends Service { } return; } - EffectSet temp = EffectsFactory.createEffectSet(getApplicationContext(), 0); + EffectSet temp = EffectsFactory.createEffectSet(getApplicationContext(), 0, null); final int numBands = temp.getNumEqualizerBands(); final int numPresets = temp.getNumEqualizerPresets(); @@ -761,6 +798,14 @@ public class AudioFxService extends Service { .commit(); } + private int findInList(String needle, List<String> haystack) { + for (int i = 0; i < haystack.size(); i++) { + if (haystack.get(i).equalsIgnoreCase(needle)) { + return i; + } + } + return -1; + } /** * This method sets up some *persisted* defaults. @@ -770,68 +815,76 @@ public class AudioFxService extends Service { if (DEBUG) { Log.d(TAG, "applyDefaults() called with overridePrevious = [" + overridePrevious + "]"); } + + if (!(overridePrevious || !getSharedPrefsFile(DEVICE_SPEAKER).exists() || + !getSharedPrefsFile(AUDIOFX_GLOBAL_FILE).exists())) { + return; + } + final SharedPreferences globalPrefs = getSharedPreferences(AUDIOFX_GLOBAL_FILE, 0); - if (globalPrefs.getBoolean(AUDIOFX_GLOBAL_HAS_MAXXAUDIO, false)) { - // Maxx Audio defaults: - // enable speaker by default, enable maxx volume, set preset to the first index, - // which should be flat - if (!getSharedPrefsFile(DEVICE_SPEAKER).exists() || overridePrevious) { - getSharedPreferences(DEVICE_SPEAKER, 0) - .edit() - .putBoolean(DEVICE_AUDIOFX_GLOBAL_ENABLE, true) - .putString(DEVICE_AUDIOFX_EQ_PRESET, "0") - .putBoolean(DEVICE_AUDIOFX_MAXXVOLUME_ENABLE, true) - .commit(); - } - } else if (globalPrefs.getBoolean(AUDIOFX_GLOBAL_HAS_DTS, false)) { - // do nothing for DTS - } else { - // apply defaults for all others - if (Integer.parseInt(globalPrefs.getString(EQUALIZER_NUMBER_OF_BANDS, "0")) == 5) { - - // for 5 band configs, let's add a `Small Speaker` configuration if one - // doesn't exist ( from oss AudioFX: -170;270;50;-220;200 ) - int currentPresets = Integer.parseInt( - globalPrefs.getString(EQUALIZER_NUMBER_OF_PRESETS, "0")); - - final String currentPresetNames = globalPrefs.getString(EQUALIZER_PRESET_NAMES, ""); - - // we use the name as keys - get the english string so its consistent with the - // others even if user has changed locale - final String smallSpeakerPresetName - = getNonLocalizedString(R.string.small_speakers); - - // sanity check - if (currentPresetNames.toLowerCase().contains(smallSpeakerPresetName)) { - // nothing to do! - return; - } - // append new preset identifier - String newPresetNames = currentPresetNames - + (currentPresets > 0 ? "|" : "") - + smallSpeakerPresetName; - - // set this new preset as the default and enable it for speaker - if (!getSharedPrefsFile(DEVICE_SPEAKER).exists() || overridePrevious) { - getSharedPreferences(DEVICE_SPEAKER, 0) - .edit() - .putBoolean(DEVICE_AUDIOFX_GLOBAL_ENABLE, true) - .putString(DEVICE_AUDIOFX_EQ_PRESET, Integer.toString(currentPresets)) - .commit(); - } + // Nothing to see here for DTS + if (globalPrefs.getBoolean(AUDIOFX_GLOBAL_HAS_DTS, false)) { + return; + } - // currentPresets is incremented below - if (!getSharedPrefsFile(AUDIOFX_GLOBAL_FILE).exists() || overridePrevious) { - globalPrefs - .edit() - .putString(EQUALIZER_PRESET + currentPresets, "-170;270;50;-220;200") - .putString(EQUALIZER_PRESET_NAMES, newPresetNames) - .putString(EQUALIZER_NUMBER_OF_PRESETS, - Integer.toString(++currentPresets)) - .commit(); - } - } + // set up the builtin speaker configuration + final String smallSpeakers = getNonLocalizedString(R.string.small_speakers); + final List<String> presetNames = Arrays.asList( + globalPrefs.getString(EQUALIZER_PRESET_NAMES, "").split("\\|")); + final SharedPreferences speakerPrefs = getSharedPreferences(DEVICE_SPEAKER, 0); + + if (globalPrefs.getBoolean(AUDIOFX_GLOBAL_HAS_MAXXAUDIO, false)) { + // MaxxAudio defaults for builtin speaker: + // maxxvolume: on maxxbass: 40% maxxtreble: 32% + speakerPrefs.edit() + .putBoolean(DEVICE_AUDIOFX_GLOBAL_ENABLE, true) + .putBoolean(DEVICE_AUDIOFX_MAXXVOLUME_ENABLE, true) + .putBoolean(DEVICE_AUDIOFX_BASS_ENABLE, true) + .putString(DEVICE_AUDIOFX_BASS_STRENGTH, "400") + .putBoolean(DEVICE_AUDIOFX_TREBLE_ENABLE, true) + .putString(DEVICE_AUDIOFX_TREBLE_STRENGTH, "32") + .commit(); + + // Defaults for headphones + // maxxvolume: on maxxbass: 20% maxxtreble: 40% maxxspace: 20% + getSharedPreferences(DEVICE_HEADSET, 0).edit() + .putBoolean(DEVICE_AUDIOFX_GLOBAL_ENABLE, true) + .putBoolean(DEVICE_AUDIOFX_MAXXVOLUME_ENABLE, true) + .putBoolean(DEVICE_AUDIOFX_BASS_ENABLE, true) + .putString(DEVICE_AUDIOFX_BASS_STRENGTH, "200") + .putBoolean(DEVICE_AUDIOFX_TREBLE_ENABLE, true) + .putString(DEVICE_AUDIOFX_TREBLE_STRENGTH, "40") + .putBoolean(DEVICE_AUDIOFX_VIRTUALIZER_ENABLE, true) + .putString(DEVICE_AUDIOFX_VIRTUALIZER_STRENGTH, "200") + .commit(); + } + + // for 5 band configs, let's add a `Small Speaker` configuration if one + // doesn't exist ( from oss AudioFX: -170;270;50;-220;200 ) + if (Integer.parseInt(globalPrefs.getString(EQUALIZER_NUMBER_OF_BANDS, "0")) == 5 && + findInList(smallSpeakers, presetNames) < 0) { + + int currentPresets = Integer.parseInt( + globalPrefs.getString(EQUALIZER_NUMBER_OF_PRESETS, "0")); + + presetNames.add(smallSpeakers); + String newPresetNames = TextUtils.join("|", presetNames); + globalPrefs.edit() + .putString(EQUALIZER_PRESET + currentPresets, "-170;270;50;-220;200") + .putString(EQUALIZER_PRESET_NAMES, newPresetNames) + .putString(EQUALIZER_NUMBER_OF_PRESETS, Integer.toString(++currentPresets)) + .commit(); + + } + + // set the small speakers preset as the default + int idx = findInList(smallSpeakers, presetNames); + if (idx >= 0) { + speakerPrefs.edit() + .putBoolean(DEVICE_AUDIOFX_GLOBAL_ENABLE, true) + .putString(DEVICE_AUDIOFX_EQ_PRESET, String.valueOf(idx)) + .commit(); } } |