bitmovin-player-react-native 0.3.1 → 0.5.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.
Files changed (56) hide show
  1. package/README.md +486 -24
  2. package/RNBitmovinPlayer.podspec +5 -1
  3. package/android/build.gradle +8 -5
  4. package/android/src/main/java/com/bitmovin/player/reactnative/AnalyticsModule.kt +154 -0
  5. package/android/src/main/java/com/bitmovin/player/reactnative/DrmModule.kt +4 -5
  6. package/android/src/main/java/com/bitmovin/player/reactnative/PlayerModule.kt +41 -5
  7. package/android/src/main/java/com/bitmovin/player/reactnative/RNPlayerView.kt +318 -2
  8. package/android/src/main/java/com/bitmovin/player/reactnative/RNPlayerViewManager.kt +70 -9
  9. package/android/src/main/java/com/bitmovin/player/reactnative/RNPlayerViewPackage.kt +3 -0
  10. package/android/src/main/java/com/bitmovin/player/reactnative/SourceModule.kt +4 -5
  11. package/android/src/main/java/com/bitmovin/player/reactnative/UuidModule.kt +3 -1
  12. package/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt +389 -0
  13. package/android/src/main/java/com/bitmovin/player/reactnative/extensions/Any.kt +27 -0
  14. package/android/src/main/java/com/bitmovin/player/reactnative/extensions/ReactContextExtension.kt +8 -0
  15. package/android/src/main/java/com/bitmovin/player/reactnative/extensions/ReadableArray.kt +19 -2
  16. package/android/src/main/java/com/bitmovin/player/reactnative/extensions/String.kt +8 -0
  17. package/android/src/main/java/com/bitmovin/player/reactnative/extensions/WritableMap.kt +19 -0
  18. package/android/src/main/java/com/bitmovin/player/reactnative/ui/FullscreenHandlerBridge.kt +37 -0
  19. package/android/src/main/java/com/bitmovin/player/reactnative/ui/FullscreenHandlerModule.kt +73 -0
  20. package/android/src/main/java/com/bitmovin/player/reactnative/ui/RNPictureInPictureHandler.kt +191 -0
  21. package/ios/AnalyticsModule.m +14 -0
  22. package/ios/AnalyticsModule.swift +180 -0
  23. package/ios/AudioSessionModule.m +10 -0
  24. package/ios/AudioSessionModule.swift +65 -0
  25. package/ios/Event+JSON.swift +134 -0
  26. package/ios/FullscreenHandlerBridge.swift +33 -0
  27. package/ios/FullscreenHandlerModule.m +9 -0
  28. package/ios/FullscreenHandlerModule.swift +71 -0
  29. package/ios/PlayerModule.m +6 -0
  30. package/ios/PlayerModule.swift +44 -0
  31. package/ios/RCTConvert+BitmovinPlayer.swift +382 -0
  32. package/ios/RNPlayerView+PlayerListener.swift +56 -0
  33. package/ios/RNPlayerView+UserInterfaceListener.swift +35 -0
  34. package/ios/RNPlayerView.swift +22 -0
  35. package/ios/RNPlayerViewManager.m +24 -1
  36. package/ios/RNPlayerViewManager.swift +23 -1
  37. package/lib/index.d.ts +1013 -150
  38. package/lib/index.js +251 -48
  39. package/lib/index.mjs +231 -34
  40. package/package.json +1 -1
  41. package/src/advertising.ts +155 -0
  42. package/src/analytics/collector.ts +97 -0
  43. package/src/analytics/config.ts +218 -0
  44. package/src/analytics/index.ts +2 -0
  45. package/src/audioSession.ts +47 -0
  46. package/src/components/PlayerView/events.ts +49 -3
  47. package/src/components/PlayerView/index.tsx +68 -11
  48. package/src/components/PlayerView/native.ts +4 -1
  49. package/src/events.ts +255 -0
  50. package/src/index.ts +4 -0
  51. package/src/media.ts +33 -0
  52. package/src/player.ts +57 -1
  53. package/src/source.ts +4 -0
  54. package/src/styleConfig.ts +87 -0
  55. package/src/ui/fullscreenhandler.ts +19 -0
  56. package/src/ui/fullscreenhandlerbridge.ts +59 -0
@@ -0,0 +1,154 @@
1
+ package com.bitmovin.player.reactnative
2
+
3
+ import com.bitmovin.analytics.bitmovin.player.BitmovinPlayerCollector
4
+ import com.bitmovin.player.reactnative.converter.JsonConverter
5
+ import com.facebook.react.bridge.*
6
+ import com.facebook.react.module.annotations.ReactModule
7
+ import com.facebook.react.uimanager.UIManagerModule
8
+
9
+ private const val MODULE_NAME = "AnalyticsModule"
10
+
11
+ @ReactModule(name = MODULE_NAME)
12
+ class AnalyticsModule(private val context: ReactApplicationContext) : ReactContextBaseJavaModule(context) {
13
+ /**
14
+ * In-memory mapping from `nativeId`s to `BitmovinPlayerCollector` instances.
15
+ */
16
+ private val collectors: Registry<BitmovinPlayerCollector> = mutableMapOf()
17
+
18
+ /**
19
+ * JS exported module name.
20
+ */
21
+ override fun getName() = MODULE_NAME
22
+
23
+ /**
24
+ * Fetches the `BitmovinPlayerCollector` instance associated with `nativeId` from the internal registry.
25
+ * @param nativeId `BitmovinPlayerCollector` instance ID.
26
+ * @return The associated `BitmovinPlayerCollector` instance or `null`.
27
+ */
28
+ fun getCollector(nativeId: NativeId?): BitmovinPlayerCollector? {
29
+ if (nativeId == null) {
30
+ return null
31
+ }
32
+ return collectors[nativeId]
33
+ }
34
+
35
+ /**
36
+ * Creates a new `BitmovinPlayerCollector` instance inside the internal registry using the provided `config` object.
37
+ * @param config `BitmovinAnalyticsConfig` object received from JS.
38
+ */
39
+ @ReactMethod
40
+ fun initWithConfig(nativeId: NativeId, config: ReadableMap?) {
41
+ uiManager()?.addUIBlock { _ ->
42
+ JsonConverter.toAnalyticsConfig(config)?.let {
43
+ collectors[nativeId] = BitmovinPlayerCollector(it, context)
44
+ }
45
+ }
46
+ }
47
+
48
+ /**
49
+ * Detaches and removes the given `BitmovinPlayerCollector` from the internal registry.
50
+ * @param nativeId Native Id of the collector instance.
51
+ */
52
+ @ReactMethod
53
+ fun destroy(nativeId: NativeId) {
54
+ uiManager()?.addUIBlock {
55
+ if (collectors.containsKey(nativeId)) {
56
+ collectors[nativeId]?.detachPlayer()
57
+ collectors.remove(nativeId)
58
+ }
59
+ }
60
+ }
61
+
62
+ /**
63
+ * Attaches a `BitmovinPlayerCollector` to the `Player` instance with native Id equal to `playerId`.
64
+ * @param nativeId Native Id of the collector instance.
65
+ * @param playerId Native Id of the player instance.
66
+ */
67
+ @ReactMethod
68
+ fun attach(nativeId: NativeId, playerId: NativeId) {
69
+ uiManager()?.addUIBlock { _ ->
70
+ playerModule()?.getPlayer(playerId)?.let {
71
+ collectors[nativeId]?.attachPlayer(it)
72
+ }
73
+ }
74
+ }
75
+
76
+ /**
77
+ * Detaches the player object from a `BitmovinPlayerCollector` instance.
78
+ * @param nativeId Native Id of the collector instance.
79
+ */
80
+ @ReactMethod
81
+ fun detach(nativeId: NativeId) {
82
+ uiManager()?.addUIBlock { _ ->
83
+ collectors[nativeId]?.detachPlayer()
84
+ }
85
+ }
86
+
87
+ /**
88
+ * Updates the custom data config for a `BitmovinPlayerCollector` instance.
89
+ * @param nativeId Native Id of the collector instance.
90
+ * @param json Custom data config json.
91
+ */
92
+ @ReactMethod
93
+ fun setCustomDataOnce(nativeId: NativeId, json: ReadableMap?) {
94
+ uiManager()?.addUIBlock { _ ->
95
+ JsonConverter.toAnalyticsCustomData(json)?.let {
96
+ collectors[nativeId]?.setCustomDataOnce(it)
97
+ }
98
+ }
99
+ }
100
+
101
+ /**
102
+ * Sets the custom data config for a `BitmovinPlayerCollector` instance.
103
+ * @param nativeId Native Id of the collector instance.
104
+ * @param json Custom data config json.
105
+ */
106
+ @ReactMethod
107
+ fun setCustomData(nativeId: NativeId, json: ReadableMap?) {
108
+ uiManager()?.addUIBlock { _ ->
109
+ JsonConverter.toAnalyticsCustomData(json)?.let {
110
+ collectors[nativeId]?.customData = it
111
+ }
112
+ }
113
+ }
114
+
115
+ /**
116
+ * Gets the current custom data config for a `BitmovinPlayerCollector` instance.
117
+ * @param nativeId Native Id of the the collector instance.
118
+ * @param promise JS promise object.
119
+ */
120
+ @ReactMethod
121
+ fun getCustomData(nativeId: NativeId, promise: Promise) {
122
+ uiManager()?.addUIBlock { _ ->
123
+ collectors[nativeId]?.let {
124
+ promise.resolve(JsonConverter.fromAnalyticsCustomData(it.customData))
125
+ }
126
+ }
127
+ }
128
+
129
+ /**
130
+ * Gets the current user Id for a `BitmovinPlayerCollector` instance.
131
+ * @param nativeId Native Id of the the collector instance.
132
+ * @param promise JS promise object.
133
+ */
134
+ @ReactMethod
135
+ fun getUserId(nativeId: NativeId, promise: Promise) {
136
+ uiManager()?.addUIBlock { _ ->
137
+ collectors[nativeId]?.let {
138
+ promise.resolve(it.userId)
139
+ }
140
+ }
141
+ }
142
+
143
+ /**
144
+ * Helper function that gets the instantiated `UIManagerModule` from modules registry.
145
+ */
146
+ private fun uiManager(): UIManagerModule? =
147
+ context.getNativeModule(UIManagerModule::class.java)
148
+
149
+ /**
150
+ * Helper function that gets the instantiated `PlayerModule` from modules registry.
151
+ */
152
+ private fun playerModule(): PlayerModule? =
153
+ context.getNativeModule(PlayerModule::class.java)
154
+ }
@@ -17,7 +17,9 @@ import kotlin.concurrent.withLock
17
17
  */
18
18
  typealias PrepareCallback = (ByteArray) -> ByteArray
19
19
 
20
- @ReactModule(name = DrmModule.name)
20
+ private const val MODULE_NAME = "DrmModule"
21
+
22
+ @ReactModule(name = MODULE_NAME)
21
23
  class DrmModule(private val context: ReactApplicationContext) : ReactContextBaseJavaModule(context) {
22
24
  /**
23
25
  * In-memory mapping from `nativeId`s to `WidevineConfig` instances.
@@ -52,10 +54,7 @@ class DrmModule(private val context: ReactApplicationContext) : ReactContextBase
52
54
  /**
53
55
  * JS exported module name.
54
56
  */
55
- companion object {
56
- const val name = "DrmModule"
57
- }
58
- override fun getName() = DrmModule.name
57
+ override fun getName() = MODULE_NAME
59
58
 
60
59
  /**
61
60
  * Fetches the `WidevineConfig` instance associated with `nativeId` from internal drmConfigs.
@@ -6,7 +6,9 @@ import com.facebook.react.bridge.*
6
6
  import com.facebook.react.module.annotations.ReactModule
7
7
  import com.facebook.react.uimanager.UIManagerModule
8
8
 
9
- @ReactModule(name = PlayerModule.name)
9
+ private const val MODULE_NAME = "PlayerModule"
10
+
11
+ @ReactModule(name = MODULE_NAME)
10
12
  class PlayerModule(private val context: ReactApplicationContext) : ReactContextBaseJavaModule(context) {
11
13
  /**
12
14
  * In-memory mapping from `nativeId`s to `Player` instances.
@@ -16,10 +18,7 @@ class PlayerModule(private val context: ReactApplicationContext) : ReactContextB
16
18
  /**
17
19
  * JS exported module name.
18
20
  */
19
- companion object {
20
- const val name = "PlayerModule"
21
- }
22
- override fun getName() = PlayerModule.name
21
+ override fun getName() = MODULE_NAME
23
22
 
24
23
  /**
25
24
  * Fetches the `Player` instance associated with `nativeId` from the internal players.
@@ -280,6 +279,43 @@ class PlayerModule(private val context: ReactApplicationContext) : ReactContextB
280
279
  }
281
280
  }
282
281
 
282
+ /**
283
+ * Schedules an `AdItem` in the `nativeId`'s associated player.
284
+ * @param nativeId Target player id.
285
+ * @param adItemJson Json representation of the `AdItem` to be scheduled.
286
+ */
287
+ @ReactMethod
288
+ fun scheduleAd(nativeId: NativeId, adItemJson: ReadableMap?) {
289
+ JsonConverter.toAdItem(adItemJson)?.let { adItem ->
290
+ uiManager()?.addUIBlock {
291
+ players[nativeId]?.scheduleAd(adItem)
292
+ }
293
+ }
294
+ }
295
+
296
+ /**
297
+ * Skips the current ad in `nativeId`'s associated player.
298
+ * Has no effect if the current ad is not skippable or if no ad is being played back.
299
+ * @param nativeId Target player id.
300
+ */
301
+ @ReactMethod
302
+ fun skipAd(nativeId: NativeId) {
303
+ uiManager()?.addUIBlock {
304
+ players[nativeId]?.skipAd()
305
+ }
306
+ }
307
+
308
+ /**
309
+ * Returns `true` while an ad is being played back or when main content playback has been paused for ad playback.
310
+ * @param nativeId Target player id.
311
+ */
312
+ @ReactMethod
313
+ fun isAd(nativeId: NativeId, promise: Promise) {
314
+ uiManager()?.addUIBlock {
315
+ promise.resolve(players[nativeId]?.isAd)
316
+ }
317
+ }
318
+
283
319
  /**
284
320
  * Helper function that returns the initialized `UIManager` instance.
285
321
  */
@@ -1,6 +1,9 @@
1
1
  package com.bitmovin.player.reactnative
2
2
 
3
3
  import android.annotation.SuppressLint
4
+ import android.content.res.Configuration
5
+ import android.graphics.Rect
6
+ import android.view.View
4
7
  import android.view.ViewGroup
5
8
  import android.widget.LinearLayout
6
9
  import com.bitmovin.player.PlayerView
@@ -10,6 +13,9 @@ import com.bitmovin.player.api.event.PlayerEvent
10
13
  import com.bitmovin.player.api.event.SourceEvent
11
14
  import com.bitmovin.player.api.event.on
12
15
  import com.bitmovin.player.reactnative.converter.JsonConverter
16
+ import com.bitmovin.player.reactnative.ui.RNPictureInPictureDelegate
17
+ import com.bitmovin.player.reactnative.ui.RNPictureInPictureHandler
18
+ import com.facebook.react.bridge.LifecycleEventListener
13
19
  import com.facebook.react.bridge.ReactApplicationContext
14
20
  import com.facebook.react.bridge.ReactContext
15
21
  import com.facebook.react.uimanager.events.RCTEventEmitter
@@ -20,9 +26,10 @@ import com.facebook.react.uimanager.events.RCTEventEmitter
20
26
  * exposes player events as bubbling events.
21
27
  */
22
28
  @SuppressLint("ViewConstructor")
23
- class RNPlayerView(context: ReactApplicationContext) : LinearLayout(context) {
29
+ class RNPlayerView(val context: ReactApplicationContext) : LinearLayout(context),
30
+ LifecycleEventListener, View.OnLayoutChangeListener, RNPictureInPictureDelegate {
24
31
  /**
25
- * Reference to the shared player view set as child.
32
+ * Associated bitmovin's `PlayerView`.
26
33
  */
27
34
  var playerView: PlayerView? = null
28
35
 
@@ -35,6 +42,57 @@ class RNPlayerView(context: ReactApplicationContext) : LinearLayout(context) {
35
42
  playerView?.player = value
36
43
  }
37
44
 
45
+ /**
46
+ * Object that handles PiP mode changes in React Native.
47
+ */
48
+ var pictureInPictureHandler: RNPictureInPictureHandler? = null
49
+
50
+ /**
51
+ * Whether this view should pause video playback when activity's onPause is called.
52
+ * By default, `shouldPausePlaybackOnActivityPause` is set to false when entering PiP mode.
53
+ */
54
+ private var shouldPausePlaybackOnActivityPause = true
55
+
56
+ /**
57
+ * Register this view as an activity lifecycle listener on initialization.
58
+ */
59
+ init {
60
+ context.addLifecycleEventListener(this)
61
+ }
62
+
63
+ /**
64
+ * Cleans up the resources and listeners produced by this view.
65
+ */
66
+ fun dispose() {
67
+ stopBubblingEvents()
68
+ context.removeLifecycleEventListener(this)
69
+ playerView?.removeOnLayoutChangeListener(this)
70
+ }
71
+
72
+ /**
73
+ * Activity's onResume
74
+ */
75
+ override fun onHostResume() {
76
+ playerView?.onResume()
77
+ }
78
+
79
+ /**
80
+ * Activity's onPause
81
+ */
82
+ override fun onHostPause() {
83
+ if (shouldPausePlaybackOnActivityPause) {
84
+ playerView?.onPause()
85
+ }
86
+ shouldPausePlaybackOnActivityPause = true
87
+ }
88
+
89
+ /**
90
+ * Activity's onDestroy
91
+ */
92
+ override fun onHostDestroy() {
93
+ playerView?.onDestroy()
94
+ }
95
+
38
96
  /**
39
97
  * Set the given `playerView` as child and start bubbling events.
40
98
  * @param playerView Shared player view instance.
@@ -44,6 +102,71 @@ class RNPlayerView(context: ReactApplicationContext) : LinearLayout(context) {
44
102
  if (playerView.parent != this) {
45
103
  (playerView.parent as ViewGroup?)?.removeView(playerView)
46
104
  addView(playerView)
105
+ startBubblingEvents()
106
+ }
107
+ pictureInPictureHandler?.let {
108
+ it.setDelegate(this)
109
+ playerView.setPictureInPictureHandler(it)
110
+ playerView.addOnLayoutChangeListener(this)
111
+ }
112
+ }
113
+
114
+ /**
115
+ * Called whenever this view's activity configuration changes.
116
+ */
117
+ override fun onConfigurationChanged(newConfig: Configuration?) {
118
+ super.onConfigurationChanged(newConfig)
119
+ pictureInPictureHandler?.onConfigurationChanged(newConfig)
120
+ }
121
+
122
+ /**
123
+ * Called when the player has just entered PiP mode.
124
+ */
125
+ override fun onEnterPictureInPicture() {
126
+ // Playback shouldn't be paused when entering PiP mode.
127
+ shouldPausePlaybackOnActivityPause = false
128
+ }
129
+
130
+ /**
131
+ * Called when the player has just exited PiP mode.
132
+ */
133
+ override fun onExitPictureInPicture() {
134
+ // Explicitly call `exitPictureInPicture()` on PlayerView when exiting PiP state, otherwise
135
+ // the `PictureInPictureExit` event won't get dispatched.
136
+ playerView?.exitPictureInPicture()
137
+ }
138
+
139
+ /**
140
+ * Called when the player's PiP mode changes with a new configuration object.
141
+ */
142
+ override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean, newConfig: Configuration?) {
143
+ playerView?.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig)
144
+ }
145
+
146
+ /**
147
+ * Called whenever the PiP handler needs to compute the PlayerView's global visible rect.
148
+ */
149
+ override fun setSourceRectHint(sourceRectHint: Rect) {
150
+ playerView?.getGlobalVisibleRect(sourceRectHint)
151
+ }
152
+
153
+ /**
154
+ * Called whenever PlayerView's layout changes.
155
+ */
156
+ override fun onLayoutChange(
157
+ view: View?,
158
+ left: Int,
159
+ top: Int,
160
+ right: Int,
161
+ bottom: Int,
162
+ oldLeft: Int,
163
+ oldTop: Int,
164
+ oldRight: Int,
165
+ oldBottom: Int,
166
+ ) {
167
+ if (left != oldLeft || right != oldRight || top != oldTop || bottom != oldBottom) {
168
+ // Update source rect hint whenever the player's layout change
169
+ pictureInPictureHandler?.updateSourceRectHint()
47
170
  }
48
171
  }
49
172
 
@@ -153,6 +276,20 @@ class RNPlayerView(context: ReactApplicationContext) : LinearLayout(context) {
153
276
  emitEvent("seeked", it)
154
277
  }
155
278
 
279
+ /**
280
+ * `onStallStarted` event callback.
281
+ */
282
+ private val onStallStarted: (PlayerEvent.StallStarted) -> Unit = {
283
+ emitEvent("stallStarted", it)
284
+ }
285
+
286
+ /**
287
+ * `onStallEnded` event callback.
288
+ */
289
+ private val onStallEnded: (PlayerEvent.StallEnded) -> Unit = {
290
+ emitEvent("stallEnded", it)
291
+ }
292
+
156
293
  /**
157
294
  * `onTimeChanged` event callback.
158
295
  */
@@ -216,6 +353,139 @@ class RNPlayerView(context: ReactApplicationContext) : LinearLayout(context) {
216
353
  emitEvent("subtitleRemoved", it)
217
354
  }
218
355
 
356
+ /**
357
+ * `onPictureInPictureAvailabilityChanged` event callback.
358
+ */
359
+ private val onPictureInPictureAvailabilityChanged: (PlayerEvent.PictureInPictureAvailabilityChanged) -> Unit = {
360
+ emitEvent("pictureInPictureAvailabilityChanged", it)
361
+ }
362
+
363
+ /**
364
+ * `onPictureInPictureEnter` event callback.
365
+ */
366
+ private val onPictureInPictureEnter: (PlayerEvent.PictureInPictureEnter) -> Unit = {
367
+ emitEvent("pictureInPictureEnter", it)
368
+ }
369
+
370
+ /**
371
+ * `onPictureInPictureExit` event callback.
372
+ */
373
+ private val onPictureInPictureExit: (PlayerEvent.PictureInPictureExit) -> Unit = {
374
+ emitEvent("pictureInPictureExit", it)
375
+ }
376
+
377
+ /**
378
+ * `onAdBreakFinished` event callback.
379
+ */
380
+ private val onAdBreakFinished: (PlayerEvent.AdBreakFinished) -> Unit = {
381
+ emitEvent("adBreakFinished", it)
382
+ }
383
+
384
+ /**
385
+ * `onAdBreakStarted` event callback.
386
+ */
387
+ private val onAdBreakStarted: (PlayerEvent.AdBreakStarted) -> Unit = {
388
+ emitEvent("adBreakStarted", it)
389
+ }
390
+
391
+ /**
392
+ * `onAdClicked` event callback.
393
+ */
394
+ private val onAdClicked: (PlayerEvent.AdClicked) -> Unit = {
395
+ emitEvent("adClicked", it)
396
+ }
397
+
398
+ /**
399
+ * `onAdError` event callback.
400
+ */
401
+ private val onAdError: (PlayerEvent.AdError) -> Unit = {
402
+ emitEvent("adError", it)
403
+ }
404
+
405
+ /**
406
+ * `onAdFinished` event callback.
407
+ */
408
+ private val onAdFinished: (PlayerEvent.AdFinished) -> Unit = {
409
+ emitEvent("adFinished", it)
410
+ }
411
+
412
+ /**
413
+ * `onAdManifestLoad` event callback.
414
+ */
415
+ private val onAdManifestLoad: (PlayerEvent.AdManifestLoad) -> Unit = {
416
+ emitEvent("adManifestLoad", it)
417
+ }
418
+
419
+ /**
420
+ * `onAdManifestLoaded` event callback.
421
+ */
422
+ private val onAdManifestLoaded: (PlayerEvent.AdManifestLoaded) -> Unit = {
423
+ emitEvent("adManifestLoaded", it)
424
+ }
425
+
426
+ /**
427
+ * `onAdQuartile` event callback.
428
+ */
429
+ private val onAdQuartile: (PlayerEvent.AdQuartile) -> Unit = {
430
+ emitEvent("adQuartile", it)
431
+ }
432
+
433
+ /**
434
+ * `onAdScheduled` event callback.
435
+ */
436
+ private val onAdScheduled: (PlayerEvent.AdScheduled) -> Unit = {
437
+ emitEvent("adScheduled", it)
438
+ }
439
+
440
+ /**
441
+ * `onAdSkipped` event callback.
442
+ */
443
+ private val onAdSkipped: (PlayerEvent.AdSkipped) -> Unit = {
444
+ emitEvent("adSkipped", it)
445
+ }
446
+
447
+ /**
448
+ * `onAdStarted` event callback.
449
+ */
450
+ private val onAdStarted: (PlayerEvent.AdStarted) -> Unit = {
451
+ emitEvent("adStarted", it)
452
+ }
453
+
454
+ /**
455
+ * `onVideoPlaybackQualityChanged` event callback.
456
+ */
457
+ private val onVideoPlaybackQualityChanged: (PlayerEvent.VideoPlaybackQualityChanged) -> Unit = {
458
+ emitEvent("videoPlaybackQualityChanged", it)
459
+ }
460
+
461
+ /**
462
+ * `onFullscreenEnabled` event callback.
463
+ */
464
+ private val onFullscreenEnabled: (PlayerEvent.FullscreenEnabled) -> Unit = {
465
+ emitEvent("fullscreenEnabled", it)
466
+ }
467
+
468
+ /**
469
+ * `onFullscreenEnabled` event callback.
470
+ */
471
+ private val onFullscreenDisabled: (PlayerEvent.FullscreenDisabled) -> Unit = {
472
+ emitEvent("fullscreenDisabled", it)
473
+ }
474
+
475
+ /**
476
+ * `onFullscreenEnter` event callback.
477
+ */
478
+ private val onFullscreenEnter: (PlayerEvent.FullscreenEnter) -> Unit = {
479
+ emitEvent("fullscreenEnter", it)
480
+ }
481
+
482
+ /**
483
+ * `onFullscreenEnter` event callback.
484
+ */
485
+ private val onFullscreenExit: (PlayerEvent.FullscreenExit) -> Unit = {
486
+ emitEvent("fullscreenExit", it)
487
+ }
488
+
219
489
  /**
220
490
  * Start listening and emitting player events as bubbling events to the js side.
221
491
  */
@@ -234,6 +504,8 @@ class RNPlayerView(context: ReactApplicationContext) : LinearLayout(context) {
234
504
  on(onPlaybackFinished)
235
505
  on(onSeek)
236
506
  on(onSeeked)
507
+ on(onStallStarted)
508
+ on(onStallEnded)
237
509
  on(onTimeChanged)
238
510
  on(onSourceLoad)
239
511
  on(onSourceLoaded)
@@ -243,6 +515,27 @@ class RNPlayerView(context: ReactApplicationContext) : LinearLayout(context) {
243
515
  on(onSubtitleAdded)
244
516
  on(onSubtitleChanged)
245
517
  on(onSubtitleRemoved)
518
+ on(onAdBreakFinished)
519
+ on(onAdBreakStarted)
520
+ on(onAdClicked)
521
+ on(onAdError)
522
+ on(onAdFinished)
523
+ on(onAdManifestLoad)
524
+ on(onAdManifestLoaded)
525
+ on(onAdQuartile)
526
+ on(onAdScheduled)
527
+ on(onAdSkipped)
528
+ on(onAdStarted)
529
+ on(onVideoPlaybackQualityChanged)
530
+ }
531
+ playerView?.apply {
532
+ on(onPictureInPictureAvailabilityChanged)
533
+ on(onPictureInPictureEnter)
534
+ on(onPictureInPictureExit)
535
+ on(onFullscreenEnabled)
536
+ on(onFullscreenDisabled)
537
+ on(onFullscreenEnter)
538
+ on(onFullscreenExit)
246
539
  }
247
540
  }
248
541
 
@@ -264,6 +557,8 @@ class RNPlayerView(context: ReactApplicationContext) : LinearLayout(context) {
264
557
  off(onPlaybackFinished)
265
558
  off(onSeek)
266
559
  off(onSeeked)
560
+ off(onStallStarted)
561
+ off(onStallEnded)
267
562
  off(onTimeChanged)
268
563
  off(onSourceLoad)
269
564
  off(onSourceLoaded)
@@ -273,6 +568,27 @@ class RNPlayerView(context: ReactApplicationContext) : LinearLayout(context) {
273
568
  off(onSubtitleAdded)
274
569
  off(onSubtitleChanged)
275
570
  off(onSubtitleRemoved)
571
+ off(onAdBreakFinished)
572
+ off(onAdBreakStarted)
573
+ off(onAdClicked)
574
+ off(onAdError)
575
+ off(onAdFinished)
576
+ off(onAdManifestLoad)
577
+ off(onAdManifestLoaded)
578
+ off(onAdQuartile)
579
+ off(onAdScheduled)
580
+ off(onAdSkipped)
581
+ off(onAdStarted)
582
+ off(onVideoPlaybackQualityChanged)
583
+ }
584
+ playerView?.apply {
585
+ off(onPictureInPictureAvailabilityChanged)
586
+ off(onPictureInPictureEnter)
587
+ off(onPictureInPictureExit)
588
+ off(onFullscreenEnabled)
589
+ off(onFullscreenDisabled)
590
+ off(onFullscreenEnter)
591
+ off(onFullscreenExit)
276
592
  }
277
593
  }
278
594