diff --git a/CHANGELOG.md b/CHANGELOG.md index edd3c01e9..6b9c20a60 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Added +- Added Android support for `ABRConfiguration.preferredMaximumResolution`, mirroring the existing iOS behaviour. Set to `(0,0)` to remove the cap. - Added basic support for CMCD event mode reporting of DRM and ad events. - Added bridging of the `hlsDateRange` property from `PlayerConfiguration` to Android's `THEOplayerConfig`. diff --git a/android/build.gradle b/android/build.gradle index 88c71ab9e..c76f121db 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -126,8 +126,8 @@ repositories { mavenLocal() } -// The minimum supported THEOplayer version is 11.4.0 -def theoVersion = safeExtGet('THEOplayer_sdk', '[11.4.0, 12.0.0)') +// The minimum supported THEOplayer version is 11.5.0 +def theoVersion = safeExtGet('THEOplayer_sdk', '[11.5.0, 12.0.0)') def theoMediaSessionVersion = safeExtGet('THEOplayer_mediasession', '[11.0.0, 12.0.0)') def theoAdsWrapperVersion = "11.0.0" def coroutinesVersion = safeExtGet('coroutinesVersion', '1.10.2') diff --git a/android/src/main/java/com/theoplayer/abr/ABRConfigurationAdapter.kt b/android/src/main/java/com/theoplayer/abr/ABRConfigurationAdapter.kt index df7e44505..a4d5c6edb 100644 --- a/android/src/main/java/com/theoplayer/abr/ABRConfigurationAdapter.kt +++ b/android/src/main/java/com/theoplayer/abr/ABRConfigurationAdapter.kt @@ -1,5 +1,6 @@ package com.theoplayer.abr +import android.util.Size import com.facebook.react.bridge.ReadableMap import com.theoplayer.android.api.abr.AbrStrategyConfiguration import com.theoplayer.android.api.abr.AbrStrategyMetadata @@ -12,6 +13,9 @@ object ABRConfigurationAdapter { private const val PROP_METADATA = "metadata" private const val PROP_TYPE = "type" private const val PROP_BITRATE = "bitrate" + private const val PROP_PREFERRED_MAXIMUM_RESOLUTION = "preferredMaximumResolution" + private const val PROP_WIDTH = "width" + private const val PROP_HEIGHT = "height" fun applyABRConfigurationFromProps(player: Player?, abrProps: ReadableMap?) { if (abrProps == null || player == null) { @@ -20,6 +24,11 @@ object ABRConfigurationAdapter { if (abrProps.hasKey(PROP_TARGET_BUFFER)) { player.abr.targetBuffer = abrProps.getInt(PROP_TARGET_BUFFER) } + // (0,0) is the documented sentinel for "no cap" and maps to a null Size on the native SDK. + val preferredMaximumResolutionProps = abrProps.getMap(PROP_PREFERRED_MAXIMUM_RESOLUTION) + if (preferredMaximumResolutionProps != null) { + player.abr.preferredMaximumResolution = preferredMaximumResolutionFromProps(preferredMaximumResolutionProps) + } // Strategy can be either a string or an object try { val abrStrategyPropsString = abrProps.getString(PROP_STRATEGY) @@ -50,6 +59,18 @@ object ABRConfigurationAdapter { } } + private fun preferredMaximumResolutionFromProps(props: ReadableMap?): Size? { + if (props == null || !props.hasKey(PROP_WIDTH) || !props.hasKey(PROP_HEIGHT)) { + return null + } + val width = props.getDouble(PROP_WIDTH).toInt() + val height = props.getDouble(PROP_HEIGHT).toInt() + if (width <= 0 || height <= 0) { + return null + } + return Size(width, height) + } + private fun abrMetadataFromProps(props: ReadableMap?): AbrStrategyMetadata? { if (props == null) { return null diff --git a/doc/abr.md b/doc/abr.md index 13603bfa4..6d81599c4 100644 --- a/doc/abr.md +++ b/doc/abr.md @@ -39,6 +39,7 @@ on the chosen strategy, as well as various parameters of the playback buffer. | `targetBuffer` | The amount that the player should buffer ahead of the current playback position, in seconds. Default is **20**s. | Android & Web | | `bufferLookbackWindow` | The amount of data which the player should keep in its buffer before the current playback position, in seconds. Default is **30**s. | Web | | `maxBufferLength` | The maximum length of the player's buffer, in seconds. | Web | | +| `preferredMaximumResolution` | A preferred upper limit on the resolution of the video to be downloaded. `(0,0)` (the default) removes the cap. | Android & iOS | When specifying the strategy, apart from the values `'performance'`, `'quality'`, `'bandwidth'`, an `ABRStrategyConfiguration` @@ -54,6 +55,13 @@ const strategyConfig: ABRStrategyConfiguration = { player.abr.strategy = strategyConfig; ``` +To cap the resolution of the variant the player downloads, set `preferredMaximumResolution` to a `Resolution` (`{width, height}`). +Pass `(0, 0)` to remove the cap. + +```typescript +player.abr.preferredMaximumResolution = { width: 1280, height: 720 }; +``` + ## Setting Target Video Quality By default, the ABR algorithm will choose, depending on the available bandwidth, diff --git a/example/android/gradle.properties b/example/android/gradle.properties index 6de786415..4efa02c59 100644 --- a/example/android/gradle.properties +++ b/example/android/gradle.properties @@ -46,7 +46,7 @@ hermesEnabled=true edgeToEdgeEnabled=false # Version of the THEOplayer SDK, if not specified, the latest available version within bounds is set. -#THEOplayer_sdk=[11.4.0, 12.0.0) +#THEOplayer_sdk=[11.5.0, 12.0.0) # Override Android sdk versions #THEOplayer_compileSdkVersion = 36 diff --git a/src/api/abr/ABRConfiguration.ts b/src/api/abr/ABRConfiguration.ts index 65ba1b70c..a320ceebb 100644 --- a/src/api/abr/ABRConfiguration.ts +++ b/src/api/abr/ABRConfiguration.ts @@ -126,9 +126,9 @@ export interface ABRConfiguration { * A preferred upper limit on the resolution of the video to be downloaded (or otherwise transferred) and rendered by the player. * * The default value is (0,0), which indicates that the client enforces no limit on video resolution. Other values indicate a preferred maximum video resolution. - * It only applies to HTTP Live Streaming asset. + * It only applies to Live Streaming asset. * - * @platform ios + * @platform ios,android */ preferredMaximumResolution?: Resolution; }