react-native-theoplayer 7.0.0 → 7.1.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 +16 -0
- package/README.md +0 -2
- package/android/build.gradle +1 -8
- package/android/src/main/java/com/theoplayer/PlayerConfigAdapter.kt +59 -2
- package/android/src/main/java/com/theoplayer/ReactTHEOplayerContext.kt +33 -12
- package/android/src/main/java/com/theoplayer/media/MediaPlaybackService.kt +1 -1
- package/android/src/main/java/com/theoplayer/media/MediaSessionConfig.kt +18 -0
- package/android/src/main/java/com/theoplayer/media/MediaSessionConfigAdapter.kt +23 -0
- package/ios/THEOplayerRCTSourceDescriptionBuilder.swift +1 -11
- package/ios/THEOplayerRCTTrackMetadataAggregator.swift +2 -0
- package/ios/ads/THEOplayerRCTAdsAPI+DAI.swift +1 -1
- package/ios/ads/THEOplayerRCTAdsAPI.swift +1 -1
- package/ios/ads/THEOplayerRCTAdsEventHandler.swift +2 -2
- package/ios/ads/THEOplayerRCTSourceDescriptionBuilder+Ads.swift +3 -3
- package/ios/ads/THEOplayerRCTView+Ads.swift +35 -1
- package/ios/ads/THEOplayerRCTView+AdsConfig.swift +33 -14
- package/ios/backgroundAudio/THEOplayerRCTRemoteCommandsManager.swift +2 -2
- package/ios/backgroundAudio/THEOplayerRCTView+BackgroundAudioConfig.swift +0 -12
- package/ios/pip/THEOplayerRCTPipControlsManager.swift +3 -3
- package/lib/commonjs/internal/THEOplayerView.web.js +11 -1
- package/lib/commonjs/internal/THEOplayerView.web.js.map +1 -1
- package/lib/commonjs/internal/adapter/THEOplayerWebAdapter.js +1 -1
- package/lib/commonjs/internal/adapter/THEOplayerWebAdapter.js.map +1 -1
- package/lib/commonjs/internal/adapter/web/WebMediaSession.js +10 -6
- package/lib/commonjs/internal/adapter/web/WebMediaSession.js.map +1 -1
- package/lib/module/internal/THEOplayerView.web.js +11 -1
- package/lib/module/internal/THEOplayerView.web.js.map +1 -1
- package/lib/module/internal/adapter/THEOplayerWebAdapter.js +1 -1
- package/lib/module/internal/adapter/THEOplayerWebAdapter.js.map +1 -1
- package/lib/module/internal/adapter/web/WebMediaSession.js +9 -5
- package/lib/module/internal/adapter/web/WebMediaSession.js.map +1 -1
- package/lib/typescript/api/ads/AdsConfiguration.d.ts +3 -2
- package/lib/typescript/api/ads/AdsConfiguration.d.ts.map +1 -1
- package/lib/typescript/api/ads/GoogleImaConfiguration.d.ts +34 -5
- package/lib/typescript/api/ads/GoogleImaConfiguration.d.ts.map +1 -1
- package/lib/typescript/api/media/MediaControlConfiguration.d.ts +19 -1
- package/lib/typescript/api/media/MediaControlConfiguration.d.ts.map +1 -1
- package/lib/typescript/internal/THEOplayerView.web.d.ts.map +1 -1
- package/lib/typescript/internal/adapter/web/WebMediaSession.d.ts +3 -6
- package/lib/typescript/internal/adapter/web/WebMediaSession.d.ts.map +1 -1
- package/package.json +1 -1
- package/react-native-theoplayer.podspec +18 -25
- package/src/api/ads/AdsConfiguration.ts +3 -2
- package/src/api/ads/GoogleImaConfiguration.ts +37 -5
- package/src/api/media/MediaControlConfiguration.ts +21 -1
- package/src/internal/THEOplayerView.web.tsx +14 -1
- package/src/internal/adapter/THEOplayerWebAdapter.ts +1 -1
- package/src/internal/adapter/web/WebMediaSession.ts +11 -9
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,22 @@ 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
|
+
## [7.1.0] - 24-04-23
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- Fixed a build issue on tvOS example app due to the deprecated `prepare` method.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- Added multiple configuration options to `GoogleImaConfiguration` for both iOS and Android. These map to the corresponding IMASettings from the underlying native Google IMA SDKs.
|
|
17
|
+
- Added `skipForwardInterval` and `skipBackwardInterval` properties to `MediaControlConfiguration` for Android and Web, enabling configurable skip intervals for media sessions.
|
|
18
|
+
- Added ios bridging code to make 'forced' property available from native iOS TextTrack API.
|
|
19
|
+
|
|
20
|
+
### Removed
|
|
21
|
+
|
|
22
|
+
- Removed support for the web-based native iOS SDK on the RN iOS Bridge.
|
|
23
|
+
|
|
8
24
|
## [7.0.0] - 24-04-10
|
|
9
25
|
|
|
10
26
|
### Fixed
|
package/README.md
CHANGED
|
@@ -168,11 +168,9 @@ This section gives an overview of features, limitations and known issues:
|
|
|
168
168
|
- [Audio Control Management](./doc/audio-control.md)
|
|
169
169
|
- [Background playback and notifications](./doc/background.md)
|
|
170
170
|
- [Casting with Chromecast and Airplay](./doc/cast.md)
|
|
171
|
-
- [Custom iOS framework](./doc/custom-ios-framework.md)
|
|
172
171
|
- [Digital Rights Management (DRM)](./doc/drm.md)
|
|
173
172
|
- [Fullscreen presentation](./doc/fullscreen.md)
|
|
174
173
|
- [Media Caching](./doc/media-caching.md)
|
|
175
|
-
- [Migrating to `react-native-theoplayer` v2.x](./doc/migrating-v2.md)
|
|
176
174
|
- [Picture-in-Picture (PiP)](./doc/pip.md)
|
|
177
175
|
- [Subtitles, Closed Captions and Metadata tracks](./doc/texttracks.md)
|
|
178
176
|
- [Limitations and known issues](./doc/limitations.md)
|
package/android/build.gradle
CHANGED
|
@@ -118,14 +118,7 @@ dependencies {
|
|
|
118
118
|
println("Using THEOplayer (${versionString(theoplayer_sdk_version)})")
|
|
119
119
|
implementation "com.theoplayer.theoplayer-sdk-android:core:${theoplayer_sdk_version}"
|
|
120
120
|
implementation "com.theoplayer.theoplayer-sdk-android:ads-wrapper:6.10.0"
|
|
121
|
-
|
|
122
|
-
if (enabledMediaSession) {
|
|
123
|
-
println("Enable THEOplayer MediaSession extension (${versionString(theoplayer_sdk_version)})")
|
|
124
|
-
implementation "com.theoplayer.android-connector:mediasession:${theoplayer_sdk_version}"
|
|
125
|
-
} else {
|
|
126
|
-
println('Disable THEOplayer MediaSession extension.')
|
|
127
|
-
compileOnly "com.theoplayer.android-connector:mediasession:${theoplayer_sdk_version}"
|
|
128
|
-
}
|
|
121
|
+
implementation "com.theoplayer.android-connector:mediasession:${theoplayer_sdk_version}"
|
|
129
122
|
|
|
130
123
|
if (enabledGoogleIMA) {
|
|
131
124
|
println('Enable THEOplayer IMA extension.')
|
|
@@ -6,11 +6,14 @@ import com.google.ads.interactivemedia.v3.api.AdsRenderingSettings
|
|
|
6
6
|
import com.google.ads.interactivemedia.v3.api.ImaSdkFactory
|
|
7
7
|
import com.google.ads.interactivemedia.v3.api.ImaSdkSettings
|
|
8
8
|
import com.theoplayer.android.api.THEOplayerConfig
|
|
9
|
+
import com.theoplayer.android.api.THEOplayerGlobal
|
|
9
10
|
import com.theoplayer.android.api.cast.CastStrategy
|
|
10
11
|
import com.theoplayer.android.api.cast.CastConfiguration
|
|
11
12
|
import com.theoplayer.android.api.pip.PipConfiguration
|
|
12
13
|
import com.theoplayer.android.api.player.NetworkConfiguration
|
|
13
14
|
import com.theoplayer.android.api.ui.UIConfiguration
|
|
15
|
+
import com.theoplayer.media.MediaSessionConfig
|
|
16
|
+
import com.theoplayer.media.MediaSessionConfigAdapter
|
|
14
17
|
|
|
15
18
|
private const val PROP_LICENSE = "license"
|
|
16
19
|
private const val PROP_LICENSE_URL = "licenseUrl"
|
|
@@ -26,7 +29,15 @@ private const val PROP_RETRY_MIN_BACKOFF = "minimumBackoff"
|
|
|
26
29
|
private const val PROP_RETRY_MAX_BACKOFF = "maximumBackoff"
|
|
27
30
|
private const val PROP_CAST_CONFIGURATION = "cast"
|
|
28
31
|
private const val PROP_ADS_CONFIGURATION = "ads"
|
|
32
|
+
private const val PROP_IMA_CONFIGURATION = "ima"
|
|
29
33
|
private const val PROP_UI_CONFIGURATION = "ui"
|
|
34
|
+
private const val PROP_MEDIA_CONTROL = "mediaControl"
|
|
35
|
+
private const val PROP_PPID = "ppid"
|
|
36
|
+
private const val PROP_MAX_REDIRECTS = "maxRedirects"
|
|
37
|
+
private const val PROP_FEATURE_FLAGS = "featureFlags"
|
|
38
|
+
private const val PROP_AUTOPLAY_AD_BREAKS = "autoPlayAdBreaks"
|
|
39
|
+
private const val PROP_SESSION_ID = "sessionID"
|
|
40
|
+
private const val PROP_ENABLE_DEBUG_MODE = "enableDebugMode"
|
|
30
41
|
|
|
31
42
|
class PlayerConfigAdapter(private val configProps: ReadableMap?) {
|
|
32
43
|
|
|
@@ -91,8 +102,44 @@ class PlayerConfigAdapter(private val configProps: ReadableMap?) {
|
|
|
91
102
|
*/
|
|
92
103
|
fun imaSdkSettings(): ImaSdkSettings{
|
|
93
104
|
return ImaSdkFactory.getInstance().createImaSdkSettings().apply {
|
|
94
|
-
configProps?.getMap(PROP_ADS_CONFIGURATION)?.run {
|
|
95
|
-
//
|
|
105
|
+
configProps?.getMap(PROP_ADS_CONFIGURATION)?.getMap(PROP_IMA_CONFIGURATION)?.run {
|
|
106
|
+
// Specifies whether VMAP and ad rules ad breaks are automatically played.
|
|
107
|
+
if (hasKey(PROP_AUTOPLAY_AD_BREAKS)) {
|
|
108
|
+
autoPlayAdBreaks = getBoolean(PROP_AUTOPLAY_AD_BREAKS)
|
|
109
|
+
}
|
|
110
|
+
// Feature flags and their states. Used to control experimental features.
|
|
111
|
+
if (hasKey(PROP_FEATURE_FLAGS)) {
|
|
112
|
+
val convertedMap: MutableMap<String, String> = mutableMapOf()
|
|
113
|
+
getMap(PROP_FEATURE_FLAGS)?.toHashMap()?.forEach { (key, value) ->
|
|
114
|
+
convertedMap[key] = value as String
|
|
115
|
+
}
|
|
116
|
+
featureFlags = convertedMap
|
|
117
|
+
}
|
|
118
|
+
// The current ISO 639-1 language code, get it from the UI config.
|
|
119
|
+
uiConfig().language?.let {
|
|
120
|
+
language = it
|
|
121
|
+
}
|
|
122
|
+
// The maximum number of VAST redirects.
|
|
123
|
+
if (hasKey(PROP_MAX_REDIRECTS)) {
|
|
124
|
+
maxRedirects = getInt(PROP_MAX_REDIRECTS)
|
|
125
|
+
}
|
|
126
|
+
// The partner provided player type.
|
|
127
|
+
playerType = "THEOplayer"
|
|
128
|
+
// The partner provided player version.
|
|
129
|
+
playerVersion = THEOplayerGlobal.getVersion()
|
|
130
|
+
// The Publisher Provided Identification (PPID) sent with ads request.
|
|
131
|
+
if (hasKey(PROP_PPID)) {
|
|
132
|
+
ppid = getString(PROP_PPID) ?: ""
|
|
133
|
+
}
|
|
134
|
+
// The session ID to identify a single user session. This should be a UUID. It
|
|
135
|
+
// is used exclusively for frequency capping across the user session.
|
|
136
|
+
if (hasKey(PROP_SESSION_ID)) {
|
|
137
|
+
sessionId = getString(PROP_PPID) ?: ""
|
|
138
|
+
}
|
|
139
|
+
// Toggles debug mode which will output detailed log information to the console.
|
|
140
|
+
if (hasKey(PROP_ENABLE_DEBUG_MODE)) {
|
|
141
|
+
isDebugMode = getBoolean(PROP_ENABLE_DEBUG_MODE)
|
|
142
|
+
}
|
|
96
143
|
}
|
|
97
144
|
}
|
|
98
145
|
}
|
|
@@ -154,4 +201,14 @@ class PlayerConfigAdapter(private val configProps: ReadableMap?) {
|
|
|
154
201
|
else -> null
|
|
155
202
|
}
|
|
156
203
|
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Get MediaSession connector configuration; these properties apply:
|
|
207
|
+
* - mediaSessionEnabled: whether or not the media session should be enabled.
|
|
208
|
+
* - skipForwardInterval: the amount of seconds the player will skip forward.
|
|
209
|
+
* - skipBackwardInterval: the amount of seconds the player will skip backward.
|
|
210
|
+
*/
|
|
211
|
+
fun mediaSessionConfig(): MediaSessionConfig {
|
|
212
|
+
return MediaSessionConfigAdapter.fromProps(configProps?.getMap(PROP_MEDIA_CONTROL))
|
|
213
|
+
}
|
|
157
214
|
}
|
|
@@ -28,6 +28,7 @@ import com.theoplayer.audio.AudioBecomingNoisyManager
|
|
|
28
28
|
import com.theoplayer.audio.AudioFocusManager
|
|
29
29
|
import com.theoplayer.audio.BackgroundAudioConfig
|
|
30
30
|
import com.theoplayer.media.MediaPlaybackService
|
|
31
|
+
import com.theoplayer.media.MediaSessionConfig
|
|
31
32
|
import java.util.concurrent.atomic.AtomicBoolean
|
|
32
33
|
|
|
33
34
|
private const val TAG = "ReactTHEOplayerContext"
|
|
@@ -42,7 +43,8 @@ private const val ALLOWED_PLAYBACK_ACTIONS = (
|
|
|
42
43
|
PlaybackStateCompat.ACTION_SET_PLAYBACK_SPEED)
|
|
43
44
|
|
|
44
45
|
class ReactTHEOplayerContext private constructor(
|
|
45
|
-
private val reactContext: ThemedReactContext
|
|
46
|
+
private val reactContext: ThemedReactContext,
|
|
47
|
+
private val configAdapter: PlayerConfigAdapter
|
|
46
48
|
) {
|
|
47
49
|
private val mainHandler = Handler(Looper.getMainLooper())
|
|
48
50
|
private var isBound = AtomicBoolean()
|
|
@@ -60,6 +62,12 @@ class ReactTHEOplayerContext private constructor(
|
|
|
60
62
|
field = value
|
|
61
63
|
}
|
|
62
64
|
|
|
65
|
+
var mediaSessionConfig: MediaSessionConfig = configAdapter.mediaSessionConfig()
|
|
66
|
+
set(value) {
|
|
67
|
+
applyMediaSessionConfig(mediaSessionConnector, value)
|
|
68
|
+
field = value
|
|
69
|
+
}
|
|
70
|
+
|
|
63
71
|
lateinit var playerView: THEOplayerView
|
|
64
72
|
|
|
65
73
|
val player: Player
|
|
@@ -85,8 +93,8 @@ class ReactTHEOplayerContext private constructor(
|
|
|
85
93
|
reactContext: ThemedReactContext,
|
|
86
94
|
configAdapter: PlayerConfigAdapter
|
|
87
95
|
): ReactTHEOplayerContext {
|
|
88
|
-
return ReactTHEOplayerContext(reactContext).apply {
|
|
89
|
-
initializePlayerView(
|
|
96
|
+
return ReactTHEOplayerContext(reactContext, configAdapter).apply {
|
|
97
|
+
initializePlayerView()
|
|
90
98
|
}
|
|
91
99
|
}
|
|
92
100
|
}
|
|
@@ -96,9 +104,9 @@ class ReactTHEOplayerContext private constructor(
|
|
|
96
104
|
binder = service as MediaPlaybackService.MediaPlaybackBinder
|
|
97
105
|
|
|
98
106
|
// Get media session connector from service
|
|
99
|
-
mediaSessionConnector = binder?.mediaSessionConnector
|
|
100
|
-
|
|
101
|
-
|
|
107
|
+
mediaSessionConnector = binder?.mediaSessionConnector?.also {
|
|
108
|
+
applyMediaSessionConfig(it, mediaSessionConfig)
|
|
109
|
+
}
|
|
102
110
|
|
|
103
111
|
// Pass player context
|
|
104
112
|
binder?.setPlayerContext(this@ReactTHEOplayerContext)
|
|
@@ -184,7 +192,7 @@ class ReactTHEOplayerContext private constructor(
|
|
|
184
192
|
binder = null
|
|
185
193
|
}
|
|
186
194
|
|
|
187
|
-
private fun initializePlayerView(
|
|
195
|
+
private fun initializePlayerView() {
|
|
188
196
|
playerView = object : THEOplayerView(reactContext.currentActivity!!, configAdapter.playerConfig()) {
|
|
189
197
|
private fun measureAndLayout() {
|
|
190
198
|
measure(
|
|
@@ -205,7 +213,7 @@ class ReactTHEOplayerContext private constructor(
|
|
|
205
213
|
// By default, the screen should remain on.
|
|
206
214
|
playerView.keepScreenOn = true
|
|
207
215
|
|
|
208
|
-
addIntegrations(
|
|
216
|
+
addIntegrations()
|
|
209
217
|
addListeners()
|
|
210
218
|
|
|
211
219
|
audioFocusManager = AudioFocusManager(reactContext, player)
|
|
@@ -229,17 +237,30 @@ class ReactTHEOplayerContext private constructor(
|
|
|
229
237
|
mediaSession.setMediaButtonReceiver(null)
|
|
230
238
|
|
|
231
239
|
// Create a MediaSessionConnector and attach the THEOplayer instance.
|
|
232
|
-
mediaSessionConnector = MediaSessionConnector(mediaSession).
|
|
240
|
+
mediaSessionConnector = MediaSessionConnector(mediaSession).also {
|
|
241
|
+
applyMediaSessionConfig(it, mediaSessionConfig)
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
private fun applyMediaSessionConfig(connector: MediaSessionConnector?, config: MediaSessionConfig) {
|
|
246
|
+
connector?.apply {
|
|
233
247
|
debug = BuildConfig.LOG_MEDIASESSION_EVENTS
|
|
248
|
+
|
|
234
249
|
player = this@ReactTHEOplayerContext.player
|
|
235
250
|
|
|
236
251
|
// Set mediaSession active and ready to receive media button events, but not if the player
|
|
237
252
|
// is backgrounded.
|
|
238
|
-
setActive(!isHostPaused)
|
|
253
|
+
setActive(!isHostPaused && BuildConfig.EXTENSION_MEDIASESSION && config.mediaSessionEnabled)
|
|
254
|
+
|
|
255
|
+
skipForwardInterval = config.skipForwardInterval
|
|
256
|
+
skipBackwardsInterval = config.skipBackwardInterval
|
|
257
|
+
|
|
258
|
+
// Pass metadata from source description
|
|
259
|
+
setMediaSessionMetadata(player?.source)
|
|
239
260
|
}
|
|
240
261
|
}
|
|
241
262
|
|
|
242
|
-
private fun addIntegrations(
|
|
263
|
+
private fun addIntegrations() {
|
|
243
264
|
try {
|
|
244
265
|
if (BuildConfig.EXTENSION_GOOGLE_IMA) {
|
|
245
266
|
imaIntegration = GoogleImaIntegrationFactory.createGoogleImaIntegration(
|
|
@@ -357,7 +378,7 @@ class ReactTHEOplayerContext private constructor(
|
|
|
357
378
|
*/
|
|
358
379
|
fun onHostResume() {
|
|
359
380
|
isHostPaused = false
|
|
360
|
-
mediaSessionConnector?.setActive(
|
|
381
|
+
mediaSessionConnector?.setActive(BuildConfig.EXTENSION_MEDIASESSION)
|
|
361
382
|
playerView.onResume()
|
|
362
383
|
if (!player.isPaused) {
|
|
363
384
|
audioFocusManager?.retrieveAudioFocus()
|
|
@@ -173,7 +173,7 @@ class MediaPlaybackService : MediaBrowserServiceCompat() {
|
|
|
173
173
|
debug = BuildConfig.LOG_MEDIASESSION_EVENTS
|
|
174
174
|
|
|
175
175
|
// Set mediaSession active
|
|
176
|
-
setActive(
|
|
176
|
+
setActive(BuildConfig.EXTENSION_MEDIASESSION)
|
|
177
177
|
}
|
|
178
178
|
|
|
179
179
|
// Set the MediaBrowserServiceCompat's media session.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
package com.theoplayer.media
|
|
2
|
+
|
|
3
|
+
data class MediaSessionConfig (
|
|
4
|
+
/**
|
|
5
|
+
* Whether or not the media session should be enabled.
|
|
6
|
+
*/
|
|
7
|
+
var mediaSessionEnabled: Boolean = true,
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* The amount of seconds the player will skip forward.
|
|
11
|
+
*/
|
|
12
|
+
var skipForwardInterval: Double = 5.0,
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The amount of seconds the player will skip backward.
|
|
16
|
+
*/
|
|
17
|
+
var skipBackwardInterval: Double = 5.0,
|
|
18
|
+
)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
package com.theoplayer.media
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.ReadableMap
|
|
4
|
+
|
|
5
|
+
object MediaSessionConfigAdapter {
|
|
6
|
+
private const val PROP_ENABLED = "mediaSessionEnabled"
|
|
7
|
+
private const val PROP_SKIP_FORWARD_INTERVAL = "skipForwardInterval"
|
|
8
|
+
private const val PROP_SKIP_BACKWARD_INTERVAL = "skipBackwardInterval"
|
|
9
|
+
|
|
10
|
+
fun fromProps(props: ReadableMap?): MediaSessionConfig {
|
|
11
|
+
return MediaSessionConfig().apply {
|
|
12
|
+
if (props?.hasKey(PROP_ENABLED) == true) {
|
|
13
|
+
mediaSessionEnabled = props.getBoolean(PROP_ENABLED)
|
|
14
|
+
}
|
|
15
|
+
if (props?.hasKey(PROP_SKIP_FORWARD_INTERVAL) == true) {
|
|
16
|
+
skipForwardInterval = props.getDouble(PROP_SKIP_FORWARD_INTERVAL)
|
|
17
|
+
}
|
|
18
|
+
if (props?.hasKey(PROP_SKIP_BACKWARD_INTERVAL) == true) {
|
|
19
|
+
skipBackwardInterval = props.getDouble(PROP_SKIP_BACKWARD_INTERVAL)
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -352,17 +352,7 @@ class THEOplayerRCTSourceDescriptionBuilder {
|
|
|
352
352
|
static func buildContentProtection(_ contentProtectionData: [String:Any]) -> MultiplatformDRMConfiguration? {
|
|
353
353
|
do {
|
|
354
354
|
let data = try JSONSerialization.data(withJSONObject: contentProtectionData)
|
|
355
|
-
|
|
356
|
-
switch integration {
|
|
357
|
-
case DRM_INTEGRATION_ID_EZDRM: return try JSONDecoder().decode(EzdrmDRMConfiguration.self, from: data)
|
|
358
|
-
case DRM_INTEGRATION_ID_KEYOS: return try JSONDecoder().decode(KeyOSDRMConfiguration.self, from: data)
|
|
359
|
-
case DRM_INTEGRATION_ID_VERIMATRIX: return try JSONDecoder().decode(VerimatrixDRMConfiguration.self, from: data)
|
|
360
|
-
default: return try JSONDecoder().decode(MultiplatformDRMConfiguration.self, from: data)
|
|
361
|
-
}
|
|
362
|
-
} else {
|
|
363
|
-
PrintUtils.printLog(logText: "[NATIVE] integration type not specified... trying default drm integration")
|
|
364
|
-
return try JSONDecoder().decode(MultiplatformDRMConfiguration.self, from: data)
|
|
365
|
-
}
|
|
355
|
+
return try JSONDecoder().decode(MultiplatformDRMConfiguration.self, from: data)
|
|
366
356
|
} catch {
|
|
367
357
|
PrintUtils.printLog(logText: "[NATIVE] unsupported contentProtection data format")
|
|
368
358
|
}
|
|
@@ -26,6 +26,7 @@ let PROP_CUES: String = "cues"
|
|
|
26
26
|
let PROP_CUE_CONTENT: String = "content"
|
|
27
27
|
let PROP_CUE_CUSTOM_ATTRIBUTES: String = "customAttributes"
|
|
28
28
|
let PROP_SRC: String = "src"
|
|
29
|
+
let PROP_FORCED: String = "forced"
|
|
29
30
|
let PROP_START_DATE: String = "startDate"
|
|
30
31
|
let PROP_END_DATE: String = "endDate"
|
|
31
32
|
let PROP_ATTRIBUTE_CLASS: String = "class"
|
|
@@ -73,6 +74,7 @@ class THEOplayerRCTTrackMetadataAggregator {
|
|
|
73
74
|
entry[PROP_LABEL] = textTrack.label
|
|
74
75
|
entry[PROP_TYPE] = textTrack.type
|
|
75
76
|
entry[PROP_SRC] = textTrack.src
|
|
77
|
+
entry[PROP_FORCED] = textTrack.forced
|
|
76
78
|
// process cues when texttrack contains them
|
|
77
79
|
if !textTrack.cues.isEmpty {
|
|
78
80
|
var cueList: [[String:Any]] = []
|
|
@@ -11,7 +11,7 @@ let ERROR_MESSAGE_DAI_GET_SNAPBACK_UNDEFINED = "Undefined dai snapback"
|
|
|
11
11
|
|
|
12
12
|
extension THEOplayerRCTAdsAPI {
|
|
13
13
|
|
|
14
|
-
#if
|
|
14
|
+
#if canImport(THEOplayerGoogleIMAIntegration)
|
|
15
15
|
@objc(daiSnapback:resolver:rejecter:)
|
|
16
16
|
func daiSnapback(_ node: NSNumber, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void {
|
|
17
17
|
DispatchQueue.main.async {
|
|
@@ -34,7 +34,7 @@ class THEOplayerRCTAdsAPI: NSObject, RCTBridgeModule {
|
|
|
34
34
|
return false
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
#if
|
|
37
|
+
#if canImport(THEOplayerGoogleIMAIntegration)
|
|
38
38
|
@objc(skip:)
|
|
39
39
|
func skip(_ node: NSNumber) -> Void {
|
|
40
40
|
|
|
@@ -54,7 +54,7 @@ class THEOplayerRCTAdsEventHandler {
|
|
|
54
54
|
return
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
#if
|
|
57
|
+
#if canImport(THEOplayerGoogleIMAIntegration)
|
|
58
58
|
// AD_BEGIN
|
|
59
59
|
self.adBeginListener = player.ads.addEventListener(type: AdsEventTypes.AD_BEGIN) { [weak self] event in
|
|
60
60
|
if DEBUG_THEOPLAYER_EVENTS { PrintUtils.printLog(logText: "[NATIVE] Received AD_BEGIN event from THEOplayer Ads") }
|
|
@@ -180,7 +180,7 @@ class THEOplayerRCTAdsEventHandler {
|
|
|
180
180
|
return
|
|
181
181
|
}
|
|
182
182
|
|
|
183
|
-
#if
|
|
183
|
+
#if canImport(THEOplayerGoogleIMAIntegration)
|
|
184
184
|
// AD_BEGIN
|
|
185
185
|
if let adBeginListener = self.adBeginListener {
|
|
186
186
|
player.ads.removeEventListener(type: AdsEventTypes.AD_BEGIN, listener: adBeginListener)
|
|
@@ -15,7 +15,7 @@ extension THEOplayerRCTSourceDescriptionBuilder {
|
|
|
15
15
|
static func buildAdDescriptions(_ sourceData: NSDictionary) -> [AdDescription]? {
|
|
16
16
|
var adsDescriptions: [AdDescription]?
|
|
17
17
|
|
|
18
|
-
#if
|
|
18
|
+
#if canImport(THEOplayerGoogleIMAIntegration)
|
|
19
19
|
if let ads = sourceData[SD_PROP_ADS] {
|
|
20
20
|
adsDescriptions = []
|
|
21
21
|
// case: array of ads objects
|
|
@@ -53,7 +53,7 @@ extension THEOplayerRCTSourceDescriptionBuilder {
|
|
|
53
53
|
- returns: a THEOplayer GoogleImaAdDescription
|
|
54
54
|
*/
|
|
55
55
|
static func buildSingleAdDescription(_ adsData: [String:Any]) -> AdDescription? {
|
|
56
|
-
#if
|
|
56
|
+
#if canImport(THEOplayerGoogleIMAIntegration)
|
|
57
57
|
if let integration = adsData[SD_PROP_INTEGRATION] as? String,
|
|
58
58
|
integration == AdIntegration.google_ima._rawValue {
|
|
59
59
|
// timeOffset can be Int or String: 10, "01:32:54.78", "1234.56", "start", "end", "10%", ...
|
|
@@ -77,7 +77,7 @@ extension THEOplayerRCTSourceDescriptionBuilder {
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
static func buildDAITypedSource(_ typedSourceData: [String:Any], contentProtection: MultiplatformDRMConfiguration?) -> TypedSource? {
|
|
80
|
-
#if
|
|
80
|
+
#if canImport(THEOplayerGoogleIMAIntegration)
|
|
81
81
|
// check for alternative Google DAI SSAI
|
|
82
82
|
if let ssaiData = typedSourceData[SD_PROP_SSAI] as? [String:Any] {
|
|
83
83
|
if let integration = ssaiData[SD_PROP_INTEGRATION] as? String,
|
|
@@ -5,6 +5,7 @@ import THEOplayerSDK
|
|
|
5
5
|
|
|
6
6
|
#if canImport(THEOplayerGoogleIMAIntegration)
|
|
7
7
|
import THEOplayerGoogleIMAIntegration
|
|
8
|
+
import GoogleInteractiveMediaAds
|
|
8
9
|
#endif
|
|
9
10
|
|
|
10
11
|
extension THEOplayerRCTView {
|
|
@@ -21,7 +22,40 @@ extension THEOplayerRCTView {
|
|
|
21
22
|
return
|
|
22
23
|
}
|
|
23
24
|
#if canImport(THEOplayerGoogleIMAIntegration)
|
|
24
|
-
|
|
25
|
+
// prepare imaSettings
|
|
26
|
+
let imaSettings = IMASettings()
|
|
27
|
+
imaSettings.language = self.uiConfig.language
|
|
28
|
+
imaSettings.maxRedirects = self.adsConfig.adsImaConfig.maxRedirects
|
|
29
|
+
imaSettings.enableDebugMode = self.adsConfig.adsImaConfig.enableDebugMode
|
|
30
|
+
imaSettings.playerType = "THEOplayer"
|
|
31
|
+
imaSettings.playerVersion = THEOplayer.version
|
|
32
|
+
imaSettings.enableBackgroundPlayback = true
|
|
33
|
+
if let ppid = self.adsConfig.adsImaConfig.ppid {
|
|
34
|
+
imaSettings.ppid = ppid
|
|
35
|
+
}
|
|
36
|
+
#if os(iOS)
|
|
37
|
+
if let featureFlags = self.adsConfig.adsImaConfig.featureFlags {
|
|
38
|
+
imaSettings.featureFlags = featureFlags
|
|
39
|
+
}
|
|
40
|
+
#endif
|
|
41
|
+
if let autoPlayAdBreaks = self.adsConfig.adsImaConfig.autoPlayAdBreaks {
|
|
42
|
+
imaSettings.autoPlayAdBreaks = autoPlayAdBreaks
|
|
43
|
+
}
|
|
44
|
+
if let sessionID = self.adsConfig.adsImaConfig.sessionID {
|
|
45
|
+
imaSettings.sessionID = sessionID
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// setup ima render settings
|
|
49
|
+
let imaRenderSettings = IMAAdsRenderingSettings()
|
|
50
|
+
let disableUi = !self.adsConfig.adSUIEnabled
|
|
51
|
+
if disableUi {
|
|
52
|
+
imaRenderSettings.disableUi = disableUi
|
|
53
|
+
imaRenderSettings.uiElements = []
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// setup integration
|
|
57
|
+
let imaIntegration = GoogleIMAIntegrationFactory.createIntegration(on: player, with: imaSettings)
|
|
58
|
+
imaIntegration.renderingSettings = imaRenderSettings
|
|
25
59
|
player.addIntegration(imaIntegration)
|
|
26
60
|
#endif
|
|
27
61
|
}
|
|
@@ -6,6 +6,16 @@ import THEOplayerSDK
|
|
|
6
6
|
struct AdsConfig {
|
|
7
7
|
var adSUIEnabled: Bool = true
|
|
8
8
|
var adPreloadTypeString: String = "none"
|
|
9
|
+
var adsImaConfig = AdsImaConfig()
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
struct AdsImaConfig {
|
|
13
|
+
var maxRedirects: UInt = 4
|
|
14
|
+
var enableDebugMode: Bool = false
|
|
15
|
+
var ppid: String?
|
|
16
|
+
var featureFlags: [String:String]?
|
|
17
|
+
var autoPlayAdBreaks: Bool?
|
|
18
|
+
var sessionID: String?
|
|
9
19
|
}
|
|
10
20
|
|
|
11
21
|
#if os(iOS)
|
|
@@ -18,23 +28,32 @@ extension THEOplayerRCTView {
|
|
|
18
28
|
if let adPreloadType = adsConfig["preload"] as? String {
|
|
19
29
|
self.adsConfig.adPreloadTypeString = adPreloadType
|
|
20
30
|
}
|
|
31
|
+
if let adsImaConfig = adsConfig["ima"] as? NSDictionary {
|
|
32
|
+
if let ppid = adsImaConfig["ppid"] as? String {
|
|
33
|
+
self.adsConfig.adsImaConfig.ppid = ppid
|
|
34
|
+
}
|
|
35
|
+
if let maxRedirects = adsImaConfig["maxRedirects"] as? UInt {
|
|
36
|
+
self.adsConfig.adsImaConfig.maxRedirects = maxRedirects
|
|
37
|
+
}
|
|
38
|
+
if let featureFlags = adsImaConfig["featureFlags"] as? [String:String] {
|
|
39
|
+
self.adsConfig.adsImaConfig.featureFlags = featureFlags
|
|
40
|
+
}
|
|
41
|
+
if let autoPlayAdBreaks = adsImaConfig["autoPlayAdBreaks"] as? Bool {
|
|
42
|
+
self.adsConfig.adsImaConfig.autoPlayAdBreaks = autoPlayAdBreaks
|
|
43
|
+
}
|
|
44
|
+
if let sessionID = adsImaConfig["sessionID"] as? String {
|
|
45
|
+
self.adsConfig.adsImaConfig.sessionID = sessionID
|
|
46
|
+
}
|
|
47
|
+
if let enableDebugMode = adsImaConfig["enableDebugMode"] as? Bool {
|
|
48
|
+
self.adsConfig.adsImaConfig.enableDebugMode = enableDebugMode
|
|
49
|
+
}
|
|
50
|
+
}
|
|
21
51
|
}
|
|
22
52
|
}
|
|
23
53
|
|
|
24
|
-
#if
|
|
54
|
+
#if canImport(THEOplayerGoogleIMAIntegration)
|
|
25
55
|
func playerAdsConfiguration() -> AdsConfiguration? {
|
|
26
|
-
|
|
27
|
-
googleBuilder.disableUI = !self.adsConfig.adSUIEnabled
|
|
28
|
-
googleBuilder.enableBackgroundPlayback = true
|
|
29
|
-
let googleIMAAdsConfiguration = googleBuilder.build()
|
|
30
|
-
let daiBuilder = GoogleDAIAdsConfigurationBuilder()
|
|
31
|
-
daiBuilder.disableUI = !self.adsConfig.adSUIEnabled
|
|
32
|
-
daiBuilder.enableBackgroundPlayback = true
|
|
33
|
-
let googleDaiAdsConfiguration = daiBuilder.build()
|
|
34
|
-
return AdsConfiguration(showCountdown: self.adsConfig.adSUIEnabled,
|
|
35
|
-
preload: self.adPreloadType(),
|
|
36
|
-
googleIma: googleIMAAdsConfiguration,
|
|
37
|
-
googleDai: googleDaiAdsConfiguration)
|
|
56
|
+
return AdsConfiguration(showCountdown: self.adsConfig.adSUIEnabled, preload: self.adPreloadType())
|
|
38
57
|
}
|
|
39
58
|
|
|
40
59
|
private func adPreloadType() -> THEOplayerSDK.AdPreloadType {
|
|
@@ -59,7 +78,7 @@ extension THEOplayerRCTView {
|
|
|
59
78
|
|
|
60
79
|
func parseAdsConfig(configDict: NSDictionary) {}
|
|
61
80
|
|
|
62
|
-
#if
|
|
81
|
+
#if canImport(THEOplayerGoogleIMAIntegration)
|
|
63
82
|
func playerAdsConfiguration() -> AdsConfiguration? { return AdsConfiguration() }
|
|
64
83
|
#else
|
|
65
84
|
func playerAdsConfiguration() -> AdsConfiguration? { return nil }
|
|
@@ -193,7 +193,7 @@ class THEOplayerRCTRemoteCommandsManager: NSObject {
|
|
|
193
193
|
self?.updateRemoteCommands()
|
|
194
194
|
}
|
|
195
195
|
|
|
196
|
-
#if
|
|
196
|
+
#if canImport(THEOplayerGoogleIMAIntegration)
|
|
197
197
|
|
|
198
198
|
// ADBREAK_BEGIN
|
|
199
199
|
self.adBreakBeginListener = player.ads.addEventListener(type: AdsEventTypes.AD_BREAK_BEGIN) { [weak self] event in
|
|
@@ -226,7 +226,7 @@ class THEOplayerRCTRemoteCommandsManager: NSObject {
|
|
|
226
226
|
player.removeEventListener(type: PlayerEventTypes.SOURCE_CHANGE, listener: sourceChangeListener)
|
|
227
227
|
}
|
|
228
228
|
|
|
229
|
-
#if
|
|
229
|
+
#if canImport(THEOplayerGoogleIMAIntegration)
|
|
230
230
|
|
|
231
231
|
// ADBREAK_BEGIN
|
|
232
232
|
if let adBreakBeginListener = self.adBreakBeginListener {
|
|
@@ -7,16 +7,6 @@ struct BackgroundAudioConfig {
|
|
|
7
7
|
var enabled: Bool = false
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
#if WEB
|
|
11
|
-
|
|
12
|
-
extension THEOplayerRCTView {
|
|
13
|
-
func initBackgroundAudio() {}
|
|
14
|
-
func destroyBackgroundAudio() {}
|
|
15
|
-
public func shouldContinueAudioPlaybackInBackground() -> Bool { return false }
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
#else
|
|
19
|
-
|
|
20
10
|
extension THEOplayerRCTView: BackgroundPlaybackDelegate {
|
|
21
11
|
|
|
22
12
|
func initBackgroundAudio() {
|
|
@@ -41,5 +31,3 @@ extension THEOplayerRCTView: BackgroundPlaybackDelegate {
|
|
|
41
31
|
struct DefaultBackgroundPlaybackDelegate: BackgroundPlaybackDelegate {
|
|
42
32
|
func shouldContinueAudioPlaybackInBackground() -> Bool { false }
|
|
43
33
|
}
|
|
44
|
-
|
|
45
|
-
#endif
|
|
@@ -43,7 +43,7 @@ class THEOplayerRCTPipControlsManager: NSObject {
|
|
|
43
43
|
if let player = self.player,
|
|
44
44
|
let duration = player.duration {
|
|
45
45
|
self.isLive = duration.isInfinite
|
|
46
|
-
#if
|
|
46
|
+
#if canImport(THEOplayerGoogleIMAIntegration)
|
|
47
47
|
self.inAd = player.ads.playing
|
|
48
48
|
self.updatePipControls()
|
|
49
49
|
#else
|
|
@@ -91,7 +91,7 @@ class THEOplayerRCTPipControlsManager: NSObject {
|
|
|
91
91
|
self?.updatePipControls()
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
#if
|
|
94
|
+
#if canImport(THEOplayerGoogleIMAIntegration)
|
|
95
95
|
|
|
96
96
|
// ADBREAK_BEGIN
|
|
97
97
|
self.adBreakBeginListener = player.ads.addEventListener(type: AdsEventTypes.AD_BREAK_BEGIN) { [weak self] event in
|
|
@@ -122,7 +122,7 @@ class THEOplayerRCTPipControlsManager: NSObject {
|
|
|
122
122
|
player.removeEventListener(type: PlayerEventTypes.SOURCE_CHANGE, listener: sourceChangeListener)
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
-
#if
|
|
125
|
+
#if canImport(THEOplayerGoogleIMAIntegration)
|
|
126
126
|
|
|
127
127
|
// ADBREAK_BEGIN
|
|
128
128
|
if let adBreakBeginListener = self.adBreakBeginListener {
|
|
@@ -21,16 +21,26 @@ function THEOplayerView(props) {
|
|
|
21
21
|
// Create player inside container.
|
|
22
22
|
if (container.current) {
|
|
23
23
|
const chromeless = config?.chromeless === true || config?.chromeless === undefined;
|
|
24
|
+
const ads = {
|
|
25
|
+
...config?.ads,
|
|
26
|
+
googleIma: {
|
|
27
|
+
useNativeIma: true,
|
|
28
|
+
language: config?.ui?.language ?? 'en'
|
|
29
|
+
}
|
|
30
|
+
};
|
|
24
31
|
const updatedConfig = {
|
|
25
32
|
...config,
|
|
26
|
-
allowNativeFullscreen: true
|
|
33
|
+
allowNativeFullscreen: true,
|
|
34
|
+
ads
|
|
27
35
|
};
|
|
28
36
|
if (chromeless) {
|
|
29
37
|
player.current = new _theoplayer.ChromelessPlayer(container.current, updatedConfig);
|
|
30
38
|
} else {
|
|
31
39
|
player.current = new _theoplayer.Player(container.current, {
|
|
32
40
|
...updatedConfig,
|
|
41
|
+
ads,
|
|
33
42
|
ui: {
|
|
43
|
+
...config?.ui,
|
|
34
44
|
fluid: true
|
|
35
45
|
}
|
|
36
46
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_react","_interopRequireWildcard","require","_theoplayer","_THEOplayerWebAdapter","_getRequireWildcardCache","e","WeakMap","r","t","__esModule","default","has","get","n","__proto__","a","Object","defineProperty","getOwnPropertyDescriptor","u","hasOwnProperty","call","i","set","THEOplayerView","props","config","children","player","useRef","adapter","container","useEffect","current","chromeless","undefined","updatedConfig","allowNativeFullscreen","ChromelessPlayer","Player","
|
|
1
|
+
{"version":3,"names":["_react","_interopRequireWildcard","require","_theoplayer","_THEOplayerWebAdapter","_getRequireWildcardCache","e","WeakMap","r","t","__esModule","default","has","get","n","__proto__","a","Object","defineProperty","getOwnPropertyDescriptor","u","hasOwnProperty","call","i","set","THEOplayerView","props","config","children","player","useRef","adapter","container","useEffect","current","chromeless","undefined","ads","googleIma","useNativeIma","language","ui","updatedConfig","allowNativeFullscreen","ChromelessPlayer","Player","fluid","THEOplayerWebAdapter","window","nativePlayer","onPlayerReady","onPlayerDestroy","destroy","createElement","Fragment","ref","style","styles","className","display","position","width","height","maxHeight","maxWidth","aspectRatio"],"sourceRoot":"../../../src","sources":["internal/THEOplayerView.web.tsx"],"mappings":"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","ignoreList":[]}
|