react-native-theoplayer 2.11.0 → 2.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/README.md +1 -0
- package/android/src/main/java/com/theoplayer/ReactTHEOplayerContext.kt +14 -0
- package/android/src/main/java/com/theoplayer/ReactTHEOplayerView.kt +1 -3
- package/android/src/main/java/com/theoplayer/audio/AudioFocusManager.kt +145 -0
- package/android/src/main/java/com/theoplayer/drm/ContentProtectionModule.kt +1 -1
- package/ios/THEOplayerRCTPlayerAPI.swift +14 -2
- package/ios/THEOplayerRCTSourceDescriptionBuilder.swift +2 -0
- package/ios/THEOplayerRCTTextTrackEventHandler.swift +32 -4
- package/ios/backgroundAudio/THEOplayerRCTRemoteCommandsManager.swift +51 -36
- package/lib/commonjs/api/source/SourceDescription.js.map +1 -1
- package/lib/commonjs/api/source/analytics/AnalyticsDescription.js +2 -0
- package/lib/commonjs/api/source/analytics/AnalyticsDescription.js.map +1 -0
- package/lib/commonjs/api/source/analytics/barrel.js +17 -0
- package/lib/commonjs/api/source/analytics/barrel.js.map +1 -0
- package/lib/commonjs/api/source/barrel.js +15 -4
- package/lib/commonjs/api/source/barrel.js.map +1 -1
- package/lib/commonjs/api/track/TextTrack.js +1 -1
- package/lib/commonjs/api/track/TextTrack.js.map +1 -1
- package/lib/commonjs/internal/adapter/THEOplayerWebAdapter.js.map +1 -1
- package/lib/module/api/source/SourceDescription.js.map +1 -1
- package/lib/module/api/source/analytics/AnalyticsDescription.js +2 -0
- package/lib/module/api/source/analytics/AnalyticsDescription.js.map +1 -0
- package/lib/module/api/source/analytics/barrel.js +2 -0
- package/lib/module/api/source/analytics/barrel.js.map +1 -0
- package/lib/module/api/source/barrel.js +1 -0
- package/lib/module/api/source/barrel.js.map +1 -1
- package/lib/module/api/track/TextTrack.js +1 -1
- package/lib/module/api/track/TextTrack.js.map +1 -1
- package/lib/module/internal/adapter/THEOplayerWebAdapter.js.map +1 -1
- package/lib/typescript/api/source/SourceDescription.d.ts +5 -0
- package/lib/typescript/api/source/analytics/AnalyticsDescription.d.ts +15 -0
- package/lib/typescript/api/source/analytics/barrel.d.ts +1 -0
- package/lib/typescript/api/source/barrel.d.ts +1 -0
- package/lib/typescript/api/track/TextTrack.d.ts +1 -1
- package/package.json +1 -1
- package/react-native-theoplayer.json +2 -1
- package/react-native-theoplayer.podspec +5 -1
- package/src/api/source/SourceDescription.ts +6 -0
- package/src/api/source/analytics/AnalyticsDescription.ts +16 -0
- package/src/api/source/analytics/barrel.ts +1 -0
- package/src/api/source/barrel.ts +1 -0
- package/src/api/track/TextTrack.ts +2 -2
- package/src/internal/adapter/THEOplayerWebAdapter.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,22 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.1.0/)
|
|
6
6
|
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [2.12.0] - 23-09-04
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Added an `AnalyticsDescription` property to `SourceDescription` to configure additional source-specific properties for analytics connectors.
|
|
13
|
+
- Added support for sideloaded webVTT and SRT texttracks on iOS.
|
|
14
|
+
- Added Audio Focus for Android, pausing play-out on audio focus loss and resuming play-out once focus has been regained.
|
|
15
|
+
- Added Audio Focus and Audio Becoming Noisy manager for Android.
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- Fixed an issue on Android that would cause the player not to reset when setting an empty source.
|
|
20
|
+
- Fixed an issue where a text track cue was not properly removed from the cue list on a TextTrackEventType.REMOVE_CUE event.
|
|
21
|
+
- Fixed an issue on tvOS that allowed the user to pause a CSAI ad using the apple remote control.
|
|
22
|
+
- Fixed an issue on iOS where the cue event listeners were not cleanup up when destroying the player instance, resulting in memory build-up.
|
|
23
|
+
|
|
8
24
|
## [2.11.0] - 23-08-10
|
|
9
25
|
|
|
10
26
|
### Added
|
package/README.md
CHANGED
|
@@ -83,6 +83,7 @@ and discussed in the next section. Finally, an overview of features, limitations
|
|
|
83
83
|
- Knowledge Base
|
|
84
84
|
- [Adaptive Bitrate (ABR)](./doc/abr.md)
|
|
85
85
|
- [Advertisements](./doc/ads.md)
|
|
86
|
+
- [Audio Control Management](./doc/audio-control.md)
|
|
86
87
|
- [Background playback and notifications](./doc/background.md)
|
|
87
88
|
- [Casting with Chromecast and Airplay](./doc/cast.md)
|
|
88
89
|
- [Custom iOS framework](./doc/custom-ios-framework.md)
|
|
@@ -27,6 +27,8 @@ import com.theoplayer.android.api.event.EventListener
|
|
|
27
27
|
import com.theoplayer.android.api.event.player.*
|
|
28
28
|
import com.theoplayer.android.api.player.Player
|
|
29
29
|
import com.theoplayer.android.connector.mediasession.MediaSessionConnector
|
|
30
|
+
import com.theoplayer.audio.AudioBecomingNoisyManager
|
|
31
|
+
import com.theoplayer.audio.AudioFocusManager
|
|
30
32
|
import com.theoplayer.audio.BackgroundAudioConfig
|
|
31
33
|
import com.theoplayer.media.MediaPlaybackService
|
|
32
34
|
import java.util.concurrent.atomic.AtomicBoolean
|
|
@@ -49,6 +51,11 @@ class ReactTHEOplayerContext private constructor(
|
|
|
49
51
|
private var isBound = AtomicBoolean()
|
|
50
52
|
private var binder: MediaPlaybackService.MediaPlaybackBinder? = null
|
|
51
53
|
private var mediaSessionConnector: MediaSessionConnector? = null
|
|
54
|
+
private var audioBecomingNoisyManager = AudioBecomingNoisyManager(reactContext) {
|
|
55
|
+
// Audio is about to become 'noisy' due to a change in audio outputs: pause the player
|
|
56
|
+
player.pause()
|
|
57
|
+
}
|
|
58
|
+
private var audioFocusManager: AudioFocusManager? = null
|
|
52
59
|
|
|
53
60
|
var backgroundAudioConfig: BackgroundAudioConfig = BackgroundAudioConfig(enabled = false)
|
|
54
61
|
set(value) {
|
|
@@ -207,6 +214,8 @@ class ReactTHEOplayerContext private constructor(
|
|
|
207
214
|
addIntegrations(playerConfig)
|
|
208
215
|
addListeners()
|
|
209
216
|
|
|
217
|
+
audioFocusManager = AudioFocusManager(reactContext, player)
|
|
218
|
+
|
|
210
219
|
if (!BuildConfig.USE_PLAYBACK_SERVICE || !isBackgroundAudioEnabled) {
|
|
211
220
|
initDefaultMediaSession()
|
|
212
221
|
}
|
|
@@ -282,11 +291,14 @@ class ReactTHEOplayerContext private constructor(
|
|
|
282
291
|
}
|
|
283
292
|
binder?.updateNotification(PlaybackStateCompat.STATE_PLAYING)
|
|
284
293
|
applyAllowedMediaControls()
|
|
294
|
+
audioBecomingNoisyManager.setEnabled(true)
|
|
295
|
+
audioFocusManager?.retrieveAudioFocus()
|
|
285
296
|
}
|
|
286
297
|
|
|
287
298
|
private val onPause = EventListener<PauseEvent> {
|
|
288
299
|
binder?.updateNotification(PlaybackStateCompat.STATE_PAUSED)
|
|
289
300
|
applyAllowedMediaControls()
|
|
301
|
+
audioBecomingNoisyManager.setEnabled(false)
|
|
290
302
|
}
|
|
291
303
|
|
|
292
304
|
private fun addListeners() {
|
|
@@ -334,6 +346,7 @@ class ReactTHEOplayerContext private constructor(
|
|
|
334
346
|
fun onHostResume() {
|
|
335
347
|
mediaSessionConnector?.setActive(true)
|
|
336
348
|
playerView.onResume()
|
|
349
|
+
audioFocusManager?.retrieveAudioFocus()
|
|
337
350
|
}
|
|
338
351
|
|
|
339
352
|
fun destroy() {
|
|
@@ -346,6 +359,7 @@ class ReactTHEOplayerContext private constructor(
|
|
|
346
359
|
// Unbind client from background service so it can stop
|
|
347
360
|
unbindMediaPlaybackService()
|
|
348
361
|
}
|
|
362
|
+
audioFocusManager?.abandonAudioFocus()
|
|
349
363
|
mediaSessionConnector?.destroy()
|
|
350
364
|
playerView.onDestroy()
|
|
351
365
|
}
|
|
@@ -130,9 +130,7 @@ class ReactTHEOplayerView(private val reactContext: ThemedReactContext) :
|
|
|
130
130
|
try {
|
|
131
131
|
val sourceDescription = SourceAdapter().parseSourceFromJS(source)
|
|
132
132
|
adsApi.setSource(sourceDescription)
|
|
133
|
-
|
|
134
|
-
player?.source = sourceDescription
|
|
135
|
-
}
|
|
133
|
+
player?.source = sourceDescription
|
|
136
134
|
} catch (exception: THEOplayerException) {
|
|
137
135
|
Log.e(TAG, exception.message ?: "")
|
|
138
136
|
eventEmitter.emitError(exception)
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
package com.theoplayer.audio
|
|
2
|
+
|
|
3
|
+
import android.app.UiModeManager
|
|
4
|
+
import android.content.Context
|
|
5
|
+
import android.content.res.Configuration
|
|
6
|
+
import android.media.AudioManager
|
|
7
|
+
import android.util.Log
|
|
8
|
+
import androidx.media.AudioAttributesCompat
|
|
9
|
+
import androidx.media.AudioFocusRequestCompat
|
|
10
|
+
import androidx.media.AudioManagerCompat
|
|
11
|
+
import com.theoplayer.BuildConfig
|
|
12
|
+
import com.theoplayer.android.api.player.Player
|
|
13
|
+
|
|
14
|
+
private const val TAG = "AudioFocusManager"
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Manages audio focus for the application, ensuring proper handling of audio focus changes
|
|
18
|
+
* to control media playback behavior.
|
|
19
|
+
*
|
|
20
|
+
* @param context The context used to access system services.
|
|
21
|
+
* @param player The media player instance associated with this audio focus manager. It can be
|
|
22
|
+
* provided optionally to control playback behavior.
|
|
23
|
+
*/
|
|
24
|
+
class AudioFocusManager(
|
|
25
|
+
context: Context,
|
|
26
|
+
private val player: Player? = null
|
|
27
|
+
) : AudioManager.OnAudioFocusChangeListener {
|
|
28
|
+
|
|
29
|
+
private val audioManager = context.getSystemService(Context.AUDIO_SERVICE) as? AudioManager
|
|
30
|
+
private val uiModeManager = context.getSystemService(Context.UI_MODE_SERVICE) as? UiModeManager
|
|
31
|
+
private var resumeOnFocusGain = false
|
|
32
|
+
private val focusLock = Any()
|
|
33
|
+
|
|
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()
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Called on the listener to notify it the audio focus for this listener has been changed.
|
|
50
|
+
*/
|
|
51
|
+
override fun onAudioFocusChange(focusChange: Int) {
|
|
52
|
+
if (uiModeManager?.currentModeType == Configuration.UI_MODE_TYPE_TELEVISION) {
|
|
53
|
+
// Ignore changes in audioFocus for Connected TVs.
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
if (BuildConfig.DEBUG) {
|
|
57
|
+
Log.d(TAG, "onAudioFocusChange: ${fromAudioFocusChange(focusChange)}")
|
|
58
|
+
}
|
|
59
|
+
when (focusChange) {
|
|
60
|
+
// Used to indicate a gain of audio focus, or a request of audio focus, of unknown duration.
|
|
61
|
+
AudioManager.AUDIOFOCUS_GAIN -> {
|
|
62
|
+
if (resumeOnFocusGain) {
|
|
63
|
+
synchronized(focusLock) {
|
|
64
|
+
// Reset resume flag
|
|
65
|
+
resumeOnFocusGain = false
|
|
66
|
+
}
|
|
67
|
+
player?.play()
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Used to indicate a loss of audio focus of unknown duration.
|
|
72
|
+
AudioManager.AUDIOFOCUS_LOSS -> {
|
|
73
|
+
synchronized (focusLock) {
|
|
74
|
+
// This is not a transient loss, we shouldn't automatically resume for now
|
|
75
|
+
resumeOnFocusGain = false;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
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) {
|
|
87
|
+
// We should only resume if playback was interrupted
|
|
88
|
+
resumeOnFocusGain = !(player?.isPaused ?: true)
|
|
89
|
+
}
|
|
90
|
+
player?.pause()
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
private fun fromAudioFocusChange(focusChange: Int?): String {
|
|
96
|
+
return when (focusChange) {
|
|
97
|
+
AudioManager.AUDIOFOCUS_GAIN -> "AUDIOFOCUS_GAIN"
|
|
98
|
+
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT -> "AUDIOFOCUS_GAIN_TRANSIENT"
|
|
99
|
+
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE -> "AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE"
|
|
100
|
+
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK -> "AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK"
|
|
101
|
+
AudioManager.AUDIOFOCUS_LOSS -> "AUDIOFOCUS_LOSS"
|
|
102
|
+
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> "AUDIOFOCUS_LOSS_TRANSIENT"
|
|
103
|
+
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> "AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK"
|
|
104
|
+
else -> "AUDIOFOCUS_NONE"
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
private fun fromAudioFocusRequest(focusRequest: Int?): String {
|
|
109
|
+
return when(focusRequest) {
|
|
110
|
+
AudioManager.AUDIOFOCUS_REQUEST_GRANTED -> "AUDIOFOCUS_REQUEST_GRANTED"
|
|
111
|
+
AudioManager.AUDIOFOCUS_REQUEST_DELAYED -> "AUDIOFOCUS_REQUEST_DELAYED"
|
|
112
|
+
else -> "AUDIOFOCUS_REQUEST_FAILED"
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Send a request to obtain the audio focus
|
|
118
|
+
*
|
|
119
|
+
* @return True if audio focus is granted, false otherwise.
|
|
120
|
+
*/
|
|
121
|
+
fun retrieveAudioFocus(): Boolean {
|
|
122
|
+
val result = audioManager?.let {
|
|
123
|
+
AudioManagerCompat.requestAudioFocus(it, audioFocusRequest)
|
|
124
|
+
}
|
|
125
|
+
if (BuildConfig.DEBUG) {
|
|
126
|
+
Log.d(TAG, "retrieveAudioFocus: ${fromAudioFocusRequest(result)}")
|
|
127
|
+
}
|
|
128
|
+
return result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
|
|
133
|
+
*/
|
|
134
|
+
fun abandonAudioFocus() {
|
|
135
|
+
synchronized (focusLock) {
|
|
136
|
+
resumeOnFocusGain = false
|
|
137
|
+
}
|
|
138
|
+
val result = audioManager?.let {
|
|
139
|
+
AudioManagerCompat.abandonAudioFocusRequest(it, audioFocusRequest)
|
|
140
|
+
}
|
|
141
|
+
if (BuildConfig.DEBUG) {
|
|
142
|
+
Log.d(TAG, "abandonAudioFocus: ${fromAudioFocusRequest(result)}")
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
@@ -111,7 +111,7 @@ class ContentProtectionModule(private val context: ReactApplicationContext) :
|
|
|
111
111
|
}
|
|
112
112
|
emit(
|
|
113
113
|
EVENT_BUILD_INTEGRATION, payload,
|
|
114
|
-
onResult = hashMapOf(),
|
|
114
|
+
onResult = hashMapOf(EVENT_BUILD_PROCESSED to { /*NoOp*/ }),
|
|
115
115
|
onError = {}
|
|
116
116
|
)
|
|
117
117
|
}
|
|
@@ -6,6 +6,10 @@ import Foundation
|
|
|
6
6
|
import UIKit
|
|
7
7
|
import THEOplayerSDK
|
|
8
8
|
|
|
9
|
+
#if canImport(THEOplayerConnectorSideloadedSubtitle)
|
|
10
|
+
import THEOplayerConnectorSideloadedSubtitle
|
|
11
|
+
#endif
|
|
12
|
+
|
|
9
13
|
let ERROR_MESSAGE_PLAYER_ABR_UNSUPPORTED_FEATURE: String = "Setting an ABRconfig is not supported on iOS/tvOS."
|
|
10
14
|
let ERROR_MESSAGE_PLAYER_QUALITY_UNSUPPORTED_FEATURE: String = "Setting a target video quality is not supported on iOS/tvOS."
|
|
11
15
|
let ERROR_MESSAGE_PLAYER_FULLSCREEN_UNSUPPORTED_FEATURE: String = "Fullscreen presentationmode should be implemented on the RN level for iOS/tvOS."
|
|
@@ -56,8 +60,7 @@ class THEOplayerRCTPlayerAPI: NSObject, RCTBridgeModule {
|
|
|
56
60
|
if let theView = self.bridge.uiManager.view(forReactTag: node) as? THEOplayerRCTView,
|
|
57
61
|
let srcDescription = THEOplayerRCTSourceDescriptionBuilder.buildSourceDescription(src) {
|
|
58
62
|
if let player = theView.player {
|
|
59
|
-
|
|
60
|
-
player.source = srcDescription
|
|
63
|
+
self.setNewSourceDescription(player: player, srcDescription: srcDescription)
|
|
61
64
|
}
|
|
62
65
|
} else {
|
|
63
66
|
if DEBUG_PLAYER_API { PrintUtils.printLog(logText: "[NATIVE] Failed to update THEOplayer source.") }
|
|
@@ -65,6 +68,15 @@ class THEOplayerRCTPlayerAPI: NSObject, RCTBridgeModule {
|
|
|
65
68
|
}
|
|
66
69
|
}
|
|
67
70
|
|
|
71
|
+
private func setNewSourceDescription(player: THEOplayer, srcDescription: SourceDescription) {
|
|
72
|
+
if DEBUG_PLAYER_API { PrintUtils.printLog(logText: "[NATIVE] Setting new source on TheoPlayer") }
|
|
73
|
+
#if canImport(THEOplayerConnectorSideloadedSubtitle)
|
|
74
|
+
player.setSourceWithSubtitles(source: srcDescription)
|
|
75
|
+
#else
|
|
76
|
+
player.source = srcDescription
|
|
77
|
+
#endif
|
|
78
|
+
}
|
|
79
|
+
|
|
68
80
|
@objc(setABRConfig:abrConfig:)
|
|
69
81
|
func setABRConfig(_ node: NSNumber, setABRConfig: NSDictionary) -> Void {
|
|
70
82
|
if DEBUG_PLAYER_API { print(ERROR_MESSAGE_PLAYER_ABR_UNSUPPORTED_FEATURE) }
|
|
@@ -375,6 +375,8 @@ class THEOplayerRCTSourceDescriptionBuilder {
|
|
|
375
375
|
|
|
376
376
|
if format == "webvtt" {
|
|
377
377
|
return THEOplayerSDK.TextTrackFormat.WebVTT
|
|
378
|
+
} else if format == "srt" {
|
|
379
|
+
return THEOplayerSDK.TextTrackFormat.SRT
|
|
378
380
|
} else {
|
|
379
381
|
return THEOplayerSDK.TextTrackFormat.none
|
|
380
382
|
}
|
|
@@ -79,16 +79,19 @@ class THEOplayerRCTTextTrackEventHandler {
|
|
|
79
79
|
"type" : TrackListEventType.REMOVE_TRACK.rawValue
|
|
80
80
|
])
|
|
81
81
|
// stop listening for cue events on this track
|
|
82
|
-
if let addCueListener = welf.addCueListeners
|
|
83
|
-
let removeCueListener = welf.removeCueListeners[textTrack.uid],
|
|
84
|
-
let enterCueListener = welf.enterCueListeners[textTrack.uid],
|
|
85
|
-
let exitCueListener = welf.exitCueListeners[textTrack.uid] {
|
|
82
|
+
if let addCueListener = welf.addCueListeners.removeValue(forKey: textTrack.uid) {
|
|
86
83
|
textTrack.removeEventListener(type: TextTrackEventTypes.ADD_CUE, listener: addCueListener)
|
|
87
84
|
if DEBUG_EVENTHANDLER { PrintUtils.printLog(logText: "[NATIVE] AddCue listener removed from THEOplayer textTrack with uid \(textTrack.uid)") }
|
|
85
|
+
}
|
|
86
|
+
if let removeCueListener = welf.removeCueListeners.removeValue(forKey: textTrack.uid) {
|
|
88
87
|
textTrack.removeEventListener(type: TextTrackEventTypes.REMOVE_CUE, listener: removeCueListener)
|
|
89
88
|
if DEBUG_EVENTHANDLER { PrintUtils.printLog(logText: "[NATIVE] RemoveCue listener removed from THEOplayer textTrack with uid \(textTrack.uid)") }
|
|
89
|
+
}
|
|
90
|
+
if let enterCueListener = welf.enterCueListeners.removeValue(forKey: textTrack.uid) {
|
|
90
91
|
textTrack.removeEventListener(type: TextTrackEventTypes.ENTER_CUE, listener: enterCueListener)
|
|
91
92
|
if DEBUG_EVENTHANDLER { PrintUtils.printLog(logText: "[NATIVE] EnterCue listener removed from THEOplayer textTrack with uid \(textTrack.uid)") }
|
|
93
|
+
}
|
|
94
|
+
if let exitCueListener = welf.exitCueListeners.removeValue(forKey: textTrack.uid) {
|
|
92
95
|
textTrack.removeEventListener(type: TextTrackEventTypes.EXIT_CUE, listener: exitCueListener)
|
|
93
96
|
if DEBUG_EVENTHANDLER { PrintUtils.printLog(logText: "[NATIVE] ExitCue listener removed from THEOplayer textTrack with uid \(textTrack.uid)") }
|
|
94
97
|
}
|
|
@@ -134,6 +137,31 @@ class THEOplayerRCTTextTrackEventHandler {
|
|
|
134
137
|
player.textTracks.removeEventListener(type: TextTrackListEventTypes.CHANGE, listener: changeTrackListener)
|
|
135
138
|
if DEBUG_EVENTHANDLER { PrintUtils.printLog(logText: "[NATIVE] ChangeTrack listener dettached from THEOplayer textTrack list") }
|
|
136
139
|
}
|
|
140
|
+
|
|
141
|
+
// ADD_CUE, REMOVE_CUE, ENTER_CUE, EXIT_CUE
|
|
142
|
+
let textTrackCount = player.textTracks.count
|
|
143
|
+
if textTrackCount > 0 {
|
|
144
|
+
for i in 0..<textTrackCount {
|
|
145
|
+
let textTrack = player.textTracks[i]
|
|
146
|
+
// stop listening for cue events on this track
|
|
147
|
+
if let addCueListener = self.addCueListeners.removeValue(forKey: textTrack.uid) {
|
|
148
|
+
textTrack.removeEventListener(type: TextTrackEventTypes.ADD_CUE, listener: addCueListener)
|
|
149
|
+
if DEBUG_EVENTHANDLER { PrintUtils.printLog(logText: "[NATIVE] AddCue listener removed from THEOplayer textTrack with uid \(textTrack.uid)") }
|
|
150
|
+
}
|
|
151
|
+
if let removeCueListener = self.removeCueListeners.removeValue(forKey: textTrack.uid) {
|
|
152
|
+
textTrack.removeEventListener(type: TextTrackEventTypes.REMOVE_CUE, listener: removeCueListener)
|
|
153
|
+
if DEBUG_EVENTHANDLER { PrintUtils.printLog(logText: "[NATIVE] RemoveCue listener removed from THEOplayer textTrack with uid \(textTrack.uid)") }
|
|
154
|
+
}
|
|
155
|
+
if let enterCueListener = self.enterCueListeners.removeValue(forKey: textTrack.uid) {
|
|
156
|
+
textTrack.removeEventListener(type: TextTrackEventTypes.ENTER_CUE, listener: enterCueListener)
|
|
157
|
+
if DEBUG_EVENTHANDLER { PrintUtils.printLog(logText: "[NATIVE] EnterCue listener removed from THEOplayer textTrack with uid \(textTrack.uid)") }
|
|
158
|
+
}
|
|
159
|
+
if let exitCueListener = self.exitCueListeners.removeValue(forKey: textTrack.uid) {
|
|
160
|
+
textTrack.removeEventListener(type: TextTrackEventTypes.EXIT_CUE, listener: exitCueListener)
|
|
161
|
+
if DEBUG_EVENTHANDLER { PrintUtils.printLog(logText: "[NATIVE] ExitCue listener removed from THEOplayer textTrack with uid \(textTrack.uid)") }
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
137
165
|
}
|
|
138
166
|
|
|
139
167
|
// MARK: - dynamic textTrack Listeners
|
|
@@ -72,100 +72,113 @@ class THEOplayerRCTRemoteCommandsManager: NSObject {
|
|
|
72
72
|
|
|
73
73
|
func updateRemoteCommands() {
|
|
74
74
|
let commandCenter = MPRemoteCommandCenter.shared()
|
|
75
|
+
|
|
76
|
+
// update the enabled state to have correct visual representation in the lockscreen
|
|
75
77
|
commandCenter.playCommand.isEnabled = !self.inAd && self.backgroundaudioConfig.enabled
|
|
76
78
|
commandCenter.pauseCommand.isEnabled = !self.inAd && self.backgroundaudioConfig.enabled
|
|
77
79
|
commandCenter.togglePlayPauseCommand.isEnabled = !self.inAd && self.backgroundaudioConfig.enabled
|
|
78
80
|
commandCenter.stopCommand.isEnabled = !self.inAd && self.backgroundaudioConfig.enabled
|
|
79
|
-
commandCenter.changePlaybackPositionCommand.isEnabled = !isLive && !self.inAd && self.backgroundaudioConfig.enabled
|
|
80
|
-
commandCenter.skipForwardCommand.isEnabled = !isLive && !self.inAd && self.backgroundaudioConfig.enabled
|
|
81
|
-
commandCenter.skipBackwardCommand.isEnabled = !isLive && !self.inAd && self.backgroundaudioConfig.enabled
|
|
81
|
+
commandCenter.changePlaybackPositionCommand.isEnabled = !self.isLive && !self.inAd && self.backgroundaudioConfig.enabled
|
|
82
|
+
commandCenter.skipForwardCommand.isEnabled = !self.isLive && !self.inAd && self.backgroundaudioConfig.enabled
|
|
83
|
+
commandCenter.skipBackwardCommand.isEnabled = !self.isLive && !self.inAd && self.backgroundaudioConfig.enabled
|
|
84
|
+
|
|
82
85
|
if DEBUG_REMOTECOMMANDS { PrintUtils.printLog(logText: "[NATIVE] Remote commands updated for \(self.isLive ? "LIVE" : "VOD") (\(self.inAd ? "AD IS PLAYING" : "NO AD PLAYING"), \(self.backgroundaudioConfig.enabled ? "BGAUDIO ENABLED" : "BGAUDIO DISABLED") ).") }
|
|
83
86
|
}
|
|
84
87
|
|
|
85
88
|
@objc private func onPlayCommand(_ event: MPRemoteCommandEvent) -> MPRemoteCommandHandlerStatus {
|
|
86
89
|
if let player = self.player,
|
|
90
|
+
!self.inAd,
|
|
87
91
|
player.paused {
|
|
88
92
|
player.play()
|
|
89
|
-
if DEBUG_REMOTECOMMANDS { PrintUtils.printLog(logText: "[NATIVE] Play command
|
|
90
|
-
|
|
93
|
+
if DEBUG_REMOTECOMMANDS { PrintUtils.printLog(logText: "[NATIVE] Play command handled.") }
|
|
94
|
+
} else {
|
|
95
|
+
if DEBUG_REMOTECOMMANDS { PrintUtils.printLog(logText: "[NATIVE] Play command not handled.") }
|
|
91
96
|
}
|
|
92
|
-
|
|
93
|
-
return .commandFailed
|
|
97
|
+
return .success
|
|
94
98
|
}
|
|
95
99
|
|
|
96
100
|
@objc private func onPauseCommand(_ event: MPRemoteCommandEvent) -> MPRemoteCommandHandlerStatus {
|
|
97
101
|
if let player = self.player,
|
|
102
|
+
!self.inAd,
|
|
98
103
|
!player.paused {
|
|
99
104
|
player.pause()
|
|
100
|
-
if DEBUG_REMOTECOMMANDS { PrintUtils.printLog(logText: "[NATIVE] Pause command
|
|
101
|
-
|
|
105
|
+
if DEBUG_REMOTECOMMANDS { PrintUtils.printLog(logText: "[NATIVE] Pause command handled.") }
|
|
106
|
+
} else {
|
|
107
|
+
if DEBUG_REMOTECOMMANDS { PrintUtils.printLog(logText: "[NATIVE] Pause command not handled.") }
|
|
102
108
|
}
|
|
103
|
-
|
|
104
|
-
return .commandFailed
|
|
109
|
+
return .success
|
|
105
110
|
}
|
|
106
111
|
|
|
107
112
|
@objc private func onTogglePlayPauseCommand(_ event: MPRemoteCommandEvent) -> MPRemoteCommandHandlerStatus {
|
|
108
|
-
if let player = self.player
|
|
113
|
+
if let player = self.player,
|
|
114
|
+
!self.inAd {
|
|
109
115
|
if player.paused {
|
|
110
116
|
player.play()
|
|
111
117
|
} else {
|
|
112
118
|
player.pause()
|
|
113
119
|
}
|
|
114
|
-
if DEBUG_REMOTECOMMANDS { PrintUtils.printLog(logText: "[NATIVE] Toggle play/pause command
|
|
115
|
-
|
|
120
|
+
if DEBUG_REMOTECOMMANDS { PrintUtils.printLog(logText: "[NATIVE] Toggle play/pause command handled.") }
|
|
121
|
+
} else {
|
|
122
|
+
if DEBUG_REMOTECOMMANDS { PrintUtils.printLog(logText: "[NATIVE] Toggle play/pause command not handled.") }
|
|
116
123
|
}
|
|
117
|
-
|
|
118
|
-
return .commandFailed
|
|
124
|
+
return .success
|
|
119
125
|
}
|
|
120
126
|
|
|
121
127
|
@objc private func onStopCommand(_ event: MPRemoteCommandEvent) -> MPRemoteCommandHandlerStatus {
|
|
122
|
-
if let player = self.player
|
|
128
|
+
if let player = self.player,
|
|
129
|
+
!self.inAd {
|
|
123
130
|
if !player.paused {
|
|
124
131
|
player.pause()
|
|
125
132
|
}
|
|
126
|
-
if DEBUG_REMOTECOMMANDS { PrintUtils.printLog(logText: "[NATIVE] Stop command
|
|
127
|
-
|
|
133
|
+
if DEBUG_REMOTECOMMANDS { PrintUtils.printLog(logText: "[NATIVE] Stop command handled.") }
|
|
134
|
+
} else {
|
|
135
|
+
if DEBUG_REMOTECOMMANDS { PrintUtils.printLog(logText: "[NATIVE] Stop command not handled.") }
|
|
128
136
|
}
|
|
129
|
-
|
|
130
|
-
return .commandFailed
|
|
137
|
+
return .success
|
|
131
138
|
}
|
|
132
139
|
|
|
133
140
|
@objc private func onScrubCommand(_ event: MPChangePlaybackPositionCommandEvent) -> MPRemoteCommandHandlerStatus {
|
|
134
|
-
if let player = self.player
|
|
141
|
+
if let player = self.player,
|
|
142
|
+
!self.isLive,
|
|
143
|
+
!self.inAd {
|
|
135
144
|
player.setCurrentTime(event.positionTime)
|
|
136
|
-
if DEBUG_REMOTECOMMANDS { PrintUtils.printLog(logText: "[NATIVE] Scrub command
|
|
137
|
-
|
|
145
|
+
if DEBUG_REMOTECOMMANDS { PrintUtils.printLog(logText: "[NATIVE] Scrub command handled.") }
|
|
146
|
+
} else {
|
|
147
|
+
if DEBUG_REMOTECOMMANDS { PrintUtils.printLog(logText: "[NATIVE] Scrub command not handled.") }
|
|
138
148
|
}
|
|
139
|
-
|
|
140
|
-
return .commandFailed
|
|
149
|
+
return .success
|
|
141
150
|
}
|
|
142
151
|
|
|
143
152
|
@objc private func onSkipForwardCommand(_ event: MPSkipIntervalCommandEvent) -> MPRemoteCommandHandlerStatus {
|
|
144
|
-
if let player = self.player
|
|
153
|
+
if let player = self.player,
|
|
154
|
+
!self.isLive,
|
|
155
|
+
!self.inAd {
|
|
145
156
|
player.requestCurrentTime(completionHandler: { time, error in
|
|
146
157
|
if let currentTime = time {
|
|
147
158
|
player.setCurrentTime(currentTime + event.interval)
|
|
148
159
|
}
|
|
149
160
|
})
|
|
150
|
-
if DEBUG_REMOTECOMMANDS { PrintUtils.printLog(logText: "[NATIVE] Skip forward command
|
|
151
|
-
|
|
161
|
+
if DEBUG_REMOTECOMMANDS { PrintUtils.printLog(logText: "[NATIVE] Skip forward command handled.") }
|
|
162
|
+
} else {
|
|
163
|
+
if DEBUG_REMOTECOMMANDS { PrintUtils.printLog(logText: "[NATIVE] Skip forward command not handled.") }
|
|
152
164
|
}
|
|
153
|
-
|
|
154
|
-
return .commandFailed
|
|
165
|
+
return .success
|
|
155
166
|
}
|
|
156
167
|
|
|
157
168
|
@objc private func onSkipBackwardCommand(_ event: MPSkipIntervalCommandEvent) -> MPRemoteCommandHandlerStatus {
|
|
158
|
-
if let player = self.player
|
|
169
|
+
if let player = self.player ,
|
|
170
|
+
!self.isLive,
|
|
171
|
+
!self.inAd {
|
|
159
172
|
player.requestCurrentTime(completionHandler: { time, error in
|
|
160
173
|
if let currentTime = time {
|
|
161
174
|
player.setCurrentTime(currentTime - event.interval)
|
|
162
175
|
}
|
|
163
176
|
})
|
|
164
|
-
if DEBUG_REMOTECOMMANDS { PrintUtils.printLog(logText: "[NATIVE] Skip backward command
|
|
165
|
-
|
|
177
|
+
if DEBUG_REMOTECOMMANDS { PrintUtils.printLog(logText: "[NATIVE] Skip backward command handled.") }
|
|
178
|
+
} else {
|
|
179
|
+
if DEBUG_REMOTECOMMANDS { PrintUtils.printLog(logText: "[NATIVE] Skip backward command not handled.") }
|
|
166
180
|
}
|
|
167
|
-
|
|
168
|
-
return .commandFailed
|
|
181
|
+
return .success
|
|
169
182
|
}
|
|
170
183
|
|
|
171
184
|
private func attachListeners() {
|
|
@@ -193,11 +206,13 @@ class THEOplayerRCTRemoteCommandsManager: NSObject {
|
|
|
193
206
|
// ADBREAK_BEGIN
|
|
194
207
|
self.adBreakBeginListener = player.ads.addEventListener(type: AdsEventTypes.AD_BREAK_BEGIN) { [weak self] event in
|
|
195
208
|
self?.inAd = true
|
|
209
|
+
self?.updateRemoteCommands()
|
|
196
210
|
}
|
|
197
211
|
|
|
198
212
|
// ADBREAK_END
|
|
199
213
|
self.adBreakEndListener = player.ads.addEventListener(type: AdsEventTypes.AD_BREAK_END) { [weak self] event in
|
|
200
214
|
self?.inAd = false
|
|
215
|
+
self?.updateRemoteCommands()
|
|
201
216
|
}
|
|
202
217
|
|
|
203
218
|
#endif
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["SourceDescription.ts"],"sourcesContent":["/**\n * Represents a media resource.\n *\n * @remarks\n * <br/> - Can be a string value representing the URL of a media resource, a {@link TypedSource}.\n *\n * @public\n */\nimport type { DashPlaybackConfiguration } from './dash/DashPlaybackConfiguration';\nimport type { DRMConfiguration } from './drm/DRMConfiguration';\nimport type { HlsPlaybackConfiguration } from './hls/HlsPlaybackConfiguration';\nimport type { AdDescription } from './ads/Ads';\nimport type { MetadataDescription } from './metadata/MetadataDescription';\nimport type { ServerSideAdInsertionConfiguration } from \"./ads/ssai/ServerSideAdInsertionConfiguration\";\n\nexport type Source = TypedSource;\n\n/**\n * A media resource or list of media resources.\n *\n * @remarks\n * <br/> - The order of sources when using a list determines their priority when attempting playback.\n *\n * @public\n */\nexport type Sources = Source | Source[];\n\n/**\n * The cross-origin setting of a source, represented by a value from the following list:\n * <br/> - `'anonymous'`: CORS requests will have the credentials flag set to 'same-origin'.\n * <br/> - `'use-credentials'`: CORS requests will have the credentials flag set to 'include'.\n * <br/> - `''`: Setting the empty string is the same as `'anonymous'`\n *\n * @remarks\n * <br/> - See {@link https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes | The crossorigin attribute: Requesting CORS access to content}\n *\n * @public\n */\nexport type CrossOriginSetting = '' | 'anonymous' | 'use-credentials';\n\n/**\n * Describes the configuration of a player's source.\n *\n * @public\n */\nexport interface SourceConfiguration {\n /**\n * List of {@link AdDescription}s to be queued for playback.\n */\n ads?: AdDescription[];\n\n /**\n * Content protection configuration.\n */\n contentProtection?: DRMConfiguration;\n\n /**\n * The poster of the media source.\n *\n * @remarks\n * <br/> - An empty string (`''`) clears the current poster.\n * <br/> - This poster has priority over {@link ChromelessPlayer.poster}.\n */\n poster?: string;\n\n /**\n * List of text tracks to be side-loaded with the media source.\n *\n * @remarks\n * <br/> - A source change will reset side-loaded text tracks.\n */\n textTracks?: TextTrackDescription[];\n\n /**\n * The URL of a time server used by the player to synchronise the time in DASH sources.\n *\n * @remarks\n * <br/> - The time server should return time in ISO-8601 format.\n * <br/> - Overrides the time server provided the DASH manifest's `<UTCTiming>`.\n * <br/> - All sources will use the time server. Alternatively, for one source use {@link BaseSource.timeServer}.\n */\n timeServer?: string;\n\n /**\n * Describes the metadata of a source.\n *\n * @public\n */\n metadata?: MetadataDescription;\n}\n\n/**\n * Describes the configuration of a player's source.\n *\n * @public\n */\nexport interface SourceDescription extends SourceConfiguration {\n /**\n * One or more media resources for playback.\n *\n * @remarks\n * <br/> - Multiple media sources should be used to increase platform compatibility. See examples below for important use cases.\n * <br/> - The player will try each source in the provided order.\n *\n * @example\n * In this example, the player will first try to play the DASH source.\n * This might fail if the browser does not support the {@link https://www.widevine.com/ | Widevine} or {@link https://www.microsoft.com/playready/ | PlayReady} CDM, for example on Safari.\n * In that case, the player will try to play the HLS source instead.\n *\n * ```\n * [{\n * src: 'dash-source-with-drm.mpd'\n * contentProtection: {\n * widevine: {\n * licenseAcquisitionURL: 'https://license.company.com/wv'\n * },\n * playready: {\n * licenseAcquisitionURL: 'https://license.company.com/pr'\n * }\n * }\n * },{\n * src: 'hls-source-with-drm.m3u8',\n * contentProtection: {\n * fairplay: {\n * certificateURL: 'https://license.company.com/fp'\n * }\n * }\n * }]\n * ```\n *\n * @example\n * In this example, the player will first try to play the DASH source.\n * This might fail if the browser does not support the {@link https://developer.mozilla.org/en-US/docs/Web/API/Media_Source_Extensions_API | Media Source Extensions API}.\n * In that case, the player will try to play the MP4 source instead, though without features such as adaptive bitrate switching.\n *\n * ```\n * [{\n * src: 'source.mpd'\n * },{\n * src: 'source.mp4'\n * }]\n * ```\n */\n sources?: Sources;\n}\n\n/**\n * Describes the configuration of a side-loaded text track.\n *\n * @public\n */\nexport interface TextTrackDescription {\n /**\n * Whether the text track should be enabled by default.\n *\n * @remarks\n * <br/> - Only one text track per {@link TextTrack.kind} may be marked as default.\n *\n * @defaultValue `false`\n */\n default?: boolean;\n\n /**\n * The kind of the text track, represented by a value from the following list:\n * <br/> - `'subtitles'`: The track provides subtitles, used to display subtitles in a video.\n * <br/> - `'captions'`: The track provides a translation of dialogue and sound effects (suitable for users with a hearing impairment).\n * <br/> - `'descriptions'`: The track provides a textual description of the video (suitable for users with a vision impairment).\n * <br/> - `'chapters'`: The track provides chapter titles (suitable for navigating the media resource).\n * <br/> - `'metadata'`: The track provides content used by scripts and is not visible for users.\n *\n * @remarks\n * <br/> - If an unrecognized value is provided, the player will interpret it as `'metadata'`.\n *\n * @defaultValue `'subtitles'`\n */\n kind?: string;\n\n /**\n * The format of the track, represented by a value from the following list:\n * <br/> - `'srt'`\n * <br/> - `'ttml'`\n * <br/> - `'webvtt'`\n * <br/> - `'emsg'`\n * <br/> - `'eventstream'`\n * <br/> - `'id3'`\n * <br/> - `'cea608'`\n * <br/> - `'daterange'`\n *\n * @defaultValue `''`\n */\n format?: string;\n\n /**\n * The source URL of the text track.\n */\n src: string;\n\n /**\n * The language of the text track.\n */\n srclang?: string;\n\n /**\n * A label for the text track.\n *\n * @remarks\n * <br/> - This will be used as an identifier on the player API and in the UI.\n */\n label?: string;\n\n /**\n * The identifier of this text track.\n *\n * @internal\n */\n // Note: This works for HLS, but not for DASH.\n id?: string;\n}\n\n/**\n * Represents the common properties of a media resource.\n *\n * @public\n */\nexport interface BaseSource {\n\n /**\n * The cross-origin setting of the source.\n *\n * @defaultValue `''`\n */\n crossOrigin?: CrossOriginSetting;\n\n /**\n * The URL of a time server used by the player to synchronise the time in DASH sources.\n *\n * @remarks\n * <br/> - Available since v2.47.0.\n * <br/> - The time server should return time in ISO-8601 format.\n * <br/> - Overrides the time server provided the DASH manifest's `<UTCTiming>`.\n * <br/> - Only this source will use the time server. Alternatively, for all source use {@link SourceConfiguration.timeServer}.\n */\n timeServer?: string;\n\n /**\n * Whether the source should be played in the low-latency-mode of the player.\n *\n * @defaultValue `false`\n *\n * @remarks\n * <br/> - This setting must be `true` when using Low-Latency CMAF with ABR.\n * <br/> - Available since v2.62.0.\n */\n lowLatency?: boolean;\n\n /**\n * The configuration for controlling playback of an MPEG-DASH stream.\n *\n * @remarks\n * <br/> - Available since v2.79.0.\n * <br/> - Ignored for non-DASH streams.\n */\n dash?: DashPlaybackConfiguration;\n\n /**\n * The configuration for controlling playback of an HLS stream.\n *\n * @remarks\n * <br/> - Available since v2.82.0.\n * <br/> - Ignored for non-HLS streams.\n */\n hls?: HlsPlaybackConfiguration;\n}\n\n/**\n * Represents a media resource characterized by a URL to the resource and optionally information about the resource.\n *\n * @public\n */\nexport interface TypedSource extends BaseSource {\n /**\n * The source URL of the media resource.\n *\n * @remarks\n * <br/> - Required if the `ssai` property is absent.\n * <br/> - Available since v2.4.0.\n */\n src?: string;\n\n /**\n * The content type (MIME type) of the media resource, represented by a value from the following list:\n * <br/> - `'application/dash+xml'`: The media resource is an MPEG-DASH stream.\n * <br/> - `'application/x-mpegURL'` or `'application/vnd.apple.mpegurl'`: The media resource is an HLS stream.\n * <br/> - `'video/mp4'`, `'video/webm'` and other formats: The media resource should use native HTML5 playback if supported by the browser.\n * <br/> - `'application/vnd.theo.hesp+json'`: The media resource is an HESP stream.\n *\n * @remarks\n * <br/> - Available since v2.4.0.\n */\n type?: string;\n\n /**\n * The content protection parameters for the media resource.\n *\n * @remarks\n * <br/> - Available since v2.15.0.\n */\n contentProtection?: DRMConfiguration;\n\n /**\n * The Server-side Ad Insertion parameters for the media resource.\n *\n * @remarks\n * <br/> - Available since v2.12.0.\n */\n ssai?: ServerSideAdInsertionConfiguration;\n}\n"],"mappings":""}
|
|
1
|
+
{"version":3,"names":[],"sources":["SourceDescription.ts"],"sourcesContent":["/**\n * Represents a media resource.\n *\n * @remarks\n * <br/> - Can be a string value representing the URL of a media resource, a {@link TypedSource}.\n *\n * @public\n */\nimport type { DashPlaybackConfiguration } from './dash/DashPlaybackConfiguration';\nimport type { DRMConfiguration } from './drm/DRMConfiguration';\nimport type { HlsPlaybackConfiguration } from './hls/HlsPlaybackConfiguration';\nimport type { AdDescription } from './ads/Ads';\nimport type { MetadataDescription } from './metadata/MetadataDescription';\nimport type { ServerSideAdInsertionConfiguration } from \"./ads/ssai/ServerSideAdInsertionConfiguration\";\nimport type { AnalyticsDescription } from \"./analytics/AnalyticsDescription\";\n\nexport type Source = TypedSource;\n\n/**\n * A media resource or list of media resources.\n *\n * @remarks\n * <br/> - The order of sources when using a list determines their priority when attempting playback.\n *\n * @public\n */\nexport type Sources = Source | Source[];\n\n/**\n * The cross-origin setting of a source, represented by a value from the following list:\n * <br/> - `'anonymous'`: CORS requests will have the credentials flag set to 'same-origin'.\n * <br/> - `'use-credentials'`: CORS requests will have the credentials flag set to 'include'.\n * <br/> - `''`: Setting the empty string is the same as `'anonymous'`\n *\n * @remarks\n * <br/> - See {@link https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes | The crossorigin attribute: Requesting CORS access to content}\n *\n * @public\n */\nexport type CrossOriginSetting = '' | 'anonymous' | 'use-credentials';\n\n/**\n * Describes the configuration of a player's source.\n *\n * @public\n */\nexport interface SourceConfiguration {\n /**\n * List of {@link AdDescription}s to be queued for playback.\n */\n ads?: AdDescription[];\n\n /**\n * Content protection configuration.\n */\n contentProtection?: DRMConfiguration;\n\n /**\n * The poster of the media source.\n *\n * @remarks\n * <br/> - An empty string (`''`) clears the current poster.\n * <br/> - This poster has priority over {@link ChromelessPlayer.poster}.\n */\n poster?: string;\n\n /**\n * List of text tracks to be side-loaded with the media source.\n *\n * @remarks\n * <br/> - A source change will reset side-loaded text tracks.\n */\n textTracks?: TextTrackDescription[];\n\n /**\n * The URL of a time server used by the player to synchronise the time in DASH sources.\n *\n * @remarks\n * <br/> - The time server should return time in ISO-8601 format.\n * <br/> - Overrides the time server provided the DASH manifest's `<UTCTiming>`.\n * <br/> - All sources will use the time server. Alternatively, for one source use {@link BaseSource.timeServer}.\n */\n timeServer?: string;\n\n /**\n * Describes the metadata of a source.\n *\n * @public\n */\n metadata?: MetadataDescription;\n\n /**\n * List of {@link AnalyticsDescription}s to configure source-related properties for analytics connectors.\n */\n analytics?: AnalyticsDescription[];\n}\n\n/**\n * Describes the configuration of a player's source.\n *\n * @public\n */\nexport interface SourceDescription extends SourceConfiguration {\n /**\n * One or more media resources for playback.\n *\n * @remarks\n * <br/> - Multiple media sources should be used to increase platform compatibility. See examples below for important use cases.\n * <br/> - The player will try each source in the provided order.\n *\n * @example\n * In this example, the player will first try to play the DASH source.\n * This might fail if the browser does not support the {@link https://www.widevine.com/ | Widevine} or {@link https://www.microsoft.com/playready/ | PlayReady} CDM, for example on Safari.\n * In that case, the player will try to play the HLS source instead.\n *\n * ```\n * [{\n * src: 'dash-source-with-drm.mpd'\n * contentProtection: {\n * widevine: {\n * licenseAcquisitionURL: 'https://license.company.com/wv'\n * },\n * playready: {\n * licenseAcquisitionURL: 'https://license.company.com/pr'\n * }\n * }\n * },{\n * src: 'hls-source-with-drm.m3u8',\n * contentProtection: {\n * fairplay: {\n * certificateURL: 'https://license.company.com/fp'\n * }\n * }\n * }]\n * ```\n *\n * @example\n * In this example, the player will first try to play the DASH source.\n * This might fail if the browser does not support the {@link https://developer.mozilla.org/en-US/docs/Web/API/Media_Source_Extensions_API | Media Source Extensions API}.\n * In that case, the player will try to play the MP4 source instead, though without features such as adaptive bitrate switching.\n *\n * ```\n * [{\n * src: 'source.mpd'\n * },{\n * src: 'source.mp4'\n * }]\n * ```\n */\n sources?: Sources;\n}\n\n/**\n * Describes the configuration of a side-loaded text track.\n *\n * @public\n */\nexport interface TextTrackDescription {\n /**\n * Whether the text track should be enabled by default.\n *\n * @remarks\n * <br/> - Only one text track per {@link TextTrack.kind} may be marked as default.\n *\n * @defaultValue `false`\n */\n default?: boolean;\n\n /**\n * The kind of the text track, represented by a value from the following list:\n * <br/> - `'subtitles'`: The track provides subtitles, used to display subtitles in a video.\n * <br/> - `'captions'`: The track provides a translation of dialogue and sound effects (suitable for users with a hearing impairment).\n * <br/> - `'descriptions'`: The track provides a textual description of the video (suitable for users with a vision impairment).\n * <br/> - `'chapters'`: The track provides chapter titles (suitable for navigating the media resource).\n * <br/> - `'metadata'`: The track provides content used by scripts and is not visible for users.\n *\n * @remarks\n * <br/> - If an unrecognized value is provided, the player will interpret it as `'metadata'`.\n *\n * @defaultValue `'subtitles'`\n */\n kind?: string;\n\n /**\n * The format of the track, represented by a value from the following list:\n * <br/> - `'srt'`\n * <br/> - `'ttml'`\n * <br/> - `'webvtt'`\n * <br/> - `'emsg'`\n * <br/> - `'eventstream'`\n * <br/> - `'id3'`\n * <br/> - `'cea608'`\n * <br/> - `'daterange'`\n *\n * @defaultValue `''`\n */\n format?: string;\n\n /**\n * The source URL of the text track.\n */\n src: string;\n\n /**\n * The language of the text track.\n */\n srclang?: string;\n\n /**\n * A label for the text track.\n *\n * @remarks\n * <br/> - This will be used as an identifier on the player API and in the UI.\n */\n label?: string;\n\n /**\n * The identifier of this text track.\n *\n * @internal\n */\n // Note: This works for HLS, but not for DASH.\n id?: string;\n}\n\n/**\n * Represents the common properties of a media resource.\n *\n * @public\n */\nexport interface BaseSource {\n\n /**\n * The cross-origin setting of the source.\n *\n * @defaultValue `''`\n */\n crossOrigin?: CrossOriginSetting;\n\n /**\n * The URL of a time server used by the player to synchronise the time in DASH sources.\n *\n * @remarks\n * <br/> - Available since v2.47.0.\n * <br/> - The time server should return time in ISO-8601 format.\n * <br/> - Overrides the time server provided the DASH manifest's `<UTCTiming>`.\n * <br/> - Only this source will use the time server. Alternatively, for all source use {@link SourceConfiguration.timeServer}.\n */\n timeServer?: string;\n\n /**\n * Whether the source should be played in the low-latency-mode of the player.\n *\n * @defaultValue `false`\n *\n * @remarks\n * <br/> - This setting must be `true` when using Low-Latency CMAF with ABR.\n * <br/> - Available since v2.62.0.\n */\n lowLatency?: boolean;\n\n /**\n * The configuration for controlling playback of an MPEG-DASH stream.\n *\n * @remarks\n * <br/> - Available since v2.79.0.\n * <br/> - Ignored for non-DASH streams.\n */\n dash?: DashPlaybackConfiguration;\n\n /**\n * The configuration for controlling playback of an HLS stream.\n *\n * @remarks\n * <br/> - Available since v2.82.0.\n * <br/> - Ignored for non-HLS streams.\n */\n hls?: HlsPlaybackConfiguration;\n}\n\n/**\n * Represents a media resource characterized by a URL to the resource and optionally information about the resource.\n *\n * @public\n */\nexport interface TypedSource extends BaseSource {\n /**\n * The source URL of the media resource.\n *\n * @remarks\n * <br/> - Required if the `ssai` property is absent.\n * <br/> - Available since v2.4.0.\n */\n src?: string;\n\n /**\n * The content type (MIME type) of the media resource, represented by a value from the following list:\n * <br/> - `'application/dash+xml'`: The media resource is an MPEG-DASH stream.\n * <br/> - `'application/x-mpegURL'` or `'application/vnd.apple.mpegurl'`: The media resource is an HLS stream.\n * <br/> - `'video/mp4'`, `'video/webm'` and other formats: The media resource should use native HTML5 playback if supported by the browser.\n * <br/> - `'application/vnd.theo.hesp+json'`: The media resource is an HESP stream.\n *\n * @remarks\n * <br/> - Available since v2.4.0.\n */\n type?: string;\n\n /**\n * The content protection parameters for the media resource.\n *\n * @remarks\n * <br/> - Available since v2.15.0.\n */\n contentProtection?: DRMConfiguration;\n\n /**\n * The Server-side Ad Insertion parameters for the media resource.\n *\n * @remarks\n * <br/> - Available since v2.12.0.\n */\n ssai?: ServerSideAdInsertionConfiguration;\n}\n"],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":[],"sources":["AnalyticsDescription.ts"],"sourcesContent":["/**\n * Describes the configuration of an analytics integration as part of the SourceDescription.\n *\n * @public\n */\nexport interface AnalyticsDescription {\n /**\n * The identifier of the analytics integration.\n */\n integration: string;\n\n /**\n * Analytics extensions can define any custom set of fields.\n */\n [key: string]: unknown;\n}\n"],"mappings":""}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
var _AnalyticsDescription = require("./AnalyticsDescription");
|
|
7
|
+
Object.keys(_AnalyticsDescription).forEach(function (key) {
|
|
8
|
+
if (key === "default" || key === "__esModule") return;
|
|
9
|
+
if (key in exports && exports[key] === _AnalyticsDescription[key]) return;
|
|
10
|
+
Object.defineProperty(exports, key, {
|
|
11
|
+
enumerable: true,
|
|
12
|
+
get: function () {
|
|
13
|
+
return _AnalyticsDescription[key];
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
//# sourceMappingURL=barrel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["_AnalyticsDescription","require","Object","keys","forEach","key","exports","defineProperty","enumerable","get"],"sources":["barrel.ts"],"sourcesContent":["export * from './AnalyticsDescription';\n"],"mappings":";;;;;AAAA,IAAAA,qBAAA,GAAAC,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAH,qBAAA,EAAAI,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAL,qBAAA,CAAAK,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAT,qBAAA,CAAAK,GAAA;IAAA;EAAA;AAAA"}
|