use of com.google.android.exoplayer2.ext.ima.ImaServerSideAdInsertionMediaSource.AdsLoader.State in project ExoPlayer by google.
the class HlsMediaPeriod method selectTracks.
@Override
public long selectTracks(@NullableType ExoTrackSelection[] selections, boolean[] mayRetainStreamFlags, @NullableType SampleStream[] streams, boolean[] streamResetFlags, long positionUs) {
// Map each selection and stream onto a child period index.
int[] streamChildIndices = new int[selections.length];
int[] selectionChildIndices = new int[selections.length];
for (int i = 0; i < selections.length; i++) {
streamChildIndices[i] = streams[i] == null ? C.INDEX_UNSET : streamWrapperIndices.get(streams[i]);
selectionChildIndices[i] = C.INDEX_UNSET;
if (selections[i] != null) {
TrackGroup trackGroup = selections[i].getTrackGroup();
for (int j = 0; j < sampleStreamWrappers.length; j++) {
if (sampleStreamWrappers[j].getTrackGroups().indexOf(trackGroup) != C.INDEX_UNSET) {
selectionChildIndices[i] = j;
break;
}
}
}
}
boolean forceReset = false;
streamWrapperIndices.clear();
// Select tracks for each child, copying the resulting streams back into a new streams array.
SampleStream[] newStreams = new SampleStream[selections.length];
@NullableType SampleStream[] childStreams = new SampleStream[selections.length];
@NullableType ExoTrackSelection[] childSelections = new ExoTrackSelection[selections.length];
int newEnabledSampleStreamWrapperCount = 0;
HlsSampleStreamWrapper[] newEnabledSampleStreamWrappers = new HlsSampleStreamWrapper[sampleStreamWrappers.length];
for (int i = 0; i < sampleStreamWrappers.length; i++) {
for (int j = 0; j < selections.length; j++) {
childStreams[j] = streamChildIndices[j] == i ? streams[j] : null;
childSelections[j] = selectionChildIndices[j] == i ? selections[j] : null;
}
HlsSampleStreamWrapper sampleStreamWrapper = sampleStreamWrappers[i];
boolean wasReset = sampleStreamWrapper.selectTracks(childSelections, mayRetainStreamFlags, childStreams, streamResetFlags, positionUs, forceReset);
boolean wrapperEnabled = false;
for (int j = 0; j < selections.length; j++) {
SampleStream childStream = childStreams[j];
if (selectionChildIndices[j] == i) {
// Assert that the child provided a stream for the selection.
Assertions.checkNotNull(childStream);
newStreams[j] = childStream;
wrapperEnabled = true;
streamWrapperIndices.put(childStream, i);
} else if (streamChildIndices[j] == i) {
// Assert that the child cleared any previous stream.
Assertions.checkState(childStream == null);
}
}
if (wrapperEnabled) {
newEnabledSampleStreamWrappers[newEnabledSampleStreamWrapperCount] = sampleStreamWrapper;
if (newEnabledSampleStreamWrapperCount++ == 0) {
// The first enabled wrapper is always allowed to initialize timestamp adjusters. Note
// that the first wrapper will correspond to a variant, or else an audio rendition, or
// else a text rendition, in that order.
sampleStreamWrapper.setIsTimestampMaster(true);
if (wasReset || enabledSampleStreamWrappers.length == 0 || sampleStreamWrapper != enabledSampleStreamWrappers[0]) {
// The wrapper responsible for initializing the timestamp adjusters was reset or
// changed. We need to reset the timestamp adjuster provider and all other wrappers.
timestampAdjusterProvider.reset();
forceReset = true;
}
} else {
// Additional wrappers are also allowed to initialize timestamp adjusters if they contain
// audio or video, since they are expected to contain dense samples. Text wrappers are not
// permitted except in the case above in which no variant or audio rendition wrappers are
// enabled.
sampleStreamWrapper.setIsTimestampMaster(i < audioVideoSampleStreamWrapperCount);
}
}
}
// Copy the new streams back into the streams array.
System.arraycopy(newStreams, 0, streams, 0, newStreams.length);
// Update the local state.
enabledSampleStreamWrappers = Util.nullSafeArrayCopy(newEnabledSampleStreamWrappers, newEnabledSampleStreamWrapperCount);
compositeSequenceableLoader = compositeSequenceableLoaderFactory.createCompositeSequenceableLoader(enabledSampleStreamWrappers);
return positionUs;
}
use of com.google.android.exoplayer2.ext.ima.ImaServerSideAdInsertionMediaSource.AdsLoader.State in project ExoPlayer by google.
the class ExoPlayerTest method setMediaSources_whenPrepared_invalidSeek_correctMaskingPlaybackState.
@Test
public void setMediaSources_whenPrepared_invalidSeek_correctMaskingPlaybackState() throws Exception {
Timeline firstTimeline = new FakeTimeline(/* windowCount= */
1, 1L);
MediaSource firstMediaSource = new FakeMediaSource(firstTimeline);
final int[] maskingPlaybackStates = new int[1];
Arrays.fill(maskingPlaybackStates, C.INDEX_UNSET);
ActionSchedule actionSchedule = new ActionSchedule.Builder(TAG).pause().waitForPlaybackState(Player.STATE_ENDED).executeRunnable(new PlayerRunnable() {
@Override
public void run(ExoPlayer player) {
// An implicit, invalid seek picking up the position set by the initial seek.
player.setMediaSource(firstMediaSource, /* resetPosition= */
false);
// Expect masking state is ended,
maskingPlaybackStates[0] = player.getPlaybackState();
}
}).waitForTimelineChanged().setMediaSources(/* mediaItemIndex= */
0, /* positionMs= */
C.TIME_UNSET, firstMediaSource).waitForPlaybackState(Player.STATE_READY).play().waitForPlaybackState(Player.STATE_ENDED).build();
ExoPlayerTestRunner exoPlayerTestRunner = new ExoPlayerTestRunner.Builder(context).setExpectedPlayerEndedCount(/* expectedPlayerEndedCount= */
2).initialSeek(/* mediaItemIndex= */
1, /* positionMs= */
C.TIME_UNSET).setMediaSources(new ConcatenatingMediaSource()).setActionSchedule(actionSchedule).build().start().blockUntilActionScheduleFinished(TIMEOUT_MS).blockUntilEnded(TIMEOUT_MS);
// Expect reset of masking to first media item.
exoPlayerTestRunner.assertPlaybackStatesEqual(// Empty source has been prepared.
Player.STATE_ENDED, // After setting another source.
Player.STATE_BUFFERING, Player.STATE_READY, Player.STATE_ENDED);
assertArrayEquals(new int[] { Player.STATE_ENDED }, maskingPlaybackStates);
exoPlayerTestRunner.assertTimelineChangeReasonsEqual(Player.TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED, Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE, Player.TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED, Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE);
}
use of com.google.android.exoplayer2.ext.ima.ImaServerSideAdInsertionMediaSource.AdsLoader.State in project ExoPlayer by google.
the class DefaultDrmSessionManagerTest method preacquireSession_releaseManagerBeforeAcquisition_acquisitionDoesntHappen.
@Test(timeout = 10_000)
public void preacquireSession_releaseManagerBeforeAcquisition_acquisitionDoesntHappen() throws Exception {
FakeExoMediaDrm.LicenseServer licenseServer = FakeExoMediaDrm.LicenseServer.allowingSchemeDatas(DRM_SCHEME_DATAS);
DrmSessionManager drmSessionManager = new DefaultDrmSessionManager.Builder().setUuidAndExoMediaDrmProvider(DRM_SCHEME_UUID, uuid -> new FakeExoMediaDrm()).setSessionKeepaliveMs(C.TIME_UNSET).build(/* mediaDrmCallback= */
licenseServer);
drmSessionManager.prepare();
drmSessionManager.setPlayer(/* playbackLooper= */
Looper.myLooper(), PlayerId.UNSET);
DrmSessionReference sessionReference = drmSessionManager.preacquireSession(/* eventDispatcher= */
null, FORMAT_WITH_DRM_INIT_DATA);
// Release the manager before the underlying session has had a chance to be constructed. This
// will release all pre-acquired sessions.
drmSessionManager.release();
// Allow the acquisition event to be handled on the main/playback thread.
ShadowLooper.idleMainLooper();
// Re-prepare the manager so we can fully acquire the same session, and check the previous
// pre-acquisition didn't do anything.
drmSessionManager.prepare();
DrmSession drmSession = checkNotNull(drmSessionManager.acquireSession(/* eventDispatcher= */
null, FORMAT_WITH_DRM_INIT_DATA));
assertThat(drmSession.getState()).isEqualTo(DrmSession.STATE_OPENED);
waitForOpenedWithKeys(drmSession);
drmSession.release(/* eventDispatcher= */
null);
// If the (still unreleased) pre-acquired session above was linked to the same underlying
// session then the state would still be OPENED_WITH_KEYS.
assertThat(drmSession.getState()).isEqualTo(DrmSession.STATE_RELEASED);
// Release the pre-acquired session from above (this is a no-op, but we do it anyway for
// correctness).
sessionReference.release();
drmSessionManager.release();
}
use of com.google.android.exoplayer2.ext.ima.ImaServerSideAdInsertionMediaSource.AdsLoader.State in project ExoPlayer by google.
the class CronetDataSource method open.
@Override
public long open(DataSpec dataSpec) throws HttpDataSourceException {
Assertions.checkNotNull(dataSpec);
Assertions.checkState(!opened);
operation.close();
resetConnectTimeout();
currentDataSpec = dataSpec;
UrlRequest urlRequest;
try {
urlRequest = buildRequestBuilder(dataSpec).build();
currentUrlRequest = urlRequest;
} catch (IOException e) {
if (e instanceof HttpDataSourceException) {
throw (HttpDataSourceException) e;
} else {
throw new OpenException(e, dataSpec, PlaybackException.ERROR_CODE_IO_UNSPECIFIED, Status.IDLE);
}
}
urlRequest.start();
transferInitializing(dataSpec);
try {
boolean connectionOpened = blockUntilConnectTimeout();
@Nullable IOException connectionOpenException = exception;
if (connectionOpenException != null) {
@Nullable String message = connectionOpenException.getMessage();
if (message != null && Ascii.toLowerCase(message).contains("err_cleartext_not_permitted")) {
throw new CleartextNotPermittedException(connectionOpenException, dataSpec);
}
throw new OpenException(connectionOpenException, dataSpec, PlaybackException.ERROR_CODE_IO_NETWORK_CONNECTION_FAILED, getStatus(urlRequest));
} else if (!connectionOpened) {
// The timeout was reached before the connection was opened.
throw new OpenException(new SocketTimeoutException(), dataSpec, PlaybackException.ERROR_CODE_IO_NETWORK_CONNECTION_TIMEOUT, getStatus(urlRequest));
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
// is failing to swallow the interruption, which makes us enter an invalid state.
throw new OpenException(new InterruptedIOException(), dataSpec, PlaybackException.ERROR_CODE_FAILED_RUNTIME_CHECK, Status.INVALID);
}
// Check for a valid response code.
UrlResponseInfo responseInfo = Assertions.checkNotNull(this.responseInfo);
int responseCode = responseInfo.getHttpStatusCode();
Map<String, List<String>> responseHeaders = responseInfo.getAllHeaders();
if (responseCode < 200 || responseCode > 299) {
if (responseCode == 416) {
long documentSize = HttpUtil.getDocumentSize(getFirstHeader(responseHeaders, HttpHeaders.CONTENT_RANGE));
if (dataSpec.position == documentSize) {
opened = true;
transferStarted(dataSpec);
return dataSpec.length != C.LENGTH_UNSET ? dataSpec.length : 0;
}
}
byte[] responseBody;
try {
responseBody = readResponseBody();
} catch (IOException e) {
responseBody = Util.EMPTY_BYTE_ARRAY;
}
@Nullable IOException cause = responseCode == 416 ? new DataSourceException(PlaybackException.ERROR_CODE_IO_READ_POSITION_OUT_OF_RANGE) : null;
throw new InvalidResponseCodeException(responseCode, responseInfo.getHttpStatusText(), cause, responseHeaders, dataSpec, responseBody);
}
// Check for a valid content type.
Predicate<String> contentTypePredicate = this.contentTypePredicate;
if (contentTypePredicate != null) {
@Nullable String contentType = getFirstHeader(responseHeaders, HttpHeaders.CONTENT_TYPE);
if (contentType != null && !contentTypePredicate.apply(contentType)) {
throw new InvalidContentTypeException(contentType, dataSpec);
}
}
// If we requested a range starting from a non-zero position and received a 200 rather than a
// 206, then the server does not support partial requests. We'll need to manually skip to the
// requested position.
long bytesToSkip = responseCode == 200 && dataSpec.position != 0 ? dataSpec.position : 0;
// Calculate the content length.
if (!isCompressed(responseInfo)) {
if (dataSpec.length != C.LENGTH_UNSET) {
bytesRemaining = dataSpec.length;
} else {
long contentLength = HttpUtil.getContentLength(getFirstHeader(responseHeaders, HttpHeaders.CONTENT_LENGTH), getFirstHeader(responseHeaders, HttpHeaders.CONTENT_RANGE));
bytesRemaining = contentLength != C.LENGTH_UNSET ? (contentLength - bytesToSkip) : C.LENGTH_UNSET;
}
} else {
// If the response is compressed then the content length will be that of the compressed data
// which isn't what we want. Always use the dataSpec length in this case.
bytesRemaining = dataSpec.length;
}
opened = true;
transferStarted(dataSpec);
skipFully(bytesToSkip, dataSpec);
return bytesRemaining;
}
use of com.google.android.exoplayer2.ext.ima.ImaServerSideAdInsertionMediaSource.AdsLoader.State in project ExoPlayer by google.
the class PlayerManager method setCurrentPlayer.
private void setCurrentPlayer(Player currentPlayer) {
if (this.currentPlayer == currentPlayer) {
return;
}
playerView.setPlayer(currentPlayer);
playerView.setControllerHideOnTouch(currentPlayer == localPlayer);
if (currentPlayer == castPlayer) {
playerView.setControllerShowTimeoutMs(0);
playerView.showController();
playerView.setDefaultArtwork(ResourcesCompat.getDrawable(context.getResources(), R.drawable.ic_baseline_cast_connected_400, /* theme= */
null));
} else {
// currentPlayer == localPlayer
playerView.setControllerShowTimeoutMs(StyledPlayerControlView.DEFAULT_SHOW_TIMEOUT_MS);
playerView.setDefaultArtwork(null);
}
// Player state management.
long playbackPositionMs = C.TIME_UNSET;
int currentItemIndex = C.INDEX_UNSET;
boolean playWhenReady = false;
Player previousPlayer = this.currentPlayer;
if (previousPlayer != null) {
// Save state from the previous player.
int playbackState = previousPlayer.getPlaybackState();
if (playbackState != Player.STATE_ENDED) {
playbackPositionMs = previousPlayer.getCurrentPosition();
playWhenReady = previousPlayer.getPlayWhenReady();
currentItemIndex = previousPlayer.getCurrentMediaItemIndex();
if (currentItemIndex != this.currentItemIndex) {
playbackPositionMs = C.TIME_UNSET;
currentItemIndex = this.currentItemIndex;
}
}
previousPlayer.stop();
previousPlayer.clearMediaItems();
}
this.currentPlayer = currentPlayer;
// Media queue management.
currentPlayer.setMediaItems(mediaQueue, currentItemIndex, playbackPositionMs);
currentPlayer.setPlayWhenReady(playWhenReady);
currentPlayer.prepare();
}
Aggregations