ExoPlayer is designed to make few assumptions about (and hence impose few restrictions on) the
+ * type of the media being played, how and where it is stored, and how it is rendered. Rather than
+ * implementing the loading and rendering of media directly, ExoPlayer implementations delegate this
+ * work to components that are injected when a player is created or when it's prepared for playback.
+ * Components common to all ExoPlayer implementations are:
+ *
+ *
A {@link MediaSource} that defines the media to be played, loads the media, and from
+ * which the loaded media can be read. A MediaSource is injected via {@link #prepare} to prepare
+ * the player for playback. The library provides default implementations for regular media files
+ * ({@link ExtractorMediaSource}), DASH ({@link DashMediaSource}), SmoothStreaming
+ * ({@link SsMediaSource}) and HLS ({@link HlsMediaSource}), implementations for merging
+ * ({@link MergingMediaSource}) and concatenating ({@link ConcatenatingMediaSource}) other
+ * MediaSources, and an implementation for loading single samples
+ * ({@link SingleSampleMediaSource}) most often used for side-loaded subtitle and closed
+ * caption files.
+ *
{@link Renderer}s that render individual components of the media. The library
+ * provides default implementations for common media types ({@link MediaCodecVideoRenderer},
+ * {@link MediaCodecAudioRenderer}, {@link TextRenderer} and {@link MetadataRenderer}). A Renderer
+ * consumes media of its corresponding type from the MediaSource being played. Renderers are
+ * injected when the player is created.
+ *
A {@link TrackSelector} that selects tracks provided by the MediaSource to be
+ * consumed by each of the available Renderers. The library provides a default implementation
+ * ({@link DefaultTrackSelector}) suitable for most use cases. A TrackSelector is injected when
+ * the player is created.
+ *
A {@link LoadControl} that controls when the MediaSource buffers more media, and how
+ * much media is buffered. The library provides a default implementation
+ * ({@link DefaultLoadControl}) suitable for most use cases. A LoadControl is injected when the
+ * player is created.
+ *
+ *
An ExoPlayer can be built using the default components provided by the library, but may also
+ * be built using custom implementations if non-standard behaviors are required. For example a
+ * custom LoadControl could be injected to change the player's buffering strategy, or a custom
+ * Renderer could be injected to use a video codec not supported natively by Android.
*
- *
- *
Assumptions and player construction
+ *
The concept of injecting components that implement pieces of player functionality is present
+ * throughout the library. The default component implementations listed above delegate work to
+ * further injected components. This allows many sub-components to be individually replaced with
+ * custom implementations. For example the default MediaSource implementations require one or more
+ * {@link DataSource} factories to be injected via their constructors. By providing a custom factory
+ * it's possible to load data from a non-standard source or through a different network stack.
*
- *
The implementation is designed to make no assumptions about (and hence impose no restrictions
- * on) the type of the media being played, how and where it is stored, or how it is rendered.
- * Rather than implementing the loading and rendering of media directly, {@link ExoPlayer} instead
- * delegates this work to one or more {@link Renderer}s, which are injected when the player
- * is created. Hence {@link ExoPlayer} is capable of loading and playing any media for which a
- * {@link Renderer} implementation can be provided.
- *
- *
{@link com.google.android.exoplayer2.audio.MediaCodecAudioRenderer} and
- * {@link com.google.android.exoplayer2.video.MediaCodecVideoRenderer} can be used for the common
- * cases of rendering audio and video. These components in turn require an upstream
- * {@link MediaPeriod} to be injected through their constructors, where upstream is defined to
- * denote a component that is closer to the source of the media. This pattern of upstream dependency
- * injection is actively encouraged, since it means that the functionality of the player is built up
- * through the composition of components that can easily be exchanged for alternate implementations.
- * For example a {@link MediaPeriod} implementation may require a further upstream data loading
- * component to be injected through its constructor, with different implementations enabling the
- * loading of data from various sources.
- *
- *
*
Threading model
- *
- *
The figure below shows the {@link ExoPlayer} threading model.
- *
+ *
The figure below shows ExoPlayer's threading model.
+ *
+ *
+ *
*
*
- *
It is recommended that instances are created and accessed from a single application thread.
- * An application's main thread is ideal. Accessing an instance from multiple threads is
+ *
It is recommended that ExoPlayer instances are created and accessed from a single application
+ * thread. The application's main thread is ideal. Accessing an instance from multiple threads is
* discouraged, however if an application does wish to do this then it may do so provided that it
- * ensures accesses are synchronized.
- *
- *
Registered {@link EventListener}s are called on the thread that created the {@link ExoPlayer}
- * instance.
- *
An internal playback thread is responsible for managing playback and invoking the
- * {@link Renderer}s in order to load and play the media.
- *
{@link Renderer} implementations (or any upstream components that they depend on) may
- * use additional background threads (e.g. to load data). These are implementation specific.
+ * ensures accesses are synchronized.
+ *
Registered listeners are called on the thread that created the ExoPlayer instance.
+ *
An internal playback thread is responsible for playback. Injected player components such as
+ * Renderers, MediaSources, TrackSelectors and LoadControls are called by the player on this
+ * thread.
+ *
When the application performs an operation on the player, for example a seek, a message is
+ * delivered to the internal playback thread via a message queue. The internal playback thread
+ * consumes messages from the queue and performs the corresponding operations. Similarly, when a
+ * playback event occurs on the internal playback thread, a message is delivered to the application
+ * thread via a second message queue. The application thread consumes messages from the queue,
+ * updating the application visible state and calling corresponding listener methods.
+ *
Injected player components may use additional background threads. For example a MediaSource
+ * may use a background thread to load data. These are implementation specific.
*
- *
- *
- *
Player state
- *
- *
The components of an {@link ExoPlayer}'s state can be divided into two distinct groups. The
- * state accessed by calling {@link #getPlayWhenReady()} is only ever changed by invoking
- * {@link #setPlayWhenReady(boolean)}, and is never changed as a result of operations that have been
- * performed asynchronously by the playback thread. In contrast, the playback state accessed by
- * calling {@link #getPlaybackState()} is only ever changed as a result of operations completing on
- * the playback thread, as illustrated below.
- *
- *
- *
- *
The possible playback state transitions are shown below. Transitions can be triggered either
- * by changes in the state of the {@link Renderer}s being used, or as a result of
- * {@link #setMediaSource(MediaSource)}, {@link #stop()} or {@link #release()} being called.
- *
*/
public interface ExoPlayer {
@@ -117,23 +127,13 @@ public interface ExoPlayer {
*/
void onPlayerStateChanged(boolean playWhenReady, int playbackState);
- // TODO: Should be windowIndex and position in the window.
/**
- * Called when the player's position changes due to a discontinuity (i.e. due to seeking,
- * playback transitioning to the next window, or a source induced discontinuity).
+ * Called when timeline and/or manifest has been refreshed.
*
- * @param periodIndex The index of the period being played.
- * @param positionMs The playback position in that period, in milliseconds.
+ * @param timeline The latest timeline.
+ * @param manifest The latest manifest.
*/
- void onPositionDiscontinuity(int periodIndex, long positionMs);
-
- /**
- * Called when manifest and/or timeline has been refreshed.
- *
- * @param timeline The source's timeline.
- * @param manifest The loaded manifest.
- */
- void onSourceInfoRefreshed(Timeline timeline, Object manifest);
+ void onTimelineChanged(Timeline timeline, Object manifest);
/**
* Called when an error occurs. The playback state will transition to {@link #STATE_IDLE}
@@ -144,6 +144,16 @@ public interface ExoPlayer {
*/
void onPlayerError(ExoPlaybackException error);
+ // TODO: Should be windowIndex and position in the window.
+ /**
+ * Called when the player's position changes due to a discontinuity (i.e. due to seeking,
+ * playback transitioning to the next window, or a source induced discontinuity).
+ *
+ * @param periodIndex The index of the period being played.
+ * @param positionMs The playback position in that period, in milliseconds.
+ */
+ void onPositionDiscontinuity(int periodIndex, long positionMs);
+
}
/**
@@ -239,19 +249,21 @@ public interface ExoPlayer {
int getPlaybackState();
/**
- * Sets the {@link MediaSource} to play. Equivalent to {@code setMediaSource(mediaSource, true)}.
+ * Prepares the player to play the provided {@link MediaSource}. Equivalent to
+ * {@code prepare(mediaSource, true)}.
*/
- void setMediaSource(MediaSource mediaSource);
+ void prepare(MediaSource mediaSource);
/**
- * Sets the {@link MediaSource} to play.
+ * Prepares the player to play the provided {@link MediaSource}, optionally resetting the playback
+ * position the default position in the first {@link Timeline.Window}.
*
* @param mediaSource The {@link MediaSource} to play.
- * @param resetPosition Whether the playback position should be reset to the source's default
- * position. If false, playback will start from the position defined by
- * {@link #getCurrentWindowIndex()} and {@link #getCurrentPosition()}.
+ * @param resetPosition Whether the playback position should be reset to the default position in
+ * the first {@link Timeline.Window}. If false, playback will start from the position defined
+ * by {@link #getCurrentWindowIndex()} and {@link #getCurrentPosition()}.
*/
- void setMediaSource(MediaSource mediaSource, boolean resetPosition);
+ void prepare(MediaSource mediaSource, boolean resetPosition);
/**
* Sets whether playback should proceed when {@link #getPlaybackState()} == {@link #STATE_READY}.
@@ -279,17 +291,15 @@ public interface ExoPlayer {
/**
* Seeks to the default position associated with the current window. The position can depend on
- * the type of source passed to {@link #setMediaSource(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.
+ * 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 #setMediaSource(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.
+ * 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.
@@ -353,7 +363,7 @@ public interface ExoPlayer {
/**
* Returns the current manifest. The type depends on the {@link MediaSource} passed to
- * {@link #setMediaSource(MediaSource)} or {@link #setMediaSource(MediaSource, boolean)}.
+ * {@link #prepare}.
*/
Object getCurrentManifest();
diff --git a/library/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java b/library/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java
index b62e196691..91cf5ec123 100644
--- a/library/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java
+++ b/library/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java
@@ -28,7 +28,7 @@ import com.google.android.exoplayer2.util.Assertions;
import java.util.concurrent.CopyOnWriteArraySet;
/**
- * Concrete implementation of {@link ExoPlayer}.
+ * An {@link ExoPlayer} implementation. Instances can be obtained from {@link ExoPlayerFactory}.
*/
/* package */ final class ExoPlayerImpl implements ExoPlayer {
@@ -62,8 +62,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
* @param loadControl The {@link LoadControl} that will be used by the instance.
*/
@SuppressLint("HandlerLeak")
- public ExoPlayerImpl(Renderer[] renderers, TrackSelector trackSelector,
- LoadControl loadControl) {
+ public ExoPlayerImpl(Renderer[] renderers, TrackSelector trackSelector, LoadControl loadControl) {
Log.i(TAG, "Init " + ExoPlayerLibraryInfo.VERSION);
Assertions.checkNotNull(renderers);
Assertions.checkState(renderers.length > 0);
@@ -99,12 +98,12 @@ import java.util.concurrent.CopyOnWriteArraySet;
}
@Override
- public void setMediaSource(MediaSource mediaSource) {
- setMediaSource(mediaSource, true);
+ public void prepare(MediaSource mediaSource) {
+ prepare(mediaSource, true);
}
@Override
- public void setMediaSource(MediaSource mediaSource, boolean resetPosition) {
+ public void prepare(MediaSource mediaSource, boolean resetPosition) {
timeline = null;
internalPlayer.setMediaSource(mediaSource, resetPosition);
}
@@ -342,7 +341,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
timeline = timelineAndManifest.first;
manifest = timelineAndManifest.second;
for (EventListener listener : listeners) {
- listener.onSourceInfoRefreshed(timeline, manifest);
+ listener.onTimelineChanged(timeline, manifest);
}
break;
}
diff --git a/library/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java b/library/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java
index 71630e3a2d..18f8fc3942 100644
--- a/library/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java
+++ b/library/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java
@@ -45,8 +45,8 @@ import java.util.ArrayList;
import java.util.List;
/**
- * An {@link ExoPlayer} that uses default {@link Renderer} components. Instances can be obtained
- * from {@link ExoPlayerFactory}.
+ * An {@link ExoPlayer} implementation that uses default {@link Renderer} components. Instances can
+ * be obtained from {@link ExoPlayerFactory}.
*/
@TargetApi(16)
public final class SimpleExoPlayer implements ExoPlayer {
@@ -367,13 +367,13 @@ public final class SimpleExoPlayer implements ExoPlayer {
}
@Override
- public void setMediaSource(MediaSource mediaSource) {
- player.setMediaSource(mediaSource);
+ public void prepare(MediaSource mediaSource) {
+ player.prepare(mediaSource);
}
@Override
- public void setMediaSource(MediaSource mediaSource, boolean resetPosition) {
- player.setMediaSource(mediaSource, resetPosition);
+ public void prepare(MediaSource mediaSource, boolean resetPosition) {
+ player.prepare(mediaSource, resetPosition);
}
@Override
diff --git a/library/src/main/java/com/google/android/exoplayer2/ui/DebugTextViewHelper.java b/library/src/main/java/com/google/android/exoplayer2/ui/DebugTextViewHelper.java
index b72bc18ef9..53e1dcee69 100644
--- a/library/src/main/java/com/google/android/exoplayer2/ui/DebugTextViewHelper.java
+++ b/library/src/main/java/com/google/android/exoplayer2/ui/DebugTextViewHelper.java
@@ -89,7 +89,7 @@ public final class DebugTextViewHelper implements Runnable, ExoPlayer.EventListe
}
@Override
- public void onSourceInfoRefreshed(Timeline timeline, Object manifest) {
+ public void onTimelineChanged(Timeline timeline, Object manifest) {
// Do nothing.
}
diff --git a/library/src/main/javadoc/com/google/android/exoplayer2/doc-files/exoplayer-playbackstate.png b/library/src/main/javadoc/com/google/android/exoplayer2/doc-files/exoplayer-playbackstate.png
deleted file mode 100644
index fb0ba72a60..0000000000
Binary files a/library/src/main/javadoc/com/google/android/exoplayer2/doc-files/exoplayer-playbackstate.png and /dev/null differ
diff --git a/library/src/main/javadoc/com/google/android/exoplayer2/doc-files/exoplayer-state.png b/library/src/main/javadoc/com/google/android/exoplayer2/doc-files/exoplayer-state.png
deleted file mode 100644
index d37a51e23a..0000000000
Binary files a/library/src/main/javadoc/com/google/android/exoplayer2/doc-files/exoplayer-state.png and /dev/null differ
diff --git a/library/src/main/javadoc/com/google/android/exoplayer2/doc-files/exoplayer-threading-model.png b/library/src/main/javadoc/com/google/android/exoplayer2/doc-files/exoplayer-threading-model.png
deleted file mode 100644
index 9f0306c111..0000000000
Binary files a/library/src/main/javadoc/com/google/android/exoplayer2/doc-files/exoplayer-threading-model.png and /dev/null differ
diff --git a/library/src/main/javadoc/com/google/android/exoplayer2/doc-files/exoplayer-threading-model.svg b/library/src/main/javadoc/com/google/android/exoplayer2/doc-files/exoplayer-threading-model.svg
new file mode 100644
index 0000000000..ec591c7516
--- /dev/null
+++ b/library/src/main/javadoc/com/google/android/exoplayer2/doc-files/exoplayer-threading-model.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/library/src/main/javadoc/com/google/android/exoplayer2/doc-files/timeline-advanced.svg b/library/src/main/javadoc/com/google/android/exoplayer2/doc-files/timeline-advanced.svg
index e376534cf6..e7a9960acc 100644
--- a/library/src/main/javadoc/com/google/android/exoplayer2/doc-files/timeline-advanced.svg
+++ b/library/src/main/javadoc/com/google/android/exoplayer2/doc-files/timeline-advanced.svg
@@ -1,3 +1,3 @@
-
+
diff --git a/library/src/main/javadoc/com/google/android/exoplayer2/doc-files/timeline-live-indefinite.svg b/library/src/main/javadoc/com/google/android/exoplayer2/doc-files/timeline-live-indefinite.svg
index 9c309a4a11..d15b27b552 100644
--- a/library/src/main/javadoc/com/google/android/exoplayer2/doc-files/timeline-live-indefinite.svg
+++ b/library/src/main/javadoc/com/google/android/exoplayer2/doc-files/timeline-live-indefinite.svg
@@ -1,3 +1,3 @@
-
+
diff --git a/library/src/main/javadoc/com/google/android/exoplayer2/doc-files/timeline-live-limited.svg b/library/src/main/javadoc/com/google/android/exoplayer2/doc-files/timeline-live-limited.svg
index 768144bee4..24c457424d 100644
--- a/library/src/main/javadoc/com/google/android/exoplayer2/doc-files/timeline-live-limited.svg
+++ b/library/src/main/javadoc/com/google/android/exoplayer2/doc-files/timeline-live-limited.svg
@@ -1,3 +1,3 @@
-
+
diff --git a/library/src/main/javadoc/com/google/android/exoplayer2/doc-files/timeline-live-multi-period.svg b/library/src/main/javadoc/com/google/android/exoplayer2/doc-files/timeline-live-multi-period.svg
index cc8c3930c1..e9528193f6 100644
--- a/library/src/main/javadoc/com/google/android/exoplayer2/doc-files/timeline-live-multi-period.svg
+++ b/library/src/main/javadoc/com/google/android/exoplayer2/doc-files/timeline-live-multi-period.svg
@@ -1,3 +1,3 @@
-
+
diff --git a/library/src/main/javadoc/com/google/android/exoplayer2/doc-files/timeline-period.svg b/library/src/main/javadoc/com/google/android/exoplayer2/doc-files/timeline-period.svg
index 2271ffd694..05a5b259ee 100644
--- a/library/src/main/javadoc/com/google/android/exoplayer2/doc-files/timeline-period.svg
+++ b/library/src/main/javadoc/com/google/android/exoplayer2/doc-files/timeline-period.svg
@@ -1,3 +1,3 @@
-
+
diff --git a/library/src/main/javadoc/com/google/android/exoplayer2/doc-files/timeline-playlist.svg b/library/src/main/javadoc/com/google/android/exoplayer2/doc-files/timeline-playlist.svg
index ba283064b5..5b775de6a5 100644
--- a/library/src/main/javadoc/com/google/android/exoplayer2/doc-files/timeline-playlist.svg
+++ b/library/src/main/javadoc/com/google/android/exoplayer2/doc-files/timeline-playlist.svg
@@ -1,3 +1,3 @@
-
+
diff --git a/library/src/main/javadoc/com/google/android/exoplayer2/doc-files/timeline-single-file.svg b/library/src/main/javadoc/com/google/android/exoplayer2/doc-files/timeline-single-file.svg
index fd644f8482..b9435ed95f 100644
--- a/library/src/main/javadoc/com/google/android/exoplayer2/doc-files/timeline-single-file.svg
+++ b/library/src/main/javadoc/com/google/android/exoplayer2/doc-files/timeline-single-file.svg
@@ -1,3 +1,3 @@
-
+
diff --git a/library/src/main/javadoc/com/google/android/exoplayer2/doc-files/timeline-window.svg b/library/src/main/javadoc/com/google/android/exoplayer2/doc-files/timeline-window.svg
index b834f02f9d..aaa4b7738b 100644
--- a/library/src/main/javadoc/com/google/android/exoplayer2/doc-files/timeline-window.svg
+++ b/library/src/main/javadoc/com/google/android/exoplayer2/doc-files/timeline-window.svg
@@ -1,3 +1,3 @@
-
+
diff --git a/playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/util/ExoHostedTest.java b/playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/util/ExoHostedTest.java
index 052de93f8a..1b87dde852 100644
--- a/playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/util/ExoHostedTest.java
+++ b/playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/util/ExoHostedTest.java
@@ -132,7 +132,7 @@ public abstract class ExoHostedTest implements HostedTest, ExoPlayer.EventListen
String userAgent = "ExoPlayerPlaybackTests";
DrmSessionManager drmSessionManager = buildDrmSessionManager(userAgent);
player = buildExoPlayer(host, surface, trackSelector, drmSessionManager);
- player.setMediaSource(buildSource(host, Util.getUserAgent(host, userAgent), bandwidthMeter));
+ player.prepare(buildSource(host, Util.getUserAgent(host, userAgent), bandwidthMeter));
player.addListener(this);
player.setAudioDebugListener(this);
player.setVideoDebugListener(this);
@@ -215,7 +215,7 @@ public abstract class ExoHostedTest implements HostedTest, ExoPlayer.EventListen
}
@Override
- public final void onSourceInfoRefreshed(Timeline timeline, Object manifest) {
+ public final void onTimelineChanged(Timeline timeline, Object manifest) {
// Do nothing.
}