diff --git a/demos/cast/build.gradle b/demos/cast/build.gradle
index c898557cab..cad97358e9 100644
--- a/demos/cast/build.gradle
+++ b/demos/cast/build.gradle
@@ -48,22 +48,6 @@ android {
// The demo app does not have translations.
disable 'MissingTranslation'
}
-
- flavorDimensions "receiver"
-
- productFlavors {
- exoCast {
- dimension "receiver"
- manifestPlaceholders =
- [castOptionsProvider: "com.google.android.exoplayer2.ext.cast.ExoCastOptionsProvider"]
- }
- defaultCast {
- dimension "receiver"
- manifestPlaceholders =
- [castOptionsProvider: "com.google.android.exoplayer2.ext.cast.DefaultCastOptionsProvider"]
- }
- }
-
}
dependencies {
diff --git a/demos/cast/src/main/AndroidManifest.xml b/demos/cast/src/main/AndroidManifest.xml
index c556721863..40dfe22167 100644
--- a/demos/cast/src/main/AndroidManifest.xml
+++ b/demos/cast/src/main/AndroidManifest.xml
@@ -23,7 +23,7 @@
android:largeHeap="true" android:allowBackup="false">
+ android:value="com.google.android.exoplayer2.ext.cast.ExoCastOptionsProvider" />
mediaQueue;
- private final QueueChangesListener queueChangesListener;
- private final ConcatenatingMediaSource concatenatingMediaSource;
-
- private boolean castMediaQueueCreationPending;
- private int currentItemIndex;
- private Player currentPlayer;
-
- /**
- * Creates a new manager for {@link SimpleExoPlayer} and {@link CastPlayer}.
- *
- * @param queueChangesListener A {@link QueueChangesListener} for queue position changes.
- * @param localPlayerView The {@link PlayerView} for local playback.
- * @param castControlView The {@link PlayerControlView} to control remote playback.
- * @param context A {@link Context}.
- * @param castContext The {@link CastContext}.
- */
- public DefaultReceiverPlayerManager(
- QueueChangesListener queueChangesListener,
- PlayerView localPlayerView,
- PlayerControlView castControlView,
- Context context,
- CastContext castContext) {
- this.queueChangesListener = queueChangesListener;
- this.localPlayerView = localPlayerView;
- this.castControlView = castControlView;
- mediaQueue = new ArrayList<>();
- currentItemIndex = C.INDEX_UNSET;
- concatenatingMediaSource = new ConcatenatingMediaSource();
-
- DefaultTrackSelector trackSelector = new DefaultTrackSelector();
- RenderersFactory renderersFactory = new DefaultRenderersFactory(context);
- exoPlayer = ExoPlayerFactory.newSimpleInstance(context, renderersFactory, trackSelector);
- exoPlayer.addListener(this);
- localPlayerView.setPlayer(exoPlayer);
-
- castPlayer = new CastPlayer(castContext);
- castPlayer.addListener(this);
- castPlayer.setSessionAvailabilityListener(this);
- castControlView.setPlayer(castPlayer);
-
- setCurrentPlayer(castPlayer.isCastSessionAvailable() ? castPlayer : exoPlayer);
- }
-
- // Queue manipulation methods.
-
- /**
- * Plays a specified queue item in the current player.
- *
- * @param itemIndex The index of the item to play.
- */
- public void selectQueueItem(int itemIndex) {
- setCurrentItem(itemIndex, C.TIME_UNSET, true);
- }
-
- /**
- * Returns the index of the currently played item.
- */
- public int getCurrentItemIndex() {
- return currentItemIndex;
- }
-
- /**
- * Appends {@code item} to the media queue.
- *
- * @param item The {@link MediaItem} to append.
- */
- public void addItem(MediaItem item) {
- mediaQueue.add(item);
- concatenatingMediaSource.addMediaSource(buildMediaSource(item));
- if (currentPlayer == castPlayer) {
- castPlayer.addItems(buildMediaQueueItem(item));
- }
- }
-
- /**
- * Returns the size of the media queue.
- */
- public int getMediaQueueSize() {
- return mediaQueue.size();
- }
-
- /**
- * Returns the item at the given index in the media queue.
- *
- * @param position The index of the item.
- * @return The item at the given index in the media queue.
- */
- public MediaItem getItem(int position) {
- return mediaQueue.get(position);
- }
-
- /**
- * Removes the item at the given index from the media queue.
- *
- * @param itemIndex The index of the item to remove.
- * @return Whether the removal was successful.
- */
- public boolean removeItem(int itemIndex) {
- concatenatingMediaSource.removeMediaSource(itemIndex);
- if (currentPlayer == castPlayer) {
- if (castPlayer.getPlaybackState() != Player.STATE_IDLE) {
- Timeline castTimeline = castPlayer.getCurrentTimeline();
- if (castTimeline.getPeriodCount() <= itemIndex) {
- return false;
- }
- castPlayer.removeItem((int) castTimeline.getPeriod(itemIndex, new Period()).id);
- }
- }
- mediaQueue.remove(itemIndex);
- if (itemIndex == currentItemIndex && itemIndex == mediaQueue.size()) {
- maybeSetCurrentItemAndNotify(C.INDEX_UNSET);
- } else if (itemIndex < currentItemIndex) {
- maybeSetCurrentItemAndNotify(currentItemIndex - 1);
- }
- return true;
- }
-
- /**
- * Moves an item within the queue.
- *
- * @param fromIndex The index of the item to move.
- * @param toIndex The target index of the item in the queue.
- * @return Whether the item move was successful.
- */
- public boolean moveItem(int fromIndex, int toIndex) {
- // Player update.
- concatenatingMediaSource.moveMediaSource(fromIndex, toIndex);
- if (currentPlayer == castPlayer && castPlayer.getPlaybackState() != Player.STATE_IDLE) {
- Timeline castTimeline = castPlayer.getCurrentTimeline();
- int periodCount = castTimeline.getPeriodCount();
- if (periodCount <= fromIndex || periodCount <= toIndex) {
- return false;
- }
- int elementId = (int) castTimeline.getPeriod(fromIndex, new Period()).id;
- castPlayer.moveItem(elementId, toIndex);
- }
-
- mediaQueue.add(toIndex, mediaQueue.remove(fromIndex));
-
- // Index update.
- if (fromIndex == currentItemIndex) {
- maybeSetCurrentItemAndNotify(toIndex);
- } else if (fromIndex < currentItemIndex && toIndex >= currentItemIndex) {
- maybeSetCurrentItemAndNotify(currentItemIndex - 1);
- } else if (fromIndex > currentItemIndex && toIndex <= currentItemIndex) {
- maybeSetCurrentItemAndNotify(currentItemIndex + 1);
- }
-
- return true;
- }
-
- // Miscellaneous methods.
-
- /**
- * Dispatches a given {@link KeyEvent} to the corresponding view of the current player.
- *
- * @param event The {@link KeyEvent}.
- * @return Whether the event was handled by the target view.
- */
- public boolean dispatchKeyEvent(KeyEvent event) {
- if (currentPlayer == exoPlayer) {
- return localPlayerView.dispatchKeyEvent(event);
- } else /* currentPlayer == castPlayer */ {
- return castControlView.dispatchKeyEvent(event);
- }
- }
-
- /**
- * Releases the manager and the players that it holds.
- */
- public void release() {
- currentItemIndex = C.INDEX_UNSET;
- mediaQueue.clear();
- concatenatingMediaSource.clear();
- castPlayer.setSessionAvailabilityListener(null);
- castPlayer.release();
- localPlayerView.setPlayer(null);
- exoPlayer.release();
- }
-
- // Player.EventListener implementation.
-
- @Override
- public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
- updateCurrentItemIndex();
- }
-
- @Override
- public void onPositionDiscontinuity(@DiscontinuityReason int reason) {
- updateCurrentItemIndex();
- }
-
- @Override
- public void onTimelineChanged(
- Timeline timeline, @Nullable Object manifest, @TimelineChangeReason int reason) {
- updateCurrentItemIndex();
- if (currentPlayer == castPlayer && timeline.isEmpty()) {
- castMediaQueueCreationPending = true;
- }
- }
-
- // CastPlayer.SessionAvailabilityListener implementation.
-
- @Override
- public void onCastSessionAvailable() {
- setCurrentPlayer(castPlayer);
- }
-
- @Override
- public void onCastSessionUnavailable() {
- setCurrentPlayer(exoPlayer);
- }
-
- // Internal methods.
-
- private void updateCurrentItemIndex() {
- int playbackState = currentPlayer.getPlaybackState();
- maybeSetCurrentItemAndNotify(
- playbackState != Player.STATE_IDLE && playbackState != Player.STATE_ENDED
- ? currentPlayer.getCurrentWindowIndex() : C.INDEX_UNSET);
- }
-
- private void setCurrentPlayer(Player currentPlayer) {
- if (this.currentPlayer == currentPlayer) {
- return;
- }
-
- // View management.
- if (currentPlayer == exoPlayer) {
- localPlayerView.setVisibility(View.VISIBLE);
- castControlView.hide();
- } else /* currentPlayer == castPlayer */ {
- localPlayerView.setVisibility(View.GONE);
- castControlView.show();
- }
-
- // Player state management.
- long playbackPositionMs = C.TIME_UNSET;
- int windowIndex = C.INDEX_UNSET;
- boolean playWhenReady = false;
- if (this.currentPlayer != null) {
- int playbackState = this.currentPlayer.getPlaybackState();
- if (playbackState != Player.STATE_ENDED) {
- playbackPositionMs = this.currentPlayer.getCurrentPosition();
- playWhenReady = this.currentPlayer.getPlayWhenReady();
- windowIndex = this.currentPlayer.getCurrentWindowIndex();
- if (windowIndex != currentItemIndex) {
- playbackPositionMs = C.TIME_UNSET;
- windowIndex = currentItemIndex;
- }
- }
- this.currentPlayer.stop(true);
- } else {
- // This is the initial setup. No need to save any state.
- }
-
- this.currentPlayer = currentPlayer;
-
- // Media queue management.
- castMediaQueueCreationPending = currentPlayer == castPlayer;
- if (currentPlayer == exoPlayer) {
- exoPlayer.prepare(concatenatingMediaSource);
- }
-
- // Playback transition.
- if (windowIndex != C.INDEX_UNSET) {
- setCurrentItem(windowIndex, playbackPositionMs, playWhenReady);
- }
- }
-
- /**
- * Starts playback of the item at the given position.
- *
- * @param itemIndex The index of the item to play.
- * @param positionMs The position at which playback should start.
- * @param playWhenReady Whether the player should proceed when ready to do so.
- */
- private void setCurrentItem(int itemIndex, long positionMs, boolean playWhenReady) {
- maybeSetCurrentItemAndNotify(itemIndex);
- if (castMediaQueueCreationPending) {
- MediaQueueItem[] items = new MediaQueueItem[mediaQueue.size()];
- for (int i = 0; i < items.length; i++) {
- items[i] = buildMediaQueueItem(mediaQueue.get(i));
- }
- castMediaQueueCreationPending = false;
- castPlayer.loadItems(items, itemIndex, positionMs, Player.REPEAT_MODE_OFF);
- } else {
- currentPlayer.seekTo(itemIndex, positionMs);
- currentPlayer.setPlayWhenReady(playWhenReady);
- }
- }
-
- private void maybeSetCurrentItemAndNotify(int currentItemIndex) {
- if (this.currentItemIndex != currentItemIndex) {
- int oldIndex = this.currentItemIndex;
- this.currentItemIndex = currentItemIndex;
- queueChangesListener.onQueuePositionChanged(oldIndex, currentItemIndex);
- }
- }
-
- private static MediaSource buildMediaSource(MediaItem item) {
- Uri uri = item.media.uri;
- switch (item.mimeType) {
- case DemoUtil.MIME_TYPE_SS:
- return new SsMediaSource.Factory(DATA_SOURCE_FACTORY).createMediaSource(uri);
- case DemoUtil.MIME_TYPE_DASH:
- return new DashMediaSource.Factory(DATA_SOURCE_FACTORY).createMediaSource(uri);
- case DemoUtil.MIME_TYPE_HLS:
- return new HlsMediaSource.Factory(DATA_SOURCE_FACTORY).createMediaSource(uri);
- case DemoUtil.MIME_TYPE_VIDEO_MP4:
- return new ProgressiveMediaSource.Factory(DATA_SOURCE_FACTORY).createMediaSource(uri);
- default: {
- throw new IllegalStateException("Unsupported type: " + item.mimeType);
- }
- }
- }
-
- private static MediaQueueItem buildMediaQueueItem(MediaItem item) {
- MediaMetadata movieMetadata = new MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE);
- movieMetadata.putString(MediaMetadata.KEY_TITLE, item.title);
- MediaInfo mediaInfo =
- new MediaInfo.Builder(item.media.uri.toString())
- .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
- .setContentType(item.mimeType)
- .setMetadata(movieMetadata)
- .build();
- return new MediaQueueItem.Builder(mediaInfo).build();
- }
-
-}
diff --git a/demos/cast/src/main/java/com/google/android/exoplayer2/castdemo/MainActivity.java b/demos/cast/src/main/java/com/google/android/exoplayer2/castdemo/MainActivity.java
index 7b525b04be..5b04502edb 100644
--- a/demos/cast/src/main/java/com/google/android/exoplayer2/castdemo/MainActivity.java
+++ b/demos/cast/src/main/java/com/google/android/exoplayer2/castdemo/MainActivity.java
@@ -38,7 +38,6 @@ import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.ext.cast.MediaItem;
import com.google.android.exoplayer2.ui.PlayerControlView;
import com.google.android.exoplayer2.ui.PlayerView;
-import com.google.android.gms.cast.CastMediaControlIntent;
import com.google.android.gms.cast.framework.CastButtonFactory;
import com.google.android.gms.cast.framework.CastContext;
import com.google.android.gms.dynamite.DynamiteModule;
@@ -49,13 +48,13 @@ import java.util.Collections;
* Cast extension.
*/
public class MainActivity extends AppCompatActivity
- implements OnClickListener, PlayerManager.QueueChangesListener {
+ implements OnClickListener, ExoCastPlayerManager.QueueChangesListener {
private final MediaItem.Builder mediaItemBuilder;
private PlayerView localPlayerView;
private PlayerControlView castControlView;
- private PlayerManager playerManager;
+ private ExoCastPlayerManager playerManager;
private RecyclerView mediaQueueList;
private MediaQueueListAdapter mediaQueueListAdapter;
private CastContext castContext;
@@ -117,29 +116,13 @@ public class MainActivity extends AppCompatActivity
// There is no Cast context to work with. Do nothing.
return;
}
- String applicationId = castContext.getCastOptions().getReceiverApplicationId();
- switch (applicationId) {
- case CastMediaControlIntent.DEFAULT_MEDIA_RECEIVER_APPLICATION_ID:
- playerManager =
- new DefaultReceiverPlayerManager(
- /* queueChangesListener= */ this,
- localPlayerView,
- castControlView,
- /* context= */ this,
- castContext);
- break;
- case ExoCastOptionsProvider.RECEIVER_ID:
- playerManager =
- new ExoCastPlayerManager(
- /* queueChangesListener= */ this,
- localPlayerView,
- castControlView,
- /* context= */ this,
- castContext);
- break;
- default:
- throw new IllegalStateException("Illegal receiver app id: " + applicationId);
- }
+ playerManager =
+ new ExoCastPlayerManager(
+ /* queueChangesListener= */ this,
+ localPlayerView,
+ castControlView,
+ /* context= */ this,
+ castContext);
mediaQueueList.setAdapter(mediaQueueListAdapter);
}
diff --git a/demos/cast/src/main/java/com/google/android/exoplayer2/castdemo/PlayerManager.java b/demos/cast/src/main/java/com/google/android/exoplayer2/castdemo/PlayerManager.java
deleted file mode 100644
index 184dfe29b3..0000000000
--- a/demos/cast/src/main/java/com/google/android/exoplayer2/castdemo/PlayerManager.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2018 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.castdemo;
-
-import android.view.KeyEvent;
-import com.google.android.exoplayer2.C;
-import com.google.android.exoplayer2.ext.cast.MediaItem;
-
-/** Manages the players in the Cast demo app. */
-interface PlayerManager {
-
- /** Listener for changes in the media queue. */
- interface QueueChangesListener {
-
- /** Called when the currently played item of the media queue changes. */
- void onQueuePositionChanged(int previousIndex, int newIndex);
-
- /** Called when the media queue changes due to modifications not caused by this manager. */
- void onQueueContentsExternallyChanged();
- }
-
- /** Redirects the given {@code keyEvent} to the active player. */
- boolean dispatchKeyEvent(KeyEvent keyEvent);
-
- /** Appends the given {@link MediaItem} to the media queue. */
- void addItem(MediaItem mediaItem);
-
- /** Returns the number of items in the media queue. */
- int getMediaQueueSize();
-
- /** Selects the item at the given position for playback. */
- void selectQueueItem(int position);
-
- /**
- * Returns the position of the item currently being played, or {@link C#INDEX_UNSET} if no item is
- * being played.
- */
- int getCurrentItemIndex();
-
- /** Returns the {@link MediaItem} at the given {@code position}. */
- MediaItem getItem(int position);
-
- /** Moves the item at position {@code from} to position {@code to}. */
- boolean moveItem(int from, int to);
-
- /** Removes the item at position {@code index}. */
- boolean removeItem(int index);
-
- /** Releases any acquired resources. */
- void release();
-}