Commit aafdd226 by aquilescanta Committed by Oliver Woodman

Add media queue support to CastPlayer

Also workaround the non-repeatable queue and fix other minor issues.

Issue:#2283

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=166848894
parent f44e30c7
......@@ -52,17 +52,17 @@ import java.util.List;
/**
* The mime type of the media sample, as required by {@link MediaInfo#setContentType}.
*/
public final String type;
public final String mimeType;
/**
* @param uri See {@link #uri}.
* @param name See {@link #name}.
* @param type See {@link #type}.
* @param mimeType See {@link #mimeType}.
*/
public Sample(String uri, String name, String type) {
public Sample(String uri, String name, String mimeType) {
this.uri = uri;
this.name = name;
this.type = type;
this.mimeType = mimeType;
}
@Override
......
......@@ -37,6 +37,9 @@ import com.google.android.exoplayer2.ui.PlaybackControlView;
import com.google.android.exoplayer2.ui.SimpleExoPlayerView;
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory;
import com.google.android.gms.cast.MediaInfo;
import com.google.android.gms.cast.MediaMetadata;
import com.google.android.gms.cast.MediaQueueItem;
import com.google.android.gms.cast.framework.CastContext;
/**
......@@ -95,12 +98,12 @@ import com.google.android.gms.cast.framework.CastContext;
boolean playWhenReady) {
this.currentSample = currentSample;
if (playbackLocation == PLAYBACK_REMOTE) {
castPlayer.load(currentSample.name, currentSample.uri, currentSample.type, positionMs,
playWhenReady);
castPlayer.loadItem(buildMediaQueueItem(currentSample), positionMs);
castPlayer.setPlayWhenReady(playWhenReady);
} else /* playbackLocation == PLAYBACK_LOCAL */ {
exoPlayer.prepare(buildMediaSource(currentSample), true, true);
exoPlayer.setPlayWhenReady(playWhenReady);
exoPlayer.seekTo(positionMs);
exoPlayer.prepare(buildMediaSource(currentSample), true, true);
}
}
......@@ -143,9 +146,18 @@ import com.google.android.gms.cast.framework.CastContext;
// Internal methods.
private static MediaQueueItem buildMediaQueueItem(CastDemoUtil.Sample sample) {
MediaMetadata movieMetadata = new MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE);
movieMetadata.putString(MediaMetadata.KEY_TITLE, sample.name);
MediaInfo mediaInfo = new MediaInfo.Builder(sample.uri)
.setStreamType(MediaInfo.STREAM_TYPE_BUFFERED).setContentType(sample.mimeType)
.setMetadata(movieMetadata).build();
return new MediaQueueItem.Builder(mediaInfo).build();
}
private static MediaSource buildMediaSource(CastDemoUtil.Sample sample) {
Uri uri = Uri.parse(sample.uri);
switch (sample.type) {
switch (sample.mimeType) {
case CastDemoUtil.MIME_TYPE_SS:
return new SsMediaSource(uri, DATA_SOURCE_FACTORY,
new DefaultSsChunkSource.Factory(DATA_SOURCE_FACTORY), null, null);
......@@ -158,7 +170,7 @@ import com.google.android.gms.cast.framework.CastContext;
return new ExtractorMediaSource(uri, DATA_SOURCE_FACTORY, new DefaultExtractorsFactory(),
null, null);
default: {
throw new IllegalStateException("Unsupported type: " + sample.type);
throw new IllegalStateException("Unsupported type: " + sample.mimeType);
}
}
}
......@@ -177,14 +189,16 @@ import com.google.android.gms.cast.framework.CastContext;
castControlView.show();
}
long playbackPositionMs = 0;
boolean playWhenReady = true;
if (exoPlayer != null) {
long playbackPositionMs;
boolean playWhenReady;
if (this.playbackLocation == PLAYBACK_LOCAL) {
playbackPositionMs = exoPlayer.getCurrentPosition();
playWhenReady = exoPlayer.getPlayWhenReady();
} else if (this.playbackLocation == PLAYBACK_REMOTE) {
exoPlayer.stop();
} else /* this.playbackLocation == PLAYBACK_REMOTE */ {
playbackPositionMs = castPlayer.getCurrentPosition();
playWhenReady = castPlayer.getPlayWhenReady();
castPlayer.stop();
}
this.playbackLocation = playbackLocation;
......
......@@ -35,7 +35,8 @@
android:id="@+id/cast_control_view"
android:layout_width="match_parent"
android:layout_height="0dp"
app:show_timeout="-1"
android:layout_weight="2"
android:visibility="gone"/>
android:visibility="gone"
app:repeat_toggle_modes="all|one"
app:show_timeout="-1"/>
</LinearLayout>
/*
* 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.ext.cast;
import android.util.SparseIntArray;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Timeline;
import com.google.android.gms.cast.MediaInfo;
import com.google.android.gms.cast.MediaQueueItem;
import java.util.Collections;
import java.util.List;
/**
* A {@link Timeline} for Cast media queues.
*/
/* package */ final class CastTimeline extends Timeline {
public static final CastTimeline EMPTY_CAST_TIMELINE =
new CastTimeline(Collections.<MediaQueueItem>emptyList());
private final SparseIntArray idsToIndex;
private final int[] ids;
private final long[] durationsUs;
private final long[] defaultPositionsUs;
public CastTimeline(List<MediaQueueItem> items) {
int itemCount = items.size();
int index = 0;
idsToIndex = new SparseIntArray(itemCount);
ids = new int[itemCount];
durationsUs = new long[itemCount];
defaultPositionsUs = new long[itemCount];
for (MediaQueueItem item : items) {
int itemId = item.getItemId();
ids[index] = itemId;
idsToIndex.put(itemId, index);
durationsUs[index] = getStreamDurationUs(item.getMedia());
defaultPositionsUs[index] = (long) (item.getStartTime() * C.MICROS_PER_SECOND);
index++;
}
}
@Override
public int getWindowCount() {
return ids.length;
}
@Override
public Window getWindow(int windowIndex, Window window, boolean setIds,
long defaultPositionProjectionUs) {
long durationUs = durationsUs[windowIndex];
boolean isDynamic = durationUs == C.TIME_UNSET;
return window.set(ids[windowIndex], C.TIME_UNSET, C.TIME_UNSET, !isDynamic, isDynamic,
defaultPositionsUs[windowIndex], durationUs, windowIndex, windowIndex, 0);
}
@Override
public int getPeriodCount() {
return ids.length;
}
@Override
public Period getPeriod(int periodIndex, Period period, boolean setIds) {
int id = ids[periodIndex];
return period.set(id, id, periodIndex, durationsUs[periodIndex], 0);
}
@Override
public int getIndexOfPeriod(Object uid) {
return uid instanceof Integer ? idsToIndex.get((int) uid, C.INDEX_UNSET) : C.INDEX_UNSET;
}
/**
* Returns whether the timeline represents a given {@code MediaQueueItem} list.
*
* @param items The {@code MediaQueueItem} list.
* @return Whether the timeline represents {@code items}.
*/
/* package */ boolean represents(List<MediaQueueItem> items) {
if (ids.length != items.size()) {
return false;
}
int index = 0;
for (MediaQueueItem item : items) {
if (ids[index] != item.getItemId()
|| durationsUs[index] != getStreamDurationUs(item.getMedia())
|| defaultPositionsUs[index] != (long) (item.getStartTime() * C.MICROS_PER_SECOND)) {
return false;
}
index++;
}
return true;
}
private static long getStreamDurationUs(MediaInfo mediaInfo) {
long durationMs = mediaInfo != null ? mediaInfo.getStreamDuration()
: MediaInfo.UNKNOWN_DURATION;
return durationMs != MediaInfo.UNKNOWN_DURATION ? C.msToUs(durationMs) : C.TIME_UNSET;
}
}
......@@ -198,7 +198,7 @@ public final class DynamicConcatenatingMediaSource implements MediaSource, ExoPl
/**
* Returns the {@link MediaSource} at a specified index.
*
* @param index A index in the range of 0 &lt;= index &lt;= {@link #getSize()}.
* @param index An index in the range of 0 &lt;= index &lt;= {@link #getSize()}.
* @return The {@link MediaSource} at this index.
*/
public synchronized MediaSource getMediaSource(int index) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment