use of com.google.android.exoplayer2.util.Assertions.checkState 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.util.Assertions.checkState in project ExoPlayer by google.
the class MediaCodecRenderer method onInputFormatChanged.
/**
* Called when a new {@link Format} is read from the upstream {@link MediaPeriod}.
*
* @param formatHolder A {@link FormatHolder} that holds the new {@link Format}.
* @throws ExoPlaybackException If an error occurs re-initializing the {@link MediaCodec}.
* @return The result of the evaluation to determine whether the existing decoder instance can be
* reused for the new format, or {@code null} if the renderer did not have a decoder.
*/
@CallSuper
@Nullable
protected DecoderReuseEvaluation onInputFormatChanged(FormatHolder formatHolder) throws ExoPlaybackException {
waitingForFirstSampleInFormat = true;
Format newFormat = checkNotNull(formatHolder.format);
if (newFormat.sampleMimeType == null) {
throw createRendererException(new IllegalArgumentException(), newFormat, PlaybackException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED);
}
setSourceDrmSession(formatHolder.drmSession);
inputFormat = newFormat;
if (bypassEnabled) {
bypassDrainAndReinitialize = true;
// Need to drain batch buffer first.
return null;
}
if (codec == null) {
availableCodecInfos = null;
maybeInitCodecOrBypass();
return null;
}
// We have an existing codec that we may need to reconfigure, re-initialize, or release to
// switch to bypass. If the existing codec instance is kept then its operating rate and DRM
// session may need to be updated.
// Copy the current codec and codecInfo to local variables so they remain accessible if the
// member variables are updated during the logic below.
MediaCodecAdapter codec = this.codec;
MediaCodecInfo codecInfo = this.codecInfo;
Format oldFormat = codecInputFormat;
if (drmNeedsCodecReinitialization(codecInfo, newFormat, codecDrmSession, sourceDrmSession)) {
drainAndReinitializeCodec();
return new DecoderReuseEvaluation(codecInfo.name, oldFormat, newFormat, REUSE_RESULT_NO, DISCARD_REASON_DRM_SESSION_CHANGED);
}
boolean drainAndUpdateCodecDrmSession = sourceDrmSession != codecDrmSession;
Assertions.checkState(!drainAndUpdateCodecDrmSession || Util.SDK_INT >= 23);
DecoderReuseEvaluation evaluation = canReuseCodec(codecInfo, oldFormat, newFormat);
@DecoderDiscardReasons int overridingDiscardReasons = 0;
switch(evaluation.result) {
case REUSE_RESULT_NO:
drainAndReinitializeCodec();
break;
case REUSE_RESULT_YES_WITH_FLUSH:
if (!updateCodecOperatingRate(newFormat)) {
overridingDiscardReasons |= DISCARD_REASON_OPERATING_RATE_CHANGED;
} else {
codecInputFormat = newFormat;
if (drainAndUpdateCodecDrmSession) {
if (!drainAndUpdateCodecDrmSessionV23()) {
overridingDiscardReasons |= DISCARD_REASON_WORKAROUND;
}
} else if (!drainAndFlushCodec()) {
overridingDiscardReasons |= DISCARD_REASON_WORKAROUND;
}
}
break;
case REUSE_RESULT_YES_WITH_RECONFIGURATION:
if (!updateCodecOperatingRate(newFormat)) {
overridingDiscardReasons |= DISCARD_REASON_OPERATING_RATE_CHANGED;
} else {
codecReconfigured = true;
codecReconfigurationState = RECONFIGURATION_STATE_WRITE_PENDING;
codecNeedsAdaptationWorkaroundBuffer = codecAdaptationWorkaroundMode == ADAPTATION_WORKAROUND_MODE_ALWAYS || (codecAdaptationWorkaroundMode == ADAPTATION_WORKAROUND_MODE_SAME_RESOLUTION && newFormat.width == oldFormat.width && newFormat.height == oldFormat.height);
codecInputFormat = newFormat;
if (drainAndUpdateCodecDrmSession && !drainAndUpdateCodecDrmSessionV23()) {
overridingDiscardReasons |= DISCARD_REASON_WORKAROUND;
}
}
break;
case REUSE_RESULT_YES_WITHOUT_RECONFIGURATION:
if (!updateCodecOperatingRate(newFormat)) {
overridingDiscardReasons |= DISCARD_REASON_OPERATING_RATE_CHANGED;
} else {
codecInputFormat = newFormat;
if (drainAndUpdateCodecDrmSession && !drainAndUpdateCodecDrmSessionV23()) {
overridingDiscardReasons |= DISCARD_REASON_WORKAROUND;
}
}
break;
default:
// Never happens.
throw new IllegalStateException();
}
if (evaluation.result != REUSE_RESULT_NO && (this.codec != codec || codecDrainAction == DRAIN_ACTION_REINITIALIZE)) {
// The reasons are indicated by overridingDiscardReasons.
return new DecoderReuseEvaluation(codecInfo.name, oldFormat, newFormat, REUSE_RESULT_NO, overridingDiscardReasons);
}
return evaluation;
}
use of com.google.android.exoplayer2.util.Assertions.checkState in project ExoPlayer by google.
the class StyledPlayerView method setPlayer.
/**
* Sets the {@link Player} to use.
*
* <p>To transition a {@link Player} from targeting one view to another, it's recommended to use
* {@link #switchTargetView(Player, StyledPlayerView, StyledPlayerView)} rather than this method.
* If you do wish to use this method directly, be sure to attach the player to the new view
* <em>before</em> calling {@code setPlayer(null)} to detach it from the old one. This ordering is
* significantly more efficient and may allow for more seamless transitions.
*
* @param player The {@link Player} to use, or {@code null} to detach the current player. Only
* players which are accessed on the main thread are supported ({@code
* player.getApplicationLooper() == Looper.getMainLooper()}).
*/
public void setPlayer(@Nullable Player player) {
Assertions.checkState(Looper.myLooper() == Looper.getMainLooper());
Assertions.checkArgument(player == null || player.getApplicationLooper() == Looper.getMainLooper());
if (this.player == player) {
return;
}
@Nullable Player oldPlayer = this.player;
if (oldPlayer != null) {
oldPlayer.removeListener(componentListener);
if (surfaceView instanceof TextureView) {
oldPlayer.clearVideoTextureView((TextureView) surfaceView);
} else if (surfaceView instanceof SurfaceView) {
oldPlayer.clearVideoSurfaceView((SurfaceView) surfaceView);
}
}
if (subtitleView != null) {
subtitleView.setCues(null);
}
this.player = player;
if (useController()) {
controller.setPlayer(player);
}
updateBuffering();
updateErrorMessage();
updateForCurrentTrackSelections(/* isNewPlayer= */
true);
if (player != null) {
if (player.isCommandAvailable(COMMAND_SET_VIDEO_SURFACE)) {
if (surfaceView instanceof TextureView) {
player.setVideoTextureView((TextureView) surfaceView);
} else if (surfaceView instanceof SurfaceView) {
player.setVideoSurfaceView((SurfaceView) surfaceView);
}
updateAspectRatio();
}
if (subtitleView != null && player.isCommandAvailable(COMMAND_GET_TEXT)) {
subtitleView.setCues(player.getCurrentCues());
}
player.addListener(componentListener);
maybeShowController(false);
} else {
hideController();
}
}
use of com.google.android.exoplayer2.util.Assertions.checkState in project ExoPlayer by google.
the class PlayerControlView method updateTimeline.
private void updateTimeline() {
@Nullable Player player = this.player;
if (player == null) {
return;
}
multiWindowTimeBar = showMultiWindowTimeBar && canShowMultiWindowTimeBar(player.getCurrentTimeline(), window);
currentWindowOffset = 0;
long durationUs = 0;
int adGroupCount = 0;
Timeline timeline = player.getCurrentTimeline();
if (!timeline.isEmpty()) {
int currentWindowIndex = player.getCurrentMediaItemIndex();
int firstWindowIndex = multiWindowTimeBar ? 0 : currentWindowIndex;
int lastWindowIndex = multiWindowTimeBar ? timeline.getWindowCount() - 1 : currentWindowIndex;
for (int i = firstWindowIndex; i <= lastWindowIndex; i++) {
if (i == currentWindowIndex) {
currentWindowOffset = Util.usToMs(durationUs);
}
timeline.getWindow(i, window);
if (window.durationUs == C.TIME_UNSET) {
Assertions.checkState(!multiWindowTimeBar);
break;
}
for (int j = window.firstPeriodIndex; j <= window.lastPeriodIndex; j++) {
timeline.getPeriod(j, period);
int removedGroups = period.getRemovedAdGroupCount();
int totalGroups = period.getAdGroupCount();
for (int adGroupIndex = removedGroups; adGroupIndex < totalGroups; adGroupIndex++) {
long adGroupTimeInPeriodUs = period.getAdGroupTimeUs(adGroupIndex);
if (adGroupTimeInPeriodUs == C.TIME_END_OF_SOURCE) {
if (period.durationUs == C.TIME_UNSET) {
// Don't show ad markers for postrolls in periods with unknown duration.
continue;
}
adGroupTimeInPeriodUs = period.durationUs;
}
long adGroupTimeInWindowUs = adGroupTimeInPeriodUs + period.getPositionInWindowUs();
if (adGroupTimeInWindowUs >= 0) {
if (adGroupCount == adGroupTimesMs.length) {
int newLength = adGroupTimesMs.length == 0 ? 1 : adGroupTimesMs.length * 2;
adGroupTimesMs = Arrays.copyOf(adGroupTimesMs, newLength);
playedAdGroups = Arrays.copyOf(playedAdGroups, newLength);
}
adGroupTimesMs[adGroupCount] = Util.usToMs(durationUs + adGroupTimeInWindowUs);
playedAdGroups[adGroupCount] = period.hasPlayedAdGroup(adGroupIndex);
adGroupCount++;
}
}
}
durationUs += window.durationUs;
}
}
long durationMs = Util.usToMs(durationUs);
if (durationView != null) {
durationView.setText(Util.getStringForTime(formatBuilder, formatter, durationMs));
}
if (timeBar != null) {
timeBar.setDuration(durationMs);
int extraAdGroupCount = extraAdGroupTimesMs.length;
int totalAdGroupCount = adGroupCount + extraAdGroupCount;
if (totalAdGroupCount > adGroupTimesMs.length) {
adGroupTimesMs = Arrays.copyOf(adGroupTimesMs, totalAdGroupCount);
playedAdGroups = Arrays.copyOf(playedAdGroups, totalAdGroupCount);
}
System.arraycopy(extraAdGroupTimesMs, 0, adGroupTimesMs, adGroupCount, extraAdGroupCount);
System.arraycopy(extraPlayedAdGroups, 0, playedAdGroups, adGroupCount, extraAdGroupCount);
timeBar.setAdGroupTimesMs(adGroupTimesMs, playedAdGroups, totalAdGroupCount);
}
updateProgress();
}
use of com.google.android.exoplayer2.util.Assertions.checkState in project ExoPlayer by google.
the class StyledPlayerControlView method updateTimeline.
private void updateTimeline() {
@Nullable Player player = this.player;
if (player == null) {
return;
}
multiWindowTimeBar = showMultiWindowTimeBar && canShowMultiWindowTimeBar(player.getCurrentTimeline(), window);
currentWindowOffset = 0;
long durationUs = 0;
int adGroupCount = 0;
Timeline timeline = player.getCurrentTimeline();
if (!timeline.isEmpty()) {
int currentWindowIndex = player.getCurrentMediaItemIndex();
int firstWindowIndex = multiWindowTimeBar ? 0 : currentWindowIndex;
int lastWindowIndex = multiWindowTimeBar ? timeline.getWindowCount() - 1 : currentWindowIndex;
for (int i = firstWindowIndex; i <= lastWindowIndex; i++) {
if (i == currentWindowIndex) {
currentWindowOffset = Util.usToMs(durationUs);
}
timeline.getWindow(i, window);
if (window.durationUs == C.TIME_UNSET) {
Assertions.checkState(!multiWindowTimeBar);
break;
}
for (int j = window.firstPeriodIndex; j <= window.lastPeriodIndex; j++) {
timeline.getPeriod(j, period);
int removedGroups = period.getRemovedAdGroupCount();
int totalGroups = period.getAdGroupCount();
for (int adGroupIndex = removedGroups; adGroupIndex < totalGroups; adGroupIndex++) {
long adGroupTimeInPeriodUs = period.getAdGroupTimeUs(adGroupIndex);
if (adGroupTimeInPeriodUs == C.TIME_END_OF_SOURCE) {
if (period.durationUs == C.TIME_UNSET) {
// Don't show ad markers for postrolls in periods with unknown duration.
continue;
}
adGroupTimeInPeriodUs = period.durationUs;
}
long adGroupTimeInWindowUs = adGroupTimeInPeriodUs + period.getPositionInWindowUs();
if (adGroupTimeInWindowUs >= 0) {
if (adGroupCount == adGroupTimesMs.length) {
int newLength = adGroupTimesMs.length == 0 ? 1 : adGroupTimesMs.length * 2;
adGroupTimesMs = Arrays.copyOf(adGroupTimesMs, newLength);
playedAdGroups = Arrays.copyOf(playedAdGroups, newLength);
}
adGroupTimesMs[adGroupCount] = Util.usToMs(durationUs + adGroupTimeInWindowUs);
playedAdGroups[adGroupCount] = period.hasPlayedAdGroup(adGroupIndex);
adGroupCount++;
}
}
}
durationUs += window.durationUs;
}
}
long durationMs = Util.usToMs(durationUs);
if (durationView != null) {
durationView.setText(Util.getStringForTime(formatBuilder, formatter, durationMs));
}
if (timeBar != null) {
timeBar.setDuration(durationMs);
int extraAdGroupCount = extraAdGroupTimesMs.length;
int totalAdGroupCount = adGroupCount + extraAdGroupCount;
if (totalAdGroupCount > adGroupTimesMs.length) {
adGroupTimesMs = Arrays.copyOf(adGroupTimesMs, totalAdGroupCount);
playedAdGroups = Arrays.copyOf(playedAdGroups, totalAdGroupCount);
}
System.arraycopy(extraAdGroupTimesMs, 0, adGroupTimesMs, adGroupCount, extraAdGroupCount);
System.arraycopy(extraPlayedAdGroups, 0, playedAdGroups, adGroupCount, extraAdGroupCount);
timeBar.setAdGroupTimesMs(adGroupTimesMs, playedAdGroups, totalAdGroupCount);
}
updateProgress();
}
Aggregations