Move AudioComponent to ExoPlayer leaving key methods in Player

PiperOrigin-RevId: 368413660
This commit is contained in:
krocard 2021-04-14 13:54:48 +01:00 committed by Andrew Lewis
parent d359882871
commit 4fc4ddbc6a
12 changed files with 240 additions and 164 deletions

View File

@ -30,6 +30,7 @@ import com.google.android.exoplayer2.MediaMetadata;
import com.google.android.exoplayer2.PlaybackParameters; import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.audio.AudioAttributes;
import com.google.android.exoplayer2.metadata.Metadata; import com.google.android.exoplayer2.metadata.Metadata;
import com.google.android.exoplayer2.source.TrackGroup; import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.source.TrackGroupArray;
@ -251,14 +252,13 @@ public final class CastPlayer extends BasePlayer {
public MediaQueueItem getItem(int periodId) { public MediaQueueItem getItem(int periodId) {
MediaStatus mediaStatus = getMediaStatus(); MediaStatus mediaStatus = getMediaStatus();
return mediaStatus != null && currentTimeline.getIndexOfPeriod(periodId) != C.INDEX_UNSET return mediaStatus != null && currentTimeline.getIndexOfPeriod(periodId) != C.INDEX_UNSET
? mediaStatus.getItemById(periodId) : null; ? mediaStatus.getItemById(periodId)
: null;
} }
// CastSession methods. // CastSession methods.
/** /** Returns whether a cast session is available. */
* Returns whether a cast session is available.
*/
public boolean isCastSessionAvailable() { public boolean isCastSessionAvailable() {
return remoteMediaClient != null; return remoteMediaClient != null;
} }
@ -274,12 +274,6 @@ public final class CastPlayer extends BasePlayer {
// Player implementation. // Player implementation.
@Override
@Nullable
public AudioComponent getAudioComponent() {
return null;
}
@Override @Override
@Nullable @Nullable
public VideoComponent getVideoComponent() { public VideoComponent getVideoComponent() {
@ -461,8 +455,10 @@ public final class CastPlayer extends BasePlayer {
positionMs = positionMs != C.TIME_UNSET ? positionMs : 0; positionMs = positionMs != C.TIME_UNSET ? positionMs : 0;
if (mediaStatus != null) { if (mediaStatus != null) {
if (getCurrentWindowIndex() != windowIndex) { if (getCurrentWindowIndex() != windowIndex) {
remoteMediaClient.queueJumpToItem((int) currentTimeline.getPeriod(windowIndex, period).uid, remoteMediaClient
positionMs, null).setResultCallback(seekResultCallback); .queueJumpToItem(
(int) currentTimeline.getPeriod(windowIndex, period).uid, positionMs, null)
.setResultCallback(seekResultCallback);
} else { } else {
remoteMediaClient.seek(positionMs).setResultCallback(seekResultCallback); remoteMediaClient.seek(positionMs).setResultCallback(seekResultCallback);
} }
@ -545,7 +541,8 @@ public final class CastPlayer extends BasePlayer {
} }
@Override @Override
@RepeatMode public int getRepeatMode() { @RepeatMode
public int getRepeatMode() {
return repeatMode.value; return repeatMode.value;
} }
@ -657,6 +654,22 @@ public final class CastPlayer extends BasePlayer {
return getBufferedPosition(); return getBufferedPosition();
} }
/** This method is not supported and returns {@link AudioAttributes#DEFAULT}. */
@Override
public AudioAttributes getAudioAttributes() {
return AudioAttributes.DEFAULT;
}
/** This method is not supported and does nothing. */
@Override
public void setVolume(float audioVolume) {}
/** This method is not supported and returns 1. */
@Override
public float getVolume() {
return 1;
}
// Internal methods. // Internal methods.
// Call deprecated callbacks. // Call deprecated callbacks.
@ -897,7 +910,8 @@ public final class CastPlayer extends BasePlayer {
long id = mediaTrack.getId(); long id = mediaTrack.getId();
int trackType = MimeTypes.getTrackType(mediaTrack.getContentType()); int trackType = MimeTypes.getTrackType(mediaTrack.getContentType());
int rendererIndex = getRendererIndexForTrackType(trackType); int rendererIndex = getRendererIndexForTrackType(trackType);
if (isTrackActive(id, activeTrackIds) && rendererIndex != C.INDEX_UNSET if (isTrackActive(id, activeTrackIds)
&& rendererIndex != C.INDEX_UNSET
&& trackSelections[rendererIndex] == null) { && trackSelections[rendererIndex] == null) {
trackSelections[rendererIndex] = new CastTrackSelection(trackGroups[i]); trackSelections[rendererIndex] = new CastTrackSelection(trackGroups[i]);
} }
@ -1097,8 +1111,8 @@ public final class CastPlayer extends BasePlayer {
} }
/** /**
* Retrieves the repeat mode from {@code remoteMediaClient} and maps it into a * Retrieves the repeat mode from {@code remoteMediaClient} and maps it into a {@link
* {@link Player.RepeatMode}. * Player.RepeatMode}.
*/ */
@RepeatMode @RepeatMode
private static int fetchRepeatMode(RemoteMediaClient remoteMediaClient) { private static int fetchRepeatMode(RemoteMediaClient remoteMediaClient) {
@ -1238,8 +1252,12 @@ public final class CastPlayer extends BasePlayer {
@Override @Override
public void onSessionResumeFailed(CastSession castSession, int statusCode) { public void onSessionResumeFailed(CastSession castSession, int statusCode) {
Log.e(TAG, "Session resume failed. Error code " + statusCode + ": " Log.e(
+ CastUtils.getLogString(statusCode)); TAG,
"Session resume failed. Error code "
+ statusCode
+ ": "
+ CastUtils.getLogString(statusCode));
} }
@Override @Override
@ -1249,8 +1267,12 @@ public final class CastPlayer extends BasePlayer {
@Override @Override
public void onSessionStartFailed(CastSession castSession, int statusCode) { public void onSessionStartFailed(CastSession castSession, int statusCode) {
Log.e(TAG, "Session start failed. Error code " + statusCode + ": " Log.e(
+ CastUtils.getLogString(statusCode)); TAG,
"Session start failed. Error code "
+ statusCode
+ ": "
+ CastUtils.getLogString(statusCode));
} }
@Override @Override
@ -1262,7 +1284,6 @@ public final class CastPlayer extends BasePlayer {
public void onSessionResuming(CastSession castSession, String s) { public void onSessionResuming(CastSession castSession, String s) {
// Do nothing. // Do nothing.
} }
} }
private final class SeekResultCallback implements ResultCallback<MediaChannelResult> { private final class SeekResultCallback implements ResultCallback<MediaChannelResult> {
@ -1274,8 +1295,9 @@ public final class CastPlayer extends BasePlayer {
public void onResult(MediaChannelResult result) { public void onResult(MediaChannelResult result) {
int statusCode = result.getStatus().getStatusCode(); int statusCode = result.getStatus().getStatusCode();
if (statusCode != CastStatusCodes.SUCCESS && statusCode != CastStatusCodes.REPLACED) { if (statusCode != CastStatusCodes.SUCCESS && statusCode != CastStatusCodes.REPLACED) {
Log.e(TAG, "Seek failed. Error code " + statusCode + ": " Log.e(
+ CastUtils.getLogString(statusCode)); TAG,
"Seek failed. Error code " + statusCode + ": " + CastUtils.getLogString(statusCode));
} }
if (--pendingSeekCount == 0) { if (--pendingSeekCount == 0) {
currentWindowIndex = pendingSeekWindowIndex; currentWindowIndex = pendingSeekWindowIndex;

View File

@ -17,6 +17,7 @@ package com.google.android.exoplayer2.ext.cast;
import static com.google.android.exoplayer2.Player.COMMAND_ADJUST_DEVICE_VOLUME; import static com.google.android.exoplayer2.Player.COMMAND_ADJUST_DEVICE_VOLUME;
import static com.google.android.exoplayer2.Player.COMMAND_CHANGE_MEDIA_ITEMS; import static com.google.android.exoplayer2.Player.COMMAND_CHANGE_MEDIA_ITEMS;
import static com.google.android.exoplayer2.Player.COMMAND_GET_AUDIO_ATTRIBUTES;
import static com.google.android.exoplayer2.Player.COMMAND_GET_CURRENT_MEDIA_ITEM; import static com.google.android.exoplayer2.Player.COMMAND_GET_CURRENT_MEDIA_ITEM;
import static com.google.android.exoplayer2.Player.COMMAND_GET_DEVICE_VOLUME; import static com.google.android.exoplayer2.Player.COMMAND_GET_DEVICE_VOLUME;
import static com.google.android.exoplayer2.Player.COMMAND_GET_MEDIA_ITEMS; import static com.google.android.exoplayer2.Player.COMMAND_GET_MEDIA_ITEMS;
@ -102,6 +103,7 @@ public class CastPlayerTest {
@Captor @Captor
private ArgumentCaptor<ResultCallback<RemoteMediaClient.MediaChannelResult>> private ArgumentCaptor<ResultCallback<RemoteMediaClient.MediaChannelResult>>
setResultCallbackArgumentCaptor; setResultCallbackArgumentCaptor;
@Captor private ArgumentCaptor<RemoteMediaClient.Callback> callbackArgumentCaptor; @Captor private ArgumentCaptor<RemoteMediaClient.Callback> callbackArgumentCaptor;
@Captor private ArgumentCaptor<MediaQueueItem[]> queueItemsArgumentCaptor; @Captor private ArgumentCaptor<MediaQueueItem[]> queueItemsArgumentCaptor;
@Captor private ArgumentCaptor<MediaItem> mediaItemCaptor; @Captor private ArgumentCaptor<MediaItem> mediaItemCaptor;
@ -1119,6 +1121,7 @@ public class CastPlayerTest {
assertThat(castPlayer.isCommandAvailable(COMMAND_GET_MEDIA_ITEMS)).isTrue(); assertThat(castPlayer.isCommandAvailable(COMMAND_GET_MEDIA_ITEMS)).isTrue();
assertThat(castPlayer.isCommandAvailable(COMMAND_GET_MEDIA_ITEMS_METADATA)).isTrue(); assertThat(castPlayer.isCommandAvailable(COMMAND_GET_MEDIA_ITEMS_METADATA)).isTrue();
assertThat(castPlayer.isCommandAvailable(COMMAND_CHANGE_MEDIA_ITEMS)).isTrue(); assertThat(castPlayer.isCommandAvailable(COMMAND_CHANGE_MEDIA_ITEMS)).isTrue();
assertThat(castPlayer.isCommandAvailable(COMMAND_GET_AUDIO_ATTRIBUTES)).isFalse();
assertThat(castPlayer.isCommandAvailable(COMMAND_GET_VOLUME)).isFalse(); assertThat(castPlayer.isCommandAvailable(COMMAND_GET_VOLUME)).isFalse();
assertThat(castPlayer.isCommandAvailable(COMMAND_GET_DEVICE_VOLUME)).isFalse(); assertThat(castPlayer.isCommandAvailable(COMMAND_GET_DEVICE_VOLUME)).isFalse();
assertThat(castPlayer.isCommandAvailable(COMMAND_SET_VOLUME)).isFalse(); assertThat(castPlayer.isCommandAvailable(COMMAND_SET_VOLUME)).isFalse();

View File

@ -15,6 +15,7 @@
*/ */
package com.google.android.exoplayer2.ext.ima; package com.google.android.exoplayer2.ext.ima;
import static com.google.android.exoplayer2.Player.COMMAND_GET_VOLUME;
import static com.google.android.exoplayer2.ext.ima.ImaUtil.BITRATE_UNSET; import static com.google.android.exoplayer2.ext.ima.ImaUtil.BITRATE_UNSET;
import static com.google.android.exoplayer2.ext.ima.ImaUtil.TIMEOUT_UNSET; import static com.google.android.exoplayer2.ext.ima.ImaUtil.TIMEOUT_UNSET;
import static com.google.android.exoplayer2.ext.ima.ImaUtil.getAdGroupTimesUsForCuePoints; import static com.google.android.exoplayer2.ext.ima.ImaUtil.getAdGroupTimesUsForCuePoints;
@ -700,9 +701,8 @@ import java.util.Map;
return lastVolumePercent; return lastVolumePercent;
} }
@Nullable Player.AudioComponent audioComponent = player.getAudioComponent(); if (player.isCommandAvailable(COMMAND_GET_VOLUME)) {
if (audioComponent != null) { return (int) (player.getVolume() * 100);
return (int) (audioComponent.getVolume() * 100);
} }
// Check for a selected track using an audio renderer. // Check for a selected track using an audio renderer.

View File

@ -194,6 +194,17 @@ import com.google.android.exoplayer2.util.ListenerSet;
listeners.remove(listener); listeners.remove(listener);
} }
@Override
public boolean isCommandAvailable(@Command int command) {
// Only support querrying the minimal set of command for testing.
switch (command) {
case COMMAND_GET_VOLUME:
return false;
default:
throw new UnsupportedOperationException();
}
}
@Override @Override
@Player.State @Player.State
public int getPlaybackState() { public int getPlaybackState() {

View File

@ -33,7 +33,6 @@ import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.audio.AudioAttributes; import com.google.android.exoplayer2.audio.AudioAttributes;
import com.google.android.exoplayer2.audio.AudioListener;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Log; import com.google.android.exoplayer2.util.Log;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
@ -138,10 +137,6 @@ import java.util.List;
controlDispatcher = new DefaultControlDispatcher(); controlDispatcher = new DefaultControlDispatcher();
componentListener = new ComponentListener(); componentListener = new ComponentListener();
player.addListener(componentListener); player.addListener(componentListener);
@Nullable Player.AudioComponent audioComponent = player.getAudioComponent();
if (audioComponent != null) {
audioComponent.addAudioListener(componentListener);
}
handler = new Handler(player.getApplicationLooper()); handler = new Handler(player.getApplicationLooper());
pollBufferRunnable = new PollBufferRunnable(); pollBufferRunnable = new PollBufferRunnable();
@ -455,15 +450,15 @@ import java.util.List;
} }
public void setAudioAttributes(AudioAttributesCompat audioAttributes) { public void setAudioAttributes(AudioAttributesCompat audioAttributes) {
Player.AudioComponent audioComponent = Assertions.checkStateNotNull(player.getAudioComponent()); // Player interface doesn't support setting audio attributes.
audioComponent.setAudioAttributes(
Utils.getAudioAttributes(audioAttributes), /* handleAudioFocus= */ true);
} }
public AudioAttributesCompat getAudioAttributes() { public AudioAttributesCompat getAudioAttributes() {
@Nullable Player.AudioComponent audioComponent = player.getAudioComponent(); AudioAttributes audioAttributes = AudioAttributes.DEFAULT;
return Utils.getAudioAttributesCompat( if (player.isCommandAvailable(Player.COMMAND_GET_AUDIO_ATTRIBUTES)) {
audioComponent != null ? audioComponent.getAudioAttributes() : AudioAttributes.DEFAULT); audioAttributes = player.getAudioAttributes();
}
return Utils.getAudioAttributesCompat(audioAttributes);
} }
public void setPlaybackSpeed(float playbackSpeed) { public void setPlaybackSpeed(float playbackSpeed) {
@ -483,11 +478,6 @@ import java.util.List;
public void close() { public void close() {
handler.removeCallbacks(pollBufferRunnable); handler.removeCallbacks(pollBufferRunnable);
player.removeListener(componentListener); player.removeListener(componentListener);
@Nullable Player.AudioComponent audioComponent = player.getAudioComponent();
if (audioComponent != null) {
audioComponent.removeAudioListener(componentListener);
}
} }
public boolean isCurrentMediaItemSeekable() { public boolean isCurrentMediaItemSeekable() {
@ -584,7 +574,7 @@ import java.util.List;
} }
} }
private final class ComponentListener implements Player.EventListener, AudioListener { private final class ComponentListener implements Player.Listener {
// Player.EventListener implementation. // Player.EventListener implementation.

View File

@ -15,7 +15,6 @@
*/ */
package com.google.android.exoplayer2; package com.google.android.exoplayer2;
import android.content.Context;
import android.os.Looper; import android.os.Looper;
import android.view.Surface; import android.view.Surface;
import android.view.SurfaceHolder; import android.view.SurfaceHolder;
@ -25,7 +24,6 @@ import androidx.annotation.IntDef;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.google.android.exoplayer2.audio.AudioAttributes; import com.google.android.exoplayer2.audio.AudioAttributes;
import com.google.android.exoplayer2.audio.AudioListener; import com.google.android.exoplayer2.audio.AudioListener;
import com.google.android.exoplayer2.audio.AuxEffectInfo;
import com.google.android.exoplayer2.device.DeviceInfo; import com.google.android.exoplayer2.device.DeviceInfo;
import com.google.android.exoplayer2.device.DeviceListener; import com.google.android.exoplayer2.device.DeviceListener;
import com.google.android.exoplayer2.metadata.Metadata; import com.google.android.exoplayer2.metadata.Metadata;
@ -68,95 +66,6 @@ import java.util.List;
*/ */
public interface Player { public interface Player {
/** The audio component of a {@link Player}. */
interface AudioComponent {
/**
* Adds a listener to receive audio events.
*
* @param listener The listener to register.
*/
void addAudioListener(AudioListener listener);
/**
* Removes a listener of audio events.
*
* @param listener The listener to unregister.
*/
void removeAudioListener(AudioListener listener);
/**
* Sets the attributes for audio playback, used by the underlying audio track. If not set, the
* default audio attributes will be used. They are suitable for general media playback.
*
* <p>Setting the audio attributes during playback may introduce a short gap in audio output as
* the audio track is recreated. A new audio session id will also be generated.
*
* <p>If tunneling is enabled by the track selector, the specified audio attributes will be
* ignored, but they will take effect if audio is later played without tunneling.
*
* <p>If the device is running a build before platform API version 21, audio attributes cannot
* be set directly on the underlying audio track. In this case, the usage will be mapped onto an
* equivalent stream type using {@link Util#getStreamTypeForAudioUsage(int)}.
*
* <p>If audio focus should be handled, the {@link AudioAttributes#usage} must be {@link
* C#USAGE_MEDIA} or {@link C#USAGE_GAME}. Other usages will throw an {@link
* IllegalArgumentException}.
*
* @param audioAttributes The attributes to use for audio playback.
* @param handleAudioFocus True if the player should handle audio focus, false otherwise.
*/
void setAudioAttributes(AudioAttributes audioAttributes, boolean handleAudioFocus);
/** Returns the attributes for audio playback. */
AudioAttributes getAudioAttributes();
/**
* Sets the ID of the audio session to attach to the underlying {@link
* android.media.AudioTrack}.
*
* <p>The audio session ID can be generated using {@link C#generateAudioSessionIdV21(Context)}
* for API 21+.
*
* @param audioSessionId The audio session ID, or {@link C#AUDIO_SESSION_ID_UNSET} if it should
* be generated by the framework.
*/
void setAudioSessionId(int audioSessionId);
/** Returns the audio session identifier, or {@link C#AUDIO_SESSION_ID_UNSET} if not set. */
int getAudioSessionId();
/** Sets information on an auxiliary audio effect to attach to the underlying audio track. */
void setAuxEffectInfo(AuxEffectInfo auxEffectInfo);
/** Detaches any previously attached auxiliary audio effect from the underlying audio track. */
void clearAuxEffectInfo();
/**
* Sets the audio volume, with 0 being silence and 1 being unity gain (signal unchanged).
*
* @param audioVolume Linear output gain to apply to all audio channels.
*/
void setVolume(float audioVolume);
/**
* Returns the audio volume, with 0 being silence and 1 being unity gain (signal unchanged).
*
* @return The linear gain applied to all audio channels.
*/
float getVolume();
/**
* Sets whether skipping silences in the audio stream is enabled.
*
* @param skipSilenceEnabled Whether skipping silences in the audio stream is enabled.
*/
void setSkipSilenceEnabled(boolean skipSilenceEnabled);
/** Returns whether skipping silences in the audio stream is enabled. */
boolean getSkipSilenceEnabled();
}
/** The video component of a {@link Player}. */ /** The video component of a {@link Player}. */
interface VideoComponent { interface VideoComponent {
@ -354,8 +263,7 @@ public interface Player {
* <p>For devices with {@link DeviceInfo#PLAYBACK_TYPE_LOCAL local playback}, the volume * <p>For devices with {@link DeviceInfo#PLAYBACK_TYPE_LOCAL local playback}, the volume
* returned by this method varies according to the current {@link C.StreamType stream type}. The * returned by this method varies according to the current {@link C.StreamType stream type}. The
* stream type is determined by {@link AudioAttributes#usage} which can be converted to stream * stream type is determined by {@link AudioAttributes#usage} which can be converted to stream
* type with {@link Util#getStreamTypeForAudioUsage(int)}. The audio attributes can be set to * type with {@link Util#getStreamTypeForAudioUsage(int)}.
* the player by calling {@link AudioComponent#setAudioAttributes}.
* *
* <p>For devices with {@link DeviceInfo#PLAYBACK_TYPE_REMOTE remote playback}, the volume of * <p>For devices with {@link DeviceInfo#PLAYBACK_TYPE_REMOTE remote playback}, the volume of
* the remote device is returned. * the remote device is returned.
@ -930,11 +838,12 @@ public interface Player {
DeviceListener, DeviceListener,
EventListener { EventListener {
@Override // For backward compatibility TextOutput and MetadataOutput must stay functional interfaces.
default void onMetadata(Metadata metadata) {}
@Override @Override
default void onCues(List<Cue> cues) {} default void onCues(List<Cue> cues) {}
@Override
default void onMetadata(Metadata metadata) {}
} }
/** /**
@ -1179,10 +1088,10 @@ public interface Player {
* #COMMAND_SET_SPEED_AND_PITCH}, {@link #COMMAND_SET_SHUFFLE_MODE}, {@link * #COMMAND_SET_SPEED_AND_PITCH}, {@link #COMMAND_SET_SHUFFLE_MODE}, {@link
* #COMMAND_SET_REPEAT_MODE}, {@link #COMMAND_GET_CURRENT_MEDIA_ITEM}, {@link * #COMMAND_SET_REPEAT_MODE}, {@link #COMMAND_GET_CURRENT_MEDIA_ITEM}, {@link
* #COMMAND_GET_MEDIA_ITEMS}, {@link #COMMAND_GET_MEDIA_ITEMS_METADATA}, {@link * #COMMAND_GET_MEDIA_ITEMS}, {@link #COMMAND_GET_MEDIA_ITEMS_METADATA}, {@link
* #COMMAND_CHANGE_MEDIA_ITEMS}, {@link #COMMAND_GET_VOLUME}, {@link #COMMAND_GET_DEVICE_VOLUME}, * #COMMAND_CHANGE_MEDIA_ITEMS}, {@link #COMMAND_GET_AUDIO_ATTRIBUTES}, {@link
* {@link #COMMAND_SET_VOLUME}, {@link #COMMAND_SET_DEVICE_VOLUME}, {@link * #COMMAND_GET_VOLUME}, {@link #COMMAND_GET_DEVICE_VOLUME}, {@link #COMMAND_SET_VOLUME}, {@link
* #COMMAND_ADJUST_DEVICE_VOLUME}, {@link #COMMAND_SET_VIDEO_SURFACE} or {@link * #COMMAND_SET_DEVICE_VOLUME}, {@link #COMMAND_ADJUST_DEVICE_VOLUME}, {@link
* #COMMAND_GET_TEXT}. * #COMMAND_SET_VIDEO_SURFACE} or {@link #COMMAND_GET_TEXT}.
*/ */
@Documented @Documented
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
@ -1201,6 +1110,7 @@ public interface Player {
COMMAND_GET_MEDIA_ITEMS, COMMAND_GET_MEDIA_ITEMS,
COMMAND_GET_MEDIA_ITEMS_METADATA, COMMAND_GET_MEDIA_ITEMS_METADATA,
COMMAND_CHANGE_MEDIA_ITEMS, COMMAND_CHANGE_MEDIA_ITEMS,
COMMAND_GET_AUDIO_ATTRIBUTES,
COMMAND_GET_VOLUME, COMMAND_GET_VOLUME,
COMMAND_GET_DEVICE_VOLUME, COMMAND_GET_DEVICE_VOLUME,
COMMAND_SET_VOLUME, COMMAND_SET_VOLUME,
@ -1238,24 +1148,22 @@ public interface Player {
int COMMAND_GET_MEDIA_ITEMS_METADATA = 13; int COMMAND_GET_MEDIA_ITEMS_METADATA = 13;
/** Command to change the {@link MediaItem MediaItems} in the playlist. */ /** Command to change the {@link MediaItem MediaItems} in the playlist. */
int COMMAND_CHANGE_MEDIA_ITEMS = 14; int COMMAND_CHANGE_MEDIA_ITEMS = 14;
/** Command to get the player current {@link AudioAttributes}. */
int COMMAND_GET_AUDIO_ATTRIBUTES = 15;
/** Command to get the player volume. */ /** Command to get the player volume. */
int COMMAND_GET_VOLUME = 15; int COMMAND_GET_VOLUME = 16;
/** Command to get the device volume and whether it is muted. */ /** Command to get the device volume and whether it is muted. */
int COMMAND_GET_DEVICE_VOLUME = 16; int COMMAND_GET_DEVICE_VOLUME = 17;
/** Command to set the player volume. */ /** Command to set the player volume. */
int COMMAND_SET_VOLUME = 17; int COMMAND_SET_VOLUME = 18;
/** Command to set the device volume and mute it. */ /** Command to set the device volume and mute it. */
int COMMAND_SET_DEVICE_VOLUME = 18; int COMMAND_SET_DEVICE_VOLUME = 19;
/** Command to increase and decrease the device volume and mute it. */ /** Command to increase and decrease the device volume and mute it. */
int COMMAND_ADJUST_DEVICE_VOLUME = 19; int COMMAND_ADJUST_DEVICE_VOLUME = 20;
/** Command to set and clear the surface on which to render the video. */ /** Command to set and clear the surface on which to render the video. */
int COMMAND_SET_VIDEO_SURFACE = 20; int COMMAND_SET_VIDEO_SURFACE = 21;
/** Command to get the text that should currently be displayed by the player. */ /** Command to get the text that should currently be displayed by the player. */
int COMMAND_GET_TEXT = 21; int COMMAND_GET_TEXT = 22;
/** Returns the component of this player for audio output, or null if audio is not supported. */
@Nullable
AudioComponent getAudioComponent();
/** Returns the component of this player for video output, or null if video is not supported. */ /** Returns the component of this player for video output, or null if video is not supported. */
@Nullable @Nullable
@ -1293,11 +1201,6 @@ public interface Player {
/** /**
* Registers a listener to receive all events from the player. * Registers a listener to receive all events from the player.
* *
* <p>Do not register the listener additionally in individual `Player` components (such as {@link
* Player.AudioComponent#addAudioListener(AudioListener)}, {@link
* Player.VideoComponent#addVideoListener(VideoListener)}) as it will already receive all their
* events.
*
* @param listener The listener to register. * @param listener The listener to register.
*/ */
void addListener(Listener listener); void addListener(Listener listener);
@ -1936,4 +1839,21 @@ public interface Player {
* playing, the returned position is the same as that returned by {@link #getBufferedPosition()}. * playing, the returned position is the same as that returned by {@link #getBufferedPosition()}.
*/ */
long getContentBufferedPosition(); long getContentBufferedPosition();
/** Returns the attributes for audio playback. */
AudioAttributes getAudioAttributes();
/**
* Sets the audio volume, with 0 being silence and 1 being unity gain (signal unchanged).
*
* @param audioVolume Linear output gain to apply to all audio channels.
*/
void setVolume(float audioVolume);
/**
* Returns the audio volume, with 0 being silence and 1 being unity gain (signal unchanged).
*
* @return The linear gain applied to all audio channels.
*/
float getVolume();
} }

View File

@ -15,9 +15,7 @@
*/ */
package com.google.android.exoplayer2.metadata; package com.google.android.exoplayer2.metadata;
/** /** Receives metadata output. */
* Receives metadata output.
*/
public interface MetadataOutput { public interface MetadataOutput {
/** /**
@ -26,5 +24,4 @@ public interface MetadataOutput {
* @param metadata The metadata. * @param metadata The metadata.
*/ */
void onMetadata(Metadata metadata); void onMetadata(Metadata metadata);
} }

View File

@ -21,8 +21,11 @@ import android.os.Looper;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import com.google.android.exoplayer2.analytics.AnalyticsCollector; import com.google.android.exoplayer2.analytics.AnalyticsCollector;
import com.google.android.exoplayer2.audio.AudioAttributes;
import com.google.android.exoplayer2.audio.AudioCapabilities; import com.google.android.exoplayer2.audio.AudioCapabilities;
import com.google.android.exoplayer2.audio.AudioListener;
import com.google.android.exoplayer2.audio.AudioSink; import com.google.android.exoplayer2.audio.AudioSink;
import com.google.android.exoplayer2.audio.AuxEffectInfo;
import com.google.android.exoplayer2.audio.DefaultAudioSink; import com.google.android.exoplayer2.audio.DefaultAudioSink;
import com.google.android.exoplayer2.audio.MediaCodecAudioRenderer; import com.google.android.exoplayer2.audio.MediaCodecAudioRenderer;
import com.google.android.exoplayer2.metadata.MetadataRenderer; import com.google.android.exoplayer2.metadata.MetadataRenderer;
@ -126,6 +129,95 @@ import java.util.List;
*/ */
public interface ExoPlayer extends Player { public interface ExoPlayer extends Player {
/** The audio component of an {@link ExoPlayer}. */
interface AudioComponent {
/**
* Adds a listener to receive audio events.
*
* @param listener The listener to register.
*/
void addAudioListener(AudioListener listener);
/**
* Removes a listener of audio events.
*
* @param listener The listener to unregister.
*/
void removeAudioListener(AudioListener listener);
/**
* Sets the attributes for audio playback, used by the underlying audio track. If not set, the
* default audio attributes will be used. They are suitable for general media playback.
*
* <p>Setting the audio attributes during playback may introduce a short gap in audio output as
* the audio track is recreated. A new audio session id will also be generated.
*
* <p>If tunneling is enabled by the track selector, the specified audio attributes will be
* ignored, but they will take effect if audio is later played without tunneling.
*
* <p>If the device is running a build before platform API version 21, audio attributes cannot
* be set directly on the underlying audio track. In this case, the usage will be mapped onto an
* equivalent stream type using {@link Util#getStreamTypeForAudioUsage(int)}.
*
* <p>If audio focus should be handled, the {@link AudioAttributes#usage} must be {@link
* C#USAGE_MEDIA} or {@link C#USAGE_GAME}. Other usages will throw an {@link
* IllegalArgumentException}.
*
* @param audioAttributes The attributes to use for audio playback.
* @param handleAudioFocus True if the player should handle audio focus, false otherwise.
*/
void setAudioAttributes(AudioAttributes audioAttributes, boolean handleAudioFocus);
/** Returns the attributes for audio playback. */
AudioAttributes getAudioAttributes();
/**
* Sets the ID of the audio session to attach to the underlying {@link
* android.media.AudioTrack}.
*
* <p>The audio session ID can be generated using {@link C#generateAudioSessionIdV21(Context)}
* for API 21+.
*
* @param audioSessionId The audio session ID, or {@link C#AUDIO_SESSION_ID_UNSET} if it should
* be generated by the framework.
*/
void setAudioSessionId(int audioSessionId);
/** Returns the audio session identifier, or {@link C#AUDIO_SESSION_ID_UNSET} if not set. */
int getAudioSessionId();
/** Sets information on an auxiliary audio effect to attach to the underlying audio track. */
void setAuxEffectInfo(AuxEffectInfo auxEffectInfo);
/** Detaches any previously attached auxiliary audio effect from the underlying audio track. */
void clearAuxEffectInfo();
/**
* Sets the audio volume, with 0 being silence and 1 being unity gain (signal unchanged).
*
* @param audioVolume Linear output gain to apply to all audio channels.
*/
void setVolume(float audioVolume);
/**
* Returns the audio volume, with 0 being silence and 1 being unity gain (signal unchanged).
*
* @return The linear gain applied to all audio channels.
*/
float getVolume();
/**
* Sets whether skipping silences in the audio stream is enabled.
*
* @param skipSilenceEnabled Whether skipping silences in the audio stream is enabled.
*/
void setSkipSilenceEnabled(boolean skipSilenceEnabled);
/** Returns whether skipping silences in the audio stream is enabled. */
boolean getSkipSilenceEnabled();
}
/** /**
* The default timeout for calls to {@link #release} and {@link #setForegroundMode}, in * The default timeout for calls to {@link #release} and {@link #setForegroundMode}, in
* milliseconds. * milliseconds.
@ -465,6 +557,10 @@ public interface ExoPlayer extends Player {
} }
} }
/** Returns the component of this player for audio output, or null if audio is not supported. */
@Nullable
AudioComponent getAudioComponent();
/** /**
* Adds a listener to receive audio offload events. * Adds a listener to receive audio offload events.
* *

View File

@ -28,6 +28,7 @@ import android.util.Pair;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.google.android.exoplayer2.PlayerMessage.Target; import com.google.android.exoplayer2.PlayerMessage.Target;
import com.google.android.exoplayer2.analytics.AnalyticsCollector; import com.google.android.exoplayer2.analytics.AnalyticsCollector;
import com.google.android.exoplayer2.audio.AudioAttributes;
import com.google.android.exoplayer2.metadata.Metadata; import com.google.android.exoplayer2.metadata.Metadata;
import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
@ -985,6 +986,22 @@ import java.util.concurrent.CopyOnWriteArraySet;
return playbackInfo.timeline; return playbackInfo.timeline;
} }
/** This method is not supported and returns {@link AudioAttributes#DEFAULT}. */
@Override
public AudioAttributes getAudioAttributes() {
return AudioAttributes.DEFAULT;
}
/** This method is not supported and does nothing. */
@Override
public void setVolume(float audioVolume) {}
/** This method is not supported and returns 1. */
@Override
public float getVolume() {
return 1;
}
private int getCurrentWindowIndexInternal() { private int getCurrentWindowIndexInternal() {
if (playbackInfo.timeline.isEmpty()) { if (playbackInfo.timeline.isEmpty()) {
return maskingWindowIndex; return maskingWindowIndex;

View File

@ -78,7 +78,7 @@ import java.util.concurrent.TimeoutException;
*/ */
public class SimpleExoPlayer extends BasePlayer public class SimpleExoPlayer extends BasePlayer
implements ExoPlayer, implements ExoPlayer,
Player.AudioComponent, ExoPlayer.AudioComponent,
Player.VideoComponent, Player.VideoComponent,
Player.TextComponent, Player.TextComponent,
Player.MetadataComponent, Player.MetadataComponent,
@ -676,6 +676,7 @@ public class SimpleExoPlayer extends BasePlayer
Commands additionalPermanentAvailableCommands = Commands additionalPermanentAvailableCommands =
new Commands.Builder() new Commands.Builder()
.addAll( .addAll(
COMMAND_GET_AUDIO_ATTRIBUTES,
COMMAND_GET_VOLUME, COMMAND_GET_VOLUME,
COMMAND_GET_DEVICE_VOLUME, COMMAND_GET_DEVICE_VOLUME,
COMMAND_SET_VOLUME, COMMAND_SET_VOLUME,

View File

@ -17,6 +17,7 @@ package com.google.android.exoplayer2;
import static com.google.android.exoplayer2.Player.COMMAND_ADJUST_DEVICE_VOLUME; import static com.google.android.exoplayer2.Player.COMMAND_ADJUST_DEVICE_VOLUME;
import static com.google.android.exoplayer2.Player.COMMAND_CHANGE_MEDIA_ITEMS; import static com.google.android.exoplayer2.Player.COMMAND_CHANGE_MEDIA_ITEMS;
import static com.google.android.exoplayer2.Player.COMMAND_GET_AUDIO_ATTRIBUTES;
import static com.google.android.exoplayer2.Player.COMMAND_GET_CURRENT_MEDIA_ITEM; import static com.google.android.exoplayer2.Player.COMMAND_GET_CURRENT_MEDIA_ITEM;
import static com.google.android.exoplayer2.Player.COMMAND_GET_DEVICE_VOLUME; import static com.google.android.exoplayer2.Player.COMMAND_GET_DEVICE_VOLUME;
import static com.google.android.exoplayer2.Player.COMMAND_GET_MEDIA_ITEMS; import static com.google.android.exoplayer2.Player.COMMAND_GET_MEDIA_ITEMS;
@ -8086,6 +8087,7 @@ public final class ExoPlayerTest {
assertThat(player.isCommandAvailable(COMMAND_GET_MEDIA_ITEMS)).isTrue(); assertThat(player.isCommandAvailable(COMMAND_GET_MEDIA_ITEMS)).isTrue();
assertThat(player.isCommandAvailable(COMMAND_GET_MEDIA_ITEMS_METADATA)).isTrue(); assertThat(player.isCommandAvailable(COMMAND_GET_MEDIA_ITEMS_METADATA)).isTrue();
assertThat(player.isCommandAvailable(COMMAND_CHANGE_MEDIA_ITEMS)).isTrue(); assertThat(player.isCommandAvailable(COMMAND_CHANGE_MEDIA_ITEMS)).isTrue();
assertThat(player.isCommandAvailable(COMMAND_GET_AUDIO_ATTRIBUTES)).isTrue();
assertThat(player.isCommandAvailable(COMMAND_GET_VOLUME)).isTrue(); assertThat(player.isCommandAvailable(COMMAND_GET_VOLUME)).isTrue();
assertThat(player.isCommandAvailable(COMMAND_GET_DEVICE_VOLUME)).isTrue(); assertThat(player.isCommandAvailable(COMMAND_GET_DEVICE_VOLUME)).isTrue();
assertThat(player.isCommandAvailable(COMMAND_SET_VOLUME)).isTrue(); assertThat(player.isCommandAvailable(COMMAND_SET_VOLUME)).isTrue();
@ -10275,6 +10277,7 @@ public final class ExoPlayerTest {
COMMAND_GET_MEDIA_ITEMS, COMMAND_GET_MEDIA_ITEMS,
COMMAND_GET_MEDIA_ITEMS_METADATA, COMMAND_GET_MEDIA_ITEMS_METADATA,
COMMAND_CHANGE_MEDIA_ITEMS, COMMAND_CHANGE_MEDIA_ITEMS,
COMMAND_GET_AUDIO_ATTRIBUTES,
COMMAND_GET_VOLUME, COMMAND_GET_VOLUME,
COMMAND_GET_DEVICE_VOLUME, COMMAND_GET_DEVICE_VOLUME,
COMMAND_SET_VOLUME, COMMAND_SET_VOLUME,

View File

@ -27,6 +27,7 @@ import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.PlayerMessage; import com.google.android.exoplayer2.PlayerMessage;
import com.google.android.exoplayer2.SeekParameters; import com.google.android.exoplayer2.SeekParameters;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.audio.AudioAttributes;
import com.google.android.exoplayer2.metadata.Metadata; import com.google.android.exoplayer2.metadata.Metadata;
import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.ShuffleOrder; import com.google.android.exoplayer2.source.ShuffleOrder;
@ -422,6 +423,21 @@ public class StubExoPlayer extends BasePlayer implements ExoPlayer {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override
public AudioAttributes getAudioAttributes() {
throw new UnsupportedOperationException();
}
@Override
public void setVolume(float audioVolume) {
throw new UnsupportedOperationException();
}
@Override
public float getVolume() {
throw new UnsupportedOperationException();
}
@Override @Override
public void setForegroundMode(boolean foregroundMode) { public void setForegroundMode(boolean foregroundMode) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();