refactor: let exoplayer handle audio focus
This commit is contained in:
parent
a68066fa61
commit
fcf2c62d9a
2 changed files with 18 additions and 111 deletions
|
|
@ -107,9 +107,6 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
|
||||||
public static final int PLAY_SONG = 3;
|
public static final int PLAY_SONG = 3;
|
||||||
public static final int PREPARE_NEXT = 4;
|
public static final int PREPARE_NEXT = 4;
|
||||||
public static final int SET_POSITION = 5;
|
public static final int SET_POSITION = 5;
|
||||||
public static final int FOCUS_CHANGE = 6;
|
|
||||||
public static final int DUCK = 7;
|
|
||||||
public static final int UNDUCK = 8;
|
|
||||||
|
|
||||||
public static final int SHUFFLE_MODE_NONE = 0;
|
public static final int SHUFFLE_MODE_NONE = 0;
|
||||||
public static final int SHUFFLE_MODE_SHUFFLE = 1;
|
public static final int SHUFFLE_MODE_SHUFFLE = 1;
|
||||||
|
|
@ -142,10 +139,8 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
|
||||||
|
|
||||||
private boolean notHandledMetaChangedForCurrentTrack;
|
private boolean notHandledMetaChangedForCurrentTrack;
|
||||||
private boolean queuesRestored;
|
private boolean queuesRestored;
|
||||||
private boolean pausedByTransientLossOfFocus;
|
|
||||||
|
|
||||||
private PlayingNotification playingNotification;
|
private PlayingNotification playingNotification;
|
||||||
private AudioManager audioManager;
|
|
||||||
private MediaSessionCompat mediaSession;
|
private MediaSessionCompat mediaSession;
|
||||||
private PowerManager.WakeLock wakeLock;
|
private PowerManager.WakeLock wakeLock;
|
||||||
|
|
||||||
|
|
@ -188,13 +183,6 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private final AudioManager.OnAudioFocusChangeListener audioFocusListener = new AudioManager.OnAudioFocusChangeListener() {
|
|
||||||
@Override
|
|
||||||
public void onAudioFocusChange(final int focusChange) {
|
|
||||||
playerHandler.obtainMessage(FOCUS_CHANGE, focusChange, 0).sendToTarget();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private static final long MEDIA_SESSION_ACTIONS = PlaybackStateCompat.ACTION_PLAY
|
private static final long MEDIA_SESSION_ACTIONS = PlaybackStateCompat.ACTION_PLAY
|
||||||
| PlaybackStateCompat.ACTION_PAUSE
|
| PlaybackStateCompat.ACTION_PAUSE
|
||||||
| PlaybackStateCompat.ACTION_PLAY_PAUSE
|
| PlaybackStateCompat.ACTION_PLAY_PAUSE
|
||||||
|
|
@ -241,14 +229,6 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
|
||||||
mediaSession.setActive(true);
|
mediaSession.setActive(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private AudioManager getAudioManager() {
|
|
||||||
if (audioManager == null) {
|
|
||||||
audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
|
|
||||||
}
|
|
||||||
|
|
||||||
return audioManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initMediaSession() {
|
private void initMediaSession() {
|
||||||
ComponentName mediaButtonReceiverComponentName = new ComponentName(getApplicationContext(), MediaButtonIntentReceiver.class);
|
ComponentName mediaButtonReceiverComponentName = new ComponentName(getApplicationContext(), MediaButtonIntentReceiver.class);
|
||||||
|
|
||||||
|
|
@ -458,7 +438,6 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
|
||||||
pause();
|
pause();
|
||||||
playingNotification.stop();
|
playingNotification.stop();
|
||||||
|
|
||||||
getAudioManager().abandonAudioFocus(audioFocusListener);
|
|
||||||
stopSelf();
|
stopSelf();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -526,10 +505,6 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean requestFocus() {
|
|
||||||
return getAudioManager().requestAudioFocus(audioFocusListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN) == AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void initNotification() {
|
public void initNotification() {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && !PreferenceUtil.getInstance(this).getClassicNotification()) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && !PreferenceUtil.getInstance(this).getClassicNotification()) {
|
||||||
playingNotification = new PlayingNotificationNougat();
|
playingNotification = new PlayingNotificationNougat();
|
||||||
|
|
@ -805,7 +780,6 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
|
||||||
}
|
}
|
||||||
|
|
||||||
public void pause() {
|
public void pause() {
|
||||||
pausedByTransientLossOfFocus = false;
|
|
||||||
if (playback.isPlaying()) {
|
if (playback.isPlaying()) {
|
||||||
playback.pause();
|
playback.pause();
|
||||||
notifyChange(STATE_CHANGED);
|
notifyChange(STATE_CHANGED);
|
||||||
|
|
@ -814,27 +788,18 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
|
||||||
|
|
||||||
public void play() {
|
public void play() {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
if (requestFocus()) {
|
if (!playback.isPlaying()) {
|
||||||
if (!playback.isPlaying()) {
|
if (!playback.isReady()) {
|
||||||
if (!playback.isReady()) {
|
playSongAt(getPosition());
|
||||||
playSongAt(getPosition());
|
} else {
|
||||||
} else {
|
playback.start();
|
||||||
playback.start();
|
if (notHandledMetaChangedForCurrentTrack) {
|
||||||
if (notHandledMetaChangedForCurrentTrack) {
|
handleChangeInternal(META_CHANGED);
|
||||||
handleChangeInternal(META_CHANGED);
|
notHandledMetaChangedForCurrentTrack = false;
|
||||||
notHandledMetaChangedForCurrentTrack = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
notifyChange(STATE_CHANGED);
|
|
||||||
|
|
||||||
// fixes a bug where the volume would stay ducked
|
|
||||||
// happens when audio focus GAIN event not sent
|
|
||||||
playerHandler.removeMessages(DUCK);
|
|
||||||
playerHandler.sendEmptyMessage(UNDUCK);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
notifyChange(STATE_CHANGED);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
Toast.makeText(this, getResources().getString(R.string.audio_focus_denied), Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1065,7 +1030,6 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
|
||||||
|
|
||||||
private static final class PlaybackHandler extends Handler {
|
private static final class PlaybackHandler extends Handler {
|
||||||
private final WeakReference<MusicService> mService;
|
private final WeakReference<MusicService> mService;
|
||||||
private int currentDuckVolume = 100;
|
|
||||||
|
|
||||||
public PlaybackHandler(final MusicService service, @NonNull final Looper looper) {
|
public PlaybackHandler(final MusicService service, @NonNull final Looper looper) {
|
||||||
super(looper);
|
super(looper);
|
||||||
|
|
@ -1080,36 +1044,6 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (msg.what) {
|
switch (msg.what) {
|
||||||
case DUCK:
|
|
||||||
if (PreferenceUtil.getInstance(service).getAudioDucking()) {
|
|
||||||
currentDuckVolume -= 5;
|
|
||||||
if (currentDuckVolume > 20) {
|
|
||||||
sendEmptyMessageDelayed(DUCK, 10);
|
|
||||||
} else {
|
|
||||||
currentDuckVolume = 20;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
currentDuckVolume = 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
service.playback.setVolume(currentDuckVolume);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case UNDUCK:
|
|
||||||
if (PreferenceUtil.getInstance(service).getAudioDucking()) {
|
|
||||||
currentDuckVolume += 3;
|
|
||||||
if (currentDuckVolume < 100) {
|
|
||||||
sendEmptyMessageDelayed(UNDUCK, 10);
|
|
||||||
} else {
|
|
||||||
currentDuckVolume = 100;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
currentDuckVolume = 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
service.playback.setVolume(currentDuckVolume);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TRACK_CHANGED:
|
case TRACK_CHANGED:
|
||||||
if (service.getRepeatMode() == REPEAT_MODE_NONE && service.isLastTrack()) {
|
if (service.getRepeatMode() == REPEAT_MODE_NONE && service.isLastTrack()) {
|
||||||
service.pause();
|
service.pause();
|
||||||
|
|
@ -1157,40 +1091,6 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
|
||||||
case PREPARE_NEXT:
|
case PREPARE_NEXT:
|
||||||
service.prepareNextImpl();
|
service.prepareNextImpl();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FOCUS_CHANGE:
|
|
||||||
switch (msg.arg1) {
|
|
||||||
case AudioManager.AUDIOFOCUS_GAIN:
|
|
||||||
if (!service.isPlaying() && service.pausedByTransientLossOfFocus) {
|
|
||||||
service.play();
|
|
||||||
service.pausedByTransientLossOfFocus = false;
|
|
||||||
}
|
|
||||||
removeMessages(DUCK);
|
|
||||||
sendEmptyMessage(UNDUCK);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case AudioManager.AUDIOFOCUS_LOSS:
|
|
||||||
// Lost focus for an unbounded amount of time: stop playback and release media playback
|
|
||||||
service.pause();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
|
|
||||||
// Lost focus for a short time, but we have to stop
|
|
||||||
// playback. We don't release the media playback because playback
|
|
||||||
// is likely to resume
|
|
||||||
boolean wasPlaying = service.isPlaying();
|
|
||||||
service.pause();
|
|
||||||
service.pausedByTransientLossOfFocus = wasPlaying;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
|
|
||||||
// Lost focus for a short time, but it's ok to keep playing
|
|
||||||
// at an attenuated level
|
|
||||||
removeMessages(UNDUCK);
|
|
||||||
sendEmptyMessage(DUCK);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@ import com.dkanada.gramophone.R;
|
||||||
import com.dkanada.gramophone.model.Song;
|
import com.dkanada.gramophone.model.Song;
|
||||||
import com.dkanada.gramophone.util.MusicUtil;
|
import com.dkanada.gramophone.util.MusicUtil;
|
||||||
import com.dkanada.gramophone.util.PreferenceUtil;
|
import com.dkanada.gramophone.util.PreferenceUtil;
|
||||||
|
import com.google.android.exoplayer2.C;
|
||||||
|
import com.google.android.exoplayer2.audio.AudioAttributes;
|
||||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||||
import com.google.android.exoplayer2.Player;
|
import com.google.android.exoplayer2.Player;
|
||||||
import com.google.android.exoplayer2.Player.EventListener;
|
import com.google.android.exoplayer2.Player.EventListener;
|
||||||
|
|
@ -82,7 +84,12 @@ public class LocalPlayer implements Playback {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
|
||||||
MediaSourceFactory mediaSourceFactory = new UnknownMediaSourceFactory(buildDataSourceFactory());
|
MediaSourceFactory mediaSourceFactory = new UnknownMediaSourceFactory(buildDataSourceFactory());
|
||||||
exoPlayer = new SimpleExoPlayer.Builder(context).setMediaSourceFactory(mediaSourceFactory).build();
|
AudioAttributes audioAttributes = new AudioAttributes.Builder()
|
||||||
|
.setUsage(C.USAGE_MEDIA)
|
||||||
|
.setContentType(C.CONTENT_TYPE_MUSIC)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
exoPlayer = new SimpleExoPlayer.Builder(context).setMediaSourceFactory(mediaSourceFactory).setAudioAttributes(audioAttributes, true).build();
|
||||||
|
|
||||||
exoPlayer.addListener(eventListener);
|
exoPlayer.addListener(eventListener);
|
||||||
exoPlayer.prepare();
|
exoPlayer.prepare();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue