Add reset to BasePreloadManager to release all the holding sources

Compared to `release`, the `reset` method doesn't release the preload manager instance. This applies to the use case that an app wants to discard all the sources but keep the preload manager active for later usage.

Also rename the `releaseSourceInternal` to `removeSourceInternal`, as the latter sounds more generic for different preload manager implementations.

PiperOrigin-RevId: 623148723
This commit is contained in:
tianyifeng 2024-04-09 06:27:29 -07:00 committed by Copybara-Service
parent 5d6f514897
commit 9c72fa8a7a
3 changed files with 99 additions and 22 deletions

View File

@ -24,6 +24,8 @@
`TargetPreloadStatusControl.getTargetPreloadStatus(T)` to indicate not
to preload a `MediaSource` with the given `rankingData`.
* Add `remove(MediaSource)` to `BasePreloadManager`.
* Add `reset` to `BasePreloadManager` to release all the holding sources
while keep the preload manager instance.
* Transformer:
* Add `audioConversionProcess` and `videoConversionProcess` to
`ExportResult` indicating how the respective track in the output file

View File

@ -184,8 +184,10 @@ public abstract class BasePreloadManager<T> {
return false;
}
/** Releases the preload manager. */
public final void release() {
/**
* Resets the preload manager. All sources that the preload manager is holding will be released.
*/
public final void reset() {
for (MediaSourceHolder sourceHolder : mediaItemMediaSourceHolderMap.values()) {
releaseSourceInternal(sourceHolder.mediaSource);
}
@ -194,6 +196,15 @@ public abstract class BasePreloadManager<T> {
sourceHolderPriorityQueue.clear();
targetPreloadStatusOfCurrentPreloadingSource = null;
}
}
/**
* Releases the preload manager.
*
* <p>The preload manager must not be used after calling this method.
*/
public final void release() {
reset();
releaseInternal();
}

View File

@ -15,7 +15,6 @@
*/
package androidx.media3.exoplayer.source.preload;
import static androidx.media3.common.util.Assertions.checkNotNull;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
@ -49,10 +48,8 @@ import androidx.media3.test.utils.FakeRenderer;
import androidx.media3.test.utils.FakeVideoRenderer;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -522,31 +519,101 @@ public class DefaultPreloadManagerTest {
}
@Test
public void release_returnZeroCountAndNullSources_sourcesReleased() {
public void reset_returnZeroCount_sourcesButNotRendererCapabilitiesListReleased() {
TargetPreloadStatusControl<Integer> targetPreloadStatusControl =
rankingData ->
new DefaultPreloadManager.Status(DefaultPreloadManager.Status.STAGE_TIMELINE_REFRESHED);
MediaSource.Factory mockMediaSourceFactory = mock(MediaSource.Factory.class);
AtomicReference<List<FakeRenderer>> underlyingRenderersReference = new AtomicReference<>();
List<FakeRenderer> underlyingRenderers = new ArrayList<>();
RenderersFactory renderersFactory =
(eventHandler,
videoRendererEventListener,
audioRendererEventListener,
textRendererOutput,
metadataRendererOutput) -> {
FakeRenderer[] createdRenderers =
new FakeRenderer[] {
new FakeVideoRenderer(
SystemClock.DEFAULT.createHandler(
eventHandler.getLooper(), /* callback= */ null),
videoRendererEventListener),
new FakeAudioRenderer(
SystemClock.DEFAULT.createHandler(
eventHandler.getLooper(), /* callback= */ null),
audioRendererEventListener)
FakeRenderer fakeVideoRenderer =
new FakeVideoRenderer(
SystemClock.DEFAULT.createHandler(eventHandler.getLooper(), /* callback= */ null),
videoRendererEventListener);
underlyingRenderers.add(fakeVideoRenderer);
FakeRenderer fakeAudioRenderer =
new FakeAudioRenderer(
SystemClock.DEFAULT.createHandler(eventHandler.getLooper(), /* callback= */ null),
audioRendererEventListener);
underlyingRenderers.add(fakeAudioRenderer);
return underlyingRenderers.toArray(new Renderer[2]);
};
DefaultPreloadManager preloadManager =
new DefaultPreloadManager(
targetPreloadStatusControl,
mockMediaSourceFactory,
trackSelector,
bandwidthMeter,
new DefaultRendererCapabilitiesList.Factory(renderersFactory),
allocator,
Util.getCurrentOrMainLooper());
MediaItem.Builder mediaItemBuilder = new MediaItem.Builder();
MediaItem mediaItem1 =
mediaItemBuilder.setMediaId("mediaId1").setUri("http://exoplayer.dev/video1").build();
MediaItem mediaItem2 =
mediaItemBuilder.setMediaId("mediaId2").setUri("http://exoplayer.dev/video2").build();
ArrayList<String> internalSourceToReleaseReferenceByMediaId = new ArrayList<>();
when(mockMediaSourceFactory.createMediaSource(any()))
.thenAnswer(
invocation -> {
MediaItem mediaItem = invocation.getArgument(0);
return new FakeMediaSource() {
@Override
public MediaItem getMediaItem() {
return mediaItem;
}
@Override
protected void releaseSourceInternal() {
internalSourceToReleaseReferenceByMediaId.add(mediaItem.mediaId);
super.releaseSourceInternal();
}
};
underlyingRenderersReference.set(ImmutableList.copyOf(createdRenderers));
return createdRenderers;
});
preloadManager.add(mediaItem1, /* rankingData= */ 1);
preloadManager.add(mediaItem2, /* rankingData= */ 2);
preloadManager.invalidate();
shadowOf(Looper.getMainLooper()).idle();
preloadManager.reset();
shadowOf(Looper.getMainLooper()).idle();
assertThat(preloadManager.getSourceCount()).isEqualTo(0);
assertThat(internalSourceToReleaseReferenceByMediaId).containsExactly("mediaId1", "mediaId2");
for (FakeRenderer renderer : underlyingRenderers) {
assertThat(renderer.isReleased).isFalse();
}
}
@Test
public void release_returnZeroCount_sourcesAndRendererCapabilitiesListReleased() {
TargetPreloadStatusControl<Integer> targetPreloadStatusControl =
rankingData ->
new DefaultPreloadManager.Status(DefaultPreloadManager.Status.STAGE_TIMELINE_REFRESHED);
MediaSource.Factory mockMediaSourceFactory = mock(MediaSource.Factory.class);
List<FakeRenderer> underlyingRenderers = new ArrayList<>();
RenderersFactory renderersFactory =
(eventHandler,
videoRendererEventListener,
audioRendererEventListener,
textRendererOutput,
metadataRendererOutput) -> {
FakeRenderer fakeVideoRenderer =
new FakeVideoRenderer(
SystemClock.DEFAULT.createHandler(eventHandler.getLooper(), /* callback= */ null),
videoRendererEventListener);
underlyingRenderers.add(fakeVideoRenderer);
FakeRenderer fakeAudioRenderer =
new FakeAudioRenderer(
SystemClock.DEFAULT.createHandler(eventHandler.getLooper(), /* callback= */ null),
audioRendererEventListener);
underlyingRenderers.add(fakeAudioRenderer);
return underlyingRenderers.toArray(new Renderer[2]);
};
DefaultPreloadManager preloadManager =
new DefaultPreloadManager(
@ -589,10 +656,7 @@ public class DefaultPreloadManagerTest {
shadowOf(Looper.getMainLooper()).idle();
assertThat(preloadManager.getSourceCount()).isEqualTo(0);
assertThat(preloadManager.getMediaSource(mediaItem1)).isNull();
assertThat(preloadManager.getMediaSource(mediaItem2)).isNull();
assertThat(internalSourceToReleaseReferenceByMediaId).containsExactly("mediaId1", "mediaId2");
List<FakeRenderer> underlyingRenderers = checkNotNull(underlyingRenderersReference.get());
for (FakeRenderer renderer : underlyingRenderers) {
assertThat(renderer.isReleased).isTrue();
}