react-native-theoplayer 3.7.1 → 3.9.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 (86) hide show
  1. package/CHANGELOG.md +24 -1
  2. package/android/build.gradle +2 -1
  3. package/android/local/com/theoplayer/theoplayer-sdk-android/ads-wrapper/6.10.0/ads-wrapper-6.10.0.aar +0 -0
  4. package/android/local/com/theoplayer/theoplayer-sdk-android/ads-wrapper/{4.8.0/ads-wrapper-4.8.0.pom → 6.10.0/ads-wrapper-6.10.0.pom} +1 -1
  5. package/android/local/com/theoplayer/theoplayer-sdk-android/ads-wrapper/maven-metadata-local.xml +4 -4
  6. package/android/src/main/java/com/theoplayer/PlayerConfigAdapter.kt +4 -0
  7. package/android/src/main/java/com/theoplayer/ReactTHEOplayerContext.kt +7 -0
  8. package/android/src/main/java/com/theoplayer/ads/AdEventAdapter.kt +9 -4
  9. package/android/src/main/java/com/theoplayer/ads/AdsModule.kt +1 -1
  10. package/android/src/main/java/com/theoplayer/audio/AudioFocusManager.kt +57 -26
  11. package/android/src/main/java/com/theoplayer/broadcast/EventBroadcastModule.kt +1 -1
  12. package/android/src/main/java/com/theoplayer/cache/CacheModule.kt +1 -1
  13. package/android/src/main/java/com/theoplayer/cast/CastModule.kt +1 -1
  14. package/android/src/main/java/com/theoplayer/drm/ContentProtectionModule.kt +1 -1
  15. package/android/src/main/java/com/theoplayer/media/MediaPlaybackService.kt +8 -17
  16. package/android/src/main/java/com/theoplayer/player/PlayerModule.kt +1 -1
  17. package/ios/THEOplayerRCTBridge.m +6 -6
  18. package/ios/THEOplayerRCTPlayerAPI.swift +25 -25
  19. package/ios/ads/THEOplayerRCTAdsAPI.swift +17 -17
  20. package/ios/backgroundAudio/THEOplayerRCTNowPlayingManager.swift +4 -0
  21. package/ios/cache/THEOplayerRCTCacheAPI.swift +29 -29
  22. package/ios/casting/THEOplayerRCTCastAPI.swift +9 -9
  23. package/ios/contentprotection/THEOplayerRCTContentProtectionAPI.swift +22 -22
  24. package/ios/eventBroadcasting/THEOplayerRCTEventBroadcastAPI.swift +5 -5
  25. package/lib/commonjs/api/config/PlayerConfiguration.js.map +1 -1
  26. package/lib/commonjs/internal/adapter/THEOplayerAdapter.js +19 -18
  27. package/lib/commonjs/internal/adapter/THEOplayerAdapter.js.map +1 -1
  28. package/lib/commonjs/internal/adapter/abr/AbrAdapter.js +2 -1
  29. package/lib/commonjs/internal/adapter/abr/AbrAdapter.js.map +1 -1
  30. package/lib/commonjs/internal/adapter/ads/THEOplayerNativeAdsAdapter.js +7 -6
  31. package/lib/commonjs/internal/adapter/ads/THEOplayerNativeAdsAdapter.js.map +1 -1
  32. package/lib/commonjs/internal/adapter/ads/THEOplayerNativeGoogleDAI.js +5 -4
  33. package/lib/commonjs/internal/adapter/ads/THEOplayerNativeGoogleDAI.js.map +1 -1
  34. package/lib/commonjs/internal/adapter/broadcast/EventBroadcastAdapter.js +2 -1
  35. package/lib/commonjs/internal/adapter/broadcast/EventBroadcastAdapter.js.map +1 -1
  36. package/lib/commonjs/internal/adapter/cast/THEOplayerNativeAirplay.js +5 -4
  37. package/lib/commonjs/internal/adapter/cast/THEOplayerNativeAirplay.js.map +1 -1
  38. package/lib/commonjs/internal/adapter/cast/THEOplayerNativeChromecast.js +7 -6
  39. package/lib/commonjs/internal/adapter/cast/THEOplayerNativeChromecast.js.map +1 -1
  40. package/lib/commonjs/internal/adapter/track/TextTrackStyleAdapter.js +11 -10
  41. package/lib/commonjs/internal/adapter/track/TextTrackStyleAdapter.js.map +1 -1
  42. package/lib/commonjs/internal/cache/MediaCache.js +4 -3
  43. package/lib/commonjs/internal/cache/MediaCache.js.map +1 -1
  44. package/lib/commonjs/internal/cache/NativeCachingTaskAdapter.js +5 -4
  45. package/lib/commonjs/internal/cache/NativeCachingTaskAdapter.js.map +1 -1
  46. package/lib/commonjs/internal/drm/ContentProtectionRegistry.js +23 -22
  47. package/lib/commonjs/internal/drm/ContentProtectionRegistry.js.map +1 -1
  48. package/lib/module/api/config/PlayerConfiguration.js.map +1 -1
  49. package/lib/module/internal/adapter/THEOplayerAdapter.js +19 -18
  50. package/lib/module/internal/adapter/THEOplayerAdapter.js.map +1 -1
  51. package/lib/module/internal/adapter/abr/AbrAdapter.js +2 -1
  52. package/lib/module/internal/adapter/abr/AbrAdapter.js.map +1 -1
  53. package/lib/module/internal/adapter/ads/THEOplayerNativeAdsAdapter.js +7 -6
  54. package/lib/module/internal/adapter/ads/THEOplayerNativeAdsAdapter.js.map +1 -1
  55. package/lib/module/internal/adapter/ads/THEOplayerNativeGoogleDAI.js +5 -4
  56. package/lib/module/internal/adapter/ads/THEOplayerNativeGoogleDAI.js.map +1 -1
  57. package/lib/module/internal/adapter/broadcast/EventBroadcastAdapter.js +2 -1
  58. package/lib/module/internal/adapter/broadcast/EventBroadcastAdapter.js.map +1 -1
  59. package/lib/module/internal/adapter/cast/THEOplayerNativeAirplay.js +5 -4
  60. package/lib/module/internal/adapter/cast/THEOplayerNativeAirplay.js.map +1 -1
  61. package/lib/module/internal/adapter/cast/THEOplayerNativeChromecast.js +7 -6
  62. package/lib/module/internal/adapter/cast/THEOplayerNativeChromecast.js.map +1 -1
  63. package/lib/module/internal/adapter/track/TextTrackStyleAdapter.js +11 -10
  64. package/lib/module/internal/adapter/track/TextTrackStyleAdapter.js.map +1 -1
  65. package/lib/module/internal/cache/MediaCache.js +4 -3
  66. package/lib/module/internal/cache/MediaCache.js.map +1 -1
  67. package/lib/module/internal/cache/NativeCachingTaskAdapter.js +5 -4
  68. package/lib/module/internal/cache/NativeCachingTaskAdapter.js.map +1 -1
  69. package/lib/module/internal/drm/ContentProtectionRegistry.js +23 -22
  70. package/lib/module/internal/drm/ContentProtectionRegistry.js.map +1 -1
  71. package/lib/typescript/api/config/PlayerConfiguration.d.ts +10 -0
  72. package/package.json +1 -1
  73. package/react-native-theoplayer.podspec +11 -6
  74. package/src/api/config/PlayerConfiguration.ts +11 -0
  75. package/src/internal/adapter/THEOplayerAdapter.ts +20 -18
  76. package/src/internal/adapter/abr/AbrAdapter.ts +3 -1
  77. package/src/internal/adapter/ads/THEOplayerNativeAdsAdapter.ts +8 -6
  78. package/src/internal/adapter/ads/THEOplayerNativeGoogleDAI.ts +6 -4
  79. package/src/internal/adapter/broadcast/EventBroadcastAdapter.ts +3 -1
  80. package/src/internal/adapter/cast/THEOplayerNativeAirplay.ts +6 -4
  81. package/src/internal/adapter/cast/THEOplayerNativeChromecast.ts +8 -6
  82. package/src/internal/adapter/track/TextTrackStyleAdapter.ts +11 -10
  83. package/src/internal/cache/MediaCache.ts +5 -3
  84. package/src/internal/cache/NativeCachingTaskAdapter.ts +6 -4
  85. package/src/internal/drm/ContentProtectionRegistry.ts +24 -22
  86. package/android/local/com/theoplayer/theoplayer-sdk-android/ads-wrapper/4.8.0/ads-wrapper-4.8.0.aar +0 -0
package/CHANGELOG.md CHANGED
@@ -5,11 +5,34 @@ 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
+ ## [3.9.0] - 24-03-04
9
+
10
+ ### Changed
11
+
12
+ - Reduce audio volume (duck) on Android when another app gains transient audio focus and ducking is allowed. In other cases the player will pause, and optionally resume if the audio focus loss was transient.
13
+
14
+ ### Fixed
15
+
16
+ - Fixed an issue on iOS where the lockscreen controls and displayed asset metadata would remain visible after the player has been destroyed.
17
+ - Fixed an issue on iOS where the castState was not initialized correctly.
18
+
19
+ ## [3.8.0] - 24-02-23
20
+
21
+ ### Changed
22
+
23
+ - Renamed native modules to avoid name collisions with external packages.
24
+
25
+ ### Added
26
+
27
+ - Added `adbreakbegin` and `adbreakend` events for Google IMA on Android.
28
+ - Added `liveOffset` property to `PlayerConfiguration`, allowing to set a custom offset from the live point.
29
+ - Added a second, alternative config filename to the iOS podspec setup to prevent a react-native-theoplayer module resolving clash.
30
+
8
31
  ## [3.7.1] - 24-02-09
9
32
 
10
33
  ### Fixed
11
34
 
12
- - Fixed a dependency issue on iOS when using chromecast or google ima features.
35
+ - Fixed a dependency issue on iOS when using chromecast or Google IMA features.
13
36
 
14
37
  ## [3.7.0] - 24-02-09
15
38
 
@@ -107,6 +107,7 @@ dependencies {
107
107
  implementation "com.facebook.react:react-native:+" // From node_modules
108
108
  implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3"
109
109
  implementation "androidx.appcompat:appcompat:1.6.1"
110
+ implementation "androidx.core:core-ktx:1.12.0"
110
111
 
111
112
  // The minimum supported THEOplayer version is 6.0.0
112
113
  def theoplayer_sdk_version = safeExtGet('THEOplayer_sdk', '[6.0.0,7.0)')
@@ -117,7 +118,7 @@ dependencies {
117
118
  println("Using THEOplayer (${versionString(theoplayer_sdk_version)})")
118
119
  implementation "com.theoplayer.theoplayer-sdk-android:core:${theoplayer_sdk_version}"
119
120
 
120
- implementation "com.theoplayer.theoplayer-sdk-android:ads-wrapper:4.8.0"
121
+ implementation "com.theoplayer.theoplayer-sdk-android:ads-wrapper:6.10.0"
121
122
 
122
123
  if (enabledMediaSession) {
123
124
  println("Enable THEOplayer MediaSession extension (${versionString(theoplayer_mediasession_version)})")
@@ -4,6 +4,6 @@
4
4
  <modelVersion>4.0.0</modelVersion>
5
5
  <groupId>com.theoplayer.theoplayer-sdk-android</groupId>
6
6
  <artifactId>ads-wrapper</artifactId>
7
- <version>4.8.0</version>
7
+ <version>6.10.0</version>
8
8
  <packaging>aar</packaging>
9
9
  </project>
@@ -3,11 +3,11 @@
3
3
  <groupId>com.theoplayer.theoplayer-sdk-android</groupId>
4
4
  <artifactId>ads-wrapper</artifactId>
5
5
  <versioning>
6
- <latest>4.8.0</latest>
7
- <release>4.8.0</release>
6
+ <latest>6.10.0</latest>
7
+ <release>6.10.0</release>
8
8
  <versions>
9
- <version>4.8.0</version>
9
+ <version>6.10.0</version>
10
10
  </versions>
11
- <lastUpdated>20230217111544</lastUpdated>
11
+ <lastUpdated>20240221111544</lastUpdated>
12
12
  </versioning>
13
13
  </metadata>
@@ -17,6 +17,7 @@ private const val PROP_LICENSE = "license"
17
17
  private const val PROP_LICENSE_URL = "licenseUrl"
18
18
  private const val PROP_PRELOAD = "preload"
19
19
  private const val PROP_LANGUAGE = "language"
20
+ private const val PROP_LIVE_OFFSET = "liveOffset"
20
21
  private const val PROP_UI_ENABLED = "uiEnabled"
21
22
  private const val PROP_CAST_STRATEGY = "strategy"
22
23
  private const val PROP_RETRY_CONFIG = "retryConfiguration"
@@ -48,6 +49,9 @@ class PlayerConfigAdapter(private val configProps: ReadableMap?) {
48
49
  if (hasKey(PROP_RETRY_CONFIG)) {
49
50
  networkConfiguration(networkConfig())
50
51
  }
52
+ if (hasKey(PROP_LIVE_OFFSET)) {
53
+ liveOffset(getDouble(PROP_LIVE_OFFSET))
54
+ }
51
55
  if (hasKey(PROP_UI_CONFIGURATION)) {
52
56
  ui(uiConfig())
53
57
  }
@@ -307,12 +307,18 @@ class ReactTHEOplayerContext private constructor(
307
307
  audioBecomingNoisyManager.setEnabled(false)
308
308
  }
309
309
 
310
+ private val onEnded = EventListener<EndedEvent> {
311
+ // Playback has ended, we can abandon audio focus.
312
+ audioFocusManager?.abandonAudioFocus()
313
+ }
314
+
310
315
  private fun addListeners() {
311
316
  player.apply {
312
317
  addEventListener(PlayerEventTypes.SOURCECHANGE, onSourceChange)
313
318
  addEventListener(PlayerEventTypes.LOADEDMETADATA, onLoadedMetadata)
314
319
  addEventListener(PlayerEventTypes.PAUSE, onPause)
315
320
  addEventListener(PlayerEventTypes.PLAY, onPlay)
321
+ addEventListener(PlayerEventTypes.ENDED, onEnded)
316
322
  }
317
323
  }
318
324
 
@@ -322,6 +328,7 @@ class ReactTHEOplayerContext private constructor(
322
328
  removeEventListener(PlayerEventTypes.LOADEDMETADATA, onLoadedMetadata)
323
329
  removeEventListener(PlayerEventTypes.PAUSE, onPause)
324
330
  removeEventListener(PlayerEventTypes.PLAY, onPlay)
331
+ removeEventListener(PlayerEventTypes.ENDED, onEnded)
325
332
  }
326
333
  }
327
334
 
@@ -4,6 +4,7 @@ import com.facebook.react.bridge.Arguments
4
4
  import com.facebook.react.bridge.ReadableMap
5
5
  import com.theoplayer.android.api.ads.wrapper.AdsApiWrapper
6
6
  import com.facebook.react.bridge.WritableMap
7
+ import com.google.ads.interactivemedia.v3.api.AdError
7
8
  import com.theoplayer.android.api.ads.Ad
8
9
  import com.theoplayer.android.api.ads.AdBreak
9
10
  import com.theoplayer.android.api.ads.GoogleImaAd
@@ -30,7 +31,9 @@ private val ALL_AD_EVENTS = arrayOf(
30
31
  GoogleImaAdEventType.SKIPPED,
31
32
  GoogleImaAdEventType.AD_ERROR,
32
33
  GoogleImaAdEventType.AD_BUFFERING,
33
- GoogleImaAdEventType.AD_BREAK_FETCH_ERROR
34
+ GoogleImaAdEventType.AD_BREAK_FETCH_ERROR,
35
+ GoogleImaAdEventType.CONTENT_PAUSE_REQUESTED,
36
+ GoogleImaAdEventType.CONTENT_RESUME_REQUESTED
34
37
  )
35
38
 
36
39
  class AdEventAdapter(private val adsApi: AdsApiWrapper, eventEmitter: AdEventEmitter) {
@@ -42,7 +45,7 @@ class AdEventAdapter(private val adsApi: AdsApiWrapper, eventEmitter: AdEventEmi
42
45
 
43
46
  init {
44
47
  eventListener = object : AdEventListener {
45
- override fun <E : AdEvent<*>?> onAdEvent(type: EventType<E>?, ad: Ad?) {
48
+ override fun <E : AdEvent<*>?> onAdEvent(type: EventType<E>?, ad: Ad?, adData: Map<String, String>?, adError: AdError?) {
46
49
  val payload = Arguments.createMap()
47
50
  if (type != null) {
48
51
  payload.putString(EVENT_PROP_TYPE, mapAdType(type))
@@ -53,7 +56,7 @@ class AdEventAdapter(private val adsApi: AdsApiWrapper, eventEmitter: AdEventEmi
53
56
  eventEmitter.emit(payload)
54
57
  }
55
58
 
56
- override fun <E : AdEvent<*>?> onAdBreakEvent(type: EventType<E>?, adBreak: AdBreak?) {
59
+ override fun <E : AdEvent<*>?> onAdBreakEvent(type: EventType<E>?, adBreak: AdBreak?, adData: Map<String, String>?, adError: AdError?) {
57
60
  val payload = Arguments.createMap()
58
61
  if (type != null) {
59
62
  payload.putString(EVENT_PROP_TYPE, mapAdType(type))
@@ -106,7 +109,7 @@ class AdEventAdapter(private val adsApi: AdsApiWrapper, eventEmitter: AdEventEmi
106
109
  "aderror" -> GoogleImaAdEventType.AD_ERROR
107
110
  "adbuffering" -> GoogleImaAdEventType.AD_BUFFERING
108
111
  "adbreakbegin" -> GoogleImaAdEventType.AD_BREAK_STARTED
109
- "adbreakend" -> GoogleImaAdEventType.CONTENT_RESUME_REQUESTED
112
+ "adbreakend" -> GoogleImaAdEventType.AD_BREAK_ENDED
110
113
  else -> null /*unknown*/
111
114
  }
112
115
  }
@@ -122,6 +125,8 @@ class AdEventAdapter(private val adsApi: AdsApiWrapper, eventEmitter: AdEventEmi
122
125
  GoogleImaAdEventType.SKIPPED -> "adskip"
123
126
  GoogleImaAdEventType.AD_ERROR -> "aderror"
124
127
  GoogleImaAdEventType.AD_BUFFERING -> "adbuffering"
128
+ GoogleImaAdEventType.CONTENT_PAUSE_REQUESTED -> "adbreakbegin"
129
+ GoogleImaAdEventType.CONTENT_RESUME_REQUESTED -> "adbreakend"
125
130
  GoogleImaAdEventType.AD_BREAK_STARTED -> "adbreakbegin"
126
131
  GoogleImaAdEventType.AD_BREAK_ENDED -> "adbreakend"
127
132
  GoogleImaAdEventType.AD_BREAK_FETCH_ERROR -> "aderror"
@@ -9,7 +9,7 @@ import com.theoplayer.util.ViewResolver
9
9
  import com.theoplayer.ReactTHEOplayerView
10
10
  import com.theoplayer.android.api.error.THEOplayerException
11
11
 
12
- private const val TAG = "AdsModule"
12
+ private const val TAG = "THEORCTAdsModule"
13
13
 
14
14
  class AdsModule(context: ReactApplicationContext) : ReactContextBaseJavaModule(context) {
15
15
  private val sourceHelper = SourceAdapter()
@@ -17,6 +17,14 @@ private const val TAG = "AudioFocusManager"
17
17
  * Manages audio focus for the application, ensuring proper handling of audio focus changes
18
18
  * to control media playback behavior.
19
19
  *
20
+ * - Android 12 (API level 31) or later: Audio focus is managed by the system.
21
+ * - Android 8.0 (API level 26) through Android 11 (API level 30): Audio focus is not managed by
22
+ * the system, but includes some changes that were introduced starting in Android 8.0
23
+ * (API level 26).
24
+ * - Android 7.1 (API level 25) and lower: Audio focus is not managed by the system.
25
+ *
26
+ * @see <a href="https://developer.android.com/media/optimize/audio-focus">documentation</a>
27
+ *
20
28
  * @param context The context used to access system services.
21
29
  * @param player The media player instance associated with this audio focus manager. It can be
22
30
  * provided optionally to control playback behavior.
@@ -29,21 +37,29 @@ class AudioFocusManager(
29
37
  private val audioManager = context.getSystemService(Context.AUDIO_SERVICE) as? AudioManager
30
38
  private val uiModeManager = context.getSystemService(Context.UI_MODE_SERVICE) as? UiModeManager
31
39
  private var resumeOnFocusGain = false
40
+ private var originalVolume: Int = -1
32
41
  private val focusLock = Any()
33
42
 
34
- private val audioFocusRequest = AudioFocusRequestCompat.Builder(AudioManagerCompat.AUDIOFOCUS_GAIN)
35
- .setAudioAttributes(
36
- AudioAttributesCompat.Builder()
37
- // Usage value to use when the usage is media, such as music, or movie soundtracks.
38
- .setUsage(AudioAttributesCompat.USAGE_MEDIA)
39
- // Content type value to use when the content type is a soundtrack, typically accompanying
40
- // a movie or TV program.
41
- .setContentType(AudioAttributesCompat.CONTENT_TYPE_MOVIE)
42
- .build()
43
- )
44
- .setOnAudioFocusChangeListener(this)
45
- .setWillPauseWhenDucked(true)
46
- .build()
43
+ // Request for audio focus of unknown duration.
44
+ private val audioFocusRequest =
45
+ AudioFocusRequestCompat.Builder(AudioManagerCompat.AUDIOFOCUS_GAIN)
46
+ .setAudioAttributes(
47
+ AudioAttributesCompat.Builder()
48
+ // Usage value to use when the usage is media, such as music, or movie soundtracks.
49
+ .setUsage(AudioAttributesCompat.USAGE_MEDIA)
50
+ // Content type value to use when the content type is a soundtrack, typically accompanying
51
+ // a movie or TV program.
52
+ .setContentType(AudioAttributesCompat.CONTENT_TYPE_MOVIE)
53
+ .build()
54
+ )
55
+ .setOnAudioFocusChangeListener(this)
56
+
57
+ // Automatic ducking was introduced in Android 8.0 (API level 26)
58
+ // The audio system ducks our player(s) while the other app has focus. When the other app abandons
59
+ // focus, it "unducks" our player. We are not notified when on focus loss.
60
+ // https://developer.android.com/media/optimize/audio-focus#automatic_ducking
61
+ .setWillPauseWhenDucked(false)
62
+ .build()
47
63
 
48
64
  /**
49
65
  * Called on the listener to notify it the audio focus for this listener has been changed.
@@ -59,6 +75,7 @@ class AudioFocusManager(
59
75
  when (focusChange) {
60
76
  // Used to indicate a gain of audio focus, or a request of audio focus, of unknown duration.
61
77
  AudioManager.AUDIOFOCUS_GAIN -> {
78
+ // Optionally resume playback
62
79
  if (resumeOnFocusGain) {
63
80
  synchronized(focusLock) {
64
81
  // Reset resume flag
@@ -66,29 +83,43 @@ class AudioFocusManager(
66
83
  }
67
84
  player?.play()
68
85
  }
86
+
87
+ // Restore the audio level
88
+ if (originalVolume != -1) {
89
+ audioManager?.setStreamVolume(AudioManager.STREAM_MUSIC, originalVolume, 0)
90
+ originalVolume = -1
91
+ }
69
92
  }
70
93
 
71
94
  // Used to indicate a loss of audio focus of unknown duration.
72
95
  AudioManager.AUDIOFOCUS_LOSS -> {
73
- synchronized (focusLock) {
74
- // This is not a transient loss, we shouldn't automatically resume for now
75
- resumeOnFocusGain = false;
96
+ synchronized(focusLock) {
97
+ // This is not a transient (short) loss, we shouldn't automatically resume for now.
98
+ resumeOnFocusGain = false
76
99
  }
100
+ player?.pause()
77
101
  }
78
102
 
79
- // Used to indicate a transient loss of audio focus.
80
- AudioManager.AUDIOFOCUS_LOSS_TRANSIENT,
81
-
82
- // Used to indicate a transient loss of audio focus where the loser of the audio focus can
83
- // lower its output volume if it wants to continue playing (also referred to as "ducking"),
84
- // as the new focus owner doesn't require others to be silent.
85
- AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> {
86
- synchronized (focusLock) {
103
+ // Used to indicate a transient (short) loss of audio focus.
104
+ AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> {
105
+ synchronized(focusLock) {
87
106
  // We should only resume if playback was interrupted
88
107
  resumeOnFocusGain = !(player?.isPaused ?: true)
89
108
  }
90
109
  player?.pause()
91
110
  }
111
+
112
+ // Used to indicate a transient (short) loss of audio focus where the loser of the audio focus
113
+ // can lower its output volume if it wants to continue playing (also referred to as "ducking"),
114
+ // as the new focus owner doesn't require others to be silent.
115
+ AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> {
116
+ synchronized(focusLock) {
117
+ audioManager?.apply {
118
+ originalVolume = getStreamVolume(AudioManager.STREAM_MUSIC)
119
+ setStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_LOWER, 0)
120
+ }
121
+ }
122
+ }
92
123
  }
93
124
  }
94
125
 
@@ -106,7 +137,7 @@ class AudioFocusManager(
106
137
  }
107
138
 
108
139
  private fun fromAudioFocusRequest(focusRequest: Int?): String {
109
- return when(focusRequest) {
140
+ return when (focusRequest) {
110
141
  AudioManager.AUDIOFOCUS_REQUEST_GRANTED -> "AUDIOFOCUS_REQUEST_GRANTED"
111
142
  AudioManager.AUDIOFOCUS_REQUEST_DELAYED -> "AUDIOFOCUS_REQUEST_DELAYED"
112
143
  else -> "AUDIOFOCUS_REQUEST_FAILED"
@@ -132,7 +163,7 @@ class AudioFocusManager(
132
163
  * Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
133
164
  */
134
165
  fun abandonAudioFocus() {
135
- synchronized (focusLock) {
166
+ synchronized(focusLock) {
136
167
  resumeOnFocusGain = false
137
168
  }
138
169
  val result = audioManager?.let {
@@ -9,7 +9,7 @@ import com.facebook.react.module.annotations.ReactModule
9
9
  import com.theoplayer.ReactTHEOplayerView
10
10
  import com.theoplayer.util.ViewResolver
11
11
 
12
- private const val TAG = "EventBroadcastModule"
12
+ private const val TAG = "THEORCTEventBroadcastModule"
13
13
 
14
14
  @ReactModule(name = TAG)
15
15
  class EventBroadcastModule(context: ReactApplicationContext) : ReactContextBaseJavaModule(context) {
@@ -30,7 +30,7 @@ import com.theoplayer.source.SourceAdapter
30
30
  import org.json.JSONException
31
31
  import org.json.JSONObject
32
32
 
33
- private const val TAG = "CacheModule"
33
+ private const val TAG = "THEORCTCacheModule"
34
34
 
35
35
  private const val PROP_STATUS = "status"
36
36
  private const val PROP_ID = "id"
@@ -14,7 +14,7 @@ class CastModule(context: ReactApplicationContext) : ReactContextBaseJavaModule(
14
14
  private val viewResolver: ViewResolver = ViewResolver(context)
15
15
 
16
16
  override fun getName(): String {
17
- return "CastModule"
17
+ return "THEORCTCastModule"
18
18
  }
19
19
 
20
20
  @ReactMethod
@@ -19,7 +19,7 @@ data class BridgeRequest(
19
19
  val onTimeout: Runnable
20
20
  )
21
21
 
22
- private const val TAG = "ContentProtectionModule"
22
+ private const val TAG = "THEORCTContentProtectionModule"
23
23
 
24
24
  private const val EVENT_CERTIFICATE_REQUEST = "onCertificateRequest"
25
25
  private const val EVENT_CERTIFICATE_REQUEST_PROCESSED_AS_REQUEST = "onCertificateRequestProcessedAsRequest"
@@ -13,6 +13,7 @@ import android.support.v4.media.session.MediaSessionCompat
13
13
  import android.support.v4.media.session.PlaybackStateCompat
14
14
  import android.text.TextUtils
15
15
  import android.util.Log
16
+ import androidx.core.app.ServiceCompat
16
17
  import androidx.core.content.ContextCompat
17
18
  import androidx.media.MediaBrowserServiceCompat
18
19
  import androidx.media.session.MediaButtonReceiver
@@ -282,12 +283,7 @@ class MediaPlaybackService : MediaBrowserServiceCompat() {
282
283
  // needed. This does not stop the service from running (for that you use stopSelf()
283
284
  // or related methods), just takes it out of the foreground state.
284
285
  // Also remove the notification.
285
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
286
- stopForeground(Service.STOP_FOREGROUND_REMOVE)
287
- } else {
288
- @Suppress("DEPRECATION")
289
- stopForeground(true)
290
- }
286
+ ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_REMOVE)
291
287
  }
292
288
  else -> {
293
289
  // Ignore
@@ -297,18 +293,13 @@ class MediaPlaybackService : MediaBrowserServiceCompat() {
297
293
 
298
294
  private fun startForegroundWithPlaybackState(@PlaybackStateCompat.State playbackState: Int, largeIcon: Bitmap? = null) {
299
295
  try {
300
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
301
- startForeground(
302
- NOTIFICATION_ID,
303
- notificationBuilder.build(playbackState, largeIcon, enableMediaControls),
296
+ ServiceCompat.startForeground(
297
+ this, NOTIFICATION_ID,
298
+ notificationBuilder.build(playbackState, largeIcon, enableMediaControls),
299
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
304
300
  ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK
305
- )
306
- } else {
307
- startForeground(
308
- NOTIFICATION_ID,
309
- notificationBuilder.build(playbackState, largeIcon, enableMediaControls)
310
- )
311
- }
301
+ else 0
302
+ )
312
303
  } catch (e: IllegalStateException) {
313
304
  // Make sure that app does not crash in case anything goes wrong with starting the service.
314
305
  // https://issuetracker.google.com/issues/229000935
@@ -14,7 +14,7 @@ import com.theoplayer.presentation.PipConfigAdapter
14
14
  import com.theoplayer.track.TextTrackStyleAdapter
15
15
  import com.theoplayer.util.ViewResolver
16
16
 
17
- private const val TAG = "PlayerModule"
17
+ private const val TAG = "THEORCTPlayerModule"
18
18
 
19
19
  @Suppress("unused")
20
20
  class PlayerModule(context: ReactApplicationContext) : ReactContextBaseJavaModule(context) {
@@ -57,7 +57,7 @@ RCT_EXTERN_METHOD(destroy:(nonnull NSNumber *)node);
57
57
  // ----------------------------------------------------------------------------
58
58
  // Player Module
59
59
  // ----------------------------------------------------------------------------
60
- @interface RCT_EXTERN_REMAP_MODULE(PlayerModule, THEOplayerRCTPlayerAPI, NSObject)
60
+ @interface RCT_EXTERN_REMAP_MODULE(THEORCTPlayerModule, THEOplayerRCTPlayerAPI, NSObject)
61
61
 
62
62
  RCT_EXTERN_METHOD(setPaused:(nonnull NSNumber *)node
63
63
  paused:(BOOL)paused)
@@ -116,7 +116,7 @@ RCT_EXTERN_METHOD(setTextTrackStyle:(nonnull NSNumber *)node
116
116
  // Ads Module
117
117
  // ----------------------------------------------------------------------------
118
118
 
119
- @interface RCT_EXTERN_REMAP_MODULE(AdsModule, THEOplayerRCTAdsAPI, NSObject)
119
+ @interface RCT_EXTERN_REMAP_MODULE(THEORCTAdsModule, THEOplayerRCTAdsAPI, NSObject)
120
120
 
121
121
  RCT_EXTERN_METHOD(skip:(nonnull NSNumber *)node)
122
122
 
@@ -161,7 +161,7 @@ RCT_EXTERN_METHOD(daiStreamTimeForContentTime:(nonnull NSNumber *)node
161
161
  // ----------------------------------------------------------------------------
162
162
  // ContentProtection Module
163
163
  // ----------------------------------------------------------------------------
164
- @interface RCT_EXTERN_REMAP_MODULE(ContentProtectionModule, THEOplayerRCTContentProtectionAPI, RCTEventEmitter)
164
+ @interface RCT_EXTERN_REMAP_MODULE(THEORCTContentProtectionModule, THEOplayerRCTContentProtectionAPI, RCTEventEmitter)
165
165
 
166
166
  RCT_EXTERN_METHOD(onBuildProcessed:(NSDictionary)result)
167
167
  RCT_EXTERN_METHOD(onCertificateRequestProcessedAsRequest:(NSDictionary)result)
@@ -180,7 +180,7 @@ RCT_EXTERN_METHOD(registerContentProtectionIntegration:(nonnull NSString *)integ
180
180
  // Cast Module
181
181
  // ----------------------------------------------------------------------------
182
182
 
183
- @interface RCT_EXTERN_REMAP_MODULE(CastModule, THEOplayerRCTCastAPI, NSObject)
183
+ @interface RCT_EXTERN_REMAP_MODULE(THEORCTCastModule, THEOplayerRCTCastAPI, NSObject)
184
184
 
185
185
  RCT_EXTERN_METHOD(casting:(nonnull NSNumber *)node
186
186
  resolver:(RCTPromiseResolveBlock)resolve
@@ -221,7 +221,7 @@ RCT_EXTERN_METHOD(airplayStop:(nonnull NSNumber *)node)
221
221
  // ----------------------------------------------------------------------------
222
222
  // Cache Module
223
223
  // ----------------------------------------------------------------------------
224
- @interface RCT_EXTERN_REMAP_MODULE(CacheModule, THEOplayerRCTCacheAPI, RCTEventEmitter)
224
+ @interface RCT_EXTERN_REMAP_MODULE(THEORCTCacheModule, THEOplayerRCTCacheAPI, RCTEventEmitter)
225
225
 
226
226
  RCT_EXTERN_METHOD(getInitialState:(RCTPromiseResolveBlock)resolve
227
227
  rejecter:(RCTPromiseRejectBlock)reject)
@@ -243,7 +243,7 @@ RCT_EXTERN_METHOD(renewLicense:(nonnull NSString *)id
243
243
  // ----------------------------------------------------------------------------
244
244
  // Broadcast Module
245
245
  // ----------------------------------------------------------------------------
246
- @interface RCT_EXTERN_REMAP_MODULE(EventBroadcastModule, THEOplayerRCTEventBroadcastAPI, NSObject)
246
+ @interface RCT_EXTERN_REMAP_MODULE(THEORCTEventBroadcastModule, THEOplayerRCTEventBroadcastAPI, NSObject)
247
247
 
248
248
  RCT_EXTERN_METHOD(broadcastEvent:(nonnull NSNumber *)node
249
249
  event:(NSDictionary)event)