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.
- package/CHANGELOG.md +24 -1
- package/android/build.gradle +2 -1
- package/android/local/com/theoplayer/theoplayer-sdk-android/ads-wrapper/6.10.0/ads-wrapper-6.10.0.aar +0 -0
- 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
- package/android/local/com/theoplayer/theoplayer-sdk-android/ads-wrapper/maven-metadata-local.xml +4 -4
- package/android/src/main/java/com/theoplayer/PlayerConfigAdapter.kt +4 -0
- package/android/src/main/java/com/theoplayer/ReactTHEOplayerContext.kt +7 -0
- package/android/src/main/java/com/theoplayer/ads/AdEventAdapter.kt +9 -4
- package/android/src/main/java/com/theoplayer/ads/AdsModule.kt +1 -1
- package/android/src/main/java/com/theoplayer/audio/AudioFocusManager.kt +57 -26
- package/android/src/main/java/com/theoplayer/broadcast/EventBroadcastModule.kt +1 -1
- package/android/src/main/java/com/theoplayer/cache/CacheModule.kt +1 -1
- package/android/src/main/java/com/theoplayer/cast/CastModule.kt +1 -1
- package/android/src/main/java/com/theoplayer/drm/ContentProtectionModule.kt +1 -1
- package/android/src/main/java/com/theoplayer/media/MediaPlaybackService.kt +8 -17
- package/android/src/main/java/com/theoplayer/player/PlayerModule.kt +1 -1
- package/ios/THEOplayerRCTBridge.m +6 -6
- package/ios/THEOplayerRCTPlayerAPI.swift +25 -25
- package/ios/ads/THEOplayerRCTAdsAPI.swift +17 -17
- package/ios/backgroundAudio/THEOplayerRCTNowPlayingManager.swift +4 -0
- package/ios/cache/THEOplayerRCTCacheAPI.swift +29 -29
- package/ios/casting/THEOplayerRCTCastAPI.swift +9 -9
- package/ios/contentprotection/THEOplayerRCTContentProtectionAPI.swift +22 -22
- package/ios/eventBroadcasting/THEOplayerRCTEventBroadcastAPI.swift +5 -5
- package/lib/commonjs/api/config/PlayerConfiguration.js.map +1 -1
- package/lib/commonjs/internal/adapter/THEOplayerAdapter.js +19 -18
- package/lib/commonjs/internal/adapter/THEOplayerAdapter.js.map +1 -1
- package/lib/commonjs/internal/adapter/abr/AbrAdapter.js +2 -1
- package/lib/commonjs/internal/adapter/abr/AbrAdapter.js.map +1 -1
- package/lib/commonjs/internal/adapter/ads/THEOplayerNativeAdsAdapter.js +7 -6
- package/lib/commonjs/internal/adapter/ads/THEOplayerNativeAdsAdapter.js.map +1 -1
- package/lib/commonjs/internal/adapter/ads/THEOplayerNativeGoogleDAI.js +5 -4
- package/lib/commonjs/internal/adapter/ads/THEOplayerNativeGoogleDAI.js.map +1 -1
- package/lib/commonjs/internal/adapter/broadcast/EventBroadcastAdapter.js +2 -1
- package/lib/commonjs/internal/adapter/broadcast/EventBroadcastAdapter.js.map +1 -1
- package/lib/commonjs/internal/adapter/cast/THEOplayerNativeAirplay.js +5 -4
- package/lib/commonjs/internal/adapter/cast/THEOplayerNativeAirplay.js.map +1 -1
- package/lib/commonjs/internal/adapter/cast/THEOplayerNativeChromecast.js +7 -6
- package/lib/commonjs/internal/adapter/cast/THEOplayerNativeChromecast.js.map +1 -1
- package/lib/commonjs/internal/adapter/track/TextTrackStyleAdapter.js +11 -10
- package/lib/commonjs/internal/adapter/track/TextTrackStyleAdapter.js.map +1 -1
- package/lib/commonjs/internal/cache/MediaCache.js +4 -3
- package/lib/commonjs/internal/cache/MediaCache.js.map +1 -1
- package/lib/commonjs/internal/cache/NativeCachingTaskAdapter.js +5 -4
- package/lib/commonjs/internal/cache/NativeCachingTaskAdapter.js.map +1 -1
- package/lib/commonjs/internal/drm/ContentProtectionRegistry.js +23 -22
- package/lib/commonjs/internal/drm/ContentProtectionRegistry.js.map +1 -1
- package/lib/module/api/config/PlayerConfiguration.js.map +1 -1
- package/lib/module/internal/adapter/THEOplayerAdapter.js +19 -18
- package/lib/module/internal/adapter/THEOplayerAdapter.js.map +1 -1
- package/lib/module/internal/adapter/abr/AbrAdapter.js +2 -1
- package/lib/module/internal/adapter/abr/AbrAdapter.js.map +1 -1
- package/lib/module/internal/adapter/ads/THEOplayerNativeAdsAdapter.js +7 -6
- package/lib/module/internal/adapter/ads/THEOplayerNativeAdsAdapter.js.map +1 -1
- package/lib/module/internal/adapter/ads/THEOplayerNativeGoogleDAI.js +5 -4
- package/lib/module/internal/adapter/ads/THEOplayerNativeGoogleDAI.js.map +1 -1
- package/lib/module/internal/adapter/broadcast/EventBroadcastAdapter.js +2 -1
- package/lib/module/internal/adapter/broadcast/EventBroadcastAdapter.js.map +1 -1
- package/lib/module/internal/adapter/cast/THEOplayerNativeAirplay.js +5 -4
- package/lib/module/internal/adapter/cast/THEOplayerNativeAirplay.js.map +1 -1
- package/lib/module/internal/adapter/cast/THEOplayerNativeChromecast.js +7 -6
- package/lib/module/internal/adapter/cast/THEOplayerNativeChromecast.js.map +1 -1
- package/lib/module/internal/adapter/track/TextTrackStyleAdapter.js +11 -10
- package/lib/module/internal/adapter/track/TextTrackStyleAdapter.js.map +1 -1
- package/lib/module/internal/cache/MediaCache.js +4 -3
- package/lib/module/internal/cache/MediaCache.js.map +1 -1
- package/lib/module/internal/cache/NativeCachingTaskAdapter.js +5 -4
- package/lib/module/internal/cache/NativeCachingTaskAdapter.js.map +1 -1
- package/lib/module/internal/drm/ContentProtectionRegistry.js +23 -22
- package/lib/module/internal/drm/ContentProtectionRegistry.js.map +1 -1
- package/lib/typescript/api/config/PlayerConfiguration.d.ts +10 -0
- package/package.json +1 -1
- package/react-native-theoplayer.podspec +11 -6
- package/src/api/config/PlayerConfiguration.ts +11 -0
- package/src/internal/adapter/THEOplayerAdapter.ts +20 -18
- package/src/internal/adapter/abr/AbrAdapter.ts +3 -1
- package/src/internal/adapter/ads/THEOplayerNativeAdsAdapter.ts +8 -6
- package/src/internal/adapter/ads/THEOplayerNativeGoogleDAI.ts +6 -4
- package/src/internal/adapter/broadcast/EventBroadcastAdapter.ts +3 -1
- package/src/internal/adapter/cast/THEOplayerNativeAirplay.ts +6 -4
- package/src/internal/adapter/cast/THEOplayerNativeChromecast.ts +8 -6
- package/src/internal/adapter/track/TextTrackStyleAdapter.ts +11 -10
- package/src/internal/cache/MediaCache.ts +5 -3
- package/src/internal/cache/NativeCachingTaskAdapter.ts +6 -4
- package/src/internal/drm/ContentProtectionRegistry.ts +24 -22
- 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
|
|
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
|
|
package/android/build.gradle
CHANGED
|
@@ -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:
|
|
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)})")
|
|
Binary file
|
package/android/local/com/theoplayer/theoplayer-sdk-android/ads-wrapper/maven-metadata-local.xml
CHANGED
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
<groupId>com.theoplayer.theoplayer-sdk-android</groupId>
|
|
4
4
|
<artifactId>ads-wrapper</artifactId>
|
|
5
5
|
<versioning>
|
|
6
|
-
<latest>
|
|
7
|
-
<release>
|
|
6
|
+
<latest>6.10.0</latest>
|
|
7
|
+
<release>6.10.0</release>
|
|
8
8
|
<versions>
|
|
9
|
-
<version>
|
|
9
|
+
<version>6.10.0</version>
|
|
10
10
|
</versions>
|
|
11
|
-
<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.
|
|
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 = "
|
|
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
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
.
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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
|
|
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
|
|
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 = "
|
|
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 = "
|
|
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 "
|
|
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 = "
|
|
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
|
-
|
|
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
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
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
|
-
|
|
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 = "
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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)
|