Extract Player interface from ExoPlayer

This is the first step towards facilitating Cast integration to ExoPlayer.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=162366198
This commit is contained in:
aquilescanta 2017-07-18 10:04:10 -07:00 committed by Oliver Woodman
parent 41028fafba
commit 4f5ac9e04f
11 changed files with 497 additions and 424 deletions

View file

@ -39,6 +39,7 @@ import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.ExoPlayerFactory;
import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Player.EventListener;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.drm.DefaultDrmSessionManager;
@ -82,7 +83,7 @@ import java.util.UUID;
/**
* An activity that plays media using {@link SimpleExoPlayer}.
*/
public class PlayerActivity extends Activity implements OnClickListener, ExoPlayer.EventListener,
public class PlayerActivity extends Activity implements OnClickListener, EventListener,
PlaybackControlView.VisibilityListener {
public static final String DRM_SCHEME_UUID_EXTRA = "drm_scheme_uuid";

View file

@ -35,6 +35,7 @@ import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.source.TrackGroupArray;
@ -484,7 +485,7 @@ public final class MediaSessionConnector {
Pair<Integer, String> message = errorMessageProvider.getErrorMessage(playbackException);
builder.setErrorMessage(message.first, message.second);
}
if (player.getPlaybackState() != ExoPlayer.STATE_IDLE) {
if (player.getPlaybackState() != Player.STATE_IDLE) {
playbackException = null;
}
}
@ -507,7 +508,7 @@ public final class MediaSessionConnector {
if (queue == null || queue.size() < 2) {
removePlaybackActions(PlaybackStateCompat.ACTION_SKIP_TO_NEXT
| PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS);
} else if (player.getRepeatMode() != ExoPlayer.REPEAT_MODE_OFF) {
} else if (player.getRepeatMode() != Player.REPEAT_MODE_OFF) {
addPlaybackActions(PlaybackStateCompat.ACTION_SKIP_TO_NEXT
| PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS);
} else if (activeQueueItemId == queue.get(0).getQueueId()) {
@ -576,11 +577,11 @@ public final class MediaSessionConnector {
private int mapPlaybackState(int exoPlayerPlaybackState, boolean playWhenReady) {
switch (exoPlayerPlaybackState) {
case ExoPlayer.STATE_BUFFERING:
case Player.STATE_BUFFERING:
return PlaybackStateCompat.STATE_BUFFERING;
case ExoPlayer.STATE_READY:
case Player.STATE_READY:
return playWhenReady ? PlaybackStateCompat.STATE_PLAYING : PlaybackStateCompat.STATE_PAUSED;
case ExoPlayer.STATE_ENDED:
case Player.STATE_ENDED:
return PlaybackStateCompat.STATE_PAUSED;
default:
return PlaybackStateCompat.STATE_NONE;
@ -599,7 +600,7 @@ public final class MediaSessionConnector {
return playbackPreparer != null && isActionPublished(action);
}
private class ExoPlayerEventListener implements ExoPlayer.EventListener {
private class ExoPlayerEventListener implements Player.EventListener {
@Override
public void onTimelineChanged(Timeline timeline, Object manifest) {
if (queueNavigator != null) {
@ -625,9 +626,9 @@ public final class MediaSessionConnector {
}
@Override
public void onRepeatModeChanged(@ExoPlayer.RepeatMode int repeatMode) {
mediaSession.setRepeatMode(repeatMode == ExoPlayer.REPEAT_MODE_ONE
? PlaybackStateCompat.REPEAT_MODE_ONE : repeatMode == ExoPlayer.REPEAT_MODE_ALL
public void onRepeatModeChanged(@Player.RepeatMode int repeatMode) {
mediaSession.setRepeatMode(repeatMode == Player.REPEAT_MODE_ONE
? PlaybackStateCompat.REPEAT_MODE_ONE : repeatMode == Player.REPEAT_MODE_ALL
? PlaybackStateCompat.REPEAT_MODE_ALL : PlaybackStateCompat.REPEAT_MODE_NONE);
updateMediaSessionPlaybackState();
}

View file

@ -19,6 +19,7 @@ import android.content.Context;
import android.os.Bundle;
import android.support.v4.media.session.PlaybackStateCompat;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.util.RepeatModeUtil;
/**
@ -81,15 +82,15 @@ public final class RepeatModeActionProvider implements MediaSessionConnector.Cus
CharSequence actionLabel;
int iconResourceId;
switch (player.getRepeatMode()) {
case ExoPlayer.REPEAT_MODE_ONE:
case Player.REPEAT_MODE_ONE:
actionLabel = repeatOneDescription;
iconResourceId = R.drawable.exo_media_action_repeat_one;
break;
case ExoPlayer.REPEAT_MODE_ALL:
case Player.REPEAT_MODE_ALL:
actionLabel = repeatAllDescription;
iconResourceId = R.drawable.exo_media_action_repeat_all;
break;
case ExoPlayer.REPEAT_MODE_OFF:
case Player.REPEAT_MODE_OFF:
default:
actionLabel = repeatOffDescription;
iconResourceId = R.drawable.exo_media_action_repeat_off;

View file

@ -23,6 +23,7 @@ import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.source.MediaSource.Listener;
import com.google.android.exoplayer2.testutil.FakeMediaSource;
@ -352,12 +353,12 @@ public final class DynamicConcatenatingMediaSourceTest extends TestCase {
}
@Override
public void addListener(EventListener listener) {
public void addListener(Player.EventListener listener) {
throw new UnsupportedOperationException();
}
@Override
public void removeListener(EventListener listener) {
public void removeListener(Player.EventListener listener) {
throw new UnsupportedOperationException();
}

View file

@ -16,8 +16,6 @@
package com.google.android.exoplayer2;
import android.os.Looper;
import android.support.annotation.IntDef;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.audio.MediaCodecAudioRenderer;
import com.google.android.exoplayer2.metadata.MetadataRenderer;
import com.google.android.exoplayer2.source.ConcatenatingMediaSource;
@ -25,15 +23,11 @@ import com.google.android.exoplayer2.source.ExtractorMediaSource;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.MergingMediaSource;
import com.google.android.exoplayer2.source.SingleSampleMediaSource;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.text.TextRenderer;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import com.google.android.exoplayer2.trackselection.TrackSelector;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.video.MediaCodecVideoRenderer;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* An extensible media player exposing traditional high-level media player functionality, such as
@ -108,91 +102,13 @@ import java.lang.annotation.RetentionPolicy;
* may use a background thread to load data. These are implementation specific.</li>
* </ul>
*/
public interface ExoPlayer {
public interface ExoPlayer extends Player {
/**
* Listener of changes in player state.
* @deprecated Use {@link Player.EventListener} instead.
*/
interface EventListener {
/**
* Called when the timeline and/or manifest has been refreshed.
* <p>
* Note that if the timeline has changed then a position discontinuity may also have occurred.
* For example, the current period index may have changed as a result of periods being added or
* removed from the timeline. This will <em>not</em> be reported via a separate call to
* {@link #onPositionDiscontinuity()}.
*
* @param timeline The latest timeline. Never null, but may be empty.
* @param manifest The latest manifest. May be null.
*/
void onTimelineChanged(Timeline timeline, Object manifest);
/**
* Called when the available or selected tracks change.
*
* @param trackGroups The available tracks. Never null, but may be of length zero.
* @param trackSelections The track selections for each {@link Renderer}. Never null and always
* of length {@link #getRendererCount()}, but may contain null elements.
*/
void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections);
/**
* Called when the player starts or stops loading the source.
*
* @param isLoading Whether the source is currently being loaded.
*/
void onLoadingChanged(boolean isLoading);
/**
* Called when the value returned from either {@link #getPlayWhenReady()} or
* {@link #getPlaybackState()} changes.
*
* @param playWhenReady Whether playback will proceed when ready.
* @param playbackState One of the {@code STATE} constants defined in the {@link ExoPlayer}
* interface.
*/
void onPlayerStateChanged(boolean playWhenReady, int playbackState);
/**
* Called when the value of {@link #getRepeatMode()} changes.
*
* @param repeatMode The {@link RepeatMode} used for playback.
*/
void onRepeatModeChanged(@RepeatMode int repeatMode);
/**
* Called when an error occurs. The playback state will transition to {@link #STATE_IDLE}
* immediately after this method is called. The player instance can still be used, and
* {@link #release()} must still be called on the player should it no longer be required.
*
* @param error The error.
*/
void onPlayerError(ExoPlaybackException error);
/**
* Called when a position discontinuity occurs without a change to the timeline. A position
* discontinuity occurs when the current window or period index changes (as a result of playback
* transitioning from one period in the timeline to the next), or when the playback position
* jumps within the period currently being played (as a result of a seek being performed, or
* when the source introduces a discontinuity internally).
* <p>
* When a position discontinuity occurs as a result of a change to the timeline this method is
* <em>not</em> called. {@link #onTimelineChanged(Timeline, Object)} is called in this case.
*/
void onPositionDiscontinuity();
/**
* Called when the current playback parameters change. The playback parameters may change due to
* a call to {@link ExoPlayer#setPlaybackParameters(PlaybackParameters)}, or the player itself
* may change them (for example, if audio playback switches to passthrough mode, where speed
* adjustment is no longer possible).
*
* @param playbackParameters The playback parameters.
*/
void onPlaybackParametersChanged(PlaybackParameters playbackParameters);
}
@Deprecated
interface EventListener extends Player.EventListener {}
/**
* A component of an {@link ExoPlayer} that can receive messages on the playback thread.
@ -245,43 +161,41 @@ public interface ExoPlayer {
}
/**
* The player does not have a source to play, so it is neither buffering nor ready to play.
* @deprecated Use {@link Player#STATE_IDLE} instead.
*/
int STATE_IDLE = 1;
@Deprecated
int STATE_IDLE = Player.STATE_IDLE;
/**
* The player not able to immediately play from the current position. The cause is
* {@link Renderer} specific, but this state typically occurs when more data needs to be
* loaded to be ready to play, or more data needs to be buffered for playback to resume.
* @deprecated Use {@link Player#STATE_BUFFERING} instead.
*/
int STATE_BUFFERING = 2;
@Deprecated
int STATE_BUFFERING = Player.STATE_BUFFERING;
/**
* The player is able to immediately play from the current position. The player will be playing if
* {@link #getPlayWhenReady()} returns true, and paused otherwise.
* @deprecated Use {@link Player#STATE_READY} instead.
*/
int STATE_READY = 3;
@Deprecated
int STATE_READY = Player.STATE_READY;
/**
* The player has finished playing the media.
* @deprecated Use {@link Player#STATE_ENDED} instead.
*/
int STATE_ENDED = 4;
@Deprecated
int STATE_ENDED = Player.STATE_ENDED;
/**
* Repeat modes for playback.
* @deprecated Use {@link Player#REPEAT_MODE_OFF} instead.
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef({REPEAT_MODE_OFF, REPEAT_MODE_ONE, REPEAT_MODE_ALL})
public @interface RepeatMode {}
@Deprecated
@RepeatMode int REPEAT_MODE_OFF = Player.REPEAT_MODE_OFF;
/**
* Normal playback without repetition.
* @deprecated Use {@link Player#REPEAT_MODE_ONE} instead.
*/
int REPEAT_MODE_OFF = 0;
@Deprecated
@RepeatMode int REPEAT_MODE_ONE = Player.REPEAT_MODE_ONE;
/**
* "Repeat One" mode to repeat the currently playing window infinitely.
* @deprecated Use {@link Player#REPEAT_MODE_ALL} instead.
*/
int REPEAT_MODE_ONE = 1;
/**
* "Repeat All" mode to repeat the entire timeline infinitely.
*/
int REPEAT_MODE_ALL = 2;
@Deprecated
@RepeatMode int REPEAT_MODE_ALL = Player.REPEAT_MODE_ALL;
/**
* Gets the {@link Looper} associated with the playback thread.
@ -290,29 +204,6 @@ public interface ExoPlayer {
*/
Looper getPlaybackLooper();
/**
* Register a listener to receive events from the player. The listener's methods will be called on
* the thread that was used to construct the player. However, if the thread used to construct the
* player does not have a {@link Looper}, then the listener will be called on the main thread.
*
* @param listener The listener to register.
*/
void addListener(EventListener listener);
/**
* Unregister a listener. The listener will no longer receive events from the player.
*
* @param listener The listener to unregister.
*/
void removeListener(EventListener listener);
/**
* Returns the current state of the player.
*
* @return One of the {@code STATE} constants defined in this interface.
*/
int getPlaybackState();
/**
* Prepares the player to play the provided {@link MediaSource}. Equivalent to
* {@code prepare(mediaSource, true, true)}.
@ -333,118 +224,6 @@ public interface ExoPlayer {
*/
void prepare(MediaSource mediaSource, boolean resetPosition, boolean resetState);
/**
* Sets whether playback should proceed when {@link #getPlaybackState()} == {@link #STATE_READY}.
* <p>
* If the player is already in the ready state then this method can be used to pause and resume
* playback.
*
* @param playWhenReady Whether playback should proceed when ready.
*/
void setPlayWhenReady(boolean playWhenReady);
/**
* Whether playback will proceed when {@link #getPlaybackState()} == {@link #STATE_READY}.
*
* @return Whether playback will proceed when ready.
*/
boolean getPlayWhenReady();
/**
* Sets the {@link RepeatMode} to be used for playback.
*
* @param repeatMode A repeat mode.
*/
void setRepeatMode(@RepeatMode int repeatMode);
/**
* Returns the current {@link RepeatMode} used for playback.
*
* @return The current repeat mode.
*/
@RepeatMode int getRepeatMode();
/**
* Whether the player is currently loading the source.
*
* @return Whether the player is currently loading the source.
*/
boolean isLoading();
/**
* Seeks to the default position associated with the current window. The position can depend on
* the type of source passed to {@link #prepare(MediaSource)}. For live streams it will typically
* be the live edge of the window. For other streams it will typically be the start of the window.
*/
void seekToDefaultPosition();
/**
* Seeks to the default position associated with the specified window. The position can depend on
* the type of source passed to {@link #prepare(MediaSource)}. For live streams it will typically
* be the live edge of the window. For other streams it will typically be the start of the window.
*
* @param windowIndex The index of the window whose associated default position should be seeked
* to.
*/
void seekToDefaultPosition(int windowIndex);
/**
* Seeks to a position specified in milliseconds in the current window.
*
* @param positionMs The seek position in the current window, or {@link C#TIME_UNSET} to seek to
* the window's default position.
*/
void seekTo(long positionMs);
/**
* Seeks to a position specified in milliseconds in the specified window.
*
* @param windowIndex The index of the window.
* @param positionMs The seek position in the specified window, or {@link C#TIME_UNSET} to seek to
* the window's default position.
*/
void seekTo(int windowIndex, long positionMs);
/**
* Attempts to set the playback parameters. Passing {@code null} sets the parameters to the
* default, {@link PlaybackParameters#DEFAULT}, which means there is no speed or pitch adjustment.
* <p>
* Playback parameters changes may cause the player to buffer.
* {@link EventListener#onPlaybackParametersChanged(PlaybackParameters)} will be called whenever
* the currently active playback parameters change. When that listener is called, the parameters
* passed to it may not match {@code playbackParameters}. For example, the chosen speed or pitch
* may be out of range, in which case they are constrained to a set of permitted values. If it is
* not possible to change the playback parameters, the listener will not be invoked.
*
* @param playbackParameters The playback parameters, or {@code null} to use the defaults.
*/
void setPlaybackParameters(@Nullable PlaybackParameters playbackParameters);
/**
* Returns the currently active playback parameters.
*
* @see EventListener#onPlaybackParametersChanged(PlaybackParameters)
*/
PlaybackParameters getPlaybackParameters();
/**
* Stops playback. Use {@code setPlayWhenReady(false)} rather than this method if the intention
* is to pause playback.
* <p>
* Calling this method will cause the playback state to transition to {@link #STATE_IDLE}. The
* player instance can still be used, and {@link #release()} must still be called on the player if
* it's no longer required.
* <p>
* Calling this method does not reset the playback position.
*/
void stop();
/**
* Releases the player. This method must be called when the player is no longer required. The
* player must not be used after calling this method.
*/
void release();
/**
* Sends messages to their target components. The messages are delivered on the playback thread.
* If a component throws an {@link ExoPlaybackException} then it is propagated out of the player
@ -462,112 +241,4 @@ public interface ExoPlayer {
*/
void blockingSendMessages(ExoPlayerMessage... messages);
/**
* Returns the number of renderers.
*/
int getRendererCount();
/**
* Returns the track type that the renderer at a given index handles.
*
* @see Renderer#getTrackType()
* @param index The index of the renderer.
* @return One of the {@code TRACK_TYPE_*} constants defined in {@link C}.
*/
int getRendererType(int index);
/**
* Returns the available track groups.
*/
TrackGroupArray getCurrentTrackGroups();
/**
* Returns the current track selections for each renderer.
*/
TrackSelectionArray getCurrentTrackSelections();
/**
* Returns the current manifest. The type depends on the {@link MediaSource} passed to
* {@link #prepare}. May be null.
*/
Object getCurrentManifest();
/**
* Returns the current {@link Timeline}. Never null, but may be empty.
*/
Timeline getCurrentTimeline();
/**
* Returns the index of the period currently being played.
*/
int getCurrentPeriodIndex();
/**
* Returns the index of the window currently being played.
*/
int getCurrentWindowIndex();
/**
* Returns the duration of the current window in milliseconds, or {@link C#TIME_UNSET} if the
* duration is not known.
*/
long getDuration();
/**
* Returns the playback position in the current window, in milliseconds.
*/
long getCurrentPosition();
/**
* Returns an estimate of the position in the current window up to which data is buffered, in
* milliseconds.
*/
long getBufferedPosition();
/**
* Returns an estimate of the percentage in the current window up to which data is buffered, or 0
* if no estimate is available.
*/
int getBufferedPercentage();
/**
* Returns whether the current window is dynamic, or {@code false} if the {@link Timeline} is
* empty.
*
* @see Timeline.Window#isDynamic
*/
boolean isCurrentWindowDynamic();
/**
* Returns whether the current window is seekable, or {@code false} if the {@link Timeline} is
* empty.
*
* @see Timeline.Window#isSeekable
*/
boolean isCurrentWindowSeekable();
/**
* Returns whether the player is currently playing an ad.
*/
boolean isPlayingAd();
/**
* If {@link #isPlayingAd()} returns true, returns the index of the ad group in the period
* currently being played. Returns {@link C#INDEX_UNSET} otherwise.
*/
int getCurrentAdGroupIndex();
/**
* If {@link #isPlayingAd()} returns true, returns the index of the ad in its ad group. Returns
* {@link C#INDEX_UNSET} otherwise.
*/
int getCurrentAdIndexInAdGroup();
/**
* If {@link #isPlayingAd()} returns {@code true}, returns the content position that will be
* played once all ads in the ad group have finished playing, in milliseconds. If there is no ad
* playing, the returned position is the same as that returned by {@link #getCurrentPosition()}.
*/
long getContentPosition();
}

View file

@ -46,7 +46,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
private final TrackSelectionArray emptyTrackSelections;
private final Handler eventHandler;
private final ExoPlayerImplInternal internalPlayer;
private final CopyOnWriteArraySet<EventListener> listeners;
private final CopyOnWriteArraySet<Player.EventListener> listeners;
private final Timeline.Window window;
private final Timeline.Period period;
@ -114,12 +114,12 @@ import java.util.concurrent.CopyOnWriteArraySet;
}
@Override
public void addListener(EventListener listener) {
public void addListener(Player.EventListener listener) {
listeners.add(listener);
}
@Override
public void removeListener(EventListener listener) {
public void removeListener(Player.EventListener listener) {
listeners.remove(listener);
}
@ -139,7 +139,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
if (!timeline.isEmpty() || manifest != null) {
timeline = Timeline.EMPTY;
manifest = null;
for (EventListener listener : listeners) {
for (Player.EventListener listener : listeners) {
listener.onTimelineChanged(timeline, manifest);
}
}
@ -148,7 +148,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
trackGroups = TrackGroupArray.EMPTY;
trackSelections = emptyTrackSelections;
trackSelector.onSelectionActivated(null);
for (EventListener listener : listeners) {
for (Player.EventListener listener : listeners) {
listener.onTracksChanged(trackGroups, trackSelections);
}
}
@ -162,7 +162,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
if (this.playWhenReady != playWhenReady) {
this.playWhenReady = playWhenReady;
internalPlayer.setPlayWhenReady(playWhenReady);
for (EventListener listener : listeners) {
for (Player.EventListener listener : listeners) {
listener.onPlayerStateChanged(playWhenReady, playbackState);
}
}
@ -178,7 +178,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
if (this.repeatMode != repeatMode) {
this.repeatMode = repeatMode;
internalPlayer.setRepeatMode(repeatMode);
for (EventListener listener : listeners) {
for (Player.EventListener listener : listeners) {
listener.onRepeatModeChanged(repeatMode);
}
}
@ -238,7 +238,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
} else {
maskingWindowPositionMs = positionMs;
internalPlayer.seekTo(timeline, windowIndex, C.msToUs(positionMs));
for (EventListener listener : listeners) {
for (Player.EventListener listener : listeners) {
listener.onPositionDiscontinuity();
}
}
@ -420,14 +420,14 @@ import java.util.concurrent.CopyOnWriteArraySet;
}
case ExoPlayerImplInternal.MSG_STATE_CHANGED: {
playbackState = msg.arg1;
for (EventListener listener : listeners) {
for (Player.EventListener listener : listeners) {
listener.onPlayerStateChanged(playWhenReady, playbackState);
}
break;
}
case ExoPlayerImplInternal.MSG_LOADING_CHANGED: {
isLoading = msg.arg1 != 0;
for (EventListener listener : listeners) {
for (Player.EventListener listener : listeners) {
listener.onLoadingChanged(isLoading);
}
break;
@ -439,7 +439,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
trackGroups = trackSelectorResult.groups;
trackSelections = trackSelectorResult.selections;
trackSelector.onSelectionActivated(trackSelectorResult.info);
for (EventListener listener : listeners) {
for (Player.EventListener listener : listeners) {
listener.onTracksChanged(trackGroups, trackSelections);
}
}
@ -449,7 +449,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
if (--pendingSeekAcks == 0) {
playbackInfo = (ExoPlayerImplInternal.PlaybackInfo) msg.obj;
if (msg.arg1 != 0) {
for (EventListener listener : listeners) {
for (Player.EventListener listener : listeners) {
listener.onPositionDiscontinuity();
}
}
@ -459,7 +459,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
case ExoPlayerImplInternal.MSG_POSITION_DISCONTINUITY: {
if (pendingSeekAcks == 0) {
playbackInfo = (ExoPlayerImplInternal.PlaybackInfo) msg.obj;
for (EventListener listener : listeners) {
for (Player.EventListener listener : listeners) {
listener.onPositionDiscontinuity();
}
}
@ -472,7 +472,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
timeline = sourceInfo.timeline;
manifest = sourceInfo.manifest;
playbackInfo = sourceInfo.playbackInfo;
for (EventListener listener : listeners) {
for (Player.EventListener listener : listeners) {
listener.onTimelineChanged(timeline, manifest);
}
}
@ -482,7 +482,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
PlaybackParameters playbackParameters = (PlaybackParameters) msg.obj;
if (!this.playbackParameters.equals(playbackParameters)) {
this.playbackParameters = playbackParameters;
for (EventListener listener : listeners) {
for (Player.EventListener listener : listeners) {
listener.onPlaybackParametersChanged(playbackParameters);
}
}
@ -490,7 +490,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
}
case ExoPlayerImplInternal.MSG_ERROR: {
ExoPlaybackException exception = (ExoPlaybackException) msg.obj;
for (EventListener listener : listeners) {
for (Player.EventListener listener : listeners) {
listener.onPlayerError(exception);
}
break;

View file

@ -16,8 +16,8 @@
package com.google.android.exoplayer2;
import android.util.Pair;
import com.google.android.exoplayer2.ExoPlayer.RepeatMode;
import com.google.android.exoplayer2.ExoPlayerImplInternal.PlaybackInfo;
import com.google.android.exoplayer2.Player.RepeatMode;
import com.google.android.exoplayer2.source.MediaPeriod;
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;

View file

@ -0,0 +1,395 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2;
import android.os.Looper;
import android.support.annotation.IntDef;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* An interface for media players.
*/
public interface Player {
/**
* Listener of changes in player state.
*/
interface EventListener {
/**
* Called when the timeline and/or manifest has been refreshed.
* <p>
* Note that if the timeline has changed then a position discontinuity may also have occurred.
* For example, the current period index may have changed as a result of periods being added or
* removed from the timeline. This will <em>not</em> be reported via a separate call to
* {@link #onPositionDiscontinuity()}.
*
* @param timeline The latest timeline. Never null, but may be empty.
* @param manifest The latest manifest. May be null.
*/
void onTimelineChanged(Timeline timeline, Object manifest);
/**
* Called when the available or selected tracks change.
*
* @param trackGroups The available tracks. Never null, but may be of length zero.
* @param trackSelections The track selections for each {@link Renderer}. Never null and always
* of length {@link #getRendererCount()}, but may contain null elements.
*/
void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections);
/**
* Called when the player starts or stops loading the source.
*
* @param isLoading Whether the source is currently being loaded.
*/
void onLoadingChanged(boolean isLoading);
/**
* Called when the value returned from either {@link #getPlayWhenReady()} or
* {@link #getPlaybackState()} changes.
*
* @param playWhenReady Whether playback will proceed when ready.
* @param playbackState One of the {@code STATE} constants.
*/
void onPlayerStateChanged(boolean playWhenReady, int playbackState);
/**
* Called when the value of {@link #getRepeatMode()} changes.
*
* @param repeatMode The {@link RepeatMode} used for playback.
*/
void onRepeatModeChanged(@RepeatMode int repeatMode);
/**
* Called when an error occurs. The playback state will transition to {@link #STATE_IDLE}
* immediately after this method is called. The player instance can still be used, and
* {@link #release()} must still be called on the player should it no longer be required.
*
* @param error The error.
*/
void onPlayerError(ExoPlaybackException error);
/**
* Called when a position discontinuity occurs without a change to the timeline. A position
* discontinuity occurs when the current window or period index changes (as a result of playback
* transitioning from one period in the timeline to the next), or when the playback position
* jumps within the period currently being played (as a result of a seek being performed, or
* when the source introduces a discontinuity internally).
* <p>
* When a position discontinuity occurs as a result of a change to the timeline this method is
* <em>not</em> called. {@link #onTimelineChanged(Timeline, Object)} is called in this case.
*/
void onPositionDiscontinuity();
/**
* Called when the current playback parameters change. The playback parameters may change due to
* a call to {@link #setPlaybackParameters(PlaybackParameters)}, or the player itself may change
* them (for example, if audio playback switches to passthrough mode, where speed adjustment is
* no longer possible).
*
* @param playbackParameters The playback parameters.
*/
void onPlaybackParametersChanged(PlaybackParameters playbackParameters);
}
/**
* The player does not have a source to play, so it is neither buffering nor ready to play.
*/
int STATE_IDLE = 1;
/**
* The player not able to immediately play from the current position. The cause is
* {@link Renderer} specific, but this state typically occurs when more data needs to be
* loaded to be ready to play, or more data needs to be buffered for playback to resume.
*/
int STATE_BUFFERING = 2;
/**
* The player is able to immediately play from the current position. The player will be playing if
* {@link #getPlayWhenReady()} returns true, and paused otherwise.
*/
int STATE_READY = 3;
/**
* The player has finished playing the media.
*/
int STATE_ENDED = 4;
/**
* Repeat modes for playback.
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef({REPEAT_MODE_OFF, REPEAT_MODE_ONE, REPEAT_MODE_ALL})
public @interface RepeatMode {}
/**
* Normal playback without repetition.
*/
int REPEAT_MODE_OFF = 0;
/**
* "Repeat One" mode to repeat the currently playing window infinitely.
*/
int REPEAT_MODE_ONE = 1;
/**
* "Repeat All" mode to repeat the entire timeline infinitely.
*/
int REPEAT_MODE_ALL = 2;
/**
* Register a listener to receive events from the player. The listener's methods will be called on
* the thread that was used to construct the player. However, if the thread used to construct the
* player does not have a {@link Looper}, then the listener will be called on the main thread.
*
* @param listener The listener to register.
*/
void addListener(EventListener listener);
/**
* Unregister a listener. The listener will no longer receive events from the player.
*
* @param listener The listener to unregister.
*/
void removeListener(EventListener listener);
/**
* Returns the current state of the player.
*
* @return One of the {@code STATE} constants defined in this interface.
*/
int getPlaybackState();
/**
* Sets whether playback should proceed when {@link #getPlaybackState()} == {@link #STATE_READY}.
* <p>
* If the player is already in the ready state then this method can be used to pause and resume
* playback.
*
* @param playWhenReady Whether playback should proceed when ready.
*/
void setPlayWhenReady(boolean playWhenReady);
/**
* Whether playback will proceed when {@link #getPlaybackState()} == {@link #STATE_READY}.
*
* @return Whether playback will proceed when ready.
*/
boolean getPlayWhenReady();
/**
* Sets the {@link RepeatMode} to be used for playback.
*
* @param repeatMode A repeat mode.
*/
void setRepeatMode(@RepeatMode int repeatMode);
/**
* Returns the current {@link RepeatMode} used for playback.
*
* @return The current repeat mode.
*/
@RepeatMode int getRepeatMode();
/**
* Whether the player is currently loading the source.
*
* @return Whether the player is currently loading the source.
*/
boolean isLoading();
/**
* Seeks to the default position associated with the current window. The position can depend on
* the type of media being played. For live streams it will typically be the live edge of the
* window. For other streams it will typically be the start of the window.
*/
void seekToDefaultPosition();
/**
* Seeks to the default position associated with the specified window. The position can depend on
* the type of media being played. For live streams it will typically be the live edge of the
* window. For other streams it will typically be the start of the window.
*
* @param windowIndex The index of the window whose associated default position should be seeked
* to.
*/
void seekToDefaultPosition(int windowIndex);
/**
* Seeks to a position specified in milliseconds in the current window.
*
* @param positionMs The seek position in the current window, or {@link C#TIME_UNSET} to seek to
* the window's default position.
*/
void seekTo(long positionMs);
/**
* Seeks to a position specified in milliseconds in the specified window.
*
* @param windowIndex The index of the window.
* @param positionMs The seek position in the specified window, or {@link C#TIME_UNSET} to seek to
* the window's default position.
*/
void seekTo(int windowIndex, long positionMs);
/**
* Attempts to set the playback parameters. Passing {@code null} sets the parameters to the
* default, {@link PlaybackParameters#DEFAULT}, which means there is no speed or pitch adjustment.
* <p>
* Playback parameters changes may cause the player to buffer.
* {@link EventListener#onPlaybackParametersChanged(PlaybackParameters)} will be called whenever
* the currently active playback parameters change. When that listener is called, the parameters
* passed to it may not match {@code playbackParameters}. For example, the chosen speed or pitch
* may be out of range, in which case they are constrained to a set of permitted values. If it is
* not possible to change the playback parameters, the listener will not be invoked.
*
* @param playbackParameters The playback parameters, or {@code null} to use the defaults.
*/
void setPlaybackParameters(@Nullable PlaybackParameters playbackParameters);
/**
* Returns the currently active playback parameters.
*
* @see EventListener#onPlaybackParametersChanged(PlaybackParameters)
*/
PlaybackParameters getPlaybackParameters();
/**
* Stops playback. Use {@code setPlayWhenReady(false)} rather than this method if the intention
* is to pause playback.
* <p>
* Calling this method will cause the playback state to transition to {@link #STATE_IDLE}. The
* player instance can still be used, and {@link #release()} must still be called on the player if
* it's no longer required.
* <p>
* Calling this method does not reset the playback position.
*/
void stop();
/**
* Releases the player. This method must be called when the player is no longer required. The
* player must not be used after calling this method.
*/
void release();
/**
* Returns the number of renderers.
*/
int getRendererCount();
/**
* Returns the track type that the renderer at a given index handles.
*
* @see Renderer#getTrackType()
* @param index The index of the renderer.
* @return One of the {@code TRACK_TYPE_*} constants defined in {@link C}.
*/
int getRendererType(int index);
/**
* Returns the available track groups.
*/
TrackGroupArray getCurrentTrackGroups();
/**
* Returns the current track selections for each renderer.
*/
TrackSelectionArray getCurrentTrackSelections();
/**
* Returns the current manifest. The type depends on the type of media being played. May be null.
*/
@Nullable Object getCurrentManifest();
/**
* Returns the current {@link Timeline}. Never null, but may be empty.
*/
Timeline getCurrentTimeline();
/**
* Returns the index of the period currently being played.
*/
int getCurrentPeriodIndex();
/**
* Returns the index of the window currently being played.
*/
int getCurrentWindowIndex();
/**
* Returns the duration of the current window in milliseconds, or {@link C#TIME_UNSET} if the
* duration is not known.
*/
long getDuration();
/**
* Returns the playback position in the current window, in milliseconds.
*/
long getCurrentPosition();
/**
* Returns an estimate of the position in the current window up to which data is buffered, in
* milliseconds.
*/
long getBufferedPosition();
/**
* Returns an estimate of the percentage in the current window up to which data is buffered, or 0
* if no estimate is available.
*/
int getBufferedPercentage();
/**
* Returns whether the current window is dynamic, or {@code false} if the {@link Timeline} is
* empty.
*
* @see Timeline.Window#isDynamic
*/
boolean isCurrentWindowDynamic();
/**
* Returns whether the current window is seekable, or {@code false} if the {@link Timeline} is
* empty.
*
* @see Timeline.Window#isSeekable
*/
boolean isCurrentWindowSeekable();
/**
* Returns whether the player is currently playing an ad.
*/
boolean isPlayingAd();
/**
* If {@link #isPlayingAd()} returns true, returns the index of the ad group in the period
* currently being played. Returns {@link C#INDEX_UNSET} otherwise.
*/
int getCurrentAdGroupIndex();
/**
* If {@link #isPlayingAd()} returns true, returns the index of the ad in its ad group. Returns
* {@link C#INDEX_UNSET} otherwise.
*/
int getCurrentAdIndexInAdGroup();
/**
* If {@link #isPlayingAd()} returns {@code true}, returns the content position that will be
* played once all ads in the ad group have finished playing, in milliseconds. If there is no ad
* playing, the returned position is the same as that returned by {@link #getCurrentPosition()}.
*/
long getContentPosition();
}

View file

@ -524,12 +524,12 @@ public class SimpleExoPlayer implements ExoPlayer {
}
@Override
public void addListener(EventListener listener) {
public void addListener(Player.EventListener listener) {
player.addListener(listener);
}
@Override
public void removeListener(EventListener listener) {
public void removeListener(Player.EventListener listener) {
player.removeListener(listener);
}

View file

@ -17,7 +17,7 @@ package com.google.android.exoplayer2.source;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.ExoPlayer.RepeatMode;
import com.google.android.exoplayer2.Player.RepeatMode;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.upstream.Allocator;
import com.google.android.exoplayer2.util.Assertions;

View file

@ -31,9 +31,10 @@ import android.widget.ImageView;
import android.widget.TextView;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Player.RepeatMode;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
@ -45,7 +46,7 @@ import java.util.Formatter;
import java.util.Locale;
/**
* A view for controlling {@link ExoPlayer} instances.
* A view for controlling {@link Player} instances.
* <p>
* A PlaybackControlView can be customized by setting attributes (or calling corresponding methods),
* overriding the view's layout file or by specifying a custom view layout file, as outlined below.
@ -183,7 +184,7 @@ public class PlaybackControlView extends FrameLayout {
}
/**
* Dispatches operations to the player.
* Dispatches operations to the {@link Player}.
* <p>
* Implementations may choose to suppress (e.g. prevent playback from resuming if audio focus is
* denied) or modify (e.g. change the seek position to prevent a user from seeking past a
@ -192,33 +193,34 @@ public class PlaybackControlView extends FrameLayout {
public interface ControlDispatcher {
/**
* Dispatches a {@link ExoPlayer#setPlayWhenReady(boolean)} operation.
* Dispatches a {@link Player#setPlayWhenReady(boolean)} operation.
*
* @param player The player to which the operation should be dispatched.
* @param player The {@link Player} to which the operation should be dispatched.
* @param playWhenReady Whether playback should proceed when ready.
* @return True if the operation was dispatched. False if suppressed.
*/
boolean dispatchSetPlayWhenReady(ExoPlayer player, boolean playWhenReady);
boolean dispatchSetPlayWhenReady(Player player, boolean playWhenReady);
/**
* Dispatches a {@link ExoPlayer#seekTo(int, long)} operation.
* Dispatches a {@link Player#seekTo(int, long)} operation.
*
* @param player The player to which the operation should be dispatched.
* @param player The {@link Player} to which the operation should be dispatched.
* @param windowIndex The index of the window.
* @param positionMs The seek position in the specified window, or {@link C#TIME_UNSET} to seek
* to the window's default position.
* @return True if the operation was dispatched. False if suppressed.
*/
boolean dispatchSeekTo(ExoPlayer player, int windowIndex, long positionMs);
boolean dispatchSeekTo(Player player, int windowIndex, long positionMs);
/**
* Dispatches a {@link ExoPlayer#setRepeatMode(int)} operation.
* Dispatches a {@link Player#setRepeatMode(int)} operation.
*
* @param player The player to which the operation should be dispatched.
* @param player The {@link Player} to which the operation should be dispatched.
* @param repeatMode The repeat mode.
* @return True if the operation was dispatched. False if suppressed.
*/
boolean dispatchSetRepeatMode(ExoPlayer player, @ExoPlayer.RepeatMode int repeatMode);
boolean dispatchSetRepeatMode(Player player, @RepeatMode int repeatMode);
}
/**
@ -228,19 +230,19 @@ public class PlaybackControlView extends FrameLayout {
public static final ControlDispatcher DEFAULT_CONTROL_DISPATCHER = new ControlDispatcher() {
@Override
public boolean dispatchSetPlayWhenReady(ExoPlayer player, boolean playWhenReady) {
public boolean dispatchSetPlayWhenReady(Player player, boolean playWhenReady) {
player.setPlayWhenReady(playWhenReady);
return true;
}
@Override
public boolean dispatchSeekTo(ExoPlayer player, int windowIndex, long positionMs) {
public boolean dispatchSeekTo(Player player, int windowIndex, long positionMs) {
player.seekTo(windowIndex, positionMs);
return true;
}
@Override
public boolean dispatchSetRepeatMode(ExoPlayer player, @ExoPlayer.RepeatMode int repeatMode) {
public boolean dispatchSetRepeatMode(Player player, @RepeatMode int repeatMode) {
player.setRepeatMode(repeatMode);
return true;
}
@ -283,7 +285,7 @@ public class PlaybackControlView extends FrameLayout {
private final String repeatOneButtonContentDescription;
private final String repeatAllButtonContentDescription;
private ExoPlayer player;
private Player player;
private ControlDispatcher controlDispatcher;
private VisibilityListener visibilityListener;
@ -409,18 +411,19 @@ public class PlaybackControlView extends FrameLayout {
}
/**
* Returns the player currently being controlled by this view, or null if no player is set.
* Returns the {@link Player} currently being controlled by this view, or null if no player is
* set.
*/
public ExoPlayer getPlayer() {
public Player getPlayer() {
return player;
}
/**
* Sets the {@link ExoPlayer} to control.
* Sets the {@link Player} to control.
*
* @param player The {@code ExoPlayer} to control.
* @param player The {@link Player} to control.
*/
public void setPlayer(ExoPlayer player) {
public void setPlayer(Player player) {
if (this.player == player) {
return;
}
@ -528,16 +531,16 @@ public class PlaybackControlView extends FrameLayout {
public void setRepeatToggleModes(@RepeatModeUtil.RepeatToggleModes int repeatToggleModes) {
this.repeatToggleModes = repeatToggleModes;
if (player != null) {
@ExoPlayer.RepeatMode int currentMode = player.getRepeatMode();
@Player.RepeatMode int currentMode = player.getRepeatMode();
if (repeatToggleModes == RepeatModeUtil.REPEAT_TOGGLE_MODE_NONE
&& currentMode != ExoPlayer.REPEAT_MODE_OFF) {
controlDispatcher.dispatchSetRepeatMode(player, ExoPlayer.REPEAT_MODE_OFF);
&& currentMode != Player.REPEAT_MODE_OFF) {
controlDispatcher.dispatchSetRepeatMode(player, Player.REPEAT_MODE_OFF);
} else if (repeatToggleModes == RepeatModeUtil.REPEAT_TOGGLE_MODE_ONE
&& currentMode == ExoPlayer.REPEAT_MODE_ALL) {
controlDispatcher.dispatchSetRepeatMode(player, ExoPlayer.REPEAT_MODE_ONE);
&& currentMode == Player.REPEAT_MODE_ALL) {
controlDispatcher.dispatchSetRepeatMode(player, Player.REPEAT_MODE_ONE);
} else if (repeatToggleModes == RepeatModeUtil.REPEAT_TOGGLE_MODE_ALL
&& currentMode == ExoPlayer.REPEAT_MODE_ONE) {
controlDispatcher.dispatchSetRepeatMode(player, ExoPlayer.REPEAT_MODE_ALL);
&& currentMode == Player.REPEAT_MODE_ONE) {
controlDispatcher.dispatchSetRepeatMode(player, Player.REPEAT_MODE_ALL);
}
}
}
@ -658,15 +661,15 @@ public class PlaybackControlView extends FrameLayout {
return;
}
switch (player.getRepeatMode()) {
case ExoPlayer.REPEAT_MODE_OFF:
case Player.REPEAT_MODE_OFF:
repeatToggleButton.setImageDrawable(repeatOffButtonDrawable);
repeatToggleButton.setContentDescription(repeatOffButtonContentDescription);
break;
case ExoPlayer.REPEAT_MODE_ONE:
case Player.REPEAT_MODE_ONE:
repeatToggleButton.setImageDrawable(repeatOneButtonDrawable);
repeatToggleButton.setContentDescription(repeatOneButtonContentDescription);
break;
case ExoPlayer.REPEAT_MODE_ALL:
case Player.REPEAT_MODE_ALL:
repeatToggleButton.setImageDrawable(repeatAllButtonDrawable);
repeatToggleButton.setContentDescription(repeatAllButtonContentDescription);
break;
@ -765,10 +768,10 @@ public class PlaybackControlView extends FrameLayout {
// Cancel any pending updates and schedule a new one if necessary.
removeCallbacks(updateProgressAction);
int playbackState = player == null ? ExoPlayer.STATE_IDLE : player.getPlaybackState();
if (playbackState != ExoPlayer.STATE_IDLE && playbackState != ExoPlayer.STATE_ENDED) {
int playbackState = player == null ? Player.STATE_IDLE : player.getPlaybackState();
if (playbackState != Player.STATE_IDLE && playbackState != Player.STATE_ENDED) {
long delayMs;
if (player.getPlayWhenReady() && playbackState == ExoPlayer.STATE_READY) {
if (player.getPlayWhenReady() && playbackState == Player.STATE_READY) {
delayMs = 1000 - (position % 1000);
if (delayMs < 200) {
delayMs += 1000;
@ -995,7 +998,7 @@ public class PlaybackControlView extends FrameLayout {
return true;
}
private final class ComponentListener implements ExoPlayer.EventListener, TimeBar.OnScrubListener,
private final class ComponentListener implements Player.EventListener, TimeBar.OnScrubListener,
OnClickListener {
@Override