mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Fix empty LoadEventInfo.uri
passed to onLoadStarted
This affects both `AnalyticsListener` and `MediaSourceEventListener` This was introduced byd051b4b993
Also fix a missing 'load started' event for HLS media playlists (this was also introduced byd051b4b993
). PiperOrigin-RevId: 691580183
This commit is contained in:
parent
6cbf77b3f0
commit
b5db8a6cbe
@ -61,7 +61,8 @@ public final class StatsDataSource implements DataSource {
|
||||
|
||||
/**
|
||||
* Returns the {@link Uri} associated with the last {@link #open(DataSpec)} call. If redirection
|
||||
* occurred, this is the redirected uri.
|
||||
* occurred, this is the redirected uri. Returns {@link Uri#EMPTY} if {@link #open(DataSpec)} has
|
||||
* never been called.
|
||||
*/
|
||||
public Uri getLastOpenedUri() {
|
||||
return lastOpenedUri;
|
||||
|
@ -30,7 +30,6 @@ import androidx.annotation.IntDef;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.media3.common.PlaybackException;
|
||||
import androidx.media3.common.util.Assertions;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
import androidx.media3.common.util.Util;
|
||||
import androidx.media3.datasource.DataSource;
|
||||
@ -189,7 +188,7 @@ public final class DrmUtil {
|
||||
} catch (Exception e) {
|
||||
throw new MediaDrmCallbackException(
|
||||
originalDataSpec,
|
||||
Assertions.checkNotNull(statsDataSource.getLastOpenedUri()),
|
||||
statsDataSource.getLastOpenedUri(),
|
||||
statsDataSource.getResponseHeaders(),
|
||||
statsDataSource.getBytesRead(),
|
||||
/* cause= */ e);
|
||||
|
@ -602,7 +602,9 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
ExtractingLoadable loadable, long elapsedRealtimeMs, long loadDurationMs, int retryCount) {
|
||||
StatsDataSource dataSource = loadable.dataSource;
|
||||
LoadEventInfo loadEventInfo =
|
||||
new LoadEventInfo(
|
||||
retryCount == 0
|
||||
? new LoadEventInfo(loadable.loadTaskId, loadable.dataSpec, elapsedRealtimeMs)
|
||||
: new LoadEventInfo(
|
||||
loadable.loadTaskId,
|
||||
loadable.dataSpec,
|
||||
dataSource.getLastOpenedUri(),
|
||||
|
@ -202,7 +202,9 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
SourceLoadable loadable, long elapsedRealtimeMs, long loadDurationMs, int retryCount) {
|
||||
StatsDataSource dataSource = loadable.dataSource;
|
||||
LoadEventInfo loadEventInfo =
|
||||
new LoadEventInfo(
|
||||
retryCount == 0
|
||||
? new LoadEventInfo(loadable.loadTaskId, loadable.dataSpec, elapsedRealtimeMs)
|
||||
: new LoadEventInfo(
|
||||
loadable.loadTaskId,
|
||||
loadable.dataSpec,
|
||||
dataSource.getLastOpenedUri(),
|
||||
|
@ -432,15 +432,19 @@ public class ChunkSampleStream<T extends ChunkSource>
|
||||
@Override
|
||||
public void onLoadStarted(
|
||||
Chunk loadable, long elapsedRealtimeMs, long loadDurationMs, int retryCount) {
|
||||
mediaSourceEventDispatcher.loadStarted(
|
||||
new LoadEventInfo(
|
||||
LoadEventInfo loadEventInfo =
|
||||
retryCount == 0
|
||||
? new LoadEventInfo(loadable.loadTaskId, loadable.dataSpec, elapsedRealtimeMs)
|
||||
: new LoadEventInfo(
|
||||
loadable.loadTaskId,
|
||||
loadable.dataSpec,
|
||||
loadable.getUri(),
|
||||
loadable.getResponseHeaders(),
|
||||
elapsedRealtimeMs,
|
||||
loadDurationMs,
|
||||
loadable.dataSource.getBytesRead()),
|
||||
loadable.bytesLoaded());
|
||||
mediaSourceEventDispatcher.loadStarted(
|
||||
loadEventInfo,
|
||||
loadable.type,
|
||||
primaryTrackType,
|
||||
loadable.trackFormat,
|
||||
|
@ -93,7 +93,10 @@ public final class Loader implements LoaderErrorThrower {
|
||||
/**
|
||||
* Called when a load has started for the first time or through a retry.
|
||||
*
|
||||
* @param loadable The loadable whose load has completed.
|
||||
* <p>This is called for the first time with {@code retryCount == 0} just <b>before</b> the load
|
||||
* is started.
|
||||
*
|
||||
* @param loadable The loadable whose load has started.
|
||||
* @param elapsedRealtimeMs {@link SystemClock#elapsedRealtime} when the load attempts to start.
|
||||
* @param loadDurationMs The duration in milliseconds of the load since {@link #startLoading}
|
||||
* was called.
|
||||
|
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright 2024 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 androidx.media3.exoplayer.e2etest;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.atLeastOnce;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import androidx.media3.common.MediaItem;
|
||||
import androidx.media3.common.Player;
|
||||
import androidx.media3.exoplayer.ExoPlayer;
|
||||
import androidx.media3.exoplayer.analytics.AnalyticsListener;
|
||||
import androidx.media3.exoplayer.source.LoadEventInfo;
|
||||
import androidx.media3.test.utils.FakeClock;
|
||||
import androidx.media3.test.utils.robolectric.ShadowMediaCodecConfig;
|
||||
import androidx.media3.test.utils.robolectric.TestPlayerRunHelper;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Lists;
|
||||
import java.util.List;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
|
||||
/** End-to-end tests of events reported to {@link AnalyticsListener}. */
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class AnalyticsListenerPlaybackTest {
|
||||
|
||||
@Rule
|
||||
public ShadowMediaCodecConfig mediaCodecConfig =
|
||||
ShadowMediaCodecConfig.forAllSupportedMimeTypes();
|
||||
|
||||
@Test
|
||||
public void loadEventsReportedAsExpected() throws Exception {
|
||||
Context applicationContext = ApplicationProvider.getApplicationContext();
|
||||
ExoPlayer player =
|
||||
new ExoPlayer.Builder(applicationContext)
|
||||
.setClock(new FakeClock(/* isAutoAdvancing= */ true))
|
||||
.build();
|
||||
AnalyticsListener mockAnalyticsListener = mock(AnalyticsListener.class);
|
||||
player.addAnalyticsListener(mockAnalyticsListener);
|
||||
Uri mediaUri = Uri.parse("asset:///media/mp4/sample.mp4");
|
||||
MediaItem mediaItem = new MediaItem.Builder().setUri(mediaUri).build();
|
||||
|
||||
player.setMediaItem(mediaItem);
|
||||
player.prepare();
|
||||
player.play();
|
||||
TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_ENDED);
|
||||
player.release();
|
||||
|
||||
ArgumentCaptor<LoadEventInfo> loadStartedEventInfoCaptor =
|
||||
ArgumentCaptor.forClass(LoadEventInfo.class);
|
||||
verify(mockAnalyticsListener, atLeastOnce())
|
||||
.onLoadStarted(any(), loadStartedEventInfoCaptor.capture(), any(), anyInt());
|
||||
List<Uri> loadStartedUris =
|
||||
Lists.transform(loadStartedEventInfoCaptor.getAllValues(), i -> i.uri);
|
||||
List<Uri> loadStartedDataSpecUris =
|
||||
Lists.transform(loadStartedEventInfoCaptor.getAllValues(), i -> i.dataSpec.uri);
|
||||
// Remove duplicates in case the load was split into multiple reads.
|
||||
assertThat(ImmutableSet.copyOf(loadStartedUris)).containsExactly(mediaUri);
|
||||
// The two sources of URI should match (because there's no redirection).
|
||||
assertThat(loadStartedDataSpecUris).containsExactlyElementsIn(loadStartedUris).inOrder();
|
||||
ArgumentCaptor<LoadEventInfo> loadCompletedEventInfoCaptor =
|
||||
ArgumentCaptor.forClass(LoadEventInfo.class);
|
||||
verify(mockAnalyticsListener, atLeastOnce())
|
||||
.onLoadCompleted(any(), loadCompletedEventInfoCaptor.capture(), any());
|
||||
List<Uri> loadCompletedUris =
|
||||
Lists.transform(loadCompletedEventInfoCaptor.getAllValues(), i -> i.uri);
|
||||
List<Uri> loadCompletedDataSpecUris =
|
||||
Lists.transform(loadCompletedEventInfoCaptor.getAllValues(), i -> i.dataSpec.uri);
|
||||
// Every started load should be completed.
|
||||
assertThat(loadCompletedUris).containsExactlyElementsIn(loadStartedUris);
|
||||
assertThat(loadCompletedDataSpecUris).containsExactlyElementsIn(loadStartedUris);
|
||||
}
|
||||
}
|
@ -634,17 +634,18 @@ public final class DashMediaSource extends BaseMediaSource {
|
||||
long elapsedRealtimeMs,
|
||||
long loadDurationMs,
|
||||
int retryCount) {
|
||||
manifestEventDispatcher.loadStarted(
|
||||
new LoadEventInfo(
|
||||
LoadEventInfo loadEventInfo =
|
||||
retryCount == 0
|
||||
? new LoadEventInfo(loadable.loadTaskId, loadable.dataSpec, elapsedRealtimeMs)
|
||||
: new LoadEventInfo(
|
||||
loadable.loadTaskId,
|
||||
loadable.dataSpec,
|
||||
loadable.getUri(),
|
||||
loadable.getResponseHeaders(),
|
||||
elapsedRealtimeMs,
|
||||
loadDurationMs,
|
||||
loadable.bytesLoaded()),
|
||||
loadable.type,
|
||||
retryCount);
|
||||
loadable.bytesLoaded());
|
||||
manifestEventDispatcher.loadStarted(loadEventInfo, loadable.type, retryCount);
|
||||
}
|
||||
|
||||
/* package */ void onManifestLoadCompleted(
|
||||
|
@ -18,6 +18,11 @@ package androidx.media3.exoplayer.dash.e2etest;
|
||||
import static androidx.media3.common.util.Assertions.checkNotNull;
|
||||
import static androidx.media3.test.utils.robolectric.TestPlayerRunHelper.run;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.atLeastOnce;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.SurfaceTexture;
|
||||
@ -53,10 +58,14 @@ import androidx.media3.test.utils.robolectric.ShadowMediaCodecConfig;
|
||||
import androidx.media3.test.utils.robolectric.TestPlayerRunHelper;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Lists;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
|
||||
/** End-to-end tests using DASH samples. */
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@ -651,7 +660,52 @@ public final class DashPlaybackTest {
|
||||
applicationContext, playbackOutput, "playbackdumps/dash/multi-period-with-offset.dump");
|
||||
}
|
||||
|
||||
private static class AnalyticsListenerImpl implements AnalyticsListener {
|
||||
@Test
|
||||
public void loadEventsReportedAsExpected() throws Exception {
|
||||
Context applicationContext = ApplicationProvider.getApplicationContext();
|
||||
ExoPlayer player =
|
||||
new ExoPlayer.Builder(applicationContext)
|
||||
.setClock(new FakeClock(/* isAutoAdvancing= */ true))
|
||||
.build();
|
||||
AnalyticsListenerImpl analyticsListener = new AnalyticsListenerImpl();
|
||||
player.addAnalyticsListener(analyticsListener);
|
||||
AnalyticsListener mockAnalyticsListener = mock(AnalyticsListener.class);
|
||||
player.addAnalyticsListener(mockAnalyticsListener);
|
||||
Uri manifestUri = Uri.parse("asset:///media/dash/emsg/sample.mpd");
|
||||
|
||||
player.setMediaItem(MediaItem.fromUri(manifestUri));
|
||||
player.prepare();
|
||||
player.play();
|
||||
TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_ENDED);
|
||||
player.release();
|
||||
|
||||
ArgumentCaptor<LoadEventInfo> loadStartedEventInfoCaptor =
|
||||
ArgumentCaptor.forClass(LoadEventInfo.class);
|
||||
verify(mockAnalyticsListener, atLeastOnce())
|
||||
.onLoadStarted(any(), loadStartedEventInfoCaptor.capture(), any(), anyInt());
|
||||
List<Uri> loadStartedUris =
|
||||
Lists.transform(loadStartedEventInfoCaptor.getAllValues(), i -> i.uri);
|
||||
List<Uri> loadStartedDataSpecUris =
|
||||
Lists.transform(loadStartedEventInfoCaptor.getAllValues(), i -> i.dataSpec.uri);
|
||||
// Remove duplicates in case the load was split into multiple reads.
|
||||
assertThat(ImmutableSet.copyOf(loadStartedUris))
|
||||
.containsExactly(manifestUri, Uri.parse("asset:///media/dash/emsg/sample.audio.mp4"));
|
||||
// The two sources of URI should match (because there's no redirection).
|
||||
assertThat(loadStartedDataSpecUris).containsExactlyElementsIn(loadStartedUris).inOrder();
|
||||
ArgumentCaptor<LoadEventInfo> loadCompletedEventInfoCaptor =
|
||||
ArgumentCaptor.forClass(LoadEventInfo.class);
|
||||
verify(mockAnalyticsListener, atLeastOnce())
|
||||
.onLoadCompleted(any(), loadCompletedEventInfoCaptor.capture(), any());
|
||||
List<Uri> loadCompletedUris =
|
||||
Lists.transform(loadCompletedEventInfoCaptor.getAllValues(), i -> i.uri);
|
||||
List<Uri> loadCompletedDataSpecUris =
|
||||
Lists.transform(loadCompletedEventInfoCaptor.getAllValues(), i -> i.dataSpec.uri);
|
||||
// Every started load should be completed.
|
||||
assertThat(loadCompletedUris).containsExactlyElementsIn(loadStartedUris);
|
||||
assertThat(loadCompletedDataSpecUris).containsExactlyElementsIn(loadStartedUris);
|
||||
}
|
||||
|
||||
private static final class AnalyticsListenerImpl implements AnalyticsListener {
|
||||
|
||||
@Nullable private LoadEventInfo loadErrorEventInfo;
|
||||
@Nullable private IOException loadError;
|
||||
|
@ -853,15 +853,19 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
||||
@Override
|
||||
public void onLoadStarted(
|
||||
Chunk loadable, long elapsedRealtimeMs, long loadDurationMs, int retryCount) {
|
||||
mediaSourceEventDispatcher.loadStarted(
|
||||
new LoadEventInfo(
|
||||
LoadEventInfo loadEventInfo =
|
||||
retryCount == 0
|
||||
? new LoadEventInfo(loadable.loadTaskId, loadable.dataSpec, elapsedRealtimeMs)
|
||||
: new LoadEventInfo(
|
||||
loadable.loadTaskId,
|
||||
loadable.dataSpec,
|
||||
loadable.getUri(),
|
||||
loadable.getResponseHeaders(),
|
||||
elapsedRealtimeMs,
|
||||
loadDurationMs,
|
||||
loadable.bytesLoaded()),
|
||||
loadable.bytesLoaded());
|
||||
mediaSourceEventDispatcher.loadStarted(
|
||||
loadEventInfo,
|
||||
loadable.type,
|
||||
trackType,
|
||||
loadable.trackFormat,
|
||||
|
@ -252,17 +252,18 @@ public final class DefaultHlsPlaylistTracker
|
||||
long elapsedRealtimeMs,
|
||||
long loadDurationMs,
|
||||
int retryCount) {
|
||||
eventDispatcher.loadStarted(
|
||||
new LoadEventInfo(
|
||||
LoadEventInfo loadEventInfo =
|
||||
retryCount == 0
|
||||
? new LoadEventInfo(loadable.loadTaskId, loadable.dataSpec, elapsedRealtimeMs)
|
||||
: new LoadEventInfo(
|
||||
loadable.loadTaskId,
|
||||
loadable.dataSpec,
|
||||
loadable.getUri(),
|
||||
loadable.getResponseHeaders(),
|
||||
elapsedRealtimeMs,
|
||||
loadDurationMs,
|
||||
loadable.bytesLoaded()),
|
||||
loadable.type,
|
||||
retryCount);
|
||||
loadable.bytesLoaded());
|
||||
eventDispatcher.loadStarted(loadEventInfo, loadable.type, retryCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -613,6 +614,26 @@ public final class DefaultHlsPlaylistTracker
|
||||
|
||||
// Loader.Callback implementation.
|
||||
|
||||
@Override
|
||||
public void onLoadStarted(
|
||||
ParsingLoadable<HlsPlaylist> loadable,
|
||||
long elapsedRealtimeMs,
|
||||
long loadDurationMs,
|
||||
int retryCount) {
|
||||
LoadEventInfo loadEventInfo =
|
||||
retryCount == 0
|
||||
? new LoadEventInfo(loadable.loadTaskId, loadable.dataSpec, elapsedRealtimeMs)
|
||||
: new LoadEventInfo(
|
||||
loadable.loadTaskId,
|
||||
loadable.dataSpec,
|
||||
loadable.getUri(),
|
||||
loadable.getResponseHeaders(),
|
||||
elapsedRealtimeMs,
|
||||
loadDurationMs,
|
||||
loadable.bytesLoaded());
|
||||
eventDispatcher.loadStarted(loadEventInfo, loadable.type, retryCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadCompleted(
|
||||
ParsingLoadable<HlsPlaylist> loadable, long elapsedRealtimeMs, long loadDurationMs) {
|
||||
|
@ -18,6 +18,11 @@ package androidx.media3.exoplayer.hls.e2etest;
|
||||
|
||||
import static androidx.media3.test.utils.robolectric.TestPlayerRunHelper.run;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.atLeastOnce;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.SurfaceTexture;
|
||||
@ -46,10 +51,14 @@ import androidx.media3.test.utils.robolectric.ShadowMediaCodecConfig;
|
||||
import androidx.media3.test.utils.robolectric.TestPlayerRunHelper;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Lists;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
|
||||
/** End-to-end tests using HLS samples. */
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@ -391,6 +400,52 @@ public final class HlsPlaybackTest {
|
||||
"playbackdumps/hls/cmcd-enabled-with-init-segment.dump");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadEventsReportedAsExpected() throws Exception {
|
||||
Context applicationContext = ApplicationProvider.getApplicationContext();
|
||||
ExoPlayer player =
|
||||
new ExoPlayer.Builder(applicationContext)
|
||||
.setClock(new FakeClock(/* isAutoAdvancing= */ true))
|
||||
.build();
|
||||
AnalyticsListener mockAnalyticsListener = mock(AnalyticsListener.class);
|
||||
player.addAnalyticsListener(mockAnalyticsListener);
|
||||
Uri manifestUri = Uri.parse("asset:///media/hls/cea608/manifest.m3u8");
|
||||
|
||||
player.setMediaItem(MediaItem.fromUri(manifestUri));
|
||||
player.prepare();
|
||||
player.play();
|
||||
TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_ENDED);
|
||||
player.release();
|
||||
|
||||
ArgumentCaptor<LoadEventInfo> loadStartedEventInfoCaptor =
|
||||
ArgumentCaptor.forClass(LoadEventInfo.class);
|
||||
verify(mockAnalyticsListener, atLeastOnce())
|
||||
.onLoadStarted(any(), loadStartedEventInfoCaptor.capture(), any(), anyInt());
|
||||
List<Uri> loadStartedUris =
|
||||
Lists.transform(loadStartedEventInfoCaptor.getAllValues(), i -> i.uri);
|
||||
List<Uri> loadStartedDataSpecUris =
|
||||
Lists.transform(loadStartedEventInfoCaptor.getAllValues(), i -> i.dataSpec.uri);
|
||||
// Remove duplicates in case the load was split into multiple reads.
|
||||
assertThat(ImmutableSet.copyOf(loadStartedUris))
|
||||
.containsExactly(
|
||||
manifestUri,
|
||||
Uri.parse("asset:///media/hls/cea608/sd-hls.m3u8"),
|
||||
Uri.parse("asset:///media/hls/cea608/sd-hls0000000000.ts"));
|
||||
// The two sources of URI should match (because there's no redirection).
|
||||
assertThat(loadStartedDataSpecUris).containsExactlyElementsIn(loadStartedUris).inOrder();
|
||||
ArgumentCaptor<LoadEventInfo> loadCompletedEventInfoCaptor =
|
||||
ArgumentCaptor.forClass(LoadEventInfo.class);
|
||||
verify(mockAnalyticsListener, atLeastOnce())
|
||||
.onLoadCompleted(any(), loadCompletedEventInfoCaptor.capture(), any());
|
||||
List<Uri> loadCompletedUris =
|
||||
Lists.transform(loadCompletedEventInfoCaptor.getAllValues(), i -> i.uri);
|
||||
List<Uri> loadCompletedDataSpecUris =
|
||||
Lists.transform(loadCompletedEventInfoCaptor.getAllValues(), i -> i.dataSpec.uri);
|
||||
// Every started load should be completed.
|
||||
assertThat(loadCompletedUris).containsExactlyElementsIn(loadStartedUris);
|
||||
assertThat(loadCompletedDataSpecUris).containsExactlyElementsIn(loadStartedUris);
|
||||
}
|
||||
|
||||
private static class AnalyticsListenerImpl implements AnalyticsListener {
|
||||
|
||||
@Nullable private LoadEventInfo loadErrorEventInfo;
|
||||
|
@ -503,17 +503,18 @@ public final class SsMediaSource extends BaseMediaSource
|
||||
long elapsedRealtimeMs,
|
||||
long loadDurationMs,
|
||||
int retryCount) {
|
||||
manifestEventDispatcher.loadStarted(
|
||||
new LoadEventInfo(
|
||||
LoadEventInfo loadEventInfo =
|
||||
retryCount == 0
|
||||
? new LoadEventInfo(loadable.loadTaskId, loadable.dataSpec, elapsedRealtimeMs)
|
||||
: new LoadEventInfo(
|
||||
loadable.loadTaskId,
|
||||
loadable.dataSpec,
|
||||
loadable.getUri(),
|
||||
loadable.getResponseHeaders(),
|
||||
elapsedRealtimeMs,
|
||||
loadDurationMs,
|
||||
loadable.bytesLoaded()),
|
||||
loadable.type,
|
||||
retryCount);
|
||||
loadable.bytesLoaded());
|
||||
manifestEventDispatcher.loadStarted(loadEventInfo, loadable.type, retryCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
Loading…
x
Reference in New Issue
Block a user