diff --git a/app/src/main/java/org/schabi/newpipe/player/Player.java b/app/src/main/java/org/schabi/newpipe/player/Player.java index b07b15a4585..ef4f86b2a2a 100644 --- a/app/src/main/java/org/schabi/newpipe/player/Player.java +++ b/app/src/main/java/org/schabi/newpipe/player/Player.java @@ -641,6 +641,15 @@ private void initPlayer(final boolean playOnReady) { simpleExoPlayer.setWakeMode(C.WAKE_MODE_NETWORK); simpleExoPlayer.setHandleAudioBecomingNoisy(true); + // Enable automatic audio focus management - let Android handle ducking automatically + simpleExoPlayer.setAudioAttributes( + new com.google.android.exoplayer2.audio.AudioAttributes.Builder() + .setUsage(C.USAGE_MEDIA) + .setContentType(C.AUDIO_CONTENT_TYPE_MUSIC) + .build(), + true // handleAudioFocus = true for automatic management + ); + audioReactor = new AudioReactor(context, simpleExoPlayer); registerBroadcastReceiver(); @@ -1190,10 +1199,6 @@ private void onPrepared(final boolean playWhenReady) { } UIs.call(PlayerUi::onPrepared); - - if (playWhenReady && !isMuted()) { - audioReactor.requestAudioFocus(); - } } private void onBlocked() { @@ -1340,10 +1345,32 @@ public void toggleShuffleModeEnabled() { public void toggleMute() { final boolean wasMuted = isMuted(); + final boolean wasPlaying = simpleExoPlayer.isPlaying(); + Log.d(TAG, "toggleMute: wasMuted=" + wasMuted + ", wasPlaying=" + wasPlaying); simpleExoPlayer.setVolume(wasMuted ? 1 : 0); if (wasMuted) { - audioReactor.requestAudioFocus(); + Log.d(TAG, "toggleMute: enabling audio focus, willPlay=" + wasPlaying); + simpleExoPlayer.setAudioAttributes( + new com.google.android.exoplayer2.audio.AudioAttributes.Builder() + .setUsage(C.USAGE_MEDIA) + .setContentType(C.AUDIO_CONTENT_TYPE_MUSIC) + .build(), + true // handleAudioFocus = true - ExoPlayer handles focus automatically + ); + if (wasPlaying) { + Log.d(TAG, "toggleMute: calling play(), isPlaying=" + simpleExoPlayer.isPlaying()); + simpleExoPlayer.play(); + Log.d(TAG, "toggleMute: after play(), isPlaying=" + simpleExoPlayer.isPlaying()); + } } else { + Log.d(TAG, "toggleMute: disabling audio focus, abandoning focus"); + simpleExoPlayer.setAudioAttributes( + new com.google.android.exoplayer2.audio.AudioAttributes.Builder() + .setUsage(C.USAGE_MEDIA) + .setContentType(C.AUDIO_CONTENT_TYPE_MUSIC) + .build(), + false // handleAudioFocus = false + ); audioReactor.abandonAudioFocus(); } UIs.call(playerUi -> playerUi.onMuteUnmuteChanged(!wasMuted)); @@ -1757,10 +1784,6 @@ public void play() { return; } - if (!isMuted()) { - audioReactor.requestAudioFocus(); - } - if (currentState == STATE_COMPLETED) { if (playQueue.getIndex() == 0) { seekToDefault(); @@ -1781,7 +1804,6 @@ public void pause() { return; } - audioReactor.abandonAudioFocus(); simpleExoPlayer.pause(); saveStreamProgressState(); } diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/AudioReactor.java b/app/src/main/java/org/schabi/newpipe/player/helper/AudioReactor.java index 084336d5483..a0cfea2c457 100644 --- a/app/src/main/java/org/schabi/newpipe/player/helper/AudioReactor.java +++ b/app/src/main/java/org/schabi/newpipe/player/helper/AudioReactor.java @@ -1,8 +1,5 @@ package org.schabi.newpipe.player.helper; -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.ValueAnimator; import android.content.Context; import android.content.Intent; import android.media.AudioManager; @@ -17,20 +14,16 @@ import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.analytics.AnalyticsListener; -public class AudioReactor implements AudioManager.OnAudioFocusChangeListener, AnalyticsListener { +public class AudioReactor implements AnalyticsListener { private static final String TAG = "AudioFocusReactor"; - private static final int DUCK_DURATION = 1500; - private static final float DUCK_AUDIO_TO = .2f; - private static final int FOCUS_GAIN_TYPE = AudioManagerCompat.AUDIOFOCUS_GAIN; private static final int STREAM_TYPE = AudioManager.STREAM_MUSIC; private final ExoPlayer player; private final Context context; private final AudioManager audioManager; - private final AudioFocusRequestCompat request; public AudioReactor(@NonNull final Context context, @@ -41,9 +34,9 @@ public AudioReactor(@NonNull final Context context, player.addAnalyticsListener(this); request = new AudioFocusRequestCompat.Builder(FOCUS_GAIN_TYPE) - //.setAcceptsDelayedFocusGain(true) .setWillPauseWhenDucked(true) - .setOnAudioFocusChangeListener(this) + .setOnAudioFocusChangeListener(focusChange -> { + }) .build(); } @@ -54,17 +47,23 @@ public void dispose() { } /*////////////////////////////////////////////////////////////////////////// - // Audio Manager + // Audio Focus //////////////////////////////////////////////////////////////////////////*/ public void requestAudioFocus() { + Log.d(TAG, "requestAudioFocus() called"); AudioManagerCompat.requestAudioFocus(audioManager, request); } public void abandonAudioFocus() { + Log.d(TAG, "abandonAudioFocus() called"); AudioManagerCompat.abandonAudioFocusRequest(audioManager, request); } + /*////////////////////////////////////////////////////////////////////////// + // Audio Manager + //////////////////////////////////////////////////////////////////////////*/ + public int getVolume() { return audioManager.getStreamVolume(STREAM_TYPE); } @@ -77,73 +76,6 @@ public int getMaxVolume() { return AudioManagerCompat.getStreamMaxVolume(audioManager, STREAM_TYPE); } - /*////////////////////////////////////////////////////////////////////////// - // AudioFocus - //////////////////////////////////////////////////////////////////////////*/ - - @Override - public void onAudioFocusChange(final int focusChange) { - Log.d(TAG, "onAudioFocusChange() called with: focusChange = [" + focusChange + "]"); - switch (focusChange) { - case AudioManager.AUDIOFOCUS_GAIN: - onAudioFocusGain(); - break; - case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: - onAudioFocusLossCanDuck(); - break; - case AudioManager.AUDIOFOCUS_LOSS: - case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: - onAudioFocusLoss(); - break; - } - } - - private void onAudioFocusGain() { - Log.d(TAG, "onAudioFocusGain() called"); - player.setVolume(DUCK_AUDIO_TO); - animateAudio(DUCK_AUDIO_TO, 1.0f); - - if (PlayerHelper.isResumeAfterAudioFocusGain(context)) { - player.play(); - } - } - - private void onAudioFocusLoss() { - Log.d(TAG, "onAudioFocusLoss() called"); - player.pause(); - } - - private void onAudioFocusLossCanDuck() { - Log.d(TAG, "onAudioFocusLossCanDuck() called"); - // Set the volume to 1/10 on ducking - player.setVolume(DUCK_AUDIO_TO); - } - - private void animateAudio(final float from, final float to) { - final ValueAnimator valueAnimator = new ValueAnimator(); - valueAnimator.setFloatValues(from, to); - valueAnimator.setDuration(AudioReactor.DUCK_DURATION); - valueAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationStart(final Animator animation) { - player.setVolume(from); - } - - @Override - public void onAnimationCancel(final Animator animation) { - player.setVolume(to); - } - - @Override - public void onAnimationEnd(final Animator animation) { - player.setVolume(to); - } - }); - valueAnimator.addUpdateListener(animation -> - player.setVolume(((float) animation.getAnimatedValue()))); - valueAnimator.start(); - } - /*////////////////////////////////////////////////////////////////////////// // Audio Processing //////////////////////////////////////////////////////////////////////////*/