diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImpl.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImpl.java
index 541e0ccf97..abc8db3654 100644
--- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImpl.java
+++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImpl.java
@@ -980,6 +980,7 @@ import java.util.concurrent.TimeoutException;
playbackInfo.bufferedPositionUs = playbackInfo.positionUs;
playbackInfo.totalBufferedDurationUs = 0;
analyticsCollector.release();
+ trackSelector.release();
removeSurfaceCallbacks();
if (ownedSurface != null) {
ownedSurface.release();
diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/offline/DownloadHelper.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/offline/DownloadHelper.java
index 12e3429e54..07db1b368e 100644
--- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/offline/DownloadHelper.java
+++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/offline/DownloadHelper.java
@@ -516,6 +516,7 @@ public final class DownloadHelper {
if (mediaPreparer != null) {
mediaPreparer.release();
}
+ trackSelector.release();
}
/**
diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/trackselection/TrackSelector.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/trackselection/TrackSelector.java
index 2fb6ea5ae3..bfde8b19c5 100644
--- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/trackselection/TrackSelector.java
+++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/trackselection/TrackSelector.java
@@ -15,10 +15,12 @@
*/
package androidx.media3.exoplayer.trackselection;
+import static androidx.media3.common.util.Assertions.checkStateNotNull;
+
import androidx.annotation.Nullable;
+import androidx.media3.common.Player;
import androidx.media3.common.Timeline;
import androidx.media3.common.TrackSelectionParameters;
-import androidx.media3.common.util.Assertions;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.exoplayer.ExoPlaybackException;
import androidx.media3.exoplayer.ExoPlayer;
@@ -65,6 +67,8 @@ import androidx.media3.exoplayer.upstream.BandwidthMeter;
* track selection for the currently playing period differs from the one that was invalidated.
* Implementing subclasses can trigger invalidation by calling {@link #invalidate()}, which
* will call {@link InvalidationListener#onTrackSelectionsInvalidated()}.
+ *
When the player is {@linkplain Player#release() released}, it will release the track
+ * selector by calling {@link #release()}.
*
*
* Renderer configuration
@@ -113,6 +117,15 @@ public abstract class TrackSelector {
this.bandwidthMeter = bandwidthMeter;
}
+ /**
+ * Called by the player to release the selector. The selector cannot be used until {@link
+ * #init(InvalidationListener, BandwidthMeter)} is called again.
+ */
+ public final void release() {
+ this.listener = null;
+ this.bandwidthMeter = null;
+ }
+
/**
* Called by the player to perform a track selection.
*
@@ -177,9 +190,10 @@ public abstract class TrackSelector {
/**
* Returns a bandwidth meter which can be used by track selections to select tracks. Must only be
- * called after {@link #init(InvalidationListener, BandwidthMeter)} has been called.
+ * called when the track selector is {@linkplain #init(InvalidationListener, BandwidthMeter)
+ * initialized}.
*/
protected final BandwidthMeter getBandwidthMeter() {
- return Assertions.checkNotNull(bandwidthMeter);
+ return checkStateNotNull(bandwidthMeter);
}
}
diff --git a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/trackselection/DefaultTrackSelectorTest.java b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/trackselection/DefaultTrackSelectorTest.java
index 0e1764a829..a9576fe88d 100644
--- a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/trackselection/DefaultTrackSelectorTest.java
+++ b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/trackselection/DefaultTrackSelectorTest.java
@@ -62,6 +62,7 @@ import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import java.util.HashMap;
import java.util.Map;
+import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -146,6 +147,11 @@ public final class DefaultTrackSelectorTest {
trackSelector.init(invalidationListener, bandwidthMeter);
}
+ @After
+ public void tearDown() {
+ trackSelector.release();
+ }
+
@Test
public void parameters_buildUponThenBuild_isEqual() {
Parameters parameters = buildParametersForEqualsTest();
diff --git a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/trackselection/TrackSelectorTest.java b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/trackselection/TrackSelectorTest.java
index a1551d0200..38eaa5c1d6 100644
--- a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/trackselection/TrackSelectorTest.java
+++ b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/trackselection/TrackSelectorTest.java
@@ -16,7 +16,7 @@
package androidx.media3.exoplayer.trackselection;
import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.fail;
+import static org.junit.Assert.assertThrows;
import androidx.annotation.Nullable;
import androidx.media3.common.Timeline;
@@ -59,12 +59,7 @@ public class TrackSelectorTest {
@Test
public void getBandwidthMeter_beforeInitialization_throwsException() {
- try {
- trackSelector.getBandwidthMeter();
- fail();
- } catch (Exception e) {
- // Expected.
- }
+ assertThrows(IllegalStateException.class, () -> trackSelector.getBandwidthMeter());
}
@Test
@@ -73,6 +68,30 @@ public class TrackSelectorTest {
BandwidthMeter bandwidthMeter = Mockito.mock(BandwidthMeter.class);
trackSelector.init(invalidationListener, bandwidthMeter);
- assertThat(trackSelector.getBandwidthMeter()).isEqualTo(bandwidthMeter);
+ assertThat(trackSelector.getBandwidthMeter()).isSameInstanceAs(bandwidthMeter);
+ }
+
+ @Test
+ public void getBandwidthMeter_afterRelease_throwsException() {
+ InvalidationListener invalidationListener = Mockito.mock(InvalidationListener.class);
+ BandwidthMeter bandwidthMeter = Mockito.mock(BandwidthMeter.class);
+ trackSelector.init(invalidationListener, bandwidthMeter);
+
+ trackSelector.release();
+
+ assertThrows(IllegalStateException.class, () -> trackSelector.getBandwidthMeter());
+ }
+
+ @Test
+ public void initialize_afterRelease() {
+ InvalidationListener invalidationListener = Mockito.mock(InvalidationListener.class);
+ BandwidthMeter bandwidthMeter = Mockito.mock(BandwidthMeter.class);
+ trackSelector.init(invalidationListener, bandwidthMeter);
+
+ trackSelector.release();
+ BandwidthMeter anotherBandwidthMeter = Mockito.mock(BandwidthMeter.class);
+ trackSelector.init(invalidationListener, anotherBandwidthMeter);
+
+ assertThat(trackSelector.getBandwidthMeter()).isSameInstanceAs(anotherBandwidthMeter);
}
}