remove widevine specific swap functions from video player base

Changelog: changed
This commit is contained in:
Kai 2025-02-10 15:30:39 -06:00
parent be6bcb37ae
commit d80cba3833
No known key found for this signature in database
9 changed files with 116 additions and 253 deletions

View File

@ -365,16 +365,20 @@ class VideoUrlSource {
this.url = obj.url; this.url = obj.url;
if(obj.requestModifier) if(obj.requestModifier)
this.requestModifier = obj.requestModifier; this.requestModifier = obj.requestModifier;
// deprecated api conversion
if(obj.licenseUri)
this.drmLicenseUri = obj.licenseUri;
if(obj.drmLicenseUri)
this.drmLicenseUri = obj.drmLicenseUri;
if(obj.getLicenseRequestExecutor)
this.getLicenseRequestExecutor = obj.getLicenseRequestExecutor;
} }
} }
class VideoUrlWidevineSource extends VideoUrlSource { class VideoUrlWidevineSource extends VideoUrlSource {
constructor(obj) { constructor(obj) {
super(obj); super(obj);
this.plugin_type = "VideoUrlWidevineSource";
this.drmLicenseUri = obj.licenseUri;
if(obj.getLicenseRequestExecutor)
this.getLicenseRequestExecutor = obj.getLicenseRequestExecutor;
} }
} }
class VideoUrlRangeSource extends VideoUrlSource { class VideoUrlRangeSource extends VideoUrlSource {
@ -402,16 +406,6 @@ class AudioUrlSource {
this.language = obj.language ?? Language.UNKNOWN; this.language = obj.language ?? Language.UNKNOWN;
if(obj.requestModifier) if(obj.requestModifier)
this.requestModifier = obj.requestModifier; this.requestModifier = obj.requestModifier;
}
}
class AudioUrlWidevineSource extends AudioUrlSource {
constructor(obj) {
super(obj);
this.plugin_type = "AudioUrlWidevineSource";
this.drmLicenseUri = obj.licenseUri;
if(obj.getLicenseRequestExecutor)
this.getLicenseRequestExecutor = obj.getLicenseRequestExecutor;
// deprecated api conversion // deprecated api conversion
if(obj.bearerToken) { if(obj.bearerToken) {
@ -429,6 +423,19 @@ class AudioUrlWidevineSource extends AudioUrlSource {
} }
} }
} }
// deprecated api conversion
if(obj.licenseUri)
this.drmLicenseUri = obj.licenseUri;
if(obj.drmLicenseUri)
this.drmLicenseUri = obj.drmLicenseUri;
if(obj.getLicenseRequestExecutor)
this.getLicenseRequestExecutor = obj.getLicenseRequestExecutor;
}
}
class AudioUrlWidevineSource extends AudioUrlSource {
constructor(obj) {
super(obj);
} }
} }
class AudioUrlRangeSource extends AudioUrlSource { class AudioUrlRangeSource extends AudioUrlSource {
@ -471,16 +478,20 @@ class DashSource {
this.requestModifier = obj.requestModifier; this.requestModifier = obj.requestModifier;
if(obj.getRequestExecutor) if(obj.getRequestExecutor)
this.getRequestExecutor = obj.getRequestExecutor; this.getRequestExecutor = obj.getRequestExecutor;
// deprecated api conversion
if(obj.licenseUri)
this.drmLicenseUri = obj.licenseUri;
if(obj.drmLicenseUri)
this.drmLicenseUri = obj.drmLicenseUri;
if(obj.getLicenseRequestExecutor)
this.getLicenseRequestExecutor = obj.getLicenseRequestExecutor;
} }
} }
class DashWidevineSource extends DashSource { class DashWidevineSource extends DashSource {
constructor(obj) { constructor(obj) {
super(obj); super(obj);
this.plugin_type = "DashWidevineSource";
this.drmLicenseUri = obj.licenseUri;
if(obj.getLicenseRequestExecutor)
this.getLicenseRequestExecutor = obj.getLicenseRequestExecutor;
} }
} }
class DashManifestRawSource { class DashManifestRawSource {
@ -513,6 +524,8 @@ class DashManifestRawAudioSource {
this.manifest = obj.manifest ?? null; this.manifest = obj.manifest ?? null;
if(obj.requestModifier) if(obj.requestModifier)
this.requestModifier = obj.requestModifier; this.requestModifier = obj.requestModifier;
if(obj.drmLicenseUri)
this.drmLicenseUri = obj.drmLicenseUri; this.drmLicenseUri = obj.drmLicenseUri;
if(obj.getLicenseRequestExecutor) if(obj.getLicenseRequestExecutor)
this.getLicenseRequestExecutor = obj.getLicenseRequestExecutor; this.getLicenseRequestExecutor = obj.getLicenseRequestExecutor;

View File

@ -1,3 +0,0 @@
package com.futo.platformplayer.api.media.models.streams.sources
interface IAudioUrlWidevineSource : IAudioUrlSource

View File

@ -1,5 +0,0 @@
package com.futo.platformplayer.api.media.models.streams.sources
interface IDashManifestWidevineSource {
val url: String
}

View File

@ -1,3 +0,0 @@
package com.futo.platformplayer.api.media.models.streams.sources
interface IVideoUrlWidevineSource : IVideoUrlSource

View File

@ -1,21 +0,0 @@
package com.futo.platformplayer.api.media.platforms.js.models.sources
import com.caoccao.javet.values.reference.V8ValueObject
import com.futo.platformplayer.api.media.models.streams.sources.IAudioUrlWidevineSource
import com.futo.platformplayer.api.media.platforms.js.JSClient
import com.futo.platformplayer.api.media.platforms.js.models.JSRequestExecutor
import com.futo.platformplayer.engine.V8Plugin
import com.futo.platformplayer.getOrThrow
class JSAudioUrlWidevineSource : JSAudioUrlSource, IAudioUrlWidevineSource {
@Suppress("ConvertSecondaryConstructorToPrimary")
constructor(plugin: JSClient, obj: V8ValueObject) : super(plugin, obj) {
val contextName = "JSAudioUrlWidevineSource"
val config = plugin.config
}
override fun toString(): String {
val url = getAudioUrl()
return "(name=$name, container=$container, bitrate=$bitrate, codec=$codec, url=$url, language=$language, duration=$duration, hasLicenseRequestExecutor=${hasLicenseRequestExecutor}, drmLicenseUri=$drmLicenseUri)"
}
}

View File

@ -1,40 +0,0 @@
package com.futo.platformplayer.api.media.platforms.js.models.sources
import com.caoccao.javet.values.reference.V8ValueObject
import com.futo.platformplayer.api.media.models.streams.sources.IDashManifestSource
import com.futo.platformplayer.api.media.models.streams.sources.IDashManifestWidevineSource
import com.futo.platformplayer.api.media.models.streams.sources.IVideoUrlSource
import com.futo.platformplayer.api.media.platforms.js.JSClient
import com.futo.platformplayer.api.media.platforms.js.models.JSRequestExecutor
import com.futo.platformplayer.engine.V8Plugin
import com.futo.platformplayer.getOrNull
import com.futo.platformplayer.getOrThrow
class JSDashManifestWidevineSource : IVideoUrlSource, IDashManifestSource,
IDashManifestWidevineSource, JSSource {
override val width: Int = 0
override val height: Int = 0
override val container: String = "application/dash+xml"
override val codec: String = "Dash"
override val name: String
override val bitrate: Int? = null
override val url: String
override val duration: Long
override var priority: Boolean = false
@Suppress("ConvertSecondaryConstructorToPrimary")
constructor(plugin: JSClient, obj: V8ValueObject) : super(TYPE_DASH, plugin, obj) {
val contextName = "DashWidevineSource"
val config = plugin.config
name = _obj.getOrThrow(config, "name", contextName)
url = _obj.getOrThrow(config, "url", contextName)
duration = _obj.getOrThrow(config, "duration", contextName)
priority = obj.getOrNull(config, "priority", contextName) ?: false
}
override fun getVideoUrl(): String {
return url
}
}

View File

@ -53,7 +53,7 @@ abstract class JSSource {
} }
hasRequestExecutor = _requestExecutor != null || obj.has("getRequestExecutor"); hasRequestExecutor = _requestExecutor != null || obj.has("getRequestExecutor");
drmLicenseUri = _obj.getOrThrow(_config, "drmLicenseUri", "JSSource.drmLicenseUri") drmLicenseUri = _obj.getOrDefault(_config, "drmLicenseUri", "JSSource.drmLicenseUri", null)
hasLicenseRequestExecutor = obj.has("getLicenseRequestExecutor") hasLicenseRequestExecutor = obj.has("getLicenseRequestExecutor")
} }
@ -115,22 +115,17 @@ abstract class JSSource {
const val TYPE_AUDIO_WITH_METADATA = "AudioUrlRangeSource"; const val TYPE_AUDIO_WITH_METADATA = "AudioUrlRangeSource";
const val TYPE_VIDEO_WITH_METADATA = "VideoUrlRangeSource"; const val TYPE_VIDEO_WITH_METADATA = "VideoUrlRangeSource";
const val TYPE_DASH = "DashSource"; const val TYPE_DASH = "DashSource";
const val TYPE_DASH_WIDEVINE = "DashWidevineSource";
const val TYPE_DASH_RAW = "DashRawSource"; const val TYPE_DASH_RAW = "DashRawSource";
const val TYPE_DASH_RAW_AUDIO = "DashRawAudioSource"; const val TYPE_DASH_RAW_AUDIO = "DashRawAudioSource";
const val TYPE_HLS = "HLSSource"; const val TYPE_HLS = "HLSSource";
const val TYPE_AUDIOURL_WIDEVINE = "AudioUrlWidevineSource"
const val TYPE_VIDEOURL_WIDEVINE = "VideoUrlWidevineSource"
fun fromV8VideoNullable(plugin: JSClient, obj: V8Value?) : IVideoSource? = obj.orNull { fromV8Video(plugin, it as V8ValueObject) }; fun fromV8VideoNullable(plugin: JSClient, obj: V8Value?) : IVideoSource? = obj.orNull { fromV8Video(plugin, it as V8ValueObject) };
fun fromV8Video(plugin: JSClient, obj: V8ValueObject) : IVideoSource? { fun fromV8Video(plugin: JSClient, obj: V8ValueObject) : IVideoSource? {
val type = obj.getString("plugin_type"); val type = obj.getString("plugin_type");
return when(type) { return when(type) {
TYPE_VIDEOURL -> JSVideoUrlSource(plugin, obj); TYPE_VIDEOURL -> JSVideoUrlSource(plugin, obj);
TYPE_VIDEOURL_WIDEVINE -> JSVideoUrlWidevineSource(plugin, obj);
TYPE_VIDEO_WITH_METADATA -> JSVideoUrlRangeSource(plugin, obj); TYPE_VIDEO_WITH_METADATA -> JSVideoUrlRangeSource(plugin, obj);
TYPE_HLS -> fromV8HLS(plugin, obj); TYPE_HLS -> fromV8HLS(plugin, obj);
TYPE_DASH_WIDEVINE -> JSDashManifestWidevineSource(plugin, obj)
TYPE_DASH -> fromV8Dash(plugin, obj); TYPE_DASH -> fromV8Dash(plugin, obj);
TYPE_DASH_RAW -> fromV8DashRaw(plugin, obj); TYPE_DASH_RAW -> fromV8DashRaw(plugin, obj);
else -> { else -> {
@ -152,7 +147,6 @@ abstract class JSSource {
TYPE_HLS -> JSHLSManifestAudioSource.fromV8HLS(plugin, obj); TYPE_HLS -> JSHLSManifestAudioSource.fromV8HLS(plugin, obj);
TYPE_AUDIOURL -> JSAudioUrlSource(plugin, obj); TYPE_AUDIOURL -> JSAudioUrlSource(plugin, obj);
TYPE_DASH_RAW_AUDIO -> fromV8DashRawAudio(plugin, obj); TYPE_DASH_RAW_AUDIO -> fromV8DashRawAudio(plugin, obj);
TYPE_AUDIOURL_WIDEVINE -> JSAudioUrlWidevineSource(plugin, obj);
TYPE_AUDIO_WITH_METADATA -> JSAudioUrlRangeSource(plugin, obj); TYPE_AUDIO_WITH_METADATA -> JSAudioUrlRangeSource(plugin, obj);
else -> { else -> {
Logger.w("JSSource", "Unknown audio type ${type}"); Logger.w("JSSource", "Unknown audio type ${type}");

View File

@ -1,21 +0,0 @@
package com.futo.platformplayer.api.media.platforms.js.models.sources
import com.caoccao.javet.values.reference.V8ValueObject
import com.futo.platformplayer.api.media.models.streams.sources.IVideoUrlWidevineSource
import com.futo.platformplayer.api.media.platforms.js.JSClient
import com.futo.platformplayer.api.media.platforms.js.models.JSRequestExecutor
import com.futo.platformplayer.engine.V8Plugin
import com.futo.platformplayer.getOrThrow
class JSVideoUrlWidevineSource : JSVideoUrlSource, IVideoUrlWidevineSource {
@Suppress("ConvertSecondaryConstructorToPrimary")
constructor(plugin: JSClient, obj: V8ValueObject) : super(plugin, obj) {
val contextName = "JSAudioUrlWidevineSource"
val config = plugin.config
}
override fun toString(): String {
val url = getVideoUrl()
return "(width=$width, height=$height, container=$container, codec=$codec, name=$name, bitrate=$bitrate, duration=$duration, url=$url, hasLicenseRequestExecutor=$hasLicenseRequestExecutor, drmLicenseUri=$drmLicenseUri)"
}
}

View File

@ -23,6 +23,7 @@ import androidx.media3.exoplayer.dash.DashMediaSource
import androidx.media3.exoplayer.dash.manifest.DashManifestParser import androidx.media3.exoplayer.dash.manifest.DashManifestParser
import androidx.media3.exoplayer.drm.DefaultDrmSessionManager import androidx.media3.exoplayer.drm.DefaultDrmSessionManager
import androidx.media3.exoplayer.drm.HttpMediaDrmCallback import androidx.media3.exoplayer.drm.HttpMediaDrmCallback
import androidx.media3.exoplayer.drm.MediaDrmCallback
import androidx.media3.exoplayer.hls.HlsMediaSource import androidx.media3.exoplayer.hls.HlsMediaSource
import androidx.media3.exoplayer.source.MediaSource import androidx.media3.exoplayer.source.MediaSource
import androidx.media3.exoplayer.source.MergingMediaSource import androidx.media3.exoplayer.source.MergingMediaSource
@ -34,14 +35,11 @@ import com.futo.platformplayer.api.media.models.chapters.IChapter
import com.futo.platformplayer.api.media.models.streams.VideoMuxedSourceDescriptor import com.futo.platformplayer.api.media.models.streams.VideoMuxedSourceDescriptor
import com.futo.platformplayer.api.media.models.streams.sources.IAudioSource import com.futo.platformplayer.api.media.models.streams.sources.IAudioSource
import com.futo.platformplayer.api.media.models.streams.sources.IAudioUrlSource import com.futo.platformplayer.api.media.models.streams.sources.IAudioUrlSource
import com.futo.platformplayer.api.media.models.streams.sources.IAudioUrlWidevineSource
import com.futo.platformplayer.api.media.models.streams.sources.IDashManifestSource import com.futo.platformplayer.api.media.models.streams.sources.IDashManifestSource
import com.futo.platformplayer.api.media.models.streams.sources.IDashManifestWidevineSource
import com.futo.platformplayer.api.media.models.streams.sources.IHLSManifestAudioSource import com.futo.platformplayer.api.media.models.streams.sources.IHLSManifestAudioSource
import com.futo.platformplayer.api.media.models.streams.sources.IHLSManifestSource import com.futo.platformplayer.api.media.models.streams.sources.IHLSManifestSource
import com.futo.platformplayer.api.media.models.streams.sources.IVideoSource import com.futo.platformplayer.api.media.models.streams.sources.IVideoSource
import com.futo.platformplayer.api.media.models.streams.sources.IVideoUrlSource import com.futo.platformplayer.api.media.models.streams.sources.IVideoUrlSource
import com.futo.platformplayer.api.media.models.streams.sources.IVideoUrlWidevineSource
import com.futo.platformplayer.api.media.models.streams.sources.LocalAudioSource import com.futo.platformplayer.api.media.models.streams.sources.LocalAudioSource
import com.futo.platformplayer.api.media.models.streams.sources.LocalVideoSource import com.futo.platformplayer.api.media.models.streams.sources.LocalVideoSource
import com.futo.platformplayer.api.media.models.subtitles.ISubtitleSource import com.futo.platformplayer.api.media.models.subtitles.ISubtitleSource
@ -413,11 +411,9 @@ abstract class FutoVideoPlayerBase : RelativeLayout {
val didSet = when(videoSource) { val didSet = when(videoSource) {
is LocalVideoSource -> { swapVideoSourceLocal(videoSource); true; } is LocalVideoSource -> { swapVideoSourceLocal(videoSource); true; }
is JSVideoUrlRangeSource -> { swapVideoSourceUrlRange(videoSource); true; } is JSVideoUrlRangeSource -> { swapVideoSourceUrlRange(videoSource); true; }
is IDashManifestWidevineSource -> { swapVideoSourceDashWidevine(videoSource); true }
is IDashManifestSource -> { swapVideoSourceDash(videoSource); true;} is IDashManifestSource -> { swapVideoSourceDash(videoSource); true;}
is JSDashManifestRawSource -> swapVideoSourceDashRaw(videoSource, play, resume); is JSDashManifestRawSource -> swapVideoSourceDashRaw(videoSource, play, resume)
is IHLSManifestSource -> { swapVideoSourceHLS(videoSource); true; } is IHLSManifestSource -> { swapVideoSourceHLS(videoSource); true; }
is IVideoUrlWidevineSource -> { swapVideoSourceUrlWidevine(videoSource); true; }
is IVideoUrlSource -> { swapVideoSourceUrl(videoSource); true; } is IVideoUrlSource -> { swapVideoSourceUrl(videoSource); true; }
null -> { _lastVideoMediaSource = null; true;} null -> { _lastVideoMediaSource = null; true;}
else -> throw IllegalArgumentException("Unsupported video source [${videoSource.javaClass.simpleName}]"); else -> throw IllegalArgumentException("Unsupported video source [${videoSource.javaClass.simpleName}]");
@ -430,8 +426,7 @@ abstract class FutoVideoPlayerBase : RelativeLayout {
is LocalAudioSource -> {swapAudioSourceLocal(audioSource); true; } is LocalAudioSource -> {swapAudioSourceLocal(audioSource); true; }
is JSAudioUrlRangeSource -> { swapAudioSourceUrlRange(audioSource); true; } is JSAudioUrlRangeSource -> { swapAudioSourceUrlRange(audioSource); true; }
is JSHLSManifestAudioSource -> { swapAudioSourceHLS(audioSource); true; } is JSHLSManifestAudioSource -> { swapAudioSourceHLS(audioSource); true; }
is JSDashManifestRawAudioSource -> swapAudioSourceDashRaw(audioSource, play, resume); is JSDashManifestRawAudioSource -> swapAudioSourceDashRaw(audioSource, play, resume)
is IAudioUrlWidevineSource -> { swapAudioSourceUrlWidevine(audioSource); true; }
is IAudioUrlSource -> { swapAudioSourceUrl(audioSource); true; } is IAudioUrlSource -> { swapAudioSourceUrl(audioSource); true; }
null -> { _lastAudioMediaSource = null; true; } null -> { _lastAudioMediaSource = null; true; }
else -> throw IllegalArgumentException("Unsupported video source [${audioSource.javaClass.simpleName}]"); else -> throw IllegalArgumentException("Unsupported video source [${audioSource.javaClass.simpleName}]");
@ -471,6 +466,7 @@ abstract class FutoVideoPlayerBase : RelativeLayout {
} }
else throw IllegalArgumentException("source without itag data..."); else throw IllegalArgumentException("source without itag data...");
} }
@OptIn(UnstableApi::class) @OptIn(UnstableApi::class)
private fun swapVideoSourceUrl(videoSource: IVideoUrlSource) { private fun swapVideoSourceUrl(videoSource: IVideoUrlSource) {
Logger.i(TAG, "Loading VideoSource [Url]"); Logger.i(TAG, "Loading VideoSource [Url]");
@ -478,40 +474,22 @@ abstract class FutoVideoPlayerBase : RelativeLayout {
videoSource.getHttpDataSourceFactory() videoSource.getHttpDataSourceFactory()
else else
DefaultHttpDataSource.Factory().setUserAgent(DEFAULT_USER_AGENT); DefaultHttpDataSource.Factory().setUserAgent(DEFAULT_USER_AGENT);
_lastVideoMediaSource = ProgressiveMediaSource.Factory(dataSource)
.createMediaSource(MediaItem.fromUri(videoSource.getVideoUrl()));
}
@OptIn(UnstableApi::class)
private fun swapVideoSourceUrlWidevine(videoSource: IVideoUrlWidevineSource) {
Logger.i(TAG, "Loading VideoSource [UrlWidevine]");
if (!MediaDrm.isCryptoSchemeSupported(C.WIDEVINE_UUID)) { val drmCallback = if (videoSource is JSSource) getDrmCallback(videoSource, dataSource) else null
throw IllegalArgumentException("Device does not support Widevine")
}
val dataSource = if(videoSource is JSSource && videoSource.requiresCustomDatasource) val factory = ProgressiveMediaSource.Factory(dataSource)
videoSource.getHttpDataSourceFactory() if (drmCallback != null) {
else factory.setDrmSessionManagerProvider {
DefaultHttpDataSource.Factory().setUserAgent(DEFAULT_USER_AGENT)
val baseCallback = HttpMediaDrmCallback((videoSource as JSSource).drmLicenseUri, dataSource)
val callback = if (videoSource.hasLicenseRequestExecutor) {
PluginMediaDrmCallback(baseCallback, videoSource.getLicenseRequestExecutor()!!, videoSource.drmLicenseUri!!)
} else {
baseCallback
}
_lastVideoMediaSource = ProgressiveMediaSource.Factory(dataSource)
.setDrmSessionManagerProvider {
DefaultDrmSessionManager.Builder() DefaultDrmSessionManager.Builder()
.setMultiSession(true) .setMultiSession(true)
.build(callback) .build(drmCallback)
} }
.createMediaSource(
MediaItem.fromUri(videoSource.getVideoUrl())
)
} }
_lastVideoMediaSource = factory
.createMediaSource(MediaItem.fromUri(videoSource.getVideoUrl()));
}
@OptIn(UnstableApi::class) @OptIn(UnstableApi::class)
private fun swapVideoSourceDash(videoSource: IDashManifestSource) { private fun swapVideoSourceDash(videoSource: IDashManifestSource) {
Logger.i(TAG, "Loading VideoSource [Dash]"); Logger.i(TAG, "Loading VideoSource [Dash]");
@ -519,32 +497,19 @@ abstract class FutoVideoPlayerBase : RelativeLayout {
videoSource.getHttpDataSourceFactory() videoSource.getHttpDataSourceFactory()
else else
DefaultHttpDataSource.Factory().setUserAgent(DEFAULT_USER_AGENT); DefaultHttpDataSource.Factory().setUserAgent(DEFAULT_USER_AGENT);
_lastVideoMediaSource = DashMediaSource.Factory(dataSource)
.createMediaSource(MediaItem.fromUri(videoSource.url))
}
@OptIn(UnstableApi::class)
private fun swapVideoSourceDashWidevine(videoSource: IDashManifestWidevineSource) {
Logger.i(TAG, "Loading VideoSource [DashWidevine]")
if (!MediaDrm.isCryptoSchemeSupported(C.WIDEVINE_UUID)) { val drmCallback =
throw IllegalArgumentException("Device does not support Widevine") if (videoSource is JSSource) getDrmCallback(videoSource, dataSource) else null
val factory = DashMediaSource.Factory(dataSource)
if (drmCallback != null) {
factory.setDrmSessionManagerProvider {
DefaultDrmSessionManager.Builder().setMultiSession(true).build(drmCallback)
}
} }
val dataSource = _lastVideoMediaSource =
if (videoSource is JSSource && (videoSource.requiresCustomDatasource)) videoSource.getHttpDataSourceFactory() factory.createMediaSource(MediaItem.fromUri(videoSource.url))
else DefaultHttpDataSource.Factory().setUserAgent(DEFAULT_USER_AGENT)
val baseCallback = HttpMediaDrmCallback((videoSource as JSSource).drmLicenseUri, dataSource)
val callback = if (videoSource.hasLicenseRequestExecutor) {
PluginMediaDrmCallback(baseCallback, videoSource.getLicenseRequestExecutor()!!, videoSource.drmLicenseUri!!)
} else {
baseCallback
}
_lastVideoMediaSource = DashMediaSource.Factory(dataSource).setDrmSessionManagerProvider {
DefaultDrmSessionManager.Builder().setMultiSession(true).build(callback)
}.createMediaSource(MediaItem.fromUri(videoSource.url))
} }
@OptIn(UnstableApi::class) @OptIn(UnstableApi::class)
private fun swapVideoSourceDashRaw(videoSource: JSDashManifestRawSource, play: Boolean, resume: Boolean): Boolean { private fun swapVideoSourceDashRaw(videoSource: JSDashManifestRawSource, play: Boolean, resume: Boolean): Boolean {
@ -639,6 +604,7 @@ abstract class FutoVideoPlayerBase : RelativeLayout {
} }
else throw IllegalArgumentException("source without itag data...") else throw IllegalArgumentException("source without itag data...")
} }
@OptIn(UnstableApi::class) @OptIn(UnstableApi::class)
private fun swapAudioSourceUrl(audioSource: IAudioUrlSource) { private fun swapAudioSourceUrl(audioSource: IAudioUrlSource) {
Logger.i(TAG, "Loading AudioSource [Url]"); Logger.i(TAG, "Loading AudioSource [Url]");
@ -646,8 +612,20 @@ abstract class FutoVideoPlayerBase : RelativeLayout {
audioSource.getHttpDataSourceFactory() audioSource.getHttpDataSourceFactory()
else else
DefaultHttpDataSource.Factory().setUserAgent(DEFAULT_USER_AGENT); DefaultHttpDataSource.Factory().setUserAgent(DEFAULT_USER_AGENT);
_lastAudioMediaSource = ProgressiveMediaSource.Factory(dataSource)
.createMediaSource(MediaItem.fromUri(audioSource.getAudioUrl())); val drmCallback =
if (audioSource is JSSource) getDrmCallback(audioSource, dataSource) else null
val factory = ProgressiveMediaSource.Factory(dataSource)
if (drmCallback != null) {
factory.setDrmSessionManagerProvider {
DefaultDrmSessionManager.Builder()
.setMultiSession(true)
.build(drmCallback)
}
}
_lastAudioMediaSource =
factory.createMediaSource(MediaItem.fromUri(audioSource.getAudioUrl()));
} }
@OptIn(UnstableApi::class) @OptIn(UnstableApi::class)
private fun swapAudioSourceHLS(audioSource: IHLSManifestAudioSource) { private fun swapAudioSourceHLS(audioSource: IHLSManifestAudioSource) {
@ -662,102 +640,73 @@ abstract class FutoVideoPlayerBase : RelativeLayout {
@OptIn(UnstableApi::class) @OptIn(UnstableApi::class)
private fun swapAudioSourceDashRaw(audioSource: JSDashManifestRawAudioSource, play: Boolean, resume: Boolean): Boolean { private fun swapAudioSourceDashRaw(audioSource: JSDashManifestRawAudioSource, play: Boolean, resume: Boolean): Boolean {
Logger.i(TAG, "Loading AudioSource [DashRaw]") Logger.i(TAG, "Loading AudioSource [DashRaw]");
val dataSource = if (audioSource.requiresCustomDatasource) val dataSource = if (audioSource.requiresCustomDatasource)
audioSource.getHttpDataSourceFactory() audioSource.getHttpDataSourceFactory()
else else
DefaultHttpDataSource.Factory().setUserAgent(DEFAULT_USER_AGENT) DefaultHttpDataSource.Factory().setUserAgent(DEFAULT_USER_AGENT);
val baseCallback = HttpMediaDrmCallback(audioSource.drmLicenseUri, dataSource) val drmCallback = getDrmCallback(audioSource, dataSource)
val callback =
if (audioSource.hasLicenseRequestExecutor && audioSource.drmLicenseUri != null) {
PluginMediaDrmCallback(baseCallback, audioSource.getLicenseRequestExecutor()!!, audioSource.drmLicenseUri)
} else {
baseCallback
}
_lastVideoMediaSource = DashMediaSource.Factory(dataSource).setDrmSessionManagerProvider {
DefaultDrmSessionManager.Builder().setMultiSession(true).build(callback)
}.createMediaSource(MediaItem.fromUri(audioSource.url))
if (audioSource.hasGenerate) { if (audioSource.hasGenerate) {
findViewTreeLifecycleOwner()?.lifecycle?.coroutineScope?.launch(Dispatchers.IO) { findViewTreeLifecycleOwner()?.lifecycle?.coroutineScope?.launch(Dispatchers.IO) {
val generated = audioSource.generate() val generated = audioSource.generate();
if (generated != null) { if (generated != null) {
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
val factory = DashMediaSource.Factory(dataSource) val factory = DashMediaSource.Factory(dataSource)
if (audioSource.drmLicenseUri != null) { if (drmCallback != null) {
if (!MediaDrm.isCryptoSchemeSupported(C.WIDEVINE_UUID)) {
throw IllegalArgumentException("Device does not support Widevine")
}
factory.setDrmSessionManagerProvider { factory.setDrmSessionManagerProvider {
DefaultDrmSessionManager.Builder().setMultiSession(true) DefaultDrmSessionManager.Builder().setMultiSession(true)
.build(callback) .build(drmCallback)
} }
} }
_lastVideoMediaSource = factory.createMediaSource( _lastVideoMediaSource = factory
.createMediaSource(
DashManifestParser().parse( DashManifestParser().parse(
Uri.parse(audioSource.url), Uri.parse(audioSource.url),
ByteArrayInputStream(generated.toByteArray() ?: ByteArray(0)) ByteArrayInputStream(generated.toByteArray() ?: ByteArray(0))
) )
) );
loadSelectedSources(play, resume) loadSelectedSources(play, resume);
} }
} }
} }
return false return false;
} else { } else {
val factory = DashMediaSource.Factory(dataSource) val factory = DashMediaSource.Factory(dataSource)
if (audioSource.drmLicenseUri != null) { if (drmCallback != null) {
if (!MediaDrm.isCryptoSchemeSupported(C.WIDEVINE_UUID)) {
throw IllegalArgumentException("Device does not support Widevine")
}
factory.setDrmSessionManagerProvider { factory.setDrmSessionManagerProvider {
DefaultDrmSessionManager.Builder().setMultiSession(true) DefaultDrmSessionManager.Builder().setMultiSession(true)
.build(callback) .build(drmCallback)
} }
} }
_lastVideoMediaSource = factory.createMediaSource( _lastVideoMediaSource = factory
.createMediaSource(
DashManifestParser().parse( DashManifestParser().parse(
Uri.parse(audioSource.url), Uri.parse(audioSource.url),
ByteArrayInputStream(audioSource.manifest?.toByteArray() ?: ByteArray(0)) ByteArrayInputStream(audioSource.manifest?.toByteArray() ?: ByteArray(0))
) )
) );
return true return true;
} }
} }
@OptIn(UnstableApi::class) @OptIn(UnstableApi::class)
private fun swapAudioSourceUrlWidevine(audioSource: IAudioUrlWidevineSource) { private fun getDrmCallback(source: JSSource, dataSource: HttpDataSource.Factory): MediaDrmCallback? {
Logger.i(TAG, "Loading AudioSource [UrlWidevine]") return if (source.drmLicenseUri != null) {
if (!MediaDrm.isCryptoSchemeSupported(C.WIDEVINE_UUID)) { if (!MediaDrm.isCryptoSchemeSupported(C.WIDEVINE_UUID)) {
throw IllegalArgumentException("Device does not support Widevine") throw IllegalArgumentException("Device does not support Widevine")
} }
val dataSource = if (audioSource is JSSource && audioSource.requiresCustomDatasource) val delegateCallback =
audioSource.getHttpDataSourceFactory() HttpMediaDrmCallback(source.drmLicenseUri, dataSource)
else
DefaultHttpDataSource.Factory().setUserAgent(DEFAULT_USER_AGENT)
val baseCallback = HttpMediaDrmCallback((audioSource as JSSource).drmLicenseUri, dataSource) if (source.hasLicenseRequestExecutor) {
PluginMediaDrmCallback(delegateCallback, source.getLicenseRequestExecutor()!!, source.drmLicenseUri)
val callback = if (audioSource.hasLicenseRequestExecutor) {
PluginMediaDrmCallback(baseCallback, audioSource.getLicenseRequestExecutor()!!, audioSource.drmLicenseUri!!)
} else { } else {
baseCallback delegateCallback
} }
} else null
_lastAudioMediaSource = ProgressiveMediaSource.Factory(dataSource)
.setDrmSessionManagerProvider {
DefaultDrmSessionManager.Builder()
.setMultiSession(true)
.build(callback)
}
.createMediaSource(
MediaItem.fromUri(audioSource.getAudioUrl())
)
} }
//Prefered source selection //Prefered source selection