Search in sources :

Example 1 with DataSpec

use of com.google.android.exoplayer2.upstream.DataSpec in project ExoPlayer by google.

the class CronetDataSourceTest method testOverread.

@Test
public void testOverread() throws HttpDataSourceException {
    testDataSpec = new DataSpec(Uri.parse(TEST_URL), 0, 16, null);
    testResponseHeader.put("Content-Length", Long.toString(16L));
    mockResponseStartSuccess();
    mockReadSuccess(0, 16);
    dataSourceUnderTest.open(testDataSpec);
    byte[] returnedBuffer = new byte[8];
    int bytesRead = dataSourceUnderTest.read(returnedBuffer, 0, 8);
    assertEquals(8, bytesRead);
    assertArrayEquals(buildTestDataArray(0, 8), returnedBuffer);
    // The current buffer is kept if not completely consumed by DataSource reader.
    returnedBuffer = new byte[8];
    bytesRead += dataSourceUnderTest.read(returnedBuffer, 0, 6);
    assertEquals(14, bytesRead);
    assertArrayEquals(suffixZeros(buildTestDataArray(8, 6), 8), returnedBuffer);
    // 2 bytes left at this point.
    returnedBuffer = new byte[8];
    bytesRead += dataSourceUnderTest.read(returnedBuffer, 0, 8);
    assertEquals(16, bytesRead);
    assertArrayEquals(suffixZeros(buildTestDataArray(14, 2), 8), returnedBuffer);
    // Should have only called read on cronet once.
    verify(mockUrlRequest, times(1)).read(any(ByteBuffer.class));
    verify(mockTransferListener, times(1)).onBytesTransferred(dataSourceUnderTest, 8);
    verify(mockTransferListener, times(1)).onBytesTransferred(dataSourceUnderTest, 6);
    verify(mockTransferListener, times(1)).onBytesTransferred(dataSourceUnderTest, 2);
    // Now we already returned the 16 bytes initially asked.
    // Try to read again even though all requested 16 bytes are already returned.
    // Return C.RESULT_END_OF_INPUT
    returnedBuffer = new byte[16];
    int bytesOverRead = dataSourceUnderTest.read(returnedBuffer, 0, 16);
    assertEquals(C.RESULT_END_OF_INPUT, bytesOverRead);
    assertArrayEquals(new byte[16], returnedBuffer);
    // C.RESULT_END_OF_INPUT should not be reported though the TransferListener.
    verify(mockTransferListener, never()).onBytesTransferred(dataSourceUnderTest, C.RESULT_END_OF_INPUT);
    // There should still be only one call to read on cronet.
    verify(mockUrlRequest, times(1)).read(any(ByteBuffer.class));
    // Check for connection not automatically closed.
    verify(mockUrlRequest, never()).cancel();
    assertEquals(16, bytesRead);
}
Also used : DataSpec(com.google.android.exoplayer2.upstream.DataSpec) ByteBuffer(java.nio.ByteBuffer) Test(org.junit.Test)

Example 2 with DataSpec

use of com.google.android.exoplayer2.upstream.DataSpec in project ExoPlayer by google.

the class CronetDataSourceTest method testRequestHeadersSet.

@Test
public void testRequestHeadersSet() throws HttpDataSourceException {
    testDataSpec = new DataSpec(Uri.parse(TEST_URL), 1000, 5000, null);
    mockResponseStartSuccess();
    dataSourceUnderTest.setRequestProperty("firstHeader", "firstValue");
    dataSourceUnderTest.setRequestProperty("secondHeader", "secondValue");
    dataSourceUnderTest.open(testDataSpec);
    // The header value to add is current position to current position + length - 1.
    verify(mockUrlRequestBuilder).addHeader("Range", "bytes=1000-5999");
    verify(mockUrlRequestBuilder).addHeader("firstHeader", "firstValue");
    verify(mockUrlRequestBuilder).addHeader("secondHeader", "secondValue");
    verify(mockUrlRequest).start();
}
Also used : DataSpec(com.google.android.exoplayer2.upstream.DataSpec) Test(org.junit.Test)

Example 3 with DataSpec

use of com.google.android.exoplayer2.upstream.DataSpec in project ExoPlayer by google.

the class DefaultExtractorInputTest method testSkipFullyLarge.

public void testSkipFullyLarge() throws Exception {
    // Tests skipping an amount of data that's larger than any internal scratch space.
    int largeSkipSize = 1024 * 1024;
    FakeDataSource.Builder builder = new FakeDataSource.Builder();
    builder.appendReadData(new byte[largeSkipSize]);
    FakeDataSource testDataSource = builder.build();
    testDataSource.open(new DataSpec(Uri.parse(TEST_URI)));
    DefaultExtractorInput input = new DefaultExtractorInput(testDataSource, 0, C.LENGTH_UNSET);
    input.skipFully(largeSkipSize);
    assertEquals(largeSkipSize, input.getPosition());
    // Check that we fail with EOFException we skip again.
    try {
        input.skipFully(1);
        fail();
    } catch (EOFException e) {
    // Expected.
    }
}
Also used : FakeDataSource(com.google.android.exoplayer2.testutil.FakeDataSource) EOFException(java.io.EOFException) DataSpec(com.google.android.exoplayer2.upstream.DataSpec)

Example 4 with DataSpec

use of com.google.android.exoplayer2.upstream.DataSpec in project ExoPlayer by google.

the class CacheDataSourceTest method testUnsatisfiableRange.

public void testUnsatisfiableRange() throws Exception {
    // Bounded request but the content length is unknown. This forces all data to be cached but not
    // the length
    assertCacheAndRead(false, true);
    // Now do an unbounded request. This will read all of the data from cache and then try to read
    // more from upstream which will cause to a 416 so CDS will store the length.
    CacheDataSource cacheDataSource = createCacheDataSource(true, true);
    assertReadDataContentLength(cacheDataSource, true, true);
    // If the user try to access off range then it should throw an IOException
    try {
        cacheDataSource = createCacheDataSource(false, false);
        cacheDataSource.open(new DataSpec(Uri.EMPTY, TEST_DATA.length, 5, KEY_1));
        fail();
    } catch (IOException e) {
    // success
    }
}
Also used : DataSpec(com.google.android.exoplayer2.upstream.DataSpec) IOException(java.io.IOException)

Example 5 with DataSpec

use of com.google.android.exoplayer2.upstream.DataSpec in project ExoPlayer by google.

the class HlsChunkSource method getNextChunk.

/**
   * Returns the next chunk to load.
   * <p>
   * If a chunk is available then {@link HlsChunkHolder#chunk} is set. If the end of the stream has
   * been reached then {@link HlsChunkHolder#endOfStream} is set. If a chunk is not available but
   * the end of the stream has not been reached, {@link HlsChunkHolder#playlist} is set to
   * contain the {@link HlsUrl} that refers to the playlist that needs refreshing.
   *
   * @param previous The most recently loaded media chunk.
   * @param playbackPositionUs The current playback position. If {@code previous} is null then this
   *     parameter is the position from which playback is expected to start (or restart) and hence
   *     should be interpreted as a seek position.
   * @param out A holder to populate.
   */
public void getNextChunk(HlsMediaChunk previous, long playbackPositionUs, HlsChunkHolder out) {
    int oldVariantIndex = previous == null ? C.INDEX_UNSET : trackGroup.indexOf(previous.trackFormat);
    // Use start time of the previous chunk rather than its end time because switching format will
    // require downloading overlapping segments.
    long bufferedDurationUs = previous == null ? 0 : Math.max(0, previous.startTimeUs - playbackPositionUs);
    // Select the variant.
    trackSelection.updateSelectedTrack(bufferedDurationUs);
    int selectedVariantIndex = trackSelection.getSelectedIndexInTrackGroup();
    boolean switchingVariant = oldVariantIndex != selectedVariantIndex;
    HlsUrl selectedUrl = variants[selectedVariantIndex];
    if (!playlistTracker.isSnapshotValid(selectedUrl)) {
        out.playlist = selectedUrl;
        // Retry when playlist is refreshed.
        return;
    }
    HlsMediaPlaylist mediaPlaylist = playlistTracker.getPlaylistSnapshot(selectedUrl);
    // Select the chunk.
    int chunkMediaSequence;
    if (previous == null || switchingVariant) {
        long targetPositionUs = previous == null ? playbackPositionUs : previous.startTimeUs;
        if (!mediaPlaylist.hasEndTag && targetPositionUs > mediaPlaylist.getEndTimeUs()) {
            // If the playlist is too old to contain the chunk, we need to refresh it.
            chunkMediaSequence = mediaPlaylist.mediaSequence + mediaPlaylist.segments.size();
        } else {
            chunkMediaSequence = Util.binarySearchFloor(mediaPlaylist.segments, targetPositionUs - mediaPlaylist.startTimeUs, true, !playlistTracker.isLive() || previous == null) + mediaPlaylist.mediaSequence;
            if (chunkMediaSequence < mediaPlaylist.mediaSequence && previous != null) {
                // We try getting the next chunk without adapting in case that's the reason for falling
                // behind the live window.
                selectedVariantIndex = oldVariantIndex;
                selectedUrl = variants[selectedVariantIndex];
                mediaPlaylist = playlistTracker.getPlaylistSnapshot(selectedUrl);
                chunkMediaSequence = previous.getNextChunkIndex();
            }
        }
    } else {
        chunkMediaSequence = previous.getNextChunkIndex();
    }
    if (chunkMediaSequence < mediaPlaylist.mediaSequence) {
        fatalError = new BehindLiveWindowException();
        return;
    }
    int chunkIndex = chunkMediaSequence - mediaPlaylist.mediaSequence;
    if (chunkIndex >= mediaPlaylist.segments.size()) {
        if (mediaPlaylist.hasEndTag) {
            out.endOfStream = true;
        } else /* Live */
        {
            out.playlist = selectedUrl;
        }
        return;
    }
    // Handle encryption.
    HlsMediaPlaylist.Segment segment = mediaPlaylist.segments.get(chunkIndex);
    // Check if encryption is specified.
    if (segment.isEncrypted) {
        Uri keyUri = UriUtil.resolveToUri(mediaPlaylist.baseUri, segment.encryptionKeyUri);
        if (!keyUri.equals(encryptionKeyUri)) {
            // Encryption is specified and the key has changed.
            out.chunk = newEncryptionKeyChunk(keyUri, segment.encryptionIV, selectedVariantIndex, trackSelection.getSelectionReason(), trackSelection.getSelectionData());
            return;
        }
        if (!Util.areEqual(segment.encryptionIV, encryptionIvString)) {
            setEncryptionData(keyUri, segment.encryptionIV, encryptionKey);
        }
    } else {
        clearEncryptionData();
    }
    DataSpec initDataSpec = null;
    Segment initSegment = mediaPlaylist.initializationSegment;
    if (initSegment != null) {
        Uri initSegmentUri = UriUtil.resolveToUri(mediaPlaylist.baseUri, initSegment.url);
        initDataSpec = new DataSpec(initSegmentUri, initSegment.byterangeOffset, initSegment.byterangeLength, null);
    }
    // Compute start time of the next chunk.
    long startTimeUs = mediaPlaylist.startTimeUs + segment.relativeStartTimeUs;
    int discontinuitySequence = mediaPlaylist.discontinuitySequence + segment.relativeDiscontinuitySequence;
    TimestampAdjuster timestampAdjuster = timestampAdjusterProvider.getAdjuster(discontinuitySequence);
    // Configure the data source and spec for the chunk.
    Uri chunkUri = UriUtil.resolveToUri(mediaPlaylist.baseUri, segment.url);
    DataSpec dataSpec = new DataSpec(chunkUri, segment.byterangeOffset, segment.byterangeLength, null);
    out.chunk = new HlsMediaChunk(mediaDataSource, dataSpec, initDataSpec, selectedUrl, muxedCaptionFormats, trackSelection.getSelectionReason(), trackSelection.getSelectionData(), startTimeUs, startTimeUs + segment.durationUs, chunkMediaSequence, discontinuitySequence, isTimestampMaster, timestampAdjuster, previous, encryptionKey, encryptionIv);
}
Also used : Segment(com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Segment) HlsUrl(com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist.HlsUrl) BehindLiveWindowException(com.google.android.exoplayer2.source.BehindLiveWindowException) DataSpec(com.google.android.exoplayer2.upstream.DataSpec) HlsMediaPlaylist(com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist) TimestampAdjuster(com.google.android.exoplayer2.util.TimestampAdjuster) Uri(android.net.Uri) Segment(com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Segment)

Aggregations

DataSpec (com.google.android.exoplayer2.upstream.DataSpec)115 Test (org.junit.Test)79 FakeDataSource (com.google.android.exoplayer2.testutil.FakeDataSource)28 DataSource (com.google.android.exoplayer2.upstream.DataSource)19 Nullable (androidx.annotation.Nullable)17 IOException (java.io.IOException)16 Uri (android.net.Uri)14 DefaultExtractorInput (com.google.android.exoplayer2.extractor.DefaultExtractorInput)9 FakeDataSet (com.google.android.exoplayer2.testutil.FakeDataSet)9 HlsMediaPlaylist (com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist)8 ArrayList (java.util.ArrayList)7 ExtractorInput (com.google.android.exoplayer2.extractor.ExtractorInput)6 InterruptedIOException (java.io.InterruptedIOException)5 List (java.util.List)5 ContainerMediaChunk (com.google.android.exoplayer2.source.chunk.ContainerMediaChunk)4 DataSourceException (com.google.android.exoplayer2.upstream.DataSourceException)4 DataSourceInputStream (com.google.android.exoplayer2.upstream.DataSourceInputStream)4 HttpDataSource (com.google.android.exoplayer2.upstream.HttpDataSource)4 ByteBuffer (java.nio.ByteBuffer)4 MockResponse (okhttp3.mockwebserver.MockResponse)4