diff --git a/src/ch/blinkenlights/android/vanilla/PlaybackService.java b/src/ch/blinkenlights/android/vanilla/PlaybackService.java index f1802fd3..048959d7 100644 --- a/src/ch/blinkenlights/android/vanilla/PlaybackService.java +++ b/src/ch/blinkenlights/android/vanilla/PlaybackService.java @@ -233,12 +233,18 @@ public final class PlaybackService extends Service * These three bits will be one of SongTimeline.SHUFFLE_*. */ public static final int MASK_SHUFFLE = 0x7 << SHIFT_SHUFFLE; + public static final int SHIFT_DUCKING = 10; + /** + * Whether we're 'ducking' (lowering the playback volume temporarily due to a transient system + * sound, such as a notification) or not + */ + public static final int FLAG_DUCKING = 0x1 << SHIFT_DUCKING; /** * The PlaybackService state, indicating if the service is playing, * repeating, etc. * - * The format of this is 0b00000000_00000000_0000000ff_feeedcba, + * The format of this is 0b00000000_00000000_000000gff_feeedcba, * where each bit is: * a: {@link PlaybackService#FLAG_PLAYING} * b: {@link PlaybackService#FLAG_NO_MEDIA} @@ -246,6 +252,7 @@ public final class PlaybackService extends Service * d: {@link PlaybackService#FLAG_EMPTY_QUEUE} * eee: {@link PlaybackService#MASK_FINISH} * fff: {@link PlaybackService#MASK_SHUFFLE} + * g: {@link PlaybackService#FLAG_DUCKING} */ int mState; @@ -661,7 +668,7 @@ public final class PlaybackService extends Service } else if (rg_result < 0.0f) { rg_result = 0.0f; } - mp.setVolume(rg_result, rg_result); + mp.setReplayGain(rg_result); } /** @@ -979,6 +986,10 @@ public final class PlaybackService extends Service mTimeline.setShuffleMode(shuffleMode(state)); if ((toggled & MASK_FINISH) != 0) mTimeline.setFinishAction(finishAction(state)); + + if((toggled & FLAG_DUCKING) != 0) { + mMediaPlayer.setIsDucking((state & FLAG_DUCKING) != 0); + } } private void broadcastChange(int state, Song song, long uptime) @@ -2010,8 +2021,8 @@ public final class PlaybackService extends Service Log.d("VanillaMusic", "audio focus change: " + type); switch (type) { case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: - mDuckedLoss = (mState & FLAG_PLAYING) != 0; - unsetFlag(FLAG_PLAYING); + mDuckedLoss = true; + setFlag(FLAG_DUCKING); break; case AudioManager.AUDIOFOCUS_LOSS: case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: @@ -2022,7 +2033,7 @@ public final class PlaybackService extends Service case AudioManager.AUDIOFOCUS_GAIN: if (mDuckedLoss) { mDuckedLoss = false; - setFlag(FLAG_PLAYING); + unsetFlag(FLAG_DUCKING); } break; } diff --git a/src/ch/blinkenlights/android/vanilla/VanillaMediaPlayer.java b/src/ch/blinkenlights/android/vanilla/VanillaMediaPlayer.java index dce062dd..a43bccc5 100644 --- a/src/ch/blinkenlights/android/vanilla/VanillaMediaPlayer.java +++ b/src/ch/blinkenlights/android/vanilla/VanillaMediaPlayer.java @@ -29,6 +29,8 @@ public class VanillaMediaPlayer extends MediaPlayer { private Context mContext; private String mDataSource; private boolean mHasNextMediaPlayer; + private float mReplayGain = Float.NaN; + private float mDuckingFactor = Float.NaN; /** * Constructs a new VanillaMediaPlayer class @@ -107,4 +109,38 @@ public class VanillaMediaPlayer extends MediaPlayer { mContext.sendBroadcast(i); } + /** + * Sets the desired scaling due to replay gain. + * @param mReplayGain the factor to adjust the volume by. Must be between 0 and 1 (inclusive) + * or {@link Float#NaN} to disable replay gain scaling + */ + public void setReplayGain(float mReplayGain) { + this.mReplayGain = mReplayGain; + updateVolume(); + } + + /** + * Sets whether we are ducking or not. Ducking is when we temporarily decrease the volume for + * a transient sound to play from another application, such as a notification's beep. + * @param isDucking true if we are ducking, false if we are not + */ + public void setIsDucking(boolean isDucking) { + mDuckingFactor = (isDucking ? 0.2f : Float.NaN); + updateVolume(); + } + + /** + * Sets the volume. Ducking takes precedence over replay gain. If neither ducking nor replay + * gain is set, uses the default value of 1.0f + */ + private void updateVolume() { + float volume = 1.0f; + if(!Float.isNaN(mDuckingFactor)) { + volume = mDuckingFactor; + } else if (!Float.isNaN(mReplayGain)) { + volume = mReplayGain; + } + setVolume(volume, volume); + } + }