react-native-theoplayer 8.16.0 → 8.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +33 -0
- package/README.md +3 -1
- package/android/build.gradle +2 -1
- package/android/src/main/java/com/theoplayer/ReactTHEOplayerContext.kt +2 -1
- package/android/src/main/java/com/theoplayer/cmcd/CmcdTransmissionMode.kt +8 -0
- package/android/src/main/java/com/theoplayer/drm/ContentProtectionAdapter.kt +39 -9
- package/android/src/main/java/com/theoplayer/player/PlayerModule.kt +13 -0
- package/android/src/main/java/com/theoplayer/presentation/FullscreenLayoutObserver.kt +39 -0
- package/android/src/main/java/com/theoplayer/presentation/PipUtils.kt +8 -14
- package/android/src/main/java/com/theoplayer/presentation/PresentationManager.kt +103 -34
- package/android/src/main/java/com/theoplayer/source/SourceAdapter.kt +39 -10
- package/android/src/main/java/com/theoplayer/util/BridgeUtils.kt +2 -2
- package/ios/THEOplayerRCTPlayerAPI.swift +1 -0
- package/ios/THEOplayerRCTSourceDescriptionBuilder.swift +10 -1
- package/ios/ads/THEOplayerRCTAdsEventHandler.swift +2 -2
- package/ios/backgroundAudio/THEOplayerRCTView+BackgroundAudioConfig.swift +1 -1
- package/ios/pip/THEOplayerRCTPipControlsManager.swift +5 -1
- package/ios/pip/THEOplayerRCTView+PipConfig.swift +2 -1
- package/ios/theoAds/THEOplayerRCTSourceDescriptionBuilder+TheoAds.swift +3 -1
- package/lib/commonjs/api/barrel.js +11 -0
- package/lib/commonjs/api/barrel.js.map +1 -1
- package/lib/commonjs/api/event/TheoAdsEvent.js +15 -0
- package/lib/commonjs/api/event/TheoAdsEvent.js.map +1 -0
- package/lib/commonjs/api/event/barrel.js +11 -0
- package/lib/commonjs/api/event/barrel.js.map +1 -1
- package/lib/commonjs/api/player/PlayerEventMap.js +1 -0
- package/lib/commonjs/api/player/PlayerEventMap.js.map +1 -1
- package/lib/commonjs/api/player/THEOplayer.js.map +1 -1
- package/lib/commonjs/api/source/SourceDescription.js.map +1 -1
- package/lib/commonjs/api/source/ads/TheoAdDescription.js.map +1 -1
- package/lib/commonjs/api/source/barrel.js +15 -4
- package/lib/commonjs/api/source/barrel.js.map +1 -1
- package/lib/commonjs/api/source/cmcd/CmcdConfiguration.js +18 -0
- package/lib/commonjs/api/source/cmcd/CmcdConfiguration.js.map +1 -0
- package/lib/commonjs/api/source/cmcd/barrel.js +17 -0
- package/lib/commonjs/api/source/cmcd/barrel.js.map +1 -0
- package/lib/commonjs/api/theoads/TheoAdsAPI.js +6 -0
- package/lib/commonjs/api/theoads/TheoAdsAPI.js.map +1 -0
- package/lib/commonjs/api/theoads/barrel.js +50 -0
- package/lib/commonjs/api/theoads/barrel.js.map +1 -0
- package/lib/commonjs/api/theoads/interstitial/AdBreakInterstitial.js +6 -0
- package/lib/commonjs/api/theoads/interstitial/AdBreakInterstitial.js.map +1 -0
- package/lib/commonjs/api/theoads/interstitial/Interstitial.js +2 -0
- package/lib/commonjs/api/theoads/interstitial/Interstitial.js.map +1 -0
- package/lib/commonjs/api/theoads/interstitial/OverlayInterstitial.js +6 -0
- package/lib/commonjs/api/theoads/interstitial/OverlayInterstitial.js.map +1 -0
- package/lib/commonjs/internal/THEOplayerView.js +12 -2
- package/lib/commonjs/internal/THEOplayerView.js.map +1 -1
- package/lib/commonjs/internal/adapter/THEOplayerAdapter.js +5 -0
- package/lib/commonjs/internal/adapter/THEOplayerAdapter.js.map +1 -1
- package/lib/commonjs/internal/adapter/THEOplayerWebAdapter.js +37 -2
- package/lib/commonjs/internal/adapter/THEOplayerWebAdapter.js.map +1 -1
- package/lib/commonjs/internal/adapter/WebEventForwarder.js +6 -0
- package/lib/commonjs/internal/adapter/WebEventForwarder.js.map +1 -1
- package/lib/commonjs/internal/adapter/event/PlayerEvents.js +9 -1
- package/lib/commonjs/internal/adapter/event/PlayerEvents.js.map +1 -1
- package/lib/commonjs/internal/adapter/theoads/THEOAdsNativeAdapter.js +31 -0
- package/lib/commonjs/internal/adapter/theoads/THEOAdsNativeAdapter.js.map +1 -0
- package/lib/commonjs/internal/adapter/theoads/THEOAdsWebAdapter.js +22 -0
- package/lib/commonjs/internal/adapter/theoads/THEOAdsWebAdapter.js.map +1 -0
- package/lib/commonjs/internal/adapter/web/WebMediaSession.js +40 -27
- package/lib/commonjs/internal/adapter/web/WebMediaSession.js.map +1 -1
- package/lib/commonjs/internal/utils/Dimensions.js +7 -15
- package/lib/commonjs/internal/utils/Dimensions.js.map +1 -1
- package/lib/commonjs/manifest.json +1 -1
- package/lib/module/api/barrel.js +1 -0
- package/lib/module/api/barrel.js.map +1 -1
- package/lib/module/api/event/TheoAdsEvent.js +9 -0
- package/lib/module/api/event/TheoAdsEvent.js.map +1 -0
- package/lib/module/api/event/barrel.js +1 -0
- package/lib/module/api/event/barrel.js.map +1 -1
- package/lib/module/api/player/PlayerEventMap.js +1 -0
- package/lib/module/api/player/PlayerEventMap.js.map +1 -1
- package/lib/module/api/player/THEOplayer.js.map +1 -1
- package/lib/module/api/source/SourceDescription.js.map +1 -1
- package/lib/module/api/source/ads/TheoAdDescription.js.map +1 -1
- package/lib/module/api/source/barrel.js +1 -0
- package/lib/module/api/source/barrel.js.map +1 -1
- package/lib/module/api/source/cmcd/CmcdConfiguration.js +13 -0
- package/lib/module/api/source/cmcd/CmcdConfiguration.js.map +1 -0
- package/lib/module/api/source/cmcd/barrel.js +2 -0
- package/lib/module/api/source/cmcd/barrel.js.map +1 -0
- package/lib/module/api/theoads/TheoAdsAPI.js +2 -0
- package/lib/module/api/theoads/TheoAdsAPI.js.map +1 -0
- package/lib/module/api/theoads/barrel.js +5 -0
- package/lib/module/api/theoads/barrel.js.map +1 -0
- package/lib/module/api/theoads/interstitial/AdBreakInterstitial.js +2 -0
- package/lib/module/api/theoads/interstitial/AdBreakInterstitial.js.map +1 -0
- package/lib/module/api/theoads/interstitial/Interstitial.js +2 -0
- package/lib/module/api/theoads/interstitial/Interstitial.js.map +1 -0
- package/lib/module/api/theoads/interstitial/OverlayInterstitial.js +2 -0
- package/lib/module/api/theoads/interstitial/OverlayInterstitial.js.map +1 -0
- package/lib/module/internal/THEOplayerView.js +12 -2
- package/lib/module/internal/THEOplayerView.js.map +1 -1
- package/lib/module/internal/adapter/THEOplayerAdapter.js +5 -0
- package/lib/module/internal/adapter/THEOplayerAdapter.js.map +1 -1
- package/lib/module/internal/adapter/THEOplayerWebAdapter.js +38 -3
- package/lib/module/internal/adapter/THEOplayerWebAdapter.js.map +1 -1
- package/lib/module/internal/adapter/WebEventForwarder.js +8 -2
- package/lib/module/internal/adapter/WebEventForwarder.js.map +1 -1
- package/lib/module/internal/adapter/event/PlayerEvents.js +7 -0
- package/lib/module/internal/adapter/event/PlayerEvents.js.map +1 -1
- package/lib/module/internal/adapter/theoads/THEOAdsNativeAdapter.js +24 -0
- package/lib/module/internal/adapter/theoads/THEOAdsNativeAdapter.js.map +1 -0
- package/lib/module/internal/adapter/theoads/THEOAdsWebAdapter.js +15 -0
- package/lib/module/internal/adapter/theoads/THEOAdsWebAdapter.js.map +1 -0
- package/lib/module/internal/adapter/web/WebMediaSession.js +40 -27
- package/lib/module/internal/adapter/web/WebMediaSession.js.map +1 -1
- package/lib/module/internal/utils/Dimensions.js +8 -16
- package/lib/module/internal/utils/Dimensions.js.map +1 -1
- package/lib/module/manifest.json +1 -1
- package/lib/typescript/api/barrel.d.ts +1 -0
- package/lib/typescript/api/barrel.d.ts.map +1 -1
- package/lib/typescript/api/event/TheoAdsEvent.d.ts +35 -0
- package/lib/typescript/api/event/TheoAdsEvent.d.ts.map +1 -0
- package/lib/typescript/api/event/barrel.d.ts +1 -0
- package/lib/typescript/api/event/barrel.d.ts.map +1 -1
- package/lib/typescript/api/pip/PiPConfiguration.d.ts +8 -1
- package/lib/typescript/api/pip/PiPConfiguration.d.ts.map +1 -1
- package/lib/typescript/api/player/PlayerEventMap.d.ts +6 -0
- package/lib/typescript/api/player/PlayerEventMap.d.ts.map +1 -1
- package/lib/typescript/api/player/THEOplayer.d.ts +6 -1
- package/lib/typescript/api/player/THEOplayer.d.ts.map +1 -1
- package/lib/typescript/api/source/SourceDescription.d.ts +6 -0
- package/lib/typescript/api/source/SourceDescription.d.ts.map +1 -1
- package/lib/typescript/api/source/ads/TheoAdDescription.d.ts +16 -0
- package/lib/typescript/api/source/ads/TheoAdDescription.d.ts.map +1 -1
- package/lib/typescript/api/source/barrel.d.ts +1 -0
- package/lib/typescript/api/source/barrel.d.ts.map +1 -1
- package/lib/typescript/api/source/cmcd/CmcdConfiguration.d.ts +79 -0
- package/lib/typescript/api/source/cmcd/CmcdConfiguration.d.ts.map +1 -0
- package/lib/typescript/api/source/cmcd/barrel.d.ts +2 -0
- package/lib/typescript/api/source/cmcd/barrel.d.ts.map +1 -0
- package/lib/typescript/api/theoads/TheoAdsAPI.d.ts +30 -0
- package/lib/typescript/api/theoads/TheoAdsAPI.d.ts.map +1 -0
- package/lib/typescript/api/theoads/barrel.d.ts +5 -0
- package/lib/typescript/api/theoads/barrel.d.ts.map +1 -0
- package/lib/typescript/api/theoads/interstitial/AdBreakInterstitial.d.ts +34 -0
- package/lib/typescript/api/theoads/interstitial/AdBreakInterstitial.d.ts.map +1 -0
- package/lib/typescript/api/theoads/interstitial/Interstitial.d.ts +33 -0
- package/lib/typescript/api/theoads/interstitial/Interstitial.d.ts.map +1 -0
- package/lib/typescript/api/theoads/interstitial/OverlayInterstitial.d.ts +49 -0
- package/lib/typescript/api/theoads/interstitial/OverlayInterstitial.d.ts.map +1 -0
- package/lib/typescript/internal/THEOplayerView.d.ts.map +1 -1
- package/lib/typescript/internal/adapter/THEOplayerAdapter.d.ts +3 -1
- package/lib/typescript/internal/adapter/THEOplayerAdapter.d.ts.map +1 -1
- package/lib/typescript/internal/adapter/THEOplayerWebAdapter.d.ts +5 -2
- package/lib/typescript/internal/adapter/THEOplayerWebAdapter.d.ts.map +1 -1
- package/lib/typescript/internal/adapter/WebEventForwarder.d.ts +1 -0
- package/lib/typescript/internal/adapter/WebEventForwarder.d.ts.map +1 -1
- package/lib/typescript/internal/adapter/event/PlayerEvents.d.ts +7 -0
- package/lib/typescript/internal/adapter/event/PlayerEvents.d.ts.map +1 -1
- package/lib/typescript/internal/adapter/theoads/THEOAdsNativeAdapter.d.ts +9 -0
- package/lib/typescript/internal/adapter/theoads/THEOAdsNativeAdapter.d.ts.map +1 -0
- package/lib/typescript/internal/adapter/theoads/THEOAdsWebAdapter.d.ts +10 -0
- package/lib/typescript/internal/adapter/theoads/THEOAdsWebAdapter.d.ts.map +1 -0
- package/lib/typescript/internal/adapter/web/WebMediaSession.d.ts +4 -6
- package/lib/typescript/internal/adapter/web/WebMediaSession.d.ts.map +1 -1
- package/lib/typescript/internal/utils/Dimensions.d.ts +1 -1
- package/lib/typescript/internal/utils/Dimensions.d.ts.map +1 -1
- package/package.json +3 -2
- package/react-native-theoplayer.podspec +7 -7
- package/src/api/barrel.ts +1 -0
- package/src/api/event/TheoAdsEvent.ts +41 -0
- package/src/api/event/barrel.ts +1 -0
- package/src/api/pip/PiPConfiguration.ts +9 -1
- package/src/api/player/PlayerEventMap.ts +7 -0
- package/src/api/player/THEOplayer.ts +7 -1
- package/src/api/source/SourceDescription.ts +7 -0
- package/src/api/source/ads/TheoAdDescription.ts +19 -0
- package/src/api/source/barrel.ts +1 -0
- package/src/api/source/cmcd/CmcdConfiguration.ts +84 -0
- package/src/api/source/cmcd/barrel.ts +1 -0
- package/src/api/theoads/TheoAdsAPI.ts +33 -0
- package/src/api/theoads/barrel.ts +4 -0
- package/src/api/theoads/interstitial/AdBreakInterstitial.ts +39 -0
- package/src/api/theoads/interstitial/Interstitial.ts +36 -0
- package/src/api/theoads/interstitial/OverlayInterstitial.ts +55 -0
- package/src/internal/THEOplayerView.tsx +10 -2
- package/src/internal/adapter/THEOplayerAdapter.ts +8 -0
- package/src/internal/adapter/THEOplayerWebAdapter.ts +50 -5
- package/src/internal/adapter/WebEventForwarder.ts +18 -0
- package/src/internal/adapter/event/PlayerEvents.ts +11 -0
- package/src/internal/adapter/theoads/THEOAdsNativeAdapter.ts +26 -0
- package/src/internal/adapter/theoads/THEOAdsWebAdapter.ts +22 -0
- package/src/internal/adapter/web/WebMediaSession.ts +39 -30
- package/src/internal/utils/Dimensions.ts +8 -16
- package/src/manifest.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,38 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.1.0/)
|
|
6
6
|
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [8.18.0] - 25-04-02
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- No longer showing poster after setting the source when the player has been configured to use autoplay. With autoplay enabled, displaying the poster will only result in a brief flash of the image.
|
|
13
|
+
- Changed the fullscreen screen dimension calculation on Android, taking into account edgeToEdge layouts.
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- Exposed THEOads API through the Player API.
|
|
18
|
+
- Added support for Common Media Client Data (CMCD) on all platforms. More info on the [documentation](./doc/cmcd.md) page.
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
|
|
22
|
+
- Fixed an issue on Android where the transition to a PiP window would not focus on the player window.
|
|
23
|
+
|
|
24
|
+
## [8.17.0] - 25-03-20
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
- Fixed an issue on Web where the metadata on the lockscreen was not showing correctly or missing occasionally.
|
|
29
|
+
- Fixed a crash on Android when setting a source with THEOads without the Media3 extension being enabled.
|
|
30
|
+
- Fixed an issue on iOS where the AdTapped and AdClicked events were not correctly cleaned up.
|
|
31
|
+
- Fixed an issue on Android where the player would sometimes crash when passing a DRM protected source without an `integration` property.
|
|
32
|
+
|
|
33
|
+
### Added
|
|
34
|
+
|
|
35
|
+
- Added SeekTo functionality to the web lockscreen controls, allowing to drag the lockscreen slider and seek to a specific time value.
|
|
36
|
+
- Added the IMA DAI `streamActivityMonitorId` property as a configuration on the SGAI `TheoAdDescription` for web.
|
|
37
|
+
- Added the THEOads API for Web.
|
|
38
|
+
- Added `retrievePodIdURI` property to `TheoAdsDescription` for Android and iOS.
|
|
39
|
+
|
|
8
40
|
## [8.16.0] - 25-02-28
|
|
9
41
|
|
|
10
42
|
### Changed
|
|
@@ -18,6 +50,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
|
18
50
|
- Fixed an issue on Android, where the player would sometimes not initialise correctly in case New Architecture was not being used, resulting in a black screen.
|
|
19
51
|
- Fixed an issue on iOS Safari browsers, where the `presentationmodechange` event would not be dispatched when entering or exiting fullscreen.
|
|
20
52
|
|
|
53
|
+
|
|
21
54
|
## [8.15.0] - 25-02-12
|
|
22
55
|
|
|
23
56
|
### Changed
|
package/README.md
CHANGED
|
@@ -105,7 +105,7 @@ please reach out to us for support.
|
|
|
105
105
|
</tr>
|
|
106
106
|
<tr>
|
|
107
107
|
<td><strong>Advertising Integration</strong></td>
|
|
108
|
-
<td colspan="3">Google IMA, Google DAI</td>
|
|
108
|
+
<td colspan="3">Google IMA, Google DAI, THEOads</td>
|
|
109
109
|
</tr>
|
|
110
110
|
<tr>
|
|
111
111
|
<td><strong>Cast Integration</strong></td>
|
|
@@ -174,9 +174,11 @@ This section gives an overview of features, limitations and known issues:
|
|
|
174
174
|
|
|
175
175
|
- [Adaptive Bitrate (ABR)](./doc/abr.md)
|
|
176
176
|
- [Advertisements](./doc/ads.md)
|
|
177
|
+
- [Android Media3 Pipeline🔥](./doc/media3.md)
|
|
177
178
|
- [Audio Control Management](./doc/audio-control.md)
|
|
178
179
|
- [Background playback and notifications](./doc/background.md)
|
|
179
180
|
- [Casting with Chromecast and Airplay](./doc/cast.md)
|
|
181
|
+
- [Common Media Client Data (CMCD)](./doc/cmcd.md)
|
|
180
182
|
- [Digital Rights Management (DRM)](./doc/drm.md)
|
|
181
183
|
- [Fullscreen presentation](./doc/fullscreen.md)
|
|
182
184
|
- [Media Caching](./doc/media-caching.md)
|
package/android/build.gradle
CHANGED
|
@@ -59,8 +59,9 @@ android {
|
|
|
59
59
|
def TimeUpdateRate = "com.theoplayer.TimeUpdateRate"
|
|
60
60
|
buildConfigField TimeUpdateRate, "TIMEUPDATE_RATE", safeExtGet('THEOplayer_timeUpdateRate', "${TimeUpdateRate}.UNLIMITED")
|
|
61
61
|
|
|
62
|
-
// Optionally re-parent player view on fullscreen event
|
|
62
|
+
// Optionally re-parent player view on fullscreen or PiP event
|
|
63
63
|
buildConfigField "boolean", "REPARENT_ON_FULLSCREEN", "${safeExtGet('THEOplayer_reparent_on_fullscreen', 'true')}"
|
|
64
|
+
buildConfigField "boolean", "REPARENT_ON_PIP", "${safeExtGet('THEOplayer_reparent_on_PiP', 'false')}"
|
|
64
65
|
|
|
65
66
|
// Optionally log events to logcat
|
|
66
67
|
buildConfigField "boolean", "LOG_PLAYER_EVENTS", "${safeExtGet('THEOplayer_logPlayerEvents', 'false')}"
|
|
@@ -346,7 +346,8 @@ class ReactTHEOplayerContext private constructor(
|
|
|
346
346
|
// return false -> the default pipeline will be used to play the selected source.
|
|
347
347
|
//
|
|
348
348
|
// @remark If the source contains THEOads, media3 is always enabled.
|
|
349
|
-
configAdapter.useMedia3 ||
|
|
349
|
+
configAdapter.useMedia3 ||
|
|
350
|
+
(BuildConfig.EXTENSION_THEOADS && source.ads.any { it is TheoAdDescription })
|
|
350
351
|
}
|
|
351
352
|
playerView.player.addIntegration(media3Integration)
|
|
352
353
|
}
|
|
@@ -12,7 +12,9 @@ import com.theoplayer.android.api.contentprotection.Response
|
|
|
12
12
|
import com.theoplayer.android.api.source.drm.DRMConfiguration
|
|
13
13
|
import com.theoplayer.android.api.source.drm.DRMIntegrationId
|
|
14
14
|
import com.theoplayer.android.api.source.drm.KeySystemConfiguration
|
|
15
|
+
import com.theoplayer.android.api.source.drm.LicenseType
|
|
15
16
|
import com.theoplayer.android.api.source.drm.preintegration.*
|
|
17
|
+
import com.theoplayer.util.BridgeUtils.fromJSONObjectToMap
|
|
16
18
|
import org.json.JSONObject
|
|
17
19
|
|
|
18
20
|
private const val TAG = "ContentProtection"
|
|
@@ -23,6 +25,7 @@ const val PROP_INTEGRATION_PARAMETERS: String = "integrationParameters"
|
|
|
23
25
|
const val PROP_REQUEST: String = "request"
|
|
24
26
|
const val PROP_KEYSYSTEM_ID: String = "keySystemId"
|
|
25
27
|
const val PROP_DRM_CONFIG: String = "drmConfig"
|
|
28
|
+
const val PROP_PLAYREADY: String = "playready"
|
|
26
29
|
const val PROP_WIDEVINE: String = "widevine"
|
|
27
30
|
const val PROP_REQUEST_ID: String = "requestId"
|
|
28
31
|
const val PROP_URL: String = "url"
|
|
@@ -33,6 +36,12 @@ const val PROP_HEADERS: String = "headers"
|
|
|
33
36
|
const val PROP_BASE64_BODY: String = "base64body"
|
|
34
37
|
const val PROP_LA_URL: String = "licenseAcquisitionURL"
|
|
35
38
|
const val PROP_USE_CREDENTIALS: String = "useCredentials"
|
|
39
|
+
const val PROP_LICENSE_ACQUISITION_URL: String = "licenseAcquisitionURL"
|
|
40
|
+
const val PROP_LICENSE_TYPE: String = "licenseType"
|
|
41
|
+
const val PROP_LICENSE_TYPE_TEMPORARY: String = "temporary"
|
|
42
|
+
const val PROP_LICENSE_TYPE_PERSISTENT: String = "persistent"
|
|
43
|
+
const val PROP_QUERY_PARAMETERS: String = "queryParameters"
|
|
44
|
+
const val PROP_CERTIFICATE: String = "certificate"
|
|
36
45
|
|
|
37
46
|
object ContentProtectionAdapter {
|
|
38
47
|
|
|
@@ -76,21 +85,42 @@ object ContentProtectionAdapter {
|
|
|
76
85
|
// Custom integration through connector
|
|
77
86
|
return DRMConfiguration.Builder().apply {
|
|
78
87
|
if (!TextUtils.isEmpty(integration)) {
|
|
79
|
-
|
|
88
|
+
customIntegrationId(integration)
|
|
89
|
+
}
|
|
90
|
+
if (jsonConfig.has(PROP_WIDEVINE)) {
|
|
91
|
+
widevine(keySystemConfigurationFromJson(jsonConfig.getJSONObject(PROP_WIDEVINE)))
|
|
92
|
+
}
|
|
93
|
+
if (jsonConfig.has(PROP_PLAYREADY)) {
|
|
94
|
+
playready(keySystemConfigurationFromJson(jsonConfig.getJSONObject(PROP_PLAYREADY)))
|
|
80
95
|
}
|
|
81
|
-
this.widevine(gson.fromJson(jsonConfig.optString("widevine"), KeySystemConfiguration::class.java))
|
|
82
|
-
this.playready(gson.fromJson(jsonConfig.optString("playready"), KeySystemConfiguration::class.java))
|
|
83
96
|
if (jsonConfig.has(PROP_INTEGRATION_PARAMETERS)) {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
97
|
+
integrationParameters(fromJSONObjectToMap(jsonConfig.getJSONObject(PROP_INTEGRATION_PARAMETERS)))
|
|
98
|
+
}
|
|
99
|
+
}.build()
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
private fun keySystemConfigurationFromJson(config: JSONObject): KeySystemConfiguration {
|
|
103
|
+
return KeySystemConfiguration.Builder(config.optString(PROP_LICENSE_ACQUISITION_URL)).apply {
|
|
104
|
+
useCredentials(config.optBoolean(PROP_USE_CREDENTIALS))
|
|
105
|
+
licenseTypeFromString(config.optString(PROP_LICENSE_TYPE))?.let {
|
|
106
|
+
licenseType(it)
|
|
107
|
+
}
|
|
108
|
+
headers(fromJSONObjectToMap(config.optJSONObject(PROP_HEADERS)))
|
|
109
|
+
queryParameters(fromJSONObjectToMap(config.optJSONObject(PROP_QUERY_PARAMETERS)))
|
|
110
|
+
if (config.has(PROP_CERTIFICATE)) {
|
|
111
|
+
certificate(config.getString(PROP_CERTIFICATE).toByteArray())
|
|
90
112
|
}
|
|
91
113
|
}.build()
|
|
92
114
|
}
|
|
93
115
|
|
|
116
|
+
private fun licenseTypeFromString(str: String?): LicenseType? {
|
|
117
|
+
return when (str) {
|
|
118
|
+
PROP_LICENSE_TYPE_PERSISTENT -> LicenseType.PERSISTENT
|
|
119
|
+
PROP_LICENSE_TYPE_TEMPORARY -> LicenseType.TEMPORARY
|
|
120
|
+
else -> null
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
94
124
|
fun fromDRMConfiguration(config: DRMConfiguration): WritableMap {
|
|
95
125
|
return Arguments.createMap().apply {
|
|
96
126
|
putString(PROP_INTEGRATION, config.customIntegrationId ?: config.integration.integrationId)
|
|
@@ -263,4 +263,17 @@ class PlayerModule(context: ReactApplicationContext) : ReactContextBaseJavaModul
|
|
|
263
263
|
)
|
|
264
264
|
}
|
|
265
265
|
}
|
|
266
|
+
|
|
267
|
+
@ReactMethod(isBlockingSynchronousMethod = true)
|
|
268
|
+
fun getUsableScreenDimensions(): WritableMap {
|
|
269
|
+
// Pass the dimensions of the top-most View in the view hierarchy.
|
|
270
|
+
val topView = reactApplicationContext.currentActivity?.window?.decorView?.rootView
|
|
271
|
+
reactApplicationContext.resources.displayMetrics.also {
|
|
272
|
+
val density = it.density
|
|
273
|
+
return Arguments.createMap().apply {
|
|
274
|
+
putDouble("width", (topView?.width ?: 0) / density.toDouble())
|
|
275
|
+
putDouble("height", (topView?.height ?: 0) / density.toDouble())
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
266
279
|
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
package com.theoplayer.presentation
|
|
2
|
+
|
|
3
|
+
import android.util.Log
|
|
4
|
+
import android.view.ViewTreeObserver
|
|
5
|
+
import com.facebook.react.views.view.ReactViewGroup
|
|
6
|
+
|
|
7
|
+
private val TAG = "FSLayoutObserver"
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* FullScreenLayoutObserver makes sure that the React Native view does not get the layout
|
|
11
|
+
* defined in React-Native during fullscreen presentation mode. We want to enforce fullscreen
|
|
12
|
+
* position & size.
|
|
13
|
+
*/
|
|
14
|
+
class FullScreenLayoutObserver {
|
|
15
|
+
private var globalLayoutListener: ViewTreeObserver.OnGlobalLayoutListener? = null
|
|
16
|
+
private var attached: ReactViewGroup? = null
|
|
17
|
+
|
|
18
|
+
fun attach(viewGroup: ReactViewGroup?) {
|
|
19
|
+
if (attached != null) {
|
|
20
|
+
Log.w(TAG, "A previously attached ViewGroup was not properly detached.")
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
viewGroup?.let {
|
|
24
|
+
globalLayoutListener = ViewTreeObserver.OnGlobalLayoutListener {
|
|
25
|
+
it.post {
|
|
26
|
+
it.layout(0, 0, viewGroup.width, viewGroup.height)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
it.viewTreeObserver.addOnGlobalLayoutListener(globalLayoutListener)
|
|
30
|
+
attached = viewGroup
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
fun remove() {
|
|
35
|
+
attached?.viewTreeObserver?.removeOnGlobalLayoutListener(globalLayoutListener)
|
|
36
|
+
attached = null
|
|
37
|
+
globalLayoutListener = null
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -12,9 +12,6 @@ import android.graphics.Rect
|
|
|
12
12
|
import android.graphics.drawable.Icon
|
|
13
13
|
import android.os.Build
|
|
14
14
|
import android.util.Rational
|
|
15
|
-
import android.view.SurfaceView
|
|
16
|
-
import android.view.TextureView
|
|
17
|
-
import android.view.View
|
|
18
15
|
import android.view.ViewGroup
|
|
19
16
|
import androidx.annotation.RequiresApi
|
|
20
17
|
import com.facebook.react.uimanager.ThemedReactContext
|
|
@@ -108,7 +105,8 @@ class PipUtils(
|
|
|
108
105
|
}
|
|
109
106
|
try {
|
|
110
107
|
reactContext.currentActivity?.unregisterReceiver(broadcastReceiver)
|
|
111
|
-
} catch (ignore: IllegalArgumentException) { /*ignore*/
|
|
108
|
+
} catch (ignore: IllegalArgumentException) { /*ignore*/
|
|
109
|
+
}
|
|
112
110
|
enabled = false
|
|
113
111
|
}
|
|
114
112
|
|
|
@@ -189,17 +187,13 @@ class PipUtils(
|
|
|
189
187
|
}
|
|
190
188
|
|
|
191
189
|
private fun getContentViewRect(view: ViewGroup): Rect? {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
child.getGlobalVisibleRect(visibleRect)
|
|
199
|
-
return visibleRect
|
|
190
|
+
return view.findViewById<ViewGroup>(com.theoplayer.android.R.id.theo_content_player_container)
|
|
191
|
+
?.getChildAt(0) // AspectRatioView
|
|
192
|
+
?.run {
|
|
193
|
+
Rect().apply {
|
|
194
|
+
getGlobalVisibleRect(this)
|
|
195
|
+
}
|
|
200
196
|
}
|
|
201
|
-
}
|
|
202
|
-
return null
|
|
203
197
|
}
|
|
204
198
|
|
|
205
199
|
@RequiresApi(Build.VERSION_CODES.O)
|
|
@@ -14,9 +14,9 @@ import android.view.ViewParent
|
|
|
14
14
|
import androidx.activity.ComponentActivity
|
|
15
15
|
import androidx.core.view.WindowInsetsCompat
|
|
16
16
|
import androidx.core.view.WindowInsetsControllerCompat
|
|
17
|
+
import androidx.core.view.children
|
|
17
18
|
import androidx.lifecycle.Lifecycle
|
|
18
19
|
import com.facebook.react.ReactRootView
|
|
19
|
-
import com.facebook.react.runtime.ReactSurfaceView
|
|
20
20
|
import com.facebook.react.uimanager.ThemedReactContext
|
|
21
21
|
import com.facebook.react.views.view.ReactViewGroup
|
|
22
22
|
import com.theoplayer.BuildConfig
|
|
@@ -35,9 +35,11 @@ class PresentationManager(
|
|
|
35
35
|
private var supportsPip = false
|
|
36
36
|
private var onUserLeaveHintReceiver: BroadcastReceiver? = null
|
|
37
37
|
private var onPictureInPictureModeChanged: BroadcastReceiver? = null
|
|
38
|
-
private var playerGroupParentNode: ViewGroup? = null
|
|
39
|
-
private var playerGroupChildIndex: Int? = null
|
|
40
38
|
private val pipUtils: PipUtils = PipUtils(viewCtx, reactContext)
|
|
39
|
+
private val fullScreenLayoutObserver = FullScreenLayoutObserver()
|
|
40
|
+
private val playerGroupRestoreOptions by lazy {
|
|
41
|
+
PlayerGroupRestoreOptions()
|
|
42
|
+
}
|
|
41
43
|
|
|
42
44
|
var currentPresentationMode: PresentationMode = PresentationMode.INLINE
|
|
43
45
|
private set
|
|
@@ -99,6 +101,7 @@ class PresentationManager(
|
|
|
99
101
|
try {
|
|
100
102
|
reactContext.currentActivity?.unregisterReceiver(onUserLeaveHintReceiver)
|
|
101
103
|
reactContext.currentActivity?.unregisterReceiver(onPictureInPictureModeChanged)
|
|
104
|
+
fullScreenLayoutObserver.remove()
|
|
102
105
|
pipUtils.destroy()
|
|
103
106
|
} catch (ignore: Exception) {
|
|
104
107
|
}
|
|
@@ -146,6 +149,9 @@ class PresentationManager(
|
|
|
146
149
|
try {
|
|
147
150
|
pipUtils.enable()
|
|
148
151
|
reactContext.currentActivity?.enterPictureInPictureMode(pipUtils.getPipParams())
|
|
152
|
+
if (BuildConfig.REPARENT_ON_PIP) {
|
|
153
|
+
reparentPlayerToRoot()
|
|
154
|
+
}
|
|
149
155
|
} catch (_: Exception) {
|
|
150
156
|
onPipError()
|
|
151
157
|
}
|
|
@@ -169,6 +175,9 @@ class PresentationManager(
|
|
|
169
175
|
} else {
|
|
170
176
|
PresentationModeChangePipContext.RESTORED
|
|
171
177
|
}
|
|
178
|
+
if (BuildConfig.REPARENT_ON_PIP) {
|
|
179
|
+
reparentPlayerToOriginal()
|
|
180
|
+
}
|
|
172
181
|
updatePresentationMode(PresentationMode.INLINE, PresentationModeChangeContext(pipCtx))
|
|
173
182
|
pipUtils.disable()
|
|
174
183
|
}
|
|
@@ -209,30 +218,23 @@ class PresentationManager(
|
|
|
209
218
|
val activity = reactContext.currentActivity ?: return
|
|
210
219
|
val window = activity.window
|
|
211
220
|
|
|
212
|
-
// Get the player's ReactViewGroup parent, which contains THEOplayerView and its children (typically the UI).
|
|
213
|
-
val reactPlayerGroup: ReactViewGroup? = getClosestParentOfType(this.viewCtx.playerView)
|
|
214
|
-
|
|
215
|
-
// Get ReactNative's root node or the render hierarchy
|
|
216
|
-
val root: ReactRootView? = getClosestParentOfType(reactPlayerGroup)
|
|
217
|
-
|
|
218
221
|
if (fullscreen) {
|
|
222
|
+
// Hide system bars for immersive mode.
|
|
223
|
+
// {@link https://developer.android.com/develop/ui/views/layout/immersive}
|
|
219
224
|
WindowInsetsControllerCompat(window, window.decorView).apply {
|
|
225
|
+
// Reveal hidden system bars on any system gestures.
|
|
220
226
|
systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
|
|
221
|
-
|
|
222
|
-
|
|
227
|
+
// Hide all system bars.
|
|
228
|
+
hide(WindowInsetsCompat.Type.systemBars())
|
|
229
|
+
}
|
|
223
230
|
|
|
224
|
-
|
|
225
|
-
|
|
231
|
+
// Delay the event making sure it does not arrive before animations ended.
|
|
232
|
+
viewCtx.playerView.postOnAnimation {
|
|
233
|
+
updatePresentationMode(PresentationMode.FULLSCREEN)
|
|
226
234
|
}
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
reactPlayerGroup?.parent as? ReactViewGroup?
|
|
231
|
-
}?.also { parent ->
|
|
232
|
-
playerGroupChildIndex = parent.indexOfChild(reactPlayerGroup)
|
|
233
|
-
// Re-parent the playerViewGroup to the root node
|
|
234
|
-
parent.removeView(reactPlayerGroup)
|
|
235
|
-
root?.addView(reactPlayerGroup)
|
|
235
|
+
|
|
236
|
+
if (BuildConfig.REPARENT_ON_FULLSCREEN) {
|
|
237
|
+
reparentPlayerToRoot()
|
|
236
238
|
}
|
|
237
239
|
} else {
|
|
238
240
|
WindowInsetsControllerCompat(window, window.decorView).show(
|
|
@@ -240,18 +242,54 @@ class PresentationManager(
|
|
|
240
242
|
)
|
|
241
243
|
updatePresentationMode(PresentationMode.INLINE)
|
|
242
244
|
|
|
243
|
-
if (
|
|
244
|
-
|
|
245
|
+
if (BuildConfig.REPARENT_ON_FULLSCREEN) {
|
|
246
|
+
reparentPlayerToOriginal()
|
|
245
247
|
}
|
|
246
|
-
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// region Re-parent playerViewGroup logic
|
|
252
|
+
private val reactPlayerGroup: ReactViewGroup?
|
|
253
|
+
get() = viewCtx.playerView.getClosestParentOfType()
|
|
254
|
+
|
|
255
|
+
private val rootView: ReactRootView?
|
|
256
|
+
get() {
|
|
257
|
+
val activity = reactContext.currentActivity ?: return null
|
|
258
|
+
// Try to search in parents and as a fallback option from root to bottom using depth-first order
|
|
259
|
+
return reactPlayerGroup?.getClosestParentOfType()
|
|
260
|
+
?: (activity.window.decorView.rootView as? ViewGroup)
|
|
261
|
+
?.getClosestParentOfType(false)
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
private fun reparentPlayerToRoot() {
|
|
265
|
+
reactPlayerGroup?.let { playerGroup ->
|
|
266
|
+
playerGroupRestoreOptions.parentNode = (playerGroup.parent as? ViewGroup)?.also { parent ->
|
|
267
|
+
playerGroupRestoreOptions.childIndex = parent.indexOfChild(playerGroup)
|
|
268
|
+
|
|
269
|
+
// Re-parent the playerViewGroup to the root node
|
|
270
|
+
parent.removeView(playerGroup)
|
|
271
|
+
rootView?.addView(playerGroup)
|
|
272
|
+
|
|
273
|
+
// Attach an observer that overrides the react-native lay-out and forces fullscreen.
|
|
274
|
+
fullScreenLayoutObserver.attach(playerGroup)
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
private fun reparentPlayerToOriginal() {
|
|
280
|
+
rootView?.run {
|
|
281
|
+
reactPlayerGroup?.let { playerGroup ->
|
|
282
|
+
// Remove forced layout observer
|
|
283
|
+
fullScreenLayoutObserver.remove()
|
|
284
|
+
|
|
247
285
|
// Re-parent the playerViewGroup from the root node to its original parent
|
|
248
|
-
removeView(
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
playerGroupChildIndex = null
|
|
286
|
+
removeView(playerGroup)
|
|
287
|
+
playerGroupRestoreOptions.parentNode?.addView(playerGroup, playerGroupRestoreOptions.childIndex ?: 0)
|
|
288
|
+
playerGroupRestoreOptions.reset()
|
|
252
289
|
}
|
|
253
290
|
}
|
|
254
291
|
}
|
|
292
|
+
// endregion
|
|
255
293
|
|
|
256
294
|
private fun updatePresentationMode(
|
|
257
295
|
presentationMode: PresentationMode,
|
|
@@ -279,10 +317,41 @@ class PresentationManager(
|
|
|
279
317
|
}
|
|
280
318
|
}
|
|
281
319
|
|
|
282
|
-
inline fun <reified T : View> getClosestParentOfType(
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
parent = parent
|
|
320
|
+
inline fun <reified T : View> ViewGroup.getClosestParentOfType(upward: Boolean = true): T? {
|
|
321
|
+
if (upward) {
|
|
322
|
+
// Search in the parent views of `this` view up to the root
|
|
323
|
+
var parent: ViewParent? = parent
|
|
324
|
+
while (parent != null && parent !is T) {
|
|
325
|
+
parent = parent.parent
|
|
326
|
+
}
|
|
327
|
+
return parent as? T
|
|
328
|
+
} else {
|
|
329
|
+
// Search in the children collection.
|
|
330
|
+
val viewStack = ArrayDeque(children.toList())
|
|
331
|
+
// Use Stack/LIFO instead of recursion
|
|
332
|
+
while (viewStack.isNotEmpty()) {
|
|
333
|
+
when (val view = viewStack.removeAt(0)) {
|
|
334
|
+
is T -> {
|
|
335
|
+
return view
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
is ViewGroup -> {
|
|
339
|
+
// Filling LIFO with all children of the ViewGroup: depth-first order
|
|
340
|
+
viewStack.addAll(0, view.children.toList())
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
// Found nothing
|
|
345
|
+
return null
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
private class PlayerGroupRestoreOptions {
|
|
350
|
+
var childIndex: Int? = null
|
|
351
|
+
var parentNode: ViewGroup? = null
|
|
352
|
+
|
|
353
|
+
fun reset() {
|
|
354
|
+
parentNode = null
|
|
355
|
+
childIndex = null
|
|
286
356
|
}
|
|
287
|
-
return parent as? T
|
|
288
357
|
}
|
|
@@ -19,10 +19,12 @@ import com.theoplayer.android.api.player.track.texttrack.TextTrackKind
|
|
|
19
19
|
import com.theoplayer.android.api.source.metadata.ChromecastMetadataImage
|
|
20
20
|
import com.theoplayer.BuildConfig
|
|
21
21
|
import com.theoplayer.android.api.ads.theoads.TheoAdsLayoutOverride
|
|
22
|
+
import com.theoplayer.android.api.cmcd.CMCDTransmissionMode
|
|
22
23
|
import com.theoplayer.android.api.error.ErrorCode
|
|
23
24
|
import com.theoplayer.android.api.source.AdIntegration
|
|
24
25
|
import com.theoplayer.android.api.source.dash.DashPlaybackConfiguration
|
|
25
26
|
import com.theoplayer.android.api.theolive.TheoLiveSource
|
|
27
|
+
import com.theoplayer.cmcd.CmcdTransmissionMode
|
|
26
28
|
import com.theoplayer.drm.ContentProtectionAdapter
|
|
27
29
|
import com.theoplayer.latency.parseLatencyConfiguration
|
|
28
30
|
import com.theoplayer.util.BridgeUtils
|
|
@@ -63,6 +65,7 @@ private const val PROP_CUSTOM_ASSET_KEY = "customAssetKey"
|
|
|
63
65
|
private const val PROP_OVERRIDE_LAYOUT = "overrideLayout"
|
|
64
66
|
private const val PROP_NETWORK_CODE = "networkCode"
|
|
65
67
|
private const val PROP_USE_ID3 = "useId3"
|
|
68
|
+
private const val PROP_RETRIEVE_POD_ID_URI = "retrievePodIdURI"
|
|
66
69
|
private const val PROP_LATENCY_CONFIGURATION = "latencyConfiguration"
|
|
67
70
|
|
|
68
71
|
private const val ERROR_IMA_NOT_ENABLED = "Google IMA support not enabled."
|
|
@@ -74,6 +77,9 @@ private const val PROP_SSAI_INTEGRATION_GOOGLE_DAI = "google-dai"
|
|
|
74
77
|
|
|
75
78
|
private const val INTEGRATION_THEOLIVE = "theolive"
|
|
76
79
|
|
|
80
|
+
private const val PROP_CMCD = "cmcd"
|
|
81
|
+
private const val CMCD_TRANSMISSION_MODE = "transmissionMode"
|
|
82
|
+
|
|
77
83
|
class SourceAdapter {
|
|
78
84
|
private val gson = Gson()
|
|
79
85
|
|
|
@@ -94,6 +100,12 @@ class SourceAdapter {
|
|
|
94
100
|
try {
|
|
95
101
|
val jsonSourceObject = JSONObject(gson.toJson(source.toHashMap()))
|
|
96
102
|
|
|
103
|
+
// CMCD
|
|
104
|
+
var cmcdTransmissionMode: CMCDTransmissionMode? = null
|
|
105
|
+
if (jsonSourceObject.has(PROP_CMCD)) {
|
|
106
|
+
cmcdTransmissionMode = parseCmcdTransmissionMode(jsonSourceObject.getJSONObject(PROP_CMCD));
|
|
107
|
+
}
|
|
108
|
+
|
|
97
109
|
// typed sources
|
|
98
110
|
val typedSources = ArrayList<TypedSource>()
|
|
99
111
|
|
|
@@ -101,11 +113,11 @@ class SourceAdapter {
|
|
|
101
113
|
val jsonSources = jsonSourceObject.optJSONArray(PROP_SOURCES)
|
|
102
114
|
if (jsonSources != null) {
|
|
103
115
|
for (i in 0 until jsonSources.length()) {
|
|
104
|
-
typedSources.add(parseTypedSource(jsonSources[i] as JSONObject))
|
|
116
|
+
typedSources.add(parseTypedSource(jsonSources[i] as JSONObject, cmcdTransmissionMode))
|
|
105
117
|
}
|
|
106
118
|
} else {
|
|
107
119
|
val jsonSource = jsonSourceObject.optJSONObject(PROP_SOURCES) ?: return null
|
|
108
|
-
typedSources.add(parseTypedSource(jsonSource))
|
|
120
|
+
typedSources.add(parseTypedSource(jsonSource, cmcdTransmissionMode))
|
|
109
121
|
}
|
|
110
122
|
|
|
111
123
|
// poster
|
|
@@ -166,16 +178,16 @@ class SourceAdapter {
|
|
|
166
178
|
}
|
|
167
179
|
|
|
168
180
|
@Throws(THEOplayerException::class)
|
|
169
|
-
private fun parseTypedSource(jsonTypedSource: JSONObject): TypedSource {
|
|
181
|
+
private fun parseTypedSource(jsonTypedSource: JSONObject, cmcdTransmissionMode: CMCDTransmissionMode? = null): TypedSource {
|
|
170
182
|
// Some integrations do not support the Builder pattern
|
|
171
183
|
return when (jsonTypedSource.optString(PROP_INTEGRATION)) {
|
|
172
184
|
INTEGRATION_THEOLIVE -> parseTheoLiveSource(jsonTypedSource)
|
|
173
|
-
else -> parseTypedSourceFromBuilder(jsonTypedSource)
|
|
185
|
+
else -> parseTypedSourceFromBuilder(jsonTypedSource, cmcdTransmissionMode)
|
|
174
186
|
}
|
|
175
187
|
}
|
|
176
188
|
|
|
177
189
|
@Throws(THEOplayerException::class)
|
|
178
|
-
private fun parseTypedSourceFromBuilder(jsonTypedSource: JSONObject): TypedSource {
|
|
190
|
+
private fun parseTypedSourceFromBuilder(jsonTypedSource: JSONObject, cmcdTransmissionMode: CMCDTransmissionMode? = null): TypedSource {
|
|
179
191
|
try {
|
|
180
192
|
var tsBuilder = TypedSource.Builder(jsonTypedSource.optString(PROP_SRC))
|
|
181
193
|
val sourceType = parseSourceType(jsonTypedSource)
|
|
@@ -215,6 +227,9 @@ class SourceAdapter {
|
|
|
215
227
|
tsBuilder.drm(drmConfig)
|
|
216
228
|
}
|
|
217
229
|
}
|
|
230
|
+
if (cmcdTransmissionMode != null) {
|
|
231
|
+
tsBuilder.cmcdTransmissionMode(cmcdTransmissionMode)
|
|
232
|
+
}
|
|
218
233
|
return tsBuilder.build()
|
|
219
234
|
} catch (e: THEOplayerException) {
|
|
220
235
|
// Rethrow THEOplayerException
|
|
@@ -327,12 +342,13 @@ class SourceAdapter {
|
|
|
327
342
|
}
|
|
328
343
|
return TheoAdDescription(
|
|
329
344
|
adTagParameters = parseAdTagParameters(jsonAdDescription.optJSONObject(PROP_AD_TAG_PARAMETERS)),
|
|
330
|
-
backdropDoubleBox = jsonAdDescription.optString(PROP_BACKDROP_DOUBLE_BOX),
|
|
331
|
-
backdropLShape = jsonAdDescription.optString(PROP_BACKDROP_LSHAPE),
|
|
332
|
-
customAssetKey = jsonAdDescription.optString(PROP_CUSTOM_ASSET_KEY),
|
|
333
|
-
networkCode = jsonAdDescription.optString(PROP_NETWORK_CODE),
|
|
345
|
+
backdropDoubleBox = jsonAdDescription.optString(PROP_BACKDROP_DOUBLE_BOX).takeIf { it.isNotEmpty() },
|
|
346
|
+
backdropLShape = jsonAdDescription.optString(PROP_BACKDROP_LSHAPE).takeIf { it.isNotEmpty() },
|
|
347
|
+
customAssetKey = jsonAdDescription.optString(PROP_CUSTOM_ASSET_KEY).takeIf { it.isNotEmpty() },
|
|
348
|
+
networkCode = jsonAdDescription.optString(PROP_NETWORK_CODE).takeIf { it.isNotEmpty() },
|
|
334
349
|
overrideLayout = parseOverrideLayout(jsonAdDescription.optString(PROP_OVERRIDE_LAYOUT)),
|
|
335
|
-
useId3 = jsonAdDescription.optBoolean(PROP_USE_ID3),
|
|
350
|
+
useId3 = jsonAdDescription.optBoolean(PROP_USE_ID3, false),
|
|
351
|
+
retrievePodIdURI = jsonAdDescription.optString(PROP_RETRIEVE_POD_ID_URI).takeIf { it.isNotEmpty() },
|
|
336
352
|
)
|
|
337
353
|
}
|
|
338
354
|
|
|
@@ -429,4 +445,17 @@ class SourceAdapter {
|
|
|
429
445
|
|
|
430
446
|
return BridgeUtils.fromJSONObjectToBridge(json)
|
|
431
447
|
}
|
|
448
|
+
|
|
449
|
+
private fun parseCmcdTransmissionMode(cmcdConfiguration : JSONObject) : CMCDTransmissionMode {
|
|
450
|
+
try {
|
|
451
|
+
val transmissionMode = cmcdConfiguration.optInt(CMCD_TRANSMISSION_MODE)
|
|
452
|
+
if (transmissionMode === CmcdTransmissionMode.QUERY_ARGUMENT.ordinal) {
|
|
453
|
+
return CMCDTransmissionMode.QUERY_ARGUMENT
|
|
454
|
+
}
|
|
455
|
+
return CMCDTransmissionMode.HTTP_HEADER
|
|
456
|
+
} catch (e: JSONException) {
|
|
457
|
+
e.printStackTrace()
|
|
458
|
+
return CMCDTransmissionMode.HTTP_HEADER
|
|
459
|
+
}
|
|
460
|
+
}
|
|
432
461
|
}
|
|
@@ -8,9 +8,9 @@ import org.json.JSONException
|
|
|
8
8
|
import org.json.JSONObject
|
|
9
9
|
|
|
10
10
|
object BridgeUtils {
|
|
11
|
-
fun fromJSONObjectToMap(json: JSONObject): Map<String, String> {
|
|
11
|
+
fun fromJSONObjectToMap(json: JSONObject?): Map<String, String> {
|
|
12
12
|
return mutableMapOf<String, String>().apply {
|
|
13
|
-
json
|
|
13
|
+
json?.keys()?.forEach { key ->
|
|
14
14
|
put(key, json.getString(key))
|
|
15
15
|
}
|
|
16
16
|
}
|
|
@@ -226,6 +226,7 @@ class THEOplayerRCTPlayerAPI: NSObject, RCTBridgeModule {
|
|
|
226
226
|
private func parsePipConfig(configDict: NSDictionary) -> PipConfig {
|
|
227
227
|
var pipConfig = PipConfig()
|
|
228
228
|
pipConfig.canStartPictureInPictureAutomaticallyFromInline = configDict["startsAutomatically"] as? Bool ?? false
|
|
229
|
+
pipConfig.retainPresentationModeOnSourceChange = configDict["retainPipOnSourceChange"] as? Bool ?? false
|
|
229
230
|
return pipConfig
|
|
230
231
|
}
|
|
231
232
|
|
|
@@ -57,7 +57,9 @@ let SD_PROP_BACKDROP_L_SHAPE: String = "backdropLShape"
|
|
|
57
57
|
let SD_PROP_OVERRIDE_LAYOUT: String = "overrideLayout"
|
|
58
58
|
let SD_PROP_OVERRIDE_AD_SRC: String = "overrideAdSrc"
|
|
59
59
|
let SD_PROP_USE_ID3: String = "useId3"
|
|
60
|
+
let SD_PROP_RETRIEVE_POD_ID_URI: String = "retrievePodIdURI"
|
|
60
61
|
let SD_PROP_HLS_DATE_RANGE: String = "hlsDateRange"
|
|
62
|
+
let SD_PROP_CMCD: String = "cmcd"
|
|
61
63
|
|
|
62
64
|
let EXTENSION_HLS: String = ".m3u8"
|
|
63
65
|
let EXTENSION_MP4: String = ".mp4"
|
|
@@ -156,8 +158,15 @@ class THEOplayerRCTSourceDescriptionBuilder {
|
|
|
156
158
|
if let metadataData = sourceData[SD_PROP_METADATA] as? [String:Any] {
|
|
157
159
|
metadataDescription = THEOplayerRCTSourceDescriptionBuilder.buildMetaDataDescription(metadataData)
|
|
158
160
|
}
|
|
161
|
+
|
|
162
|
+
// 6. configure CMCD
|
|
163
|
+
if let cmcd = sourceData[SD_PROP_CMCD] as? [String:Any] {
|
|
164
|
+
typedSources.forEach { typedSource in
|
|
165
|
+
typedSource.cmcd = true;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
159
168
|
|
|
160
|
-
//
|
|
169
|
+
// 7. construct the SourceDescription
|
|
161
170
|
let sourceDescription = SourceDescription(sources: typedSources,
|
|
162
171
|
textTracks: textTrackDescriptions,
|
|
163
172
|
ads: adsDescriptions,
|