mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Fix setDataSourceFactory handling in DefaultMediaSourceFactory
The call doesn't currently reset the already loaded suppliers and
factories. Also fix the supplier loading code to use a local copy
of the current dataSourceFactory to avoid leaking an updated
instance to a later invocation.
Issue: androidx/media#116
#minor-release
PiperOrigin-RevId: 460721541
(cherry picked from commit 6be0d6ea25)
This commit is contained in:
parent
77a3b16d6b
commit
b82be0472a
5 changed files with 170 additions and 6 deletions
|
|
@ -274,6 +274,7 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
|
||||||
*/
|
*/
|
||||||
public DefaultMediaSourceFactory setDataSourceFactory(DataSource.Factory dataSourceFactory) {
|
public DefaultMediaSourceFactory setDataSourceFactory(DataSource.Factory dataSourceFactory) {
|
||||||
this.dataSourceFactory = dataSourceFactory;
|
this.dataSourceFactory = dataSourceFactory;
|
||||||
|
delegateFactoryLoader.setDataSourceFactory(dataSourceFactory);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -576,6 +577,7 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
|
||||||
this.dataSourceFactory = dataSourceFactory;
|
this.dataSourceFactory = dataSourceFactory;
|
||||||
// TODO(b/233577470): Call MediaSource.Factory.setDataSourceFactory on each value when it
|
// TODO(b/233577470): Call MediaSource.Factory.setDataSourceFactory on each value when it
|
||||||
// exists on the interface.
|
// exists on the interface.
|
||||||
|
mediaSourceFactorySuppliers.clear();
|
||||||
mediaSourceFactories.clear();
|
mediaSourceFactories.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -609,6 +611,7 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable Supplier<MediaSource.Factory> mediaSourceFactorySupplier = null;
|
@Nullable Supplier<MediaSource.Factory> mediaSourceFactorySupplier = null;
|
||||||
|
DataSource.Factory dataSourceFactory = checkNotNull(this.dataSourceFactory);
|
||||||
try {
|
try {
|
||||||
Class<? extends MediaSource.Factory> clazz;
|
Class<? extends MediaSource.Factory> clazz;
|
||||||
switch (contentType) {
|
switch (contentType) {
|
||||||
|
|
@ -616,20 +619,20 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
|
||||||
clazz =
|
clazz =
|
||||||
Class.forName("com.google.android.exoplayer2.source.dash.DashMediaSource$Factory")
|
Class.forName("com.google.android.exoplayer2.source.dash.DashMediaSource$Factory")
|
||||||
.asSubclass(MediaSource.Factory.class);
|
.asSubclass(MediaSource.Factory.class);
|
||||||
mediaSourceFactorySupplier = () -> newInstance(clazz, checkNotNull(dataSourceFactory));
|
mediaSourceFactorySupplier = () -> newInstance(clazz, dataSourceFactory);
|
||||||
break;
|
break;
|
||||||
case C.CONTENT_TYPE_SS:
|
case C.CONTENT_TYPE_SS:
|
||||||
clazz =
|
clazz =
|
||||||
Class.forName(
|
Class.forName(
|
||||||
"com.google.android.exoplayer2.source.smoothstreaming.SsMediaSource$Factory")
|
"com.google.android.exoplayer2.source.smoothstreaming.SsMediaSource$Factory")
|
||||||
.asSubclass(MediaSource.Factory.class);
|
.asSubclass(MediaSource.Factory.class);
|
||||||
mediaSourceFactorySupplier = () -> newInstance(clazz, checkNotNull(dataSourceFactory));
|
mediaSourceFactorySupplier = () -> newInstance(clazz, dataSourceFactory);
|
||||||
break;
|
break;
|
||||||
case C.CONTENT_TYPE_HLS:
|
case C.CONTENT_TYPE_HLS:
|
||||||
clazz =
|
clazz =
|
||||||
Class.forName("com.google.android.exoplayer2.source.hls.HlsMediaSource$Factory")
|
Class.forName("com.google.android.exoplayer2.source.hls.HlsMediaSource$Factory")
|
||||||
.asSubclass(MediaSource.Factory.class);
|
.asSubclass(MediaSource.Factory.class);
|
||||||
mediaSourceFactorySupplier = () -> newInstance(clazz, checkNotNull(dataSourceFactory));
|
mediaSourceFactorySupplier = () -> newInstance(clazz, dataSourceFactory);
|
||||||
break;
|
break;
|
||||||
case C.CONTENT_TYPE_RTSP:
|
case C.CONTENT_TYPE_RTSP:
|
||||||
clazz =
|
clazz =
|
||||||
|
|
@ -639,9 +642,7 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
|
||||||
break;
|
break;
|
||||||
case C.CONTENT_TYPE_OTHER:
|
case C.CONTENT_TYPE_OTHER:
|
||||||
mediaSourceFactorySupplier =
|
mediaSourceFactorySupplier =
|
||||||
() ->
|
() -> new ProgressiveMediaSource.Factory(dataSourceFactory, extractorsFactory);
|
||||||
new ProgressiveMediaSource.Factory(
|
|
||||||
checkNotNull(dataSourceFactory), extractorsFactory);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// Do nothing.
|
// Do nothing.
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer2.source.dash;
|
package com.google.android.exoplayer2.source.dash;
|
||||||
|
|
||||||
|
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
@ -22,9 +23,13 @@ import androidx.test.core.app.ApplicationProvider;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.MediaItem;
|
import com.google.android.exoplayer2.MediaItem;
|
||||||
|
import com.google.android.exoplayer2.analytics.PlayerId;
|
||||||
|
import com.google.android.exoplayer2.robolectric.RobolectricUtil;
|
||||||
import com.google.android.exoplayer2.source.DefaultMediaSourceFactory;
|
import com.google.android.exoplayer2.source.DefaultMediaSourceFactory;
|
||||||
import com.google.android.exoplayer2.source.MediaSource;
|
import com.google.android.exoplayer2.source.MediaSource;
|
||||||
|
import com.google.android.exoplayer2.testutil.FakeDataSource;
|
||||||
import com.google.android.exoplayer2.util.MimeTypes;
|
import com.google.android.exoplayer2.util.MimeTypes;
|
||||||
|
import java.io.IOException;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
|
@ -82,4 +87,53 @@ public class DefaultMediaSourceFactoryTest {
|
||||||
|
|
||||||
assertThat(supportedTypes).asList().containsExactly(C.CONTENT_TYPE_OTHER, C.CONTENT_TYPE_DASH);
|
assertThat(supportedTypes).asList().containsExactly(C.CONTENT_TYPE_OTHER, C.CONTENT_TYPE_DASH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createMediaSource_withSetDataSourceFactory_usesDataSourceFactory() throws Exception {
|
||||||
|
FakeDataSource fakeDataSource = new FakeDataSource();
|
||||||
|
DefaultMediaSourceFactory defaultMediaSourceFactory =
|
||||||
|
new DefaultMediaSourceFactory((Context) ApplicationProvider.getApplicationContext())
|
||||||
|
.setDataSourceFactory(() -> fakeDataSource);
|
||||||
|
|
||||||
|
prepareDashUrlAndWaitForPrepareError(defaultMediaSourceFactory);
|
||||||
|
|
||||||
|
assertThat(fakeDataSource.getAndClearOpenedDataSpecs()).asList().isNotEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void
|
||||||
|
createMediaSource_usingDefaultDataSourceFactoryAndSetDataSourceFactory_usesUpdatesDataSourceFactory()
|
||||||
|
throws Exception {
|
||||||
|
FakeDataSource fakeDataSource = new FakeDataSource();
|
||||||
|
DefaultMediaSourceFactory defaultMediaSourceFactory =
|
||||||
|
new DefaultMediaSourceFactory((Context) ApplicationProvider.getApplicationContext());
|
||||||
|
|
||||||
|
// Use default DataSource.Factory first.
|
||||||
|
prepareDashUrlAndWaitForPrepareError(defaultMediaSourceFactory);
|
||||||
|
defaultMediaSourceFactory.setDataSourceFactory(() -> fakeDataSource);
|
||||||
|
prepareDashUrlAndWaitForPrepareError(defaultMediaSourceFactory);
|
||||||
|
|
||||||
|
assertThat(fakeDataSource.getAndClearOpenedDataSpecs()).asList().isNotEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void prepareDashUrlAndWaitForPrepareError(
|
||||||
|
DefaultMediaSourceFactory defaultMediaSourceFactory) throws Exception {
|
||||||
|
MediaSource mediaSource =
|
||||||
|
defaultMediaSourceFactory.createMediaSource(MediaItem.fromUri(URI_MEDIA + "/file.mpd"));
|
||||||
|
getInstrumentation()
|
||||||
|
.runOnMainSync(
|
||||||
|
() ->
|
||||||
|
mediaSource.prepareSource(
|
||||||
|
(source, timeline) -> {}, /* mediaTransferListener= */ null, PlayerId.UNSET));
|
||||||
|
// We don't expect this to prepare successfully.
|
||||||
|
RobolectricUtil.runMainLooperUntil(
|
||||||
|
() -> {
|
||||||
|
try {
|
||||||
|
mediaSource.maybeThrowSourceInfoRefreshError();
|
||||||
|
return false;
|
||||||
|
} catch (IOException e) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer2.source.hls;
|
package com.google.android.exoplayer2.source.hls;
|
||||||
|
|
||||||
|
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
@ -22,9 +23,13 @@ import androidx.test.core.app.ApplicationProvider;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.MediaItem;
|
import com.google.android.exoplayer2.MediaItem;
|
||||||
|
import com.google.android.exoplayer2.analytics.PlayerId;
|
||||||
|
import com.google.android.exoplayer2.robolectric.RobolectricUtil;
|
||||||
import com.google.android.exoplayer2.source.DefaultMediaSourceFactory;
|
import com.google.android.exoplayer2.source.DefaultMediaSourceFactory;
|
||||||
import com.google.android.exoplayer2.source.MediaSource;
|
import com.google.android.exoplayer2.source.MediaSource;
|
||||||
|
import com.google.android.exoplayer2.testutil.FakeDataSource;
|
||||||
import com.google.android.exoplayer2.util.MimeTypes;
|
import com.google.android.exoplayer2.util.MimeTypes;
|
||||||
|
import java.io.IOException;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
|
@ -82,4 +87,53 @@ public class DefaultMediaSourceFactoryTest {
|
||||||
|
|
||||||
assertThat(supportedTypes).asList().containsExactly(C.CONTENT_TYPE_OTHER, C.CONTENT_TYPE_HLS);
|
assertThat(supportedTypes).asList().containsExactly(C.CONTENT_TYPE_OTHER, C.CONTENT_TYPE_HLS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createMediaSource_withSetDataSourceFactory_usesDataSourceFactory() throws Exception {
|
||||||
|
FakeDataSource fakeDataSource = new FakeDataSource();
|
||||||
|
DefaultMediaSourceFactory defaultMediaSourceFactory =
|
||||||
|
new DefaultMediaSourceFactory((Context) ApplicationProvider.getApplicationContext())
|
||||||
|
.setDataSourceFactory(() -> fakeDataSource);
|
||||||
|
|
||||||
|
prepareHlsUrlAndWaitForPrepareError(defaultMediaSourceFactory);
|
||||||
|
|
||||||
|
assertThat(fakeDataSource.getAndClearOpenedDataSpecs()).asList().isNotEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void
|
||||||
|
createMediaSource_usingDefaultDataSourceFactoryAndSetDataSourceFactory_usesUpdatesDataSourceFactory()
|
||||||
|
throws Exception {
|
||||||
|
FakeDataSource fakeDataSource = new FakeDataSource();
|
||||||
|
DefaultMediaSourceFactory defaultMediaSourceFactory =
|
||||||
|
new DefaultMediaSourceFactory((Context) ApplicationProvider.getApplicationContext());
|
||||||
|
|
||||||
|
// Use default DataSource.Factory first.
|
||||||
|
prepareHlsUrlAndWaitForPrepareError(defaultMediaSourceFactory);
|
||||||
|
defaultMediaSourceFactory.setDataSourceFactory(() -> fakeDataSource);
|
||||||
|
prepareHlsUrlAndWaitForPrepareError(defaultMediaSourceFactory);
|
||||||
|
|
||||||
|
assertThat(fakeDataSource.getAndClearOpenedDataSpecs()).asList().isNotEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void prepareHlsUrlAndWaitForPrepareError(
|
||||||
|
DefaultMediaSourceFactory defaultMediaSourceFactory) throws Exception {
|
||||||
|
MediaSource mediaSource =
|
||||||
|
defaultMediaSourceFactory.createMediaSource(MediaItem.fromUri(URI_MEDIA + "/file.m3u8"));
|
||||||
|
getInstrumentation()
|
||||||
|
.runOnMainSync(
|
||||||
|
() ->
|
||||||
|
mediaSource.prepareSource(
|
||||||
|
(source, timeline) -> {}, /* mediaTransferListener= */ null, PlayerId.UNSET));
|
||||||
|
// We don't expect this to prepare successfully.
|
||||||
|
RobolectricUtil.runMainLooperUntil(
|
||||||
|
() -> {
|
||||||
|
try {
|
||||||
|
mediaSource.maybeThrowSourceInfoRefreshError();
|
||||||
|
return false;
|
||||||
|
} catch (IOException e) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ dependencies {
|
||||||
compileOnly 'org.checkerframework:checker-compat-qual:' + checkerframeworkCompatVersion
|
compileOnly 'org.checkerframework:checker-compat-qual:' + checkerframeworkCompatVersion
|
||||||
compileOnly 'org.jetbrains.kotlin:kotlin-annotations-jvm:' + kotlinAnnotationsVersion
|
compileOnly 'org.jetbrains.kotlin:kotlin-annotations-jvm:' + kotlinAnnotationsVersion
|
||||||
implementation 'androidx.annotation:annotation:' + androidxAnnotationVersion
|
implementation 'androidx.annotation:annotation:' + androidxAnnotationVersion
|
||||||
|
testImplementation project(modulePrefix + 'robolectricutils')
|
||||||
testImplementation project(modulePrefix + 'testutils')
|
testImplementation project(modulePrefix + 'testutils')
|
||||||
testImplementation 'org.robolectric:robolectric:' + robolectricVersion
|
testImplementation 'org.robolectric:robolectric:' + robolectricVersion
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer2.source.smoothstreaming;
|
package com.google.android.exoplayer2.source.smoothstreaming;
|
||||||
|
|
||||||
|
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
@ -22,9 +23,13 @@ import androidx.test.core.app.ApplicationProvider;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.MediaItem;
|
import com.google.android.exoplayer2.MediaItem;
|
||||||
|
import com.google.android.exoplayer2.analytics.PlayerId;
|
||||||
|
import com.google.android.exoplayer2.robolectric.RobolectricUtil;
|
||||||
import com.google.android.exoplayer2.source.DefaultMediaSourceFactory;
|
import com.google.android.exoplayer2.source.DefaultMediaSourceFactory;
|
||||||
import com.google.android.exoplayer2.source.MediaSource;
|
import com.google.android.exoplayer2.source.MediaSource;
|
||||||
|
import com.google.android.exoplayer2.testutil.FakeDataSource;
|
||||||
import com.google.android.exoplayer2.util.MimeTypes;
|
import com.google.android.exoplayer2.util.MimeTypes;
|
||||||
|
import java.io.IOException;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
|
@ -93,4 +98,53 @@ public class DefaultMediaSourceFactoryTest {
|
||||||
|
|
||||||
assertThat(supportedTypes).asList().containsExactly(C.CONTENT_TYPE_OTHER, C.CONTENT_TYPE_SS);
|
assertThat(supportedTypes).asList().containsExactly(C.CONTENT_TYPE_OTHER, C.CONTENT_TYPE_SS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createMediaSource_withSetDataSourceFactory_usesDataSourceFactory() throws Exception {
|
||||||
|
FakeDataSource fakeDataSource = new FakeDataSource();
|
||||||
|
DefaultMediaSourceFactory defaultMediaSourceFactory =
|
||||||
|
new DefaultMediaSourceFactory((Context) ApplicationProvider.getApplicationContext())
|
||||||
|
.setDataSourceFactory(() -> fakeDataSource);
|
||||||
|
|
||||||
|
prepareSsUrlAndWaitForPrepareError(defaultMediaSourceFactory);
|
||||||
|
|
||||||
|
assertThat(fakeDataSource.getAndClearOpenedDataSpecs()).asList().isNotEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void
|
||||||
|
createMediaSource_usingDefaultDataSourceFactoryAndSetDataSourceFactory_usesUpdatesDataSourceFactory()
|
||||||
|
throws Exception {
|
||||||
|
FakeDataSource fakeDataSource = new FakeDataSource();
|
||||||
|
DefaultMediaSourceFactory defaultMediaSourceFactory =
|
||||||
|
new DefaultMediaSourceFactory((Context) ApplicationProvider.getApplicationContext());
|
||||||
|
|
||||||
|
// Use default DataSource.Factory first.
|
||||||
|
prepareSsUrlAndWaitForPrepareError(defaultMediaSourceFactory);
|
||||||
|
defaultMediaSourceFactory.setDataSourceFactory(() -> fakeDataSource);
|
||||||
|
prepareSsUrlAndWaitForPrepareError(defaultMediaSourceFactory);
|
||||||
|
|
||||||
|
assertThat(fakeDataSource.getAndClearOpenedDataSpecs()).asList().isNotEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void prepareSsUrlAndWaitForPrepareError(
|
||||||
|
DefaultMediaSourceFactory defaultMediaSourceFactory) throws Exception {
|
||||||
|
MediaSource mediaSource =
|
||||||
|
defaultMediaSourceFactory.createMediaSource(MediaItem.fromUri(URI_MEDIA + "/file.ism"));
|
||||||
|
getInstrumentation()
|
||||||
|
.runOnMainSync(
|
||||||
|
() ->
|
||||||
|
mediaSource.prepareSource(
|
||||||
|
(source, timeline) -> {}, /* mediaTransferListener= */ null, PlayerId.UNSET));
|
||||||
|
// We don't expect this to prepare successfully.
|
||||||
|
RobolectricUtil.runMainLooperUntil(
|
||||||
|
() -> {
|
||||||
|
try {
|
||||||
|
mediaSource.maybeThrowSourceInfoRefreshError();
|
||||||
|
return false;
|
||||||
|
} catch (IOException e) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue