if (!Util.areEqual(this.audioAttributes, audioAttributes)) { this.audioAttributes = audioAttributes; focusGain = convertAudioAttributesToFocusGain(audioAttributes); if (playWhenReady && (playerState == Player.STATE_BUFFERING || playerState == Player.STATE_READY)) { return requestAudioFocus(); ? handleIdle(playWhenReady) : handlePrepare(playWhenReady);
/** * Called by the player as part of {@link ExoPlayer#setPlayWhenReady(boolean)}. * * @param playWhenReady The desired value of playWhenReady. * @param playerState The current state of the player. * @return A {@link PlayerCommand} to execute on the player. */ public @PlayerCommand int handleSetPlayWhenReady(boolean playWhenReady, int playerState) { if (audioManager == null) { return PLAYER_COMMAND_PLAY_WHEN_READY; } if (!playWhenReady) { abandonAudioFocus(); return PLAYER_COMMAND_DO_NOT_PLAY; } return playerState == Player.STATE_IDLE ? handleIdle(playWhenReady) : requestAudioFocus(); }
private void abandonAudioFocus(boolean forceAbandon) { if (focusGain == C.AUDIOFOCUS_NONE && audioFocusState == AUDIO_FOCUS_STATE_NO_FOCUS) { return; } if (focusGain != C.AUDIOFOCUS_GAIN || audioFocusState == AUDIO_FOCUS_STATE_LOST_FOCUS || forceAbandon) { if (Util.SDK_INT >= 26) { abandonAudioFocusV26(); } else { abandonAudioFocusDefault(); } audioFocusState = AUDIO_FOCUS_STATE_NO_FOCUS; } }
private @PlayerCommand int requestAudioFocus() { int focusRequestResult; if (focusGain == C.AUDIOFOCUS_NONE) { if (audioFocusState != AUDIO_FOCUS_STATE_NO_FOCUS) { abandonAudioFocus(/* forceAbandon= */ true); } return PLAYER_COMMAND_PLAY_WHEN_READY; } if (audioFocusState == AUDIO_FOCUS_STATE_NO_FOCUS) { if (Util.SDK_INT >= 26) { focusRequestResult = requestAudioFocusV26(); } else { focusRequestResult = requestAudioFocusDefault(); } audioFocusState = focusRequestResult == AudioManager.AUDIOFOCUS_REQUEST_GRANTED ? AUDIO_FOCUS_STATE_HAVE_FOCUS : AUDIO_FOCUS_STATE_NO_FOCUS; } if (audioFocusState == AUDIO_FOCUS_STATE_NO_FOCUS) { return PLAYER_COMMAND_DO_NOT_PLAY; } return audioFocusState == AUDIO_FOCUS_STATE_LOSS_TRANSIENT ? PLAYER_COMMAND_WAIT_FOR_CALLBACK : PLAYER_COMMAND_PLAY_WHEN_READY; }
@Test public void handleStop_withoutHandlingAudioFocus_isNoOp() { // Ensure that handleStop is a no-op if audio focus isn't handled. Shadows.shadowOf(audioManager) .setNextFocusRequestResponse(AudioManager.AUDIOFOCUS_REQUEST_GRANTED); assertThat( audioFocusManager.setAudioAttributes( /* audioAttributes= */ null, /* playWhenReady= */ false, Player.STATE_READY)) .isEqualTo(PLAYER_COMMAND_DO_NOT_PLAY); assertThat(Shadows.shadowOf(audioManager).getLastAbandonedAudioFocusListener()).isNull(); ShadowAudioManager.AudioFocusRequest request = Shadows.shadowOf(audioManager).getLastAudioFocusRequest(); assertThat(request).isNull(); audioFocusManager.handleStop(); assertThat(Shadows.shadowOf(audioManager).getLastAbandonedAudioFocusListener()).isNull(); }
@Test public void setAudioAttributes_withNullUsage_doesNotManageAudioFocus() { // Ensure that NULL audio attributes -> don't manage audio focus assertThat( audioFocusManager.setAudioAttributes( /* audioAttributes= */ null, /* playWhenReady= */ false, Player.STATE_IDLE)) .isEqualTo(PLAYER_COMMAND_DO_NOT_PLAY); assertThat( audioFocusManager.setAudioAttributes( /* audioAttributes= */ null, /* playWhenReady= */ true, Player.STATE_READY)) .isEqualTo(PLAYER_COMMAND_PLAY_WHEN_READY); ShadowAudioManager.AudioFocusRequest request = Shadows.shadowOf(audioManager).getLastAudioFocusRequest(); assertThat(request).isNull(); }
@Test public void handleSetPlayWhenReady_afterSetAudioAttributes_setsPlayerCommandPlayWhenReady() { // Ensure that audio focus is not requested until playWhenReady is true. AudioAttributes media = new AudioAttributes.Builder().setUsage(C.USAGE_MEDIA).build(); Shadows.shadowOf(audioManager) .setNextFocusRequestResponse(AudioManager.AUDIOFOCUS_REQUEST_GRANTED); assertThat(audioFocusManager.handlePrepare(/* playWhenReady= */ false)) .isEqualTo(PLAYER_COMMAND_DO_NOT_PLAY); assertThat(Shadows.shadowOf(audioManager).getLastAudioFocusRequest()).isNull(); assertThat( audioFocusManager.setAudioAttributes( media, /* playWhenReady= */ false, Player.STATE_READY)) .isEqualTo(PLAYER_COMMAND_DO_NOT_PLAY); assertThat(Shadows.shadowOf(audioManager).getLastAudioFocusRequest()).isNull(); assertThat( audioFocusManager.handleSetPlayWhenReady(/* playWhenReady= */ true, Player.STATE_READY)) .isEqualTo(PLAYER_COMMAND_PLAY_WHEN_READY); }
@Test public void handlePrepare_afterSetAudioAttributes_setsPlayerCommandPlayWhenReady() { // Ensure that when playWhenReady is true while the player is IDLE, audio focus is only // requested after calling handlePrepare. AudioAttributes media = new AudioAttributes.Builder().setUsage(C.USAGE_MEDIA).build(); Shadows.shadowOf(audioManager) .setNextFocusRequestResponse(AudioManager.AUDIOFOCUS_REQUEST_GRANTED); assertThat( audioFocusManager.setAudioAttributes( media, /* playWhenReady= */ true, Player.STATE_IDLE)) .isEqualTo(PLAYER_COMMAND_PLAY_WHEN_READY); assertThat(Shadows.shadowOf(audioManager).getLastAudioFocusRequest()).isNull(); assertThat(audioFocusManager.handlePrepare(/* playWhenReady= */ true)) .isEqualTo(PLAYER_COMMAND_PLAY_WHEN_READY); }
/** @deprecated Use {@link com.google.android.exoplayer2.video.VideoListener}. */ @Deprecated public interface VideoListener extends com.google.android.exoplayer2.video.VideoListener {}
@Override public void stop(boolean reset) { verifyApplicationThread(); player.stop(reset); if (mediaSource != null) { mediaSource.removeEventListener(analyticsCollector); analyticsCollector.resetForNewMediaSource(); if (reset) { mediaSource = null; } } audioFocusManager.handleStop(); currentCues = Collections.emptyList(); }
@Override public void setPlayWhenReady(boolean playWhenReady) { verifyApplicationThread(); @AudioFocusManager.PlayerCommand int playerCommand = audioFocusManager.handleSetPlayWhenReady(playWhenReady, getPlaybackState()); updatePlayWhenReady(playWhenReady, playerCommand); }
@Override public void prepare(MediaSource mediaSource, boolean resetPosition, boolean resetState) { verifyApplicationThread(); if (this.mediaSource != null) { this.mediaSource.removeEventListener(analyticsCollector); analyticsCollector.resetForNewMediaSource(); } this.mediaSource = mediaSource; mediaSource.addEventListener(eventHandler, analyticsCollector); @AudioFocusManager.PlayerCommand int playerCommand = audioFocusManager.handlePrepare(getPlayWhenReady()); updatePlayWhenReady(getPlayWhenReady(), playerCommand); player.prepare(mediaSource, resetPosition, resetState); }
/** Called by the player as part of {@link ExoPlayer#stop(boolean)}. */ public void handleStop() { if (audioManager == null) { return; } abandonAudioFocus(/* forceAbandon= */ true); }
private void sendVolumeToRenderers() { float scaledVolume = audioVolume * audioFocusManager.getVolumeMultiplier(); for (Renderer renderer : renderers) { if (renderer.getTrackType() == C.TRACK_TYPE_AUDIO) { player.createMessage(renderer).setType(C.MSG_SET_VOLUME).setPayload(scaledVolume).send(); } } }
@Test public void handleStop_withoutAudioFocus_stillAbandonsFocus() { // Ensure that handleStop causes AudioFocusManager to call through to abandon audio focus // even if focus wasn't requested. AudioAttributes media = new AudioAttributes.Builder() .setUsage(C.USAGE_MEDIA) .setContentType(C.CONTENT_TYPE_SPEECH) .build(); Shadows.shadowOf(audioManager) .setNextFocusRequestResponse(AudioManager.AUDIOFOCUS_REQUEST_GRANTED); assertThat( audioFocusManager.setAudioAttributes( media, /* playWhenReady= */ false, Player.STATE_READY)) .isEqualTo(PLAYER_COMMAND_DO_NOT_PLAY); assertThat(Shadows.shadowOf(audioManager).getLastAbandonedAudioFocusListener()).isNull(); ShadowAudioManager.AudioFocusRequest request = Shadows.shadowOf(audioManager).getLastAudioFocusRequest(); assertThat(request).isNull(); audioFocusManager.handleStop(); assertThat(Shadows.shadowOf(audioManager).getLastAbandonedAudioFocusListener()).isNotNull(); }
@Test public void setAudioAttributes_withUsageAlarm_throwsIllegalArgumentException() { // Ensure that audio attributes that map to AUDIOFOCUS_GAIN_TRANSIENT* throw AudioAttributes alarm = new AudioAttributes.Builder().setUsage(C.USAGE_ALARM).build(); try { audioFocusManager.setAudioAttributes(alarm, /* playWhenReady= */ false, Player.STATE_IDLE); fail(); } catch (IllegalArgumentException e) { // Expected } }
@Before public void setUp() { audioManager = (AudioManager) RuntimeEnvironment.application.getSystemService(Context.AUDIO_SERVICE); testPlayerControl = new TestPlayerControl(); audioFocusManager = new AudioFocusManager(RuntimeEnvironment.application, testPlayerControl); }
@Override public void release() { audioFocusManager.handleStop(); player.release(); removeSurfaceCallbacks(); if (surface != null) { if (ownsSurface) { surface.release(); } surface = null; } if (mediaSource != null) { mediaSource.removeEventListener(analyticsCollector); mediaSource = null; } bandwidthMeter.removeEventListener(analyticsCollector); currentCues = Collections.emptyList(); }
private void abandonAudioFocus() { abandonAudioFocus(/* forceAbandon= */ false); }
@Test public void handleStop_withAudioFocus_abandonsAudioFocus() { // Ensure that handleStop causes AudioFocusManager to abandon audio focus. AudioAttributes media = new AudioAttributes.Builder() .setUsage(C.USAGE_MEDIA) .setContentType(C.CONTENT_TYPE_SPEECH) .build(); Shadows.shadowOf(audioManager) .setNextFocusRequestResponse(AudioManager.AUDIOFOCUS_REQUEST_GRANTED); assertThat( audioFocusManager.setAudioAttributes( media, /* playWhenReady= */ true, Player.STATE_READY)) .isEqualTo(PLAYER_COMMAND_PLAY_WHEN_READY); assertThat(Shadows.shadowOf(audioManager).getLastAbandonedAudioFocusListener()).isNull(); ShadowAudioManager.AudioFocusRequest request = Shadows.shadowOf(audioManager).getLastAudioFocusRequest(); audioFocusManager.handleStop(); assertThat(Shadows.shadowOf(audioManager).getLastAbandonedAudioFocusListener()) .isEqualTo(request.listener); }