Added support for audio ducking (not just loss of focus).

This commit is contained in:
casey langen 2017-05-21 12:52:56 -07:00
parent 59b96d2891
commit 20a19218fb
5 changed files with 61 additions and 27 deletions

View File

@ -9,6 +9,8 @@ import io.casey.musikcube.remote.util.Preconditions;
public abstract class PlayerWrapper {
private static final String TAG = "MediaPlayerWrapper";
private static final float DUCK_COEF = 0.2f; /* volume = 20% when ducked */
private static final float DUCK_NONE = -1.0f;
public enum State {
Stopped,
@ -29,19 +31,52 @@ public abstract class PlayerWrapper {
private static Set<PlayerWrapper> activePlayers = new HashSet<>();
private static float globalVolume = 1.0f;
private static boolean globalMuted = false;
private static float preDuckGlobalVolume = DUCK_NONE;
public static void setGlobalVolume(final float volume) {
public static void duck() {
Preconditions.throwIfNotOnMainThread();
globalVolume = volume;
for (final PlayerWrapper w : activePlayers) {
w.updateVolume();
if (preDuckGlobalVolume == DUCK_NONE) {
final float lastVolume = globalVolume;
setGlobalVolume(globalVolume * DUCK_COEF);
preDuckGlobalVolume = lastVolume;
}
}
public static void unduck() {
Preconditions.throwIfNotOnMainThread();
if (preDuckGlobalVolume != DUCK_NONE) {
final float temp = preDuckGlobalVolume;
preDuckGlobalVolume = DUCK_NONE;
setGlobalVolume(temp);
}
}
public static void setGlobalVolume(float volume) {
Preconditions.throwIfNotOnMainThread();
if (preDuckGlobalVolume != DUCK_NONE) {
preDuckGlobalVolume = volume;
volume = volume * DUCK_COEF;
}
if (volume != globalVolume) {
globalVolume = volume;
for (final PlayerWrapper w : activePlayers) {
w.updateVolume();
}
}
}
public static float getGlobalVolume() {
Preconditions.throwIfNotOnMainThread();
return globalMuted ? 0 : globalVolume;
if (globalMuted) {
return 0;
}
return (preDuckGlobalVolume == DUCK_NONE) ? globalVolume : preDuckGlobalVolume;
}
public static void setGlobalMute(final boolean muted) {

View File

@ -858,23 +858,23 @@ public class StreamingPlaybackService implements PlaybackService {
private Runnable pauseServiceShutdownRunnable = () -> SystemService.shutdown();
private AudioManager.OnAudioFocusChangeListener audioFocusChangeListener
= new AudioManager.OnAudioFocusChangeListener() {
@Override
public void onAudioFocusChange(int flag) {
switch (flag) {
case AudioManager.AUDIOFOCUS_GAIN:
case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT:
case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE:
case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
break;
private AudioManager.OnAudioFocusChangeListener audioFocusChangeListener = (flag) -> {
switch (flag) {
case AudioManager.AUDIOFOCUS_GAIN:
case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT:
case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE:
case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
PlayerWrapper.unduck();
break;
case AudioManager.AUDIOFOCUS_LOSS:
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
killAudioFocus();
break;
}
case AudioManager.AUDIOFOCUS_LOSS:
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
killAudioFocus();
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
PlayerWrapper.duck();
break;
}
};

View File

@ -77,10 +77,6 @@ public class SystemService extends Service {
public static void shutdown() {
final Context c = Application.getInstance();
c.startService(new Intent(c, SystemService.class).setAction(ACTION_SHUT_DOWN));
final Exception ex = new Exception();
ex.fillInStackTrace();
ex.printStackTrace();
}
@Override
@ -266,8 +262,8 @@ public class SystemService extends Service {
}
else if (albumArtModel.is(artist, album)) {
if (image == null && Strings.notEmpty(albumArtModel.getUrl())) {
/* lookup may have failed -- try again. if the fetch is already in
progress this will be a no-op */
/* lookup may have failed -- try again. if the fetch is already in
progress this will be a no-op */
albumArtModel.fetch();
}

View File

@ -16,6 +16,7 @@ public interface Prefs {
String CERT_VALIDATION_DISABLED = "cert_validation_disabled";
String TRANSCODER_BITRATE_INDEX = "transcoder_bitrate_index";
String DISK_CACHE_SIZE_INDEX = "disk_cache_size_index";
String SYSTEM_SERVICE_FOR_REMOTE = "system_service_for_remote";
}
interface Default {
@ -31,5 +32,6 @@ public interface Prefs {
boolean CERT_VALIDATION_DISABLED = false;
int TRANSCODER_BITRATE_INDEX = 0;
int DISK_CACHE_SIZE_INDEX = 0;
boolean SYSTEM_SERVICE_FOR_REMOTE = false;
}
}

View File

@ -67,6 +67,7 @@
<string name="settings_ssl_dialog_message">the musikcube server doesn\'t support ssl by default. it does, however, work very well with nginx and ssl termination. press \'learn more\' for configuration information.</string>
<string name="settings_disable_cert_validation_title">certificate verification</string>
<string name="settings_disable_cert_validation_message">there is really no reason to enable this setting. ssl without certificate validation opens you up to man-in-the-middle attacks, and only adds a false sense of security.\n\nare you sure you want to enable this setting?</string>
<string name="settings_enable_notification_for_remote_playback">enable lock screen integration for remote playback</string>
<string name="unknown_artist">[unknown artist]</string>
<string name="unknown_album">[unknown album]</string>
<string name="unknown_title">[unknown title]</string>