diff --git a/app/src/main/assets/scripts/source.js b/app/src/main/assets/scripts/source.js index f254370e45698321a61403866ac04d3876c52459..7e619b3e61d6882848ec08e80aff97832094f8e7 100644 --- a/app/src/main/assets/scripts/source.js +++ b/app/src/main/assets/scripts/source.js @@ -357,6 +357,15 @@ class AudioUrlSource { this.requestModifier = obj.requestModifier; } } +class AudioUrlWidevineSource extends AudioUrlSource { + constructor(obj) { + super(obj); + this.plugin_type = "AudioUrlWidevineSource"; + + this.bearerToken = obj.bearerToken; + this.licenseUri = obj.licenseUri; + } +} class AudioUrlRangeSource extends AudioUrlSource { constructor(obj) { super(obj); diff --git a/app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/IAudioUrlWidevineSource.kt b/app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/IAudioUrlWidevineSource.kt new file mode 100644 index 0000000000000000000000000000000000000000..311c5ed055fc88caa1f5db713d1ae0e8993ab6af --- /dev/null +++ b/app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/IAudioUrlWidevineSource.kt @@ -0,0 +1,6 @@ +package com.futo.platformplayer.api.media.models.streams.sources + +interface IAudioUrlWidevineSource : IAudioUrlSource { + val bearerToken: String + val licenseUri: String +} diff --git a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSAudioUrlWidevineSource.kt b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSAudioUrlWidevineSource.kt new file mode 100644 index 0000000000000000000000000000000000000000..dcacdb726de253e0f1867fb743c64bdf0a13a839 --- /dev/null +++ b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSAudioUrlWidevineSource.kt @@ -0,0 +1,24 @@ +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.getOrThrow + +class JSAudioUrlWidevineSource : JSAudioUrlSource, IAudioUrlWidevineSource { + override val bearerToken: String + override val licenseUri: String + + @Suppress("ConvertSecondaryConstructorToPrimary") + constructor(plugin: JSClient, obj: V8ValueObject) : super(plugin, obj) { + val contextName = "JSAudioUrlWidevineSource" + val config = plugin.config + bearerToken = _obj.getOrThrow(config, "bearerToken", contextName) + licenseUri = _obj.getOrThrow(config, "licenseUri", contextName) + } + + override fun toString(): String { + val url = getAudioUrl() + return "(name=$name, container=$container, bitrate=$bitrate, codec=$codec, url=$url, language=$language, duration=$duration, bearerToken=$bearerToken, licenseUri=$licenseUri)" + } +} diff --git a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSSource.kt b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSSource.kt index 9074e28e6952891c88910fa4a4b33e342d6c590a..862a53a5352e84ab8375c241180ac9b3aa2a6bfa 100644 --- a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSSource.kt +++ b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSSource.kt @@ -66,6 +66,7 @@ abstract class JSSource { const val TYPE_VIDEO_WITH_METADATA = "VideoUrlRangeSource"; const val TYPE_DASH = "DashSource"; const val TYPE_HLS = "HLSSource"; + const val TYPE_AUDIOURL_WIDEVINE = "AudioUrlWidevineSource" fun fromV8VideoNullable(plugin: JSClient, obj: V8Value?) : IVideoSource? = obj.orNull { fromV8Video(plugin, it as V8ValueObject) }; fun fromV8Video(plugin: JSClient, obj: V8ValueObject) : IVideoSource { @@ -88,6 +89,7 @@ abstract class JSSource { return when(type) { TYPE_HLS -> JSHLSManifestAudioSource.fromV8HLS(plugin, obj); TYPE_AUDIOURL -> JSAudioUrlSource(plugin, obj); + TYPE_AUDIOURL_WIDEVINE -> JSAudioUrlWidevineSource(plugin, obj); TYPE_AUDIO_WITH_METADATA -> JSAudioUrlRangeSource(plugin, obj); else -> throw NotImplementedError("Unknown type ${type}"); } diff --git a/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayerBase.kt b/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayerBase.kt index 3179e2829de0d0ba5ba32fe13e14f4d037aaad53..519ab6ecf205980702e6d2618bc44c527a232a97 100644 --- a/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayerBase.kt +++ b/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayerBase.kt @@ -16,6 +16,7 @@ import androidx.media3.datasource.DefaultDataSource import androidx.media3.datasource.DefaultHttpDataSource import androidx.media3.exoplayer.ExoPlayer import androidx.media3.exoplayer.dash.DashMediaSource +import androidx.media3.exoplayer.drm.DefaultDrmSessionManagerProvider import androidx.media3.exoplayer.hls.HlsMediaSource import androidx.media3.exoplayer.source.MediaSource import androidx.media3.exoplayer.source.MergingMediaSource @@ -27,6 +28,7 @@ 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.sources.IAudioSource 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.IHLSManifestAudioSource import com.futo.platformplayer.api.media.models.streams.sources.IHLSManifestSource @@ -389,6 +391,7 @@ abstract class FutoVideoPlayerBase : RelativeLayout { is LocalAudioSource -> swapAudioSourceLocal(audioSource); is JSAudioUrlRangeSource -> swapAudioSourceUrlRange(audioSource); is JSHLSManifestAudioSource -> swapAudioSourceHLS(audioSource); + is IAudioUrlWidevineSource -> swapAudioSourceUrlWidevine(audioSource) is IAudioUrlSource -> swapAudioSourceUrl(audioSource); null -> _lastAudioMediaSource = null; else -> throw IllegalArgumentException("Unsupported video source [${audioSource.javaClass.simpleName}]"); @@ -508,6 +511,31 @@ abstract class FutoVideoPlayerBase : RelativeLayout { .createMediaSource(MediaItem.fromUri(audioSource.url)); } + @OptIn(UnstableApi::class) + private fun swapAudioSourceUrlWidevine(audioSource: IAudioUrlWidevineSource) { + Logger.i(TAG, "Loading AudioSource [UrlWidevine]") + val dataSource = if (audioSource is JSSource && audioSource.hasRequestModifier) + audioSource.getHttpDataSourceFactory() + else + DefaultHttpDataSource.Factory().setUserAgent(DEFAULT_USER_AGENT) + + val httpRequestHeaders = mapOf("Authorization" to "Bearer " + audioSource.bearerToken) + val provider = DefaultDrmSessionManagerProvider() + provider.setDrmHttpDataSourceFactory(dataSource) + _lastAudioMediaSource = ProgressiveMediaSource.Factory(dataSource) + .setDrmSessionManagerProvider(provider) + .createMediaSource( + MediaItem.Builder() + .setUri(audioSource.getAudioUrl()).setDrmConfiguration( + MediaItem.DrmConfiguration.Builder(C.WIDEVINE_UUID) + .setLicenseUri(audioSource.licenseUri) + .setMultiSession(true) + .setLicenseRequestHeaders(httpRequestHeaders) + .build() + ).build() + ) + } + //Prefered source selection fun getPreferredVideoSource(video: IPlatformVideoDetails, targetPixels: Int = -1): IVideoSource? {