Search in sources :

Example 1 with InvalidResponseCodeException

use of androidx.media3.datasource.HttpDataSource.InvalidResponseCodeException in project media by androidx.

the class OkHttpDataSource method open.

@Override
public long open(DataSpec dataSpec) throws HttpDataSourceException {
    this.dataSpec = dataSpec;
    bytesRead = 0;
    bytesToRead = 0;
    transferInitializing(dataSpec);
    Request request = makeRequest(dataSpec);
    Response response;
    ResponseBody responseBody;
    try {
        this.response = callFactory.newCall(request).execute();
        response = this.response;
        responseBody = Assertions.checkNotNull(response.body());
        responseByteStream = responseBody.byteStream();
    } catch (IOException e) {
        throw HttpDataSourceException.createForIOException(e, dataSpec, HttpDataSourceException.TYPE_OPEN);
    }
    int responseCode = response.code();
    // Check for a valid response code.
    if (!response.isSuccessful()) {
        if (responseCode == 416) {
            long documentSize = HttpUtil.getDocumentSize(response.headers().get(HttpHeaders.CONTENT_RANGE));
            if (dataSpec.position == documentSize) {
                opened = true;
                transferStarted(dataSpec);
                return dataSpec.length != C.LENGTH_UNSET ? dataSpec.length : 0;
            }
        }
        byte[] errorResponseBody;
        try {
            errorResponseBody = Util.toByteArray(Assertions.checkNotNull(responseByteStream));
        } catch (IOException e) {
            errorResponseBody = Util.EMPTY_BYTE_ARRAY;
        }
        Map<String, List<String>> headers = response.headers().toMultimap();
        closeConnectionQuietly();
        @Nullable IOException cause = responseCode == 416 ? new DataSourceException(PlaybackException.ERROR_CODE_IO_READ_POSITION_OUT_OF_RANGE) : null;
        throw new InvalidResponseCodeException(responseCode, response.message(), cause, headers, dataSpec, errorResponseBody);
    }
    // Check for a valid content type.
    @Nullable MediaType mediaType = responseBody.contentType();
    String contentType = mediaType != null ? mediaType.toString() : "";
    if (contentTypePredicate != null && !contentTypePredicate.apply(contentType)) {
        closeConnectionQuietly();
        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;
    // Determine the length of the data to be read, after skipping.
    if (dataSpec.length != C.LENGTH_UNSET) {
        bytesToRead = dataSpec.length;
    } else {
        long contentLength = responseBody.contentLength();
        bytesToRead = contentLength != -1 ? (contentLength - bytesToSkip) : C.LENGTH_UNSET;
    }
    opened = true;
    transferStarted(dataSpec);
    try {
        skipFully(bytesToSkip, dataSpec);
    } catch (HttpDataSourceException e) {
        closeConnectionQuietly();
        throw e;
    }
    return bytesToRead;
}
Also used : Request(okhttp3.Request) InterruptedIOException(java.io.InterruptedIOException) IOException(java.io.IOException) ResponseBody(okhttp3.ResponseBody) Response(okhttp3.Response) DataSourceException(androidx.media3.datasource.DataSourceException) MediaType(okhttp3.MediaType) List(java.util.List) Nullable(androidx.annotation.Nullable)

Example 2 with InvalidResponseCodeException

use of androidx.media3.datasource.HttpDataSource.InvalidResponseCodeException in project media by androidx.

the class DefaultDashChunkSourceTest method createFakeLoadErrorInfo.

private LoadErrorHandlingPolicy.LoadErrorInfo createFakeLoadErrorInfo(DataSpec dataSpec, int httpResponseCode, int errorCount) {
    LoadEventInfo loadEventInfo = new LoadEventInfo(/* loadTaskId= */
    0, dataSpec, SystemClock.elapsedRealtime());
    MediaLoadData mediaLoadData = new MediaLoadData(C.DATA_TYPE_MEDIA);
    HttpDataSource.InvalidResponseCodeException invalidResponseCodeException = new HttpDataSource.InvalidResponseCodeException(httpResponseCode, /* responseMessage= */
    null, /* cause= */
    null, ImmutableMap.of(), dataSpec, new byte[0]);
    return new LoadErrorHandlingPolicy.LoadErrorInfo(loadEventInfo, mediaLoadData, invalidResponseCodeException, errorCount);
}
Also used : LoadEventInfo(androidx.media3.exoplayer.source.LoadEventInfo) MediaLoadData(androidx.media3.exoplayer.source.MediaLoadData) HttpDataSource(androidx.media3.datasource.HttpDataSource)

Example 3 with InvalidResponseCodeException

use of androidx.media3.datasource.HttpDataSource.InvalidResponseCodeException in project media by androidx.

the class DefaultDashChunkSource method onChunkLoadError.

@Override
public boolean onChunkLoadError(Chunk chunk, boolean cancelable, LoadErrorHandlingPolicy.LoadErrorInfo loadErrorInfo, LoadErrorHandlingPolicy loadErrorHandlingPolicy) {
    if (!cancelable) {
        return false;
    }
    if (playerTrackEmsgHandler != null && playerTrackEmsgHandler.onChunkLoadError(chunk)) {
        return true;
    }
    // Workaround for missing segment at the end of the period
    if (!manifest.dynamic && chunk instanceof MediaChunk && loadErrorInfo.exception instanceof InvalidResponseCodeException && ((InvalidResponseCodeException) loadErrorInfo.exception).responseCode == 404) {
        RepresentationHolder representationHolder = representationHolders[trackSelection.indexOf(chunk.trackFormat)];
        long segmentCount = representationHolder.getSegmentCount();
        if (segmentCount != DashSegmentIndex.INDEX_UNBOUNDED && segmentCount != 0) {
            long lastAvailableSegmentNum = representationHolder.getFirstSegmentNum() + segmentCount - 1;
            if (((MediaChunk) chunk).getNextChunkIndex() > lastAvailableSegmentNum) {
                missingLastSegment = true;
                return true;
            }
        }
    }
    int trackIndex = trackSelection.indexOf(chunk.trackFormat);
    RepresentationHolder representationHolder = representationHolders[trackIndex];
    @Nullable BaseUrl newBaseUrl = baseUrlExclusionList.selectBaseUrl(representationHolder.representation.baseUrls);
    if (newBaseUrl != null && !representationHolder.selectedBaseUrl.equals(newBaseUrl)) {
        // which will use the new base URL.
        return true;
    }
    LoadErrorHandlingPolicy.FallbackOptions fallbackOptions = createFallbackOptions(trackSelection, representationHolder.representation.baseUrls);
    if (!fallbackOptions.isFallbackAvailable(LoadErrorHandlingPolicy.FALLBACK_TYPE_TRACK) && !fallbackOptions.isFallbackAvailable(LoadErrorHandlingPolicy.FALLBACK_TYPE_LOCATION)) {
        return false;
    }
    @Nullable LoadErrorHandlingPolicy.FallbackSelection fallbackSelection = loadErrorHandlingPolicy.getFallbackSelectionFor(fallbackOptions, loadErrorInfo);
    if (fallbackSelection == null || !fallbackOptions.isFallbackAvailable(fallbackSelection.type)) {
        // Policy indicated to not use any fallback or a fallback type that is not available.
        return false;
    }
    boolean cancelLoad = false;
    if (fallbackSelection.type == LoadErrorHandlingPolicy.FALLBACK_TYPE_TRACK) {
        cancelLoad = trackSelection.blacklist(trackSelection.indexOf(chunk.trackFormat), fallbackSelection.exclusionDurationMs);
    } else if (fallbackSelection.type == LoadErrorHandlingPolicy.FALLBACK_TYPE_LOCATION) {
        baseUrlExclusionList.exclude(representationHolder.selectedBaseUrl, fallbackSelection.exclusionDurationMs);
        cancelLoad = true;
    }
    return cancelLoad;
}
Also used : SingleSampleMediaChunk(androidx.media3.exoplayer.source.chunk.SingleSampleMediaChunk) ContainerMediaChunk(androidx.media3.exoplayer.source.chunk.ContainerMediaChunk) MediaChunk(androidx.media3.exoplayer.source.chunk.MediaChunk) BaseUrl(androidx.media3.exoplayer.dash.manifest.BaseUrl) LoadErrorHandlingPolicy(androidx.media3.exoplayer.upstream.LoadErrorHandlingPolicy) InvalidResponseCodeException(androidx.media3.datasource.HttpDataSource.InvalidResponseCodeException) Nullable(androidx.annotation.Nullable)

Example 4 with InvalidResponseCodeException

use of androidx.media3.datasource.HttpDataSource.InvalidResponseCodeException in project media by androidx.

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;
}
Also used : InterruptedIOException(java.io.InterruptedIOException) UrlRequest(org.chromium.net.UrlRequest) UrlResponseInfo(org.chromium.net.UrlResponseInfo) InterruptedIOException(java.io.InterruptedIOException) IOException(java.io.IOException) SocketTimeoutException(java.net.SocketTimeoutException) DataSourceException(androidx.media3.datasource.DataSourceException) List(java.util.List) Nullable(androidx.annotation.Nullable)

Example 5 with InvalidResponseCodeException

use of androidx.media3.datasource.HttpDataSource.InvalidResponseCodeException in project media by androidx.

the class DefaultLoadErrorHandlingPolicyTest method getFallbackSelectionFor_responseCode500.

@Test
public void getFallbackSelectionFor_responseCode500() {
    InvalidResponseCodeException exception = buildInvalidResponseCodeException(500, "Internal server error");
    @Nullable LoadErrorHandlingPolicy.FallbackSelection defaultPolicyFallbackSelection = getDefaultPolicyFallbackSelection(exception, /* numberOfLocations= */
    1, /* numberOfExcludedLocations= */
    0, /* numberOfTracks= */
    10, /* numberOfExcludedTracks= */
    0);
    assertThat(defaultPolicyFallbackSelection.type).isEqualTo(FALLBACK_TYPE_TRACK);
    assertThat(defaultPolicyFallbackSelection.exclusionDurationMs).isEqualTo(DEFAULT_TRACK_EXCLUSION_MS);
    defaultPolicyFallbackSelection = getDefaultPolicyFallbackSelection(exception, /* numberOfLocations= */
    2, /* numberOfExcludedLocations= */
    0, /* numberOfTracks= */
    4, /* numberOfExcludedTracks= */
    1);
    assertThat(defaultPolicyFallbackSelection.type).isEqualTo(FALLBACK_TYPE_LOCATION);
    assertThat(defaultPolicyFallbackSelection.exclusionDurationMs).isEqualTo(DEFAULT_LOCATION_EXCLUSION_MS);
}
Also used : InvalidResponseCodeException(androidx.media3.datasource.HttpDataSource.InvalidResponseCodeException) Nullable(androidx.annotation.Nullable) Test(org.junit.Test)

Aggregations

Nullable (androidx.annotation.Nullable)9 InvalidResponseCodeException (androidx.media3.datasource.HttpDataSource.InvalidResponseCodeException)8 Test (org.junit.Test)6 DataSourceException (androidx.media3.datasource.DataSourceException)2 IOException (java.io.IOException)2 InterruptedIOException (java.io.InterruptedIOException)2 List (java.util.List)2 DataSourceInputStream (androidx.media3.datasource.DataSourceInputStream)1 DataSpec (androidx.media3.datasource.DataSpec)1 HttpDataSource (androidx.media3.datasource.HttpDataSource)1 StatsDataSource (androidx.media3.datasource.StatsDataSource)1 BaseUrl (androidx.media3.exoplayer.dash.manifest.BaseUrl)1 LoadEventInfo (androidx.media3.exoplayer.source.LoadEventInfo)1 MediaLoadData (androidx.media3.exoplayer.source.MediaLoadData)1 ContainerMediaChunk (androidx.media3.exoplayer.source.chunk.ContainerMediaChunk)1 MediaChunk (androidx.media3.exoplayer.source.chunk.MediaChunk)1 SingleSampleMediaChunk (androidx.media3.exoplayer.source.chunk.SingleSampleMediaChunk)1 LoadErrorHandlingPolicy (androidx.media3.exoplayer.upstream.LoadErrorHandlingPolicy)1 SocketTimeoutException (java.net.SocketTimeoutException)1 MediaType (okhttp3.MediaType)1