mirror of
https://github.com/clangen/musikcube.git
synced 2025-02-06 12:39:54 +00:00
Added support for audio ducking (not just loss of focus).
This commit is contained in:
parent
59b96d2891
commit
20a19218fb
@ -9,6 +9,8 @@ import io.casey.musikcube.remote.util.Preconditions;
|
|||||||
|
|
||||||
public abstract class PlayerWrapper {
|
public abstract class PlayerWrapper {
|
||||||
private static final String TAG = "MediaPlayerWrapper";
|
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 {
|
public enum State {
|
||||||
Stopped,
|
Stopped,
|
||||||
@ -29,19 +31,52 @@ public abstract class PlayerWrapper {
|
|||||||
private static Set<PlayerWrapper> activePlayers = new HashSet<>();
|
private static Set<PlayerWrapper> activePlayers = new HashSet<>();
|
||||||
private static float globalVolume = 1.0f;
|
private static float globalVolume = 1.0f;
|
||||||
private static boolean globalMuted = false;
|
private static boolean globalMuted = false;
|
||||||
|
private static float preDuckGlobalVolume = DUCK_NONE;
|
||||||
|
|
||||||
public static void setGlobalVolume(final float volume) {
|
public static void duck() {
|
||||||
Preconditions.throwIfNotOnMainThread();
|
Preconditions.throwIfNotOnMainThread();
|
||||||
|
|
||||||
globalVolume = volume;
|
if (preDuckGlobalVolume == DUCK_NONE) {
|
||||||
for (final PlayerWrapper w : activePlayers) {
|
final float lastVolume = globalVolume;
|
||||||
w.updateVolume();
|
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() {
|
public static float getGlobalVolume() {
|
||||||
Preconditions.throwIfNotOnMainThread();
|
Preconditions.throwIfNotOnMainThread();
|
||||||
return globalMuted ? 0 : globalVolume;
|
|
||||||
|
if (globalMuted) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (preDuckGlobalVolume == DUCK_NONE) ? globalVolume : preDuckGlobalVolume;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setGlobalMute(final boolean muted) {
|
public static void setGlobalMute(final boolean muted) {
|
||||||
|
@ -858,23 +858,23 @@ public class StreamingPlaybackService implements PlaybackService {
|
|||||||
|
|
||||||
private Runnable pauseServiceShutdownRunnable = () -> SystemService.shutdown();
|
private Runnable pauseServiceShutdownRunnable = () -> SystemService.shutdown();
|
||||||
|
|
||||||
private AudioManager.OnAudioFocusChangeListener audioFocusChangeListener
|
private AudioManager.OnAudioFocusChangeListener audioFocusChangeListener = (flag) -> {
|
||||||
= new AudioManager.OnAudioFocusChangeListener() {
|
switch (flag) {
|
||||||
@Override
|
case AudioManager.AUDIOFOCUS_GAIN:
|
||||||
public void onAudioFocusChange(int flag) {
|
case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT:
|
||||||
switch (flag) {
|
case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE:
|
||||||
case AudioManager.AUDIOFOCUS_GAIN:
|
case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
|
||||||
case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT:
|
PlayerWrapper.unduck();
|
||||||
case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE:
|
break;
|
||||||
case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case AudioManager.AUDIOFOCUS_LOSS:
|
case AudioManager.AUDIOFOCUS_LOSS:
|
||||||
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
|
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
|
||||||
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
|
killAudioFocus();
|
||||||
killAudioFocus();
|
break;
|
||||||
break;
|
|
||||||
}
|
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
|
||||||
|
PlayerWrapper.duck();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -77,10 +77,6 @@ public class SystemService extends Service {
|
|||||||
public static void shutdown() {
|
public static void shutdown() {
|
||||||
final Context c = Application.getInstance();
|
final Context c = Application.getInstance();
|
||||||
c.startService(new Intent(c, SystemService.class).setAction(ACTION_SHUT_DOWN));
|
c.startService(new Intent(c, SystemService.class).setAction(ACTION_SHUT_DOWN));
|
||||||
|
|
||||||
final Exception ex = new Exception();
|
|
||||||
ex.fillInStackTrace();
|
|
||||||
ex.printStackTrace();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -266,8 +262,8 @@ public class SystemService extends Service {
|
|||||||
}
|
}
|
||||||
else if (albumArtModel.is(artist, album)) {
|
else if (albumArtModel.is(artist, album)) {
|
||||||
if (image == null && Strings.notEmpty(albumArtModel.getUrl())) {
|
if (image == null && Strings.notEmpty(albumArtModel.getUrl())) {
|
||||||
/* lookup may have failed -- try again. if the fetch is already in
|
/* lookup may have failed -- try again. if the fetch is already in
|
||||||
progress this will be a no-op */
|
progress this will be a no-op */
|
||||||
albumArtModel.fetch();
|
albumArtModel.fetch();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ public interface Prefs {
|
|||||||
String CERT_VALIDATION_DISABLED = "cert_validation_disabled";
|
String CERT_VALIDATION_DISABLED = "cert_validation_disabled";
|
||||||
String TRANSCODER_BITRATE_INDEX = "transcoder_bitrate_index";
|
String TRANSCODER_BITRATE_INDEX = "transcoder_bitrate_index";
|
||||||
String DISK_CACHE_SIZE_INDEX = "disk_cache_size_index";
|
String DISK_CACHE_SIZE_INDEX = "disk_cache_size_index";
|
||||||
|
String SYSTEM_SERVICE_FOR_REMOTE = "system_service_for_remote";
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Default {
|
interface Default {
|
||||||
@ -31,5 +32,6 @@ public interface Prefs {
|
|||||||
boolean CERT_VALIDATION_DISABLED = false;
|
boolean CERT_VALIDATION_DISABLED = false;
|
||||||
int TRANSCODER_BITRATE_INDEX = 0;
|
int TRANSCODER_BITRATE_INDEX = 0;
|
||||||
int DISK_CACHE_SIZE_INDEX = 0;
|
int DISK_CACHE_SIZE_INDEX = 0;
|
||||||
|
boolean SYSTEM_SERVICE_FOR_REMOTE = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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_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_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_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_artist">[unknown artist]</string>
|
||||||
<string name="unknown_album">[unknown album]</string>
|
<string name="unknown_album">[unknown album]</string>
|
||||||
<string name="unknown_title">[unknown title]</string>
|
<string name="unknown_title">[unknown title]</string>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user