Merge 3c58b34ac49de1c9f9b957c88fe539fe1636df94 into 4481dd7fe6dd8c9bd116c391aed544de6239c640

This commit is contained in:
Yubi Lee 2026-02-21 12:38:29 +01:00 committed by GitHub
commit 3310493626
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 10 additions and 108 deletions

View File

@ -641,6 +641,15 @@ public final class Player implements PlaybackListener, Listener {
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 @@ public final class Player implements PlaybackListener, Listener {
}
UIs.call(PlayerUi::onPrepared);
if (playWhenReady && !isMuted()) {
audioReactor.requestAudioFocus();
}
}
private void onBlocked() {
@ -1341,11 +1346,6 @@ public final class Player implements PlaybackListener, Listener {
public void toggleMute() {
final boolean wasMuted = isMuted();
simpleExoPlayer.setVolume(wasMuted ? 1 : 0);
if (wasMuted) {
audioReactor.requestAudioFocus();
} else {
audioReactor.abandonAudioFocus();
}
UIs.call(playerUi -> playerUi.onMuteUnmuteChanged(!wasMuted));
notifyPlaybackUpdateToListeners();
}
@ -1757,10 +1757,6 @@ public final class Player implements PlaybackListener, Listener {
return;
}
if (!isMuted()) {
audioReactor.requestAudioFocus();
}
if (currentState == STATE_COMPLETED) {
if (playQueue.getIndex() == 0) {
seekToDefault();
@ -1781,7 +1777,6 @@ public final class Player implements PlaybackListener, Listener {
return;
}
audioReactor.abandonAudioFocus();
simpleExoPlayer.pause();
saveStreamProgressState();
}

View File

@ -1,54 +1,36 @@
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;
import android.media.audiofx.AudioEffect;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import androidx.media.AudioFocusRequestCompat;
import androidx.media.AudioManagerCompat;
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,
@NonNull final ExoPlayer player) {
this.player = player;
this.context = context;
this.audioManager = ContextCompat.getSystemService(context, AudioManager.class);
player.addAnalyticsListener(this);
request = new AudioFocusRequestCompat.Builder(FOCUS_GAIN_TYPE)
//.setAcceptsDelayedFocusGain(true)
.setWillPauseWhenDucked(true)
.setOnAudioFocusChangeListener(this)
.build();
}
public void dispose() {
abandonAudioFocus();
player.removeAnalyticsListener(this);
notifyAudioSessionUpdate(false, player.getAudioSessionId());
}
@ -57,14 +39,6 @@ public class AudioReactor implements AudioManager.OnAudioFocusChangeListener, An
// Audio Manager
//////////////////////////////////////////////////////////////////////////*/
public void requestAudioFocus() {
AudioManagerCompat.requestAudioFocus(audioManager, request);
}
public void abandonAudioFocus() {
AudioManagerCompat.abandonAudioFocusRequest(audioManager, request);
}
public int getVolume() {
return audioManager.getStreamVolume(STREAM_TYPE);
}
@ -77,73 +51,6 @@ public class AudioReactor implements AudioManager.OnAudioFocusChangeListener, An
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
//////////////////////////////////////////////////////////////////////////*/