@24i/smartapps-bigscreen-rnv-build-engine 0.17.26 → 0.17.27-alpha.2774

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.
@@ -200,6 +200,7 @@ const configureEntryUrl = (c) => {
200
200
  || rnv_1.Common.getConfigProp(c, c.platform, 'theoLicense', '');
201
201
  const npawAccountCode = process.env.NPAW_ACCOUNT_CODE
202
202
  || rnv_1.Common.getConfigProp(c, c.platform, 'npawAccountCode', '');
203
+ const enableImaSdk = !!rnv_1.Common.getConfigProp(c, c.platform, 'enableImaSdk', false);
203
204
  const injects = [{
204
205
  pattern: '{{APP_URL}}',
205
206
  override: entryUrl,
@@ -209,6 +210,9 @@ const configureEntryUrl = (c) => {
209
210
  }, {
210
211
  pattern: '{{NPAW_ACCOUNT_CODE}}',
211
212
  override: npawAccountCode,
213
+ }, {
214
+ pattern: '{{ENABLE_IMA_SDK}}',
215
+ override: enableImaSdk,
212
216
  }];
213
217
  rnv_1.Common.addSystemInjects(c, injects);
214
218
  rnv_1.FileUtils.writeCleanFile(buildGradleFilePath, buildGradleFilePath, injects, null, c);
@@ -6,6 +6,7 @@ def theoLicense = '{{THEO_LICENSE}}'
6
6
  def useTheoPlayer = theoLicense != ''
7
7
  def npawAccountCode = '{{NPAW_ACCOUNT_CODE}}'
8
8
  def useNpawPlugin = npawAccountCode != ''
9
+ def useImaSdk = {{ENABLE_IMA_SDK}}
9
10
 
10
11
  android {
11
12
  namespace = 'com.twentyfouri.tvbridge'
@@ -104,12 +105,12 @@ dependencies {
104
105
  implementation "com.squareup.okhttp3:logging-interceptor:4.9.2"
105
106
  implementation "com.squareup.okhttp3:okhttp:4.9.2"
106
107
  if (useTheoPlayer) {
107
- compileOnly "com.twentyfouri.player:exoplayer:0.8.0-alpha.8"
108
- implementation "com.twentyfouri.player:theoplayer:0.8.0-alpha.8"
108
+ compileOnly "com.twentyfouri.player:exoplayer:0.8.0-alpha.15"
109
+ implementation "com.twentyfouri.player:theoplayer:0.8.0-alpha.15"
109
110
  implementation "com.theoplayer.theoplayer-sdk-android:core:8.2.0"
110
111
  } else {
111
- implementation "com.twentyfouri.player:exoplayer:0.8.0-alpha.8"
112
- compileOnly "com.twentyfouri.player:theoplayer:0.8.0-alpha.8"
112
+ implementation "com.twentyfouri.player:exoplayer:0.8.0-alpha.15"
113
+ compileOnly "com.twentyfouri.player:theoplayer:0.8.0-alpha.15"
113
114
  compileOnly "com.theoplayer.theoplayer-sdk-android:core:8.2.0"
114
115
  }
115
116
 
@@ -123,6 +124,10 @@ dependencies {
123
124
  compileOnly 'com.google.android.exoplayer:extension-okhttp:2.19.1'
124
125
  }
125
126
 
127
+ if (useImaSdk) {
128
+ implementation 'com.google.ads.interactivemedia.v3:interactivemedia:3.36.0'
129
+ }
130
+
126
131
  implementation project(':common')
127
132
  }
128
133
 
@@ -1,6 +1,8 @@
1
1
  package com.twentyfouri.tvbridge.bridge
2
2
 
3
3
  import android.util.Log
4
+ import com.twentyfouri.player.base.Ad
5
+ import com.twentyfouri.player.base.AdBreak
4
6
  import com.twentyfouri.player.base.AudioTrack
5
7
  import com.twentyfouri.player.base.DefaultSourceSerializer
6
8
  import com.twentyfouri.player.base.TextTrack
@@ -63,6 +65,20 @@ class BridgeToJavaScript(
63
65
  executeJavaScript(mediaEventString)
64
66
  }
65
67
 
68
+ fun bridgeAndroidToJavaScript_MediaAdEvent(
69
+ mediaEvent: String,
70
+ adBreak: AdBreak?,
71
+ ad: Ad?
72
+ ) {
73
+ val serializer = DefaultSourceSerializer()
74
+ val adBreakJson = adBreak?.let { serializer.toPersistentMap(it).toString() } ?: ""
75
+ val adJson = ad?.let { serializer.toPersistentMap(it).toString() } ?: ""
76
+
77
+ val mediaEventString = "javascript:((function dispatchEvent(){var evt = document.createEvent('Events');evt.initEvent('$mediaEventPrefix$mediaEvent',true,true);evt.adbreak='$adBreakJson';evt.adbreak='$adJson';document.dispatchEvent(evt);})())"
78
+ Log.v(LOG_TAG, mediaEventString)
79
+ executeJavaScript(mediaEventString)
80
+ }
81
+
66
82
  fun bridgeAndroidToJavaScript_MediaAdBreaksEvent(
67
83
  mediaEvent: String,
68
84
  timeline: List<TimelineEvent>
@@ -1,7 +1,6 @@
1
1
  package com.twentyfouri.tvbridge.global.utils
2
2
 
3
3
  import android.annotation.SuppressLint
4
- import android.app.Application
5
4
  import android.content.Context
6
5
  import android.content.ContextWrapper
7
6
  import android.os.Bundle
@@ -45,13 +44,16 @@ import com.npaw.analytics.video.VideoOptions
45
44
  import com.npaw.core.options.AnalyticsOptions
46
45
  import com.npaw.exoplayer.ExoPlayerAdapter
47
46
  import com.npaw.exoplayer.ExoPlayerBalancer
47
+ import com.twentyfouri.player.base.BackgroundMode
48
48
  import com.twentyfouri.player.base.CastingEnded
49
49
  import com.twentyfouri.player.base.CastingStarted
50
+ import com.twentyfouri.player.base.CastingType
50
51
  import com.twentyfouri.player.base.DrmPlayready
51
52
  import com.twentyfouri.player.base.DrmWidevine
52
53
  import com.twentyfouri.player.base.EventListenerDispose
53
54
  import com.twentyfouri.player.base.PlayerBase
54
55
  import com.twentyfouri.player.base.PlayerGesturesTarget
56
+ import com.twentyfouri.player.base.PlayerProxy
55
57
  import com.twentyfouri.player.base.PlayerSurface
56
58
  import com.twentyfouri.player.base.ResizeEvent
57
59
  import com.twentyfouri.player.base.ScaleType
@@ -71,11 +73,11 @@ import com.twentyfouri.player.exoplayer.DrmSessionManagerProvider
71
73
  import com.twentyfouri.player.exoplayer.PlayerComponents
72
74
  import com.twentyfouri.player.exoplayer.PlayerExoPlayer
73
75
  import com.twentyfouri.player.exoplayer.PlayerFactoryExoPlayer
74
- import com.twentyfouri.player.exoplayer.PlayerProxy
75
76
  import com.twentyfouri.player.exoplayer.PlayerViewAdvertisement
76
77
  import com.twentyfouri.player.exoplayer.SharedComponents
77
78
  import com.twentyfouri.tvbridge.BuildConfig
78
79
  import com.twentyfouri.tvbridge.configuration.BridgeConfig
80
+ import java.util.WeakHashMap
79
81
  import com.npaw.core.util.extensions.Log as NpawLog
80
82
 
81
83
  class PlayerFactoryExoPlayerNpaw(
@@ -86,9 +88,11 @@ class PlayerFactoryExoPlayerNpaw(
86
88
 
87
89
  override val engineVersion: String = ExoPlayerLibraryInfo.VERSION
88
90
 
91
+ private val activePlayers = WeakHashMap<PlayerBase, Boolean>()
92
+
89
93
  override fun createSharedComponents(context: Context): SharedComponents =
90
94
  CustomizedSharedComponents(context)
91
-
95
+
92
96
  override fun createView(parent: ViewGroup): View {
93
97
  return NpawPlayerView(parent.context).also {
94
98
  val basePlayer = createPlayer(parent.context)
@@ -97,7 +101,7 @@ class PlayerFactoryExoPlayerNpaw(
97
101
  .sharedComponents as CustomizedSharedComponents
98
102
  ).npawPlugin
99
103
  val npawPlayer = NpawPlayer(basePlayer, npawPlugin)
100
- trackPlayer(npawPlayer)
104
+ activePlayers[npawPlayer] = true
101
105
  it.player = npawPlayer
102
106
  }
103
107
  }
@@ -111,10 +115,15 @@ class PlayerFactoryExoPlayerNpaw(
111
115
  ?: throw IllegalStateException("Player was not initialized by PlayerFactory")
112
116
  }
113
117
 
114
- private inner class CustomizedSharedComponents(context: Context) : DefaultSharedComponents(context) {
118
+ override fun release() {
119
+ activePlayers.keys.forEach {
120
+ it.destroy()
121
+ }
122
+ activePlayers.clear()
123
+ super.release()
124
+ }
115
125
 
116
- val application = context.applicationContext as? Application
117
- ?: throw IllegalStateException("Missing application")
126
+ private inner class CustomizedSharedComponents(context: Context) : DefaultSharedComponents(context) {
118
127
 
119
128
  val npawPlugin: NpawPlugin = NpawPlugin
120
129
  .Builder(application, config.npawAccount)
@@ -335,6 +344,10 @@ class PlayerFactoryExoPlayerNpaw(
335
344
  adOverlay.gesturesTarget = value
336
345
  }
337
346
 
347
+ override var supportsPictureInPicture: Boolean
348
+ get() = false
349
+ set(value) {}
350
+
338
351
  var player: PlayerBase? = null
339
352
  set(value) {
340
353
  if (field == value) return
@@ -474,6 +487,23 @@ class PlayerFactoryExoPlayerNpaw(
474
487
  }
475
488
  }
476
489
 
490
+ override fun onUserLeaveHint() {
491
+ (player as? PlayerProxy)?.onUserLeaveHint()
492
+ }
493
+
494
+ override fun onPictureInPictureModeChanged(inPictureInPictureMode: Boolean) {
495
+ }
496
+
497
+ fun autoPauseByBackground() {
498
+ val player = this.player ?: return
499
+ if (player.live) {
500
+ player.stop()
501
+ } else {
502
+ player.pause()
503
+ }
504
+ pausedByBackground = true
505
+ }
506
+
477
507
  private inner class ComponentListener : TextOutput, Player.Listener,
478
508
  DefaultLifecycleObserver {
479
509
  override fun onCues(cueGroup: CueGroup) {
@@ -499,29 +529,46 @@ class PlayerFactoryExoPlayerNpaw(
499
529
  this@NpawPlayerView.keepScreenOn = isPlaying
500
530
  }
501
531
 
502
- override fun onPause(owner: LifecycleOwner) {
532
+ override fun onStop(owner: LifecycleOwner) {
503
533
  val player = this@NpawPlayerView.player ?: return
504
534
  player.asPlayerExoPlayer()?.also {
505
535
  detachSurface(it)
506
536
  }
507
- if (!player.continueInBackground && !player.paused && player.state.source != null) {
508
- if (player.live) {
509
- player.stop()
510
- } else {
511
- player.pause()
537
+ if (
538
+ !player.paused && player.state.source != null &&
539
+ player.castingType == CastingType.NONE
540
+ ) {
541
+ val shouldPause = when (player.continueInBackgroundMode) {
542
+ BackgroundMode.PAUSE -> true
543
+ BackgroundMode.PICTURE_IN_PICTURE -> when {
544
+ player.isCastingHost -> false
545
+ player.pictureInPicture -> false
546
+ else -> true // PiP disabled in system settings?
547
+ }
548
+ else -> false
549
+ }
550
+ if (shouldPause) {
551
+ autoPauseByBackground()
512
552
  }
513
- pausedByBackground = true
553
+ }
554
+ if (player is PlayerProxy) {
555
+ player.onLifecycleStop()
514
556
  }
515
557
  }
516
558
 
517
- override fun onResume(owner: LifecycleOwner) {
559
+ override fun onStart(owner: LifecycleOwner) {
518
560
  val player = this@NpawPlayerView.player ?: return
519
561
  if (pausedByBackground) {
520
562
  pausedByBackground = false
521
563
  player.play()
522
564
  }
565
+ if (player is PlayerProxy) {
566
+ player.onLifecycleStart()
567
+ }
523
568
  player.asPlayerExoPlayer()?.also {
524
- attachSurface(it)
569
+ if (player.castingType == CastingType.NONE) {
570
+ attachSurface(it)
571
+ }
525
572
  }
526
573
  }
527
574
 
@@ -20,7 +20,10 @@ object MediaEventType {
20
20
  const val KEY_UP = "keyup"
21
21
  const val KEY_DOWN = "keydown"
22
22
  const val TRACKS_CHANGED = "trackschanged"
23
- const val AD_BREAK_START = "adbreakstart"
23
+ const val AD_BREAK_START = "adbreakbegin"
24
24
  const val AD_BREAK_END = "adbreakend"
25
- const val AD_BREAKS_RESCHEDULED = "adbreaksrescheduled"
25
+ const val AD_BREAKS_RESCHEDULED = "admetadata"
26
+ const val AD_STARTED = "adbegin"
27
+ const val AD_ERROR = "aderror"
28
+ const val AD_SKIPPED = "adskip"
26
29
  }
@@ -328,14 +328,23 @@ class WebViewModel @Inject constructor(
328
328
  Log.d("WebViewModel", "onTrackschanged: audio=$audioTrack subtitle=$subtitleTrack")
329
329
  jsBridge.bridgeAndroidToJavaScript_MediaTrackEvent(MediaEventType.TRACKS_CHANGED, player.audioTracks, player.textTracks)
330
330
  }
331
+ is AdBreaksRescheduledEvent -> {
332
+ jsBridge.bridgeAndroidToJavaScript_MediaAdBreaksEvent(MediaEventType.AD_BREAKS_RESCHEDULED, player.timeline)
333
+ }
331
334
  is AdBreakStartedEvent -> {
332
- jsBridge.bridgeAndroidToJavaScript_MediaEvent(MediaEventType.AD_BREAK_START)
335
+ jsBridge.bridgeAndroidToJavaScript_MediaAdEvent(MediaEventType.AD_BREAK_START, player.currentAdBreak, player.currentAd)
333
336
  }
334
337
  is AdBreakEndedEvent -> {
335
- jsBridge.bridgeAndroidToJavaScript_MediaEvent(MediaEventType.AD_BREAK_END)
338
+ jsBridge.bridgeAndroidToJavaScript_MediaAdEvent(MediaEventType.AD_BREAK_END, player.currentAdBreak, player.currentAd)
336
339
  }
337
- is AdBreaksRescheduledEvent -> {
338
- jsBridge.bridgeAndroidToJavaScript_MediaAdBreaksEvent(MediaEventType.AD_BREAKS_RESCHEDULED, player.timeline)
340
+ is AdStartedEvent -> {
341
+ jsBridge.bridgeAndroidToJavaScript_MediaAdEvent(MediaEventType.AD_STARTED, player.currentAdBreak, player.currentAd)
342
+ }
343
+ is AdErrorEvent -> {
344
+ jsBridge.bridgeAndroidToJavaScript_MediaAdEvent(MediaEventType.AD_ERROR, player.currentAdBreak, player.currentAd)
345
+ }
346
+ is AdSkippedEvent -> {
347
+ jsBridge.bridgeAndroidToJavaScript_MediaAdEvent(MediaEventType.AD_SKIPPED, player.currentAdBreak, player.currentAd)
339
348
  }
340
349
  }
341
350
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@24i/smartapps-bigscreen-rnv-build-engine",
3
- "version": "0.17.26",
3
+ "version": "0.17.27-alpha.2774",
4
4
  "description": "Package with build engine for SmartApps BIGscreen projects...",
5
5
  "main": "dist/src/index.js",
6
6
  "scripts": {