mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
make media source factories reusable
First cl towards DefaultMediaSourceFactory (<unknown commit>) does not change the MediaSourceFactory interface except adding @Nullable anotations to setters. PiperOrigin-RevId: 290269640
This commit is contained in:
parent
118d690666
commit
c5e1169666
6 changed files with 163 additions and 251 deletions
|
|
@ -64,12 +64,11 @@ public final class ExtractorMediaSource extends CompositeMediaSource<Void> {
|
|||
|
||||
private final DataSource.Factory dataSourceFactory;
|
||||
|
||||
@Nullable private ExtractorsFactory extractorsFactory;
|
||||
@Nullable private String customCacheKey;
|
||||
@Nullable private Object tag;
|
||||
private ExtractorsFactory extractorsFactory;
|
||||
private LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
||||
private int continueLoadingCheckIntervalBytes;
|
||||
private boolean isCreateCalled;
|
||||
@Nullable private String customCacheKey;
|
||||
@Nullable private Object tag;
|
||||
|
||||
/**
|
||||
* Creates a new factory for {@link ExtractorMediaSource}s.
|
||||
|
|
@ -78,6 +77,7 @@ public final class ExtractorMediaSource extends CompositeMediaSource<Void> {
|
|||
*/
|
||||
public Factory(DataSource.Factory dataSourceFactory) {
|
||||
this.dataSourceFactory = dataSourceFactory;
|
||||
extractorsFactory = new DefaultExtractorsFactory();
|
||||
loadErrorHandlingPolicy = new DefaultLoadErrorHandlingPolicy();
|
||||
continueLoadingCheckIntervalBytes = DEFAULT_LOADING_CHECK_INTERVAL_BYTES;
|
||||
}
|
||||
|
|
@ -90,11 +90,10 @@ public final class ExtractorMediaSource extends CompositeMediaSource<Void> {
|
|||
* possible formats are known, pass a factory that instantiates extractors for those
|
||||
* formats.
|
||||
* @return This factory, for convenience.
|
||||
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
||||
*/
|
||||
public Factory setExtractorsFactory(ExtractorsFactory extractorsFactory) {
|
||||
Assertions.checkState(!isCreateCalled);
|
||||
this.extractorsFactory = extractorsFactory;
|
||||
public Factory setExtractorsFactory(@Nullable ExtractorsFactory extractorsFactory) {
|
||||
this.extractorsFactory =
|
||||
extractorsFactory != null ? extractorsFactory : new DefaultExtractorsFactory();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -105,10 +104,8 @@ public final class ExtractorMediaSource extends CompositeMediaSource<Void> {
|
|||
* @param customCacheKey A custom key that uniquely identifies the original stream. Used for
|
||||
* cache indexing.
|
||||
* @return This factory, for convenience.
|
||||
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
||||
*/
|
||||
public Factory setCustomCacheKey(String customCacheKey) {
|
||||
Assertions.checkState(!isCreateCalled);
|
||||
public Factory setCustomCacheKey(@Nullable String customCacheKey) {
|
||||
this.customCacheKey = customCacheKey;
|
||||
return this;
|
||||
}
|
||||
|
|
@ -120,27 +117,13 @@ public final class ExtractorMediaSource extends CompositeMediaSource<Void> {
|
|||
*
|
||||
* @param tag A tag for the media source.
|
||||
* @return This factory, for convenience.
|
||||
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
||||
*/
|
||||
public Factory setTag(Object tag) {
|
||||
Assertions.checkState(!isCreateCalled);
|
||||
public Factory setTag(@Nullable Object tag) {
|
||||
this.tag = tag;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the minimum number of times to retry if a loading error occurs. See {@link
|
||||
* #setLoadErrorHandlingPolicy} for the default value.
|
||||
*
|
||||
* <p>Calling this method is equivalent to calling {@link #setLoadErrorHandlingPolicy} with
|
||||
* {@link DefaultLoadErrorHandlingPolicy#DefaultLoadErrorHandlingPolicy(int)
|
||||
* DefaultLoadErrorHandlingPolicy(minLoadableRetryCount)}
|
||||
*
|
||||
* @param minLoadableRetryCount The minimum number of times to retry if a loading error occurs.
|
||||
* @return This factory, for convenience.
|
||||
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
||||
* @deprecated Use {@link #setLoadErrorHandlingPolicy(LoadErrorHandlingPolicy)} instead.
|
||||
*/
|
||||
/** @deprecated Use {@link #setLoadErrorHandlingPolicy(LoadErrorHandlingPolicy)} instead. */
|
||||
@Deprecated
|
||||
public Factory setMinLoadableRetryCount(int minLoadableRetryCount) {
|
||||
return setLoadErrorHandlingPolicy(new DefaultLoadErrorHandlingPolicy(minLoadableRetryCount));
|
||||
|
|
@ -154,11 +137,13 @@ public final class ExtractorMediaSource extends CompositeMediaSource<Void> {
|
|||
*
|
||||
* @param loadErrorHandlingPolicy A {@link LoadErrorHandlingPolicy}.
|
||||
* @return This factory, for convenience.
|
||||
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
||||
*/
|
||||
public Factory setLoadErrorHandlingPolicy(LoadErrorHandlingPolicy loadErrorHandlingPolicy) {
|
||||
Assertions.checkState(!isCreateCalled);
|
||||
this.loadErrorHandlingPolicy = loadErrorHandlingPolicy;
|
||||
public Factory setLoadErrorHandlingPolicy(
|
||||
@Nullable LoadErrorHandlingPolicy loadErrorHandlingPolicy) {
|
||||
this.loadErrorHandlingPolicy =
|
||||
loadErrorHandlingPolicy != null
|
||||
? loadErrorHandlingPolicy
|
||||
: new DefaultLoadErrorHandlingPolicy();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -171,18 +156,16 @@ public final class ExtractorMediaSource extends CompositeMediaSource<Void> {
|
|||
* each invocation of {@link
|
||||
* MediaPeriod.Callback#onContinueLoadingRequested(SequenceableLoader)}.
|
||||
* @return This factory, for convenience.
|
||||
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
||||
*/
|
||||
public Factory setContinueLoadingCheckIntervalBytes(int continueLoadingCheckIntervalBytes) {
|
||||
Assertions.checkState(!isCreateCalled);
|
||||
this.continueLoadingCheckIntervalBytes = continueLoadingCheckIntervalBytes;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** @deprecated Use {@link ProgressiveMediaSource.Factory#setDrmSessionManager} instead. */
|
||||
@Override
|
||||
@Deprecated
|
||||
public Factory setDrmSessionManager(DrmSessionManager<?> drmSessionManager) {
|
||||
@Override
|
||||
public Factory setDrmSessionManager(@Nullable DrmSessionManager<?> drmSessionManager) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
|
@ -194,10 +177,6 @@ public final class ExtractorMediaSource extends CompositeMediaSource<Void> {
|
|||
*/
|
||||
@Override
|
||||
public ExtractorMediaSource createMediaSource(Uri uri) {
|
||||
isCreateCalled = true;
|
||||
if (extractorsFactory == null) {
|
||||
extractorsFactory = new DefaultExtractorsFactory();
|
||||
}
|
||||
return new ExtractorMediaSource(
|
||||
uri,
|
||||
dataSourceFactory,
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
package com.google.android.exoplayer2.source;
|
||||
|
||||
import android.net.Uri;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.drm.DrmSession;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
|
|
@ -30,9 +31,8 @@ public interface MediaSourceFactory {
|
|||
*
|
||||
* @param streamKeys A list of {@link StreamKey StreamKeys}.
|
||||
* @return This factory, for convenience.
|
||||
* @throws IllegalStateException If {@link #createMediaSource(Uri)} has already been called.
|
||||
*/
|
||||
default MediaSourceFactory setStreamKeys(List<StreamKey> streamKeys) {
|
||||
default MediaSourceFactory setStreamKeys(@Nullable List<StreamKey> streamKeys) {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -41,9 +41,8 @@ public interface MediaSourceFactory {
|
|||
*
|
||||
* @param drmSessionManager The {@link DrmSessionManager}.
|
||||
* @return This factory, for convenience.
|
||||
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
||||
*/
|
||||
MediaSourceFactory setDrmSessionManager(DrmSessionManager<?> drmSessionManager);
|
||||
MediaSourceFactory setDrmSessionManager(@Nullable DrmSessionManager<?> drmSessionManager);
|
||||
|
||||
/**
|
||||
* Creates a new {@link MediaSource} with the specified {@code uri}.
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ import com.google.android.exoplayer2.upstream.DataSource;
|
|||
import com.google.android.exoplayer2.upstream.DefaultLoadErrorHandlingPolicy;
|
||||
import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy;
|
||||
import com.google.android.exoplayer2.upstream.TransferListener;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
|
|
@ -51,12 +50,11 @@ public final class ProgressiveMediaSource extends BaseMediaSource
|
|||
private final DataSource.Factory dataSourceFactory;
|
||||
|
||||
private ExtractorsFactory extractorsFactory;
|
||||
@Nullable private String customCacheKey;
|
||||
@Nullable private Object tag;
|
||||
private DrmSessionManager<?> drmSessionManager;
|
||||
private LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
||||
private int continueLoadingCheckIntervalBytes;
|
||||
private boolean isCreateCalled;
|
||||
@Nullable private String customCacheKey;
|
||||
@Nullable private Object tag;
|
||||
|
||||
/**
|
||||
* Creates a new factory for {@link ProgressiveMediaSource}s, using the extractors provided by
|
||||
|
|
@ -83,22 +81,14 @@ public final class ProgressiveMediaSource extends BaseMediaSource
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets the factory for {@link Extractor}s to process the media stream. The default value is an
|
||||
* instance of {@link DefaultExtractorsFactory}.
|
||||
*
|
||||
* @param extractorsFactory A factory for {@link Extractor}s to process the media stream. If the
|
||||
* possible formats are known, pass a factory that instantiates extractors for those
|
||||
* formats.
|
||||
* @return This factory, for convenience.
|
||||
* @throws IllegalStateException If {@link #createMediaSource(Uri)} has already been called.
|
||||
* @deprecated Pass the {@link ExtractorsFactory} via {@link #Factory(DataSource.Factory,
|
||||
* ExtractorsFactory)}. This is necessary so that proguard can treat the default extractors
|
||||
* factory as unused.
|
||||
*/
|
||||
@Deprecated
|
||||
public Factory setExtractorsFactory(ExtractorsFactory extractorsFactory) {
|
||||
Assertions.checkState(!isCreateCalled);
|
||||
this.extractorsFactory = extractorsFactory;
|
||||
public Factory setExtractorsFactory(@Nullable ExtractorsFactory extractorsFactory) {
|
||||
this.extractorsFactory =
|
||||
extractorsFactory != null ? extractorsFactory : new DefaultExtractorsFactory();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -109,10 +99,8 @@ public final class ProgressiveMediaSource extends BaseMediaSource
|
|||
* @param customCacheKey A custom key that uniquely identifies the original stream. Used for
|
||||
* cache indexing.
|
||||
* @return This factory, for convenience.
|
||||
* @throws IllegalStateException If {@link #createMediaSource(Uri)} has already been called.
|
||||
*/
|
||||
public Factory setCustomCacheKey(@Nullable String customCacheKey) {
|
||||
Assertions.checkState(!isCreateCalled);
|
||||
this.customCacheKey = customCacheKey;
|
||||
return this;
|
||||
}
|
||||
|
|
@ -124,10 +112,8 @@ public final class ProgressiveMediaSource extends BaseMediaSource
|
|||
*
|
||||
* @param tag A tag for the media source.
|
||||
* @return This factory, for convenience.
|
||||
* @throws IllegalStateException If {@link #createMediaSource(Uri)} has already been called.
|
||||
*/
|
||||
public Factory setTag(Object tag) {
|
||||
Assertions.checkState(!isCreateCalled);
|
||||
public Factory setTag(@Nullable Object tag) {
|
||||
this.tag = tag;
|
||||
return this;
|
||||
}
|
||||
|
|
@ -138,11 +124,13 @@ public final class ProgressiveMediaSource extends BaseMediaSource
|
|||
*
|
||||
* @param loadErrorHandlingPolicy A {@link LoadErrorHandlingPolicy}.
|
||||
* @return This factory, for convenience.
|
||||
* @throws IllegalStateException If {@link #createMediaSource(Uri)} has already been called.
|
||||
*/
|
||||
public Factory setLoadErrorHandlingPolicy(LoadErrorHandlingPolicy loadErrorHandlingPolicy) {
|
||||
Assertions.checkState(!isCreateCalled);
|
||||
this.loadErrorHandlingPolicy = loadErrorHandlingPolicy;
|
||||
public Factory setLoadErrorHandlingPolicy(
|
||||
@Nullable LoadErrorHandlingPolicy loadErrorHandlingPolicy) {
|
||||
this.loadErrorHandlingPolicy =
|
||||
loadErrorHandlingPolicy != null
|
||||
? loadErrorHandlingPolicy
|
||||
: new DefaultLoadErrorHandlingPolicy();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -155,10 +143,8 @@ public final class ProgressiveMediaSource extends BaseMediaSource
|
|||
* each invocation of {@link
|
||||
* MediaPeriod.Callback#onContinueLoadingRequested(SequenceableLoader)}.
|
||||
* @return This factory, for convenience.
|
||||
* @throws IllegalStateException If {@link #createMediaSource(Uri)} has already been called.
|
||||
*/
|
||||
public Factory setContinueLoadingCheckIntervalBytes(int continueLoadingCheckIntervalBytes) {
|
||||
Assertions.checkState(!isCreateCalled);
|
||||
this.continueLoadingCheckIntervalBytes = continueLoadingCheckIntervalBytes;
|
||||
return this;
|
||||
}
|
||||
|
|
@ -169,12 +155,13 @@ public final class ProgressiveMediaSource extends BaseMediaSource
|
|||
*
|
||||
* @param drmSessionManager The {@link DrmSessionManager}.
|
||||
* @return This factory, for convenience.
|
||||
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
||||
*/
|
||||
@Override
|
||||
public Factory setDrmSessionManager(DrmSessionManager<?> drmSessionManager) {
|
||||
Assertions.checkState(!isCreateCalled);
|
||||
this.drmSessionManager = drmSessionManager;
|
||||
public Factory setDrmSessionManager(@Nullable DrmSessionManager<?> drmSessionManager) {
|
||||
this.drmSessionManager =
|
||||
drmSessionManager != null
|
||||
? drmSessionManager
|
||||
: DrmSessionManager.getDummyDrmSessionManager();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -186,7 +173,6 @@ public final class ProgressiveMediaSource extends BaseMediaSource
|
|||
*/
|
||||
@Override
|
||||
public ProgressiveMediaSource createMediaSource(Uri uri) {
|
||||
isCreateCalled = true;
|
||||
return new ProgressiveMediaSource(
|
||||
uri,
|
||||
dataSourceFactory,
|
||||
|
|
|
|||
|
|
@ -83,13 +83,12 @@ public final class DashMediaSource extends BaseMediaSource {
|
|||
@Nullable private final DataSource.Factory manifestDataSourceFactory;
|
||||
|
||||
private DrmSessionManager<?> drmSessionManager;
|
||||
@Nullable private ParsingLoadable.Parser<? extends DashManifest> manifestParser;
|
||||
@Nullable private List<StreamKey> streamKeys;
|
||||
private CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
|
||||
private LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
||||
private long livePresentationDelayMs;
|
||||
private boolean livePresentationDelayOverridesManifest;
|
||||
private boolean isCreateCalled;
|
||||
@Nullable private ParsingLoadable.Parser<? extends DashManifest> manifestParser;
|
||||
@Nullable private List<StreamKey> streamKeys;
|
||||
@Nullable private Object tag;
|
||||
|
||||
/**
|
||||
|
|
@ -129,27 +128,35 @@ public final class DashMediaSource extends BaseMediaSource {
|
|||
*
|
||||
* @param tag A tag for the media source.
|
||||
* @return This factory, for convenience.
|
||||
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
||||
*/
|
||||
public Factory setTag(@Nullable Object tag) {
|
||||
Assertions.checkState(!isCreateCalled);
|
||||
this.tag = tag;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Factory setStreamKeys(@Nullable List<StreamKey> streamKeys) {
|
||||
this.streamKeys = streamKeys != null && !streamKeys.isEmpty() ? streamKeys : null;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the minimum number of times to retry if a loading error occurs. See {@link
|
||||
* #setLoadErrorHandlingPolicy} for the default value.
|
||||
* Sets the {@link DrmSessionManager} to use for acquiring {@link DrmSession DrmSessions}. The
|
||||
* default value is {@link DrmSessionManager#DUMMY}.
|
||||
*
|
||||
* <p>Calling this method is equivalent to calling {@link #setLoadErrorHandlingPolicy} with
|
||||
* {@link DefaultLoadErrorHandlingPolicy#DefaultLoadErrorHandlingPolicy(int)
|
||||
* DefaultLoadErrorHandlingPolicy(minLoadableRetryCount)}
|
||||
*
|
||||
* @param minLoadableRetryCount The minimum number of times to retry if a loading error occurs.
|
||||
* @param drmSessionManager The {@link DrmSessionManager}.
|
||||
* @return This factory, for convenience.
|
||||
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
||||
* @deprecated Use {@link #setLoadErrorHandlingPolicy(LoadErrorHandlingPolicy)} instead.
|
||||
*/
|
||||
@Override
|
||||
public Factory setDrmSessionManager(@Nullable DrmSessionManager<?> drmSessionManager) {
|
||||
this.drmSessionManager =
|
||||
drmSessionManager != null
|
||||
? drmSessionManager
|
||||
: DrmSessionManager.getDummyDrmSessionManager();
|
||||
return this;
|
||||
}
|
||||
|
||||
/** @deprecated Use {@link #setLoadErrorHandlingPolicy(LoadErrorHandlingPolicy)} instead. */
|
||||
@Deprecated
|
||||
public Factory setMinLoadableRetryCount(int minLoadableRetryCount) {
|
||||
return setLoadErrorHandlingPolicy(new DefaultLoadErrorHandlingPolicy(minLoadableRetryCount));
|
||||
|
|
@ -163,15 +170,16 @@ public final class DashMediaSource extends BaseMediaSource {
|
|||
*
|
||||
* @param loadErrorHandlingPolicy A {@link LoadErrorHandlingPolicy}.
|
||||
* @return This factory, for convenience.
|
||||
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
||||
*/
|
||||
public Factory setLoadErrorHandlingPolicy(LoadErrorHandlingPolicy loadErrorHandlingPolicy) {
|
||||
Assertions.checkState(!isCreateCalled);
|
||||
this.loadErrorHandlingPolicy = loadErrorHandlingPolicy;
|
||||
public Factory setLoadErrorHandlingPolicy(
|
||||
@Nullable LoadErrorHandlingPolicy loadErrorHandlingPolicy) {
|
||||
this.loadErrorHandlingPolicy =
|
||||
loadErrorHandlingPolicy != null
|
||||
? loadErrorHandlingPolicy
|
||||
: new DefaultLoadErrorHandlingPolicy();
|
||||
return this;
|
||||
}
|
||||
|
||||
/** @deprecated Use {@link #setLivePresentationDelayMs(long, boolean)}. */
|
||||
@Deprecated
|
||||
@SuppressWarnings("deprecation")
|
||||
public Factory setLivePresentationDelayMs(long livePresentationDelayMs) {
|
||||
|
|
@ -194,11 +202,9 @@ public final class DashMediaSource extends BaseMediaSource {
|
|||
* @param overridesManifest Whether the value is used in preference to one in the manifest, if
|
||||
* present.
|
||||
* @return This factory, for convenience.
|
||||
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
||||
*/
|
||||
public Factory setLivePresentationDelayMs(
|
||||
long livePresentationDelayMs, boolean overridesManifest) {
|
||||
Assertions.checkState(!isCreateCalled);
|
||||
this.livePresentationDelayMs = livePresentationDelayMs;
|
||||
this.livePresentationDelayOverridesManifest = overridesManifest;
|
||||
return this;
|
||||
|
|
@ -209,12 +215,10 @@ public final class DashMediaSource extends BaseMediaSource {
|
|||
*
|
||||
* @param manifestParser A parser for loaded manifest data.
|
||||
* @return This factory, for convenience.
|
||||
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
||||
*/
|
||||
public Factory setManifestParser(
|
||||
ParsingLoadable.Parser<? extends DashManifest> manifestParser) {
|
||||
Assertions.checkState(!isCreateCalled);
|
||||
this.manifestParser = Assertions.checkNotNull(manifestParser);
|
||||
@Nullable ParsingLoadable.Parser<? extends DashManifest> manifestParser) {
|
||||
this.manifestParser = manifestParser;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -227,13 +231,13 @@ public final class DashMediaSource extends BaseMediaSource {
|
|||
* SequenceableLoader}s for when this media source loads data from multiple streams (video,
|
||||
* audio etc...).
|
||||
* @return This factory, for convenience.
|
||||
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
||||
*/
|
||||
public Factory setCompositeSequenceableLoaderFactory(
|
||||
CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory) {
|
||||
Assertions.checkState(!isCreateCalled);
|
||||
@Nullable CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory) {
|
||||
this.compositeSequenceableLoaderFactory =
|
||||
Assertions.checkNotNull(compositeSequenceableLoaderFactory);
|
||||
compositeSequenceableLoaderFactory != null
|
||||
? compositeSequenceableLoaderFactory
|
||||
: new DefaultCompositeSequenceableLoaderFactory();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -247,8 +251,7 @@ public final class DashMediaSource extends BaseMediaSource {
|
|||
*/
|
||||
public DashMediaSource createMediaSource(DashManifest manifest) {
|
||||
Assertions.checkArgument(!manifest.dynamic);
|
||||
isCreateCalled = true;
|
||||
if (streamKeys != null && !streamKeys.isEmpty()) {
|
||||
if (streamKeys != null) {
|
||||
manifest = manifest.copy(streamKeys);
|
||||
}
|
||||
return new DashMediaSource(
|
||||
|
|
@ -297,21 +300,6 @@ public final class DashMediaSource extends BaseMediaSource {
|
|||
return mediaSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link DrmSessionManager} to use for acquiring {@link DrmSession DrmSessions}. The
|
||||
* default value is {@link DrmSessionManager#DUMMY}.
|
||||
*
|
||||
* @param drmSessionManager The {@link DrmSessionManager}.
|
||||
* @return This factory, for convenience.
|
||||
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
||||
*/
|
||||
@Override
|
||||
public Factory setDrmSessionManager(DrmSessionManager<?> drmSessionManager) {
|
||||
Assertions.checkState(!isCreateCalled);
|
||||
this.drmSessionManager = drmSessionManager;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new {@link DashMediaSource} using the current parameters.
|
||||
*
|
||||
|
|
@ -320,7 +308,7 @@ public final class DashMediaSource extends BaseMediaSource {
|
|||
*/
|
||||
@Override
|
||||
public DashMediaSource createMediaSource(Uri manifestUri) {
|
||||
isCreateCalled = true;
|
||||
@Nullable ParsingLoadable.Parser<? extends DashManifest> manifestParser = this.manifestParser;
|
||||
if (manifestParser == null) {
|
||||
manifestParser = new DashManifestParser();
|
||||
}
|
||||
|
|
@ -341,13 +329,6 @@ public final class DashMediaSource extends BaseMediaSource {
|
|||
tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Factory setStreamKeys(List<StreamKey> streamKeys) {
|
||||
Assertions.checkState(!isCreateCalled);
|
||||
this.streamKeys = streamKeys;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getSupportedTypes() {
|
||||
return new int[] {C.TYPE_DASH};
|
||||
|
|
|
|||
|
|
@ -91,7 +91,6 @@ public final class HlsMediaSource extends BaseMediaSource
|
|||
|
||||
private HlsExtractorFactory extractorFactory;
|
||||
private HlsPlaylistParserFactory playlistParserFactory;
|
||||
@Nullable private List<StreamKey> streamKeys;
|
||||
private HlsPlaylistTracker.Factory playlistTrackerFactory;
|
||||
private CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
|
||||
private DrmSessionManager<?> drmSessionManager;
|
||||
|
|
@ -99,7 +98,7 @@ public final class HlsMediaSource extends BaseMediaSource
|
|||
private boolean allowChunklessPreparation;
|
||||
@MetadataType private int metadataType;
|
||||
private boolean useSessionKeys;
|
||||
private boolean isCreateCalled;
|
||||
@Nullable private List<StreamKey> streamKeys;
|
||||
@Nullable private Object tag;
|
||||
|
||||
/**
|
||||
|
|
@ -137,10 +136,8 @@ public final class HlsMediaSource extends BaseMediaSource
|
|||
*
|
||||
* @param tag A tag for the media source.
|
||||
* @return This factory, for convenience.
|
||||
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
||||
*/
|
||||
public Factory setTag(@Nullable Object tag) {
|
||||
Assertions.checkState(!isCreateCalled);
|
||||
this.tag = tag;
|
||||
return this;
|
||||
}
|
||||
|
|
@ -152,11 +149,10 @@ public final class HlsMediaSource extends BaseMediaSource
|
|||
* @param extractorFactory An {@link HlsExtractorFactory} for {@link Extractor}s for the
|
||||
* segments.
|
||||
* @return This factory, for convenience.
|
||||
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
||||
*/
|
||||
public Factory setExtractorFactory(HlsExtractorFactory extractorFactory) {
|
||||
Assertions.checkState(!isCreateCalled);
|
||||
this.extractorFactory = Assertions.checkNotNull(extractorFactory);
|
||||
public Factory setExtractorFactory(@Nullable HlsExtractorFactory extractorFactory) {
|
||||
this.extractorFactory =
|
||||
extractorFactory != null ? extractorFactory : HlsExtractorFactory.DEFAULT;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -168,30 +164,19 @@ public final class HlsMediaSource extends BaseMediaSource
|
|||
*
|
||||
* @param loadErrorHandlingPolicy A {@link LoadErrorHandlingPolicy}.
|
||||
* @return This factory, for convenience.
|
||||
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
||||
*/
|
||||
public Factory setLoadErrorHandlingPolicy(LoadErrorHandlingPolicy loadErrorHandlingPolicy) {
|
||||
Assertions.checkState(!isCreateCalled);
|
||||
this.loadErrorHandlingPolicy = loadErrorHandlingPolicy;
|
||||
public Factory setLoadErrorHandlingPolicy(
|
||||
@Nullable LoadErrorHandlingPolicy loadErrorHandlingPolicy) {
|
||||
this.loadErrorHandlingPolicy =
|
||||
loadErrorHandlingPolicy != null
|
||||
? loadErrorHandlingPolicy
|
||||
: new DefaultLoadErrorHandlingPolicy();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the minimum number of times to retry if a loading error occurs. The default value is
|
||||
* {@link DefaultLoadErrorHandlingPolicy#DEFAULT_MIN_LOADABLE_RETRY_COUNT}.
|
||||
*
|
||||
* <p>Calling this method is equivalent to calling {@link #setLoadErrorHandlingPolicy} with
|
||||
* {@link DefaultLoadErrorHandlingPolicy#DefaultLoadErrorHandlingPolicy(int)
|
||||
* DefaultLoadErrorHandlingPolicy(minLoadableRetryCount)}
|
||||
*
|
||||
* @param minLoadableRetryCount The minimum number of times to retry if a loading error occurs.
|
||||
* @return This factory, for convenience.
|
||||
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
||||
* @deprecated Use {@link #setLoadErrorHandlingPolicy(LoadErrorHandlingPolicy)} instead.
|
||||
*/
|
||||
/** @deprecated Use {@link #setLoadErrorHandlingPolicy(LoadErrorHandlingPolicy)} instead. */
|
||||
@Deprecated
|
||||
public Factory setMinLoadableRetryCount(int minLoadableRetryCount) {
|
||||
Assertions.checkState(!isCreateCalled);
|
||||
this.loadErrorHandlingPolicy = new DefaultLoadErrorHandlingPolicy(minLoadableRetryCount);
|
||||
return this;
|
||||
}
|
||||
|
|
@ -202,11 +187,13 @@ public final class HlsMediaSource extends BaseMediaSource
|
|||
*
|
||||
* @param playlistParserFactory An {@link HlsPlaylistParserFactory}.
|
||||
* @return This factory, for convenience.
|
||||
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
||||
*/
|
||||
public Factory setPlaylistParserFactory(HlsPlaylistParserFactory playlistParserFactory) {
|
||||
Assertions.checkState(!isCreateCalled);
|
||||
this.playlistParserFactory = Assertions.checkNotNull(playlistParserFactory);
|
||||
public Factory setPlaylistParserFactory(
|
||||
@Nullable HlsPlaylistParserFactory playlistParserFactory) {
|
||||
this.playlistParserFactory =
|
||||
playlistParserFactory != null
|
||||
? playlistParserFactory
|
||||
: new DefaultHlsPlaylistParserFactory();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -216,11 +203,13 @@ public final class HlsMediaSource extends BaseMediaSource
|
|||
*
|
||||
* @param playlistTrackerFactory A factory for {@link HlsPlaylistTracker} instances.
|
||||
* @return This factory, for convenience.
|
||||
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
||||
*/
|
||||
public Factory setPlaylistTrackerFactory(HlsPlaylistTracker.Factory playlistTrackerFactory) {
|
||||
Assertions.checkState(!isCreateCalled);
|
||||
this.playlistTrackerFactory = Assertions.checkNotNull(playlistTrackerFactory);
|
||||
public Factory setPlaylistTrackerFactory(
|
||||
@Nullable HlsPlaylistTracker.Factory playlistTrackerFactory) {
|
||||
this.playlistTrackerFactory =
|
||||
playlistTrackerFactory != null
|
||||
? playlistTrackerFactory
|
||||
: DefaultHlsPlaylistTracker.FACTORY;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -233,13 +222,13 @@ public final class HlsMediaSource extends BaseMediaSource
|
|||
* SequenceableLoader}s for when this media source loads data from multiple streams (video,
|
||||
* audio etc...).
|
||||
* @return This factory, for convenience.
|
||||
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
||||
*/
|
||||
public Factory setCompositeSequenceableLoaderFactory(
|
||||
CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory) {
|
||||
Assertions.checkState(!isCreateCalled);
|
||||
@Nullable CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory) {
|
||||
this.compositeSequenceableLoaderFactory =
|
||||
Assertions.checkNotNull(compositeSequenceableLoaderFactory);
|
||||
compositeSequenceableLoaderFactory != null
|
||||
? compositeSequenceableLoaderFactory
|
||||
: new DefaultCompositeSequenceableLoaderFactory();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -249,10 +238,8 @@ public final class HlsMediaSource extends BaseMediaSource
|
|||
*
|
||||
* @param allowChunklessPreparation Whether chunkless preparation is allowed.
|
||||
* @return This factory, for convenience.
|
||||
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
||||
*/
|
||||
public Factory setAllowChunklessPreparation(boolean allowChunklessPreparation) {
|
||||
Assertions.checkState(!isCreateCalled);
|
||||
this.allowChunklessPreparation = allowChunklessPreparation;
|
||||
return this;
|
||||
}
|
||||
|
|
@ -277,7 +264,6 @@ public final class HlsMediaSource extends BaseMediaSource
|
|||
* @return This factory, for convenience.
|
||||
*/
|
||||
public Factory setMetadataType(@MetadataType int metadataType) {
|
||||
Assertions.checkState(!isCreateCalled);
|
||||
this.metadataType = metadataType;
|
||||
return this;
|
||||
}
|
||||
|
|
@ -296,6 +282,28 @@ public final class HlsMediaSource extends BaseMediaSource
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link DrmSessionManager} to use for acquiring {@link DrmSession DrmSessions}. The
|
||||
* default value is {@link DrmSessionManager#DUMMY}.
|
||||
*
|
||||
* @param drmSessionManager The {@link DrmSessionManager}.
|
||||
* @return This factory, for convenience.
|
||||
*/
|
||||
@Override
|
||||
public Factory setDrmSessionManager(@Nullable DrmSessionManager<?> drmSessionManager) {
|
||||
this.drmSessionManager =
|
||||
drmSessionManager != null
|
||||
? drmSessionManager
|
||||
: DrmSessionManager.getDummyDrmSessionManager();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Factory setStreamKeys(@Nullable List<StreamKey> streamKeys) {
|
||||
this.streamKeys = streamKeys != null && !streamKeys.isEmpty() ? streamKeys : null;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #createMediaSource(Uri)} and {@link #addEventListener(Handler,
|
||||
* MediaSourceEventListener)} instead.
|
||||
|
|
@ -312,21 +320,6 @@ public final class HlsMediaSource extends BaseMediaSource
|
|||
return mediaSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link DrmSessionManager} to use for acquiring {@link DrmSession DrmSessions}. The
|
||||
* default value is {@link DrmSessionManager#DUMMY}.
|
||||
*
|
||||
* @param drmSessionManager The {@link DrmSessionManager}.
|
||||
* @return This factory, for convenience.
|
||||
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
||||
*/
|
||||
@Override
|
||||
public Factory setDrmSessionManager(DrmSessionManager<?> drmSessionManager) {
|
||||
Assertions.checkState(!isCreateCalled);
|
||||
this.drmSessionManager = drmSessionManager;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new {@link HlsMediaSource} using the current parameters.
|
||||
*
|
||||
|
|
@ -334,7 +327,7 @@ public final class HlsMediaSource extends BaseMediaSource
|
|||
*/
|
||||
@Override
|
||||
public HlsMediaSource createMediaSource(Uri playlistUri) {
|
||||
isCreateCalled = true;
|
||||
HlsPlaylistParserFactory playlistParserFactory = this.playlistParserFactory;
|
||||
if (streamKeys != null) {
|
||||
playlistParserFactory =
|
||||
new FilteringHlsPlaylistParserFactory(playlistParserFactory, streamKeys);
|
||||
|
|
@ -354,18 +347,10 @@ public final class HlsMediaSource extends BaseMediaSource
|
|||
tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Factory setStreamKeys(List<StreamKey> streamKeys) {
|
||||
Assertions.checkState(!isCreateCalled);
|
||||
this.streamKeys = streamKeys;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getSupportedTypes() {
|
||||
return new int[] {C.TYPE_HLS};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private final HlsExtractorFactory extractorFactory;
|
||||
|
|
|
|||
|
|
@ -69,13 +69,12 @@ public final class SsMediaSource extends BaseMediaSource
|
|||
private final SsChunkSource.Factory chunkSourceFactory;
|
||||
@Nullable private final DataSource.Factory manifestDataSourceFactory;
|
||||
|
||||
@Nullable private ParsingLoadable.Parser<? extends SsManifest> manifestParser;
|
||||
@Nullable private List<StreamKey> streamKeys;
|
||||
private CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
|
||||
private DrmSessionManager<?> drmSessionManager;
|
||||
private LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
||||
private long livePresentationDelayMs;
|
||||
private boolean isCreateCalled;
|
||||
@Nullable private ParsingLoadable.Parser<? extends SsManifest> manifestParser;
|
||||
@Nullable private List<StreamKey> streamKeys;
|
||||
@Nullable private Object tag;
|
||||
|
||||
/**
|
||||
|
|
@ -114,27 +113,13 @@ public final class SsMediaSource extends BaseMediaSource
|
|||
*
|
||||
* @param tag A tag for the media source.
|
||||
* @return This factory, for convenience.
|
||||
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
||||
*/
|
||||
public Factory setTag(@Nullable Object tag) {
|
||||
Assertions.checkState(!isCreateCalled);
|
||||
this.tag = tag;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the minimum number of times to retry if a loading error occurs. See {@link
|
||||
* #setLoadErrorHandlingPolicy} for the default value.
|
||||
*
|
||||
* <p>Calling this method is equivalent to calling {@link #setLoadErrorHandlingPolicy} with
|
||||
* {@link DefaultLoadErrorHandlingPolicy#DefaultLoadErrorHandlingPolicy(int)
|
||||
* DefaultLoadErrorHandlingPolicy(minLoadableRetryCount)}
|
||||
*
|
||||
* @param minLoadableRetryCount The minimum number of times to retry if a loading error occurs.
|
||||
* @return This factory, for convenience.
|
||||
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
||||
* @deprecated Use {@link #setLoadErrorHandlingPolicy(LoadErrorHandlingPolicy)} instead.
|
||||
*/
|
||||
/** @deprecated Use {@link #setLoadErrorHandlingPolicy(LoadErrorHandlingPolicy)} instead. */
|
||||
@Deprecated
|
||||
public Factory setMinLoadableRetryCount(int minLoadableRetryCount) {
|
||||
return setLoadErrorHandlingPolicy(new DefaultLoadErrorHandlingPolicy(minLoadableRetryCount));
|
||||
|
|
@ -148,11 +133,13 @@ public final class SsMediaSource extends BaseMediaSource
|
|||
*
|
||||
* @param loadErrorHandlingPolicy A {@link LoadErrorHandlingPolicy}.
|
||||
* @return This factory, for convenience.
|
||||
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
||||
*/
|
||||
public Factory setLoadErrorHandlingPolicy(LoadErrorHandlingPolicy loadErrorHandlingPolicy) {
|
||||
Assertions.checkState(!isCreateCalled);
|
||||
this.loadErrorHandlingPolicy = loadErrorHandlingPolicy;
|
||||
public Factory setLoadErrorHandlingPolicy(
|
||||
@Nullable LoadErrorHandlingPolicy loadErrorHandlingPolicy) {
|
||||
this.loadErrorHandlingPolicy =
|
||||
loadErrorHandlingPolicy != null
|
||||
? loadErrorHandlingPolicy
|
||||
: new DefaultLoadErrorHandlingPolicy();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -164,10 +151,8 @@ public final class SsMediaSource extends BaseMediaSource
|
|||
* @param livePresentationDelayMs For live playbacks, the duration in milliseconds by which the
|
||||
* default start position should precede the end of the live window.
|
||||
* @return This factory, for convenience.
|
||||
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
||||
*/
|
||||
public Factory setLivePresentationDelayMs(long livePresentationDelayMs) {
|
||||
Assertions.checkState(!isCreateCalled);
|
||||
this.livePresentationDelayMs = livePresentationDelayMs;
|
||||
return this;
|
||||
}
|
||||
|
|
@ -177,11 +162,10 @@ public final class SsMediaSource extends BaseMediaSource
|
|||
*
|
||||
* @param manifestParser A parser for loaded manifest data.
|
||||
* @return This factory, for convenience.
|
||||
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
||||
*/
|
||||
public Factory setManifestParser(ParsingLoadable.Parser<? extends SsManifest> manifestParser) {
|
||||
Assertions.checkState(!isCreateCalled);
|
||||
this.manifestParser = Assertions.checkNotNull(manifestParser);
|
||||
public Factory setManifestParser(
|
||||
@Nullable ParsingLoadable.Parser<? extends SsManifest> manifestParser) {
|
||||
this.manifestParser = manifestParser;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -194,13 +178,35 @@ public final class SsMediaSource extends BaseMediaSource
|
|||
* SequenceableLoader}s for when this media source loads data from multiple streams (video,
|
||||
* audio etc.).
|
||||
* @return This factory, for convenience.
|
||||
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
||||
*/
|
||||
public Factory setCompositeSequenceableLoaderFactory(
|
||||
CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory) {
|
||||
Assertions.checkState(!isCreateCalled);
|
||||
@Nullable CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory) {
|
||||
this.compositeSequenceableLoaderFactory =
|
||||
Assertions.checkNotNull(compositeSequenceableLoaderFactory);
|
||||
compositeSequenceableLoaderFactory != null
|
||||
? compositeSequenceableLoaderFactory
|
||||
: new DefaultCompositeSequenceableLoaderFactory();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link DrmSessionManager} to use for acquiring {@link DrmSession DrmSessions}. The
|
||||
* default value is {@link DrmSessionManager#DUMMY}.
|
||||
*
|
||||
* @param drmSessionManager The {@link DrmSessionManager}.
|
||||
* @return This factory, for convenience.
|
||||
*/
|
||||
@Override
|
||||
public Factory setDrmSessionManager(@Nullable DrmSessionManager<?> drmSessionManager) {
|
||||
this.drmSessionManager =
|
||||
drmSessionManager != null
|
||||
? drmSessionManager
|
||||
: DrmSessionManager.getDummyDrmSessionManager();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Factory setStreamKeys(List<StreamKey> streamKeys) {
|
||||
this.streamKeys = streamKeys != null && !streamKeys.isEmpty() ? streamKeys : null;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -214,8 +220,7 @@ public final class SsMediaSource extends BaseMediaSource
|
|||
*/
|
||||
public SsMediaSource createMediaSource(SsManifest manifest) {
|
||||
Assertions.checkArgument(!manifest.isLive);
|
||||
isCreateCalled = true;
|
||||
if (streamKeys != null && !streamKeys.isEmpty()) {
|
||||
if (streamKeys != null) {
|
||||
manifest = manifest.copy(streamKeys);
|
||||
}
|
||||
return new SsMediaSource(
|
||||
|
|
@ -263,21 +268,6 @@ public final class SsMediaSource extends BaseMediaSource
|
|||
return mediaSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link DrmSessionManager} to use for acquiring {@link DrmSession DrmSessions}. The
|
||||
* default value is {@link DrmSessionManager#DUMMY}.
|
||||
*
|
||||
* @param drmSessionManager The {@link DrmSessionManager}.
|
||||
* @return This factory, for convenience.
|
||||
* @throws IllegalStateException If one of the {@code create} methods has already been called.
|
||||
*/
|
||||
@Override
|
||||
public Factory setDrmSessionManager(DrmSessionManager<?> drmSessionManager) {
|
||||
Assertions.checkState(!isCreateCalled);
|
||||
this.drmSessionManager = drmSessionManager;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new {@link SsMediaSource} using the current parameters.
|
||||
*
|
||||
|
|
@ -286,7 +276,7 @@ public final class SsMediaSource extends BaseMediaSource
|
|||
*/
|
||||
@Override
|
||||
public SsMediaSource createMediaSource(Uri manifestUri) {
|
||||
isCreateCalled = true;
|
||||
@Nullable ParsingLoadable.Parser<? extends SsManifest> manifestParser = this.manifestParser;
|
||||
if (manifestParser == null) {
|
||||
manifestParser = new SsManifestParser();
|
||||
}
|
||||
|
|
@ -306,18 +296,10 @@ public final class SsMediaSource extends BaseMediaSource
|
|||
tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Factory setStreamKeys(List<StreamKey> streamKeys) {
|
||||
Assertions.checkState(!isCreateCalled);
|
||||
this.streamKeys = streamKeys;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getSupportedTypes() {
|
||||
return new int[] {C.TYPE_SS};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in a new issue