bitmovin-player-react-native 0.9.2 → 0.11.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/RNBitmovinPlayer.podspec +1 -1
- package/android/build.gradle +1 -2
- package/android/src/main/java/com/bitmovin/player/reactnative/AnalyticsModule.kt +43 -11
- package/android/src/main/java/com/bitmovin/player/reactnative/OfflineModule.kt +279 -0
- package/android/src/main/java/com/bitmovin/player/reactnative/PlayerModule.kt +73 -1
- package/android/src/main/java/com/bitmovin/player/reactnative/RNPlayerViewPackage.kt +1 -0
- package/android/src/main/java/com/bitmovin/player/reactnative/SourceModule.kt +12 -1
- package/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt +143 -35
- package/android/src/main/java/com/bitmovin/player/reactnative/offline/OfflineContentManagerBridge.kt +216 -0
- package/android/src/main/java/com/bitmovin/player/reactnative/offline/OfflineDownloadRequest.kt +7 -0
- package/ios/DrmModule.swift +5 -5
- package/ios/OfflineContentManagerBridge.swift +141 -0
- package/ios/OfflineModule.m +19 -0
- package/ios/OfflineModule.swift +465 -0
- package/ios/PlayerModule.m +15 -0
- package/ios/PlayerModule.swift +92 -7
- package/ios/RCTConvert+BitmovinPlayer.swift +160 -1
- package/ios/RNBitmovinPlayer.h +1 -0
- package/ios/SourceModule.m +5 -0
- package/ios/SourceModule.swift +18 -0
- package/lib/index.d.mts +450 -2
- package/lib/index.d.ts +450 -2
- package/lib/index.js +267 -0
- package/lib/index.mjs +265 -0
- package/package.json +3 -3
- package/src/adaptationConfig.ts +10 -0
- package/src/index.ts +3 -0
- package/src/offline/index.ts +7 -0
- package/src/offline/offlineContentConfig.ts +18 -0
- package/src/offline/offlineContentManager.ts +216 -0
- package/src/offline/offlineContentManagerListener.ts +187 -0
- package/src/offline/offlineContentOptions.ts +29 -0
- package/src/offline/offlineDownloadRequest.ts +20 -0
- package/src/offline/offlineSourceOptions.ts +11 -0
- package/src/offline/offlineState.ts +22 -0
- package/src/player.ts +57 -0
- package/src/source.ts +55 -0
- package/src/thumbnail.ts +37 -0
package/RNBitmovinPlayer.podspec
CHANGED
|
@@ -19,7 +19,7 @@ Pod::Spec.new do |s|
|
|
|
19
19
|
s.source_files = "ios/**/*.{h,m,mm,swift}"
|
|
20
20
|
|
|
21
21
|
s.dependency "React-Core"
|
|
22
|
-
s.dependency "BitmovinPlayer", "3.
|
|
22
|
+
s.dependency "BitmovinPlayer", "3.44.1"
|
|
23
23
|
s.ios.dependency "GoogleAds-IMA-iOS-SDK", "3.18.4"
|
|
24
24
|
s.tvos.dependency "GoogleAds-IMA-tvOS-SDK", "4.8.2"
|
|
25
25
|
end
|
package/android/build.gradle
CHANGED
|
@@ -53,8 +53,7 @@ dependencies {
|
|
|
53
53
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion"
|
|
54
54
|
implementation 'com.google.ads.interactivemedia.v3:interactivemedia:3.29.0'
|
|
55
55
|
implementation 'com.google.android.gms:play-services-ads-identifier:18.0.1'
|
|
56
|
-
implementation 'com.bitmovin.
|
|
57
|
-
implementation 'com.bitmovin.player:player:3.40.0'
|
|
56
|
+
implementation 'com.bitmovin.player:player:3.43.0'
|
|
58
57
|
//noinspection GradleDynamicVersion
|
|
59
58
|
implementation 'com.facebook.react:react-native:+' // From node_modules
|
|
60
59
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
package com.bitmovin.player.reactnative
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import android.util.Log
|
|
4
|
+
import com.bitmovin.analytics.bitmovin.player.api.IBitmovinPlayerCollector
|
|
4
5
|
import com.bitmovin.player.reactnative.converter.JsonConverter
|
|
5
6
|
import com.facebook.react.bridge.*
|
|
6
7
|
import com.facebook.react.module.annotations.ReactModule
|
|
@@ -13,7 +14,7 @@ class AnalyticsModule(private val context: ReactApplicationContext) : ReactConte
|
|
|
13
14
|
/**
|
|
14
15
|
* In-memory mapping from `nativeId`s to `BitmovinPlayerCollector` instances.
|
|
15
16
|
*/
|
|
16
|
-
private val collectors: Registry<
|
|
17
|
+
private val collectors: Registry<IBitmovinPlayerCollector> = mutableMapOf()
|
|
17
18
|
|
|
18
19
|
/**
|
|
19
20
|
* JS exported module name.
|
|
@@ -25,7 +26,7 @@ class AnalyticsModule(private val context: ReactApplicationContext) : ReactConte
|
|
|
25
26
|
* @param nativeId `BitmovinPlayerCollector` instance ID.
|
|
26
27
|
* @return The associated `BitmovinPlayerCollector` instance or `null`.
|
|
27
28
|
*/
|
|
28
|
-
fun getCollector(nativeId: NativeId?):
|
|
29
|
+
fun getCollector(nativeId: NativeId?): IBitmovinPlayerCollector? {
|
|
29
30
|
if (nativeId == null) {
|
|
30
31
|
return null
|
|
31
32
|
}
|
|
@@ -40,7 +41,7 @@ class AnalyticsModule(private val context: ReactApplicationContext) : ReactConte
|
|
|
40
41
|
fun initWithConfig(nativeId: NativeId, config: ReadableMap?) {
|
|
41
42
|
uiManager()?.addUIBlock { _ ->
|
|
42
43
|
JsonConverter.toAnalyticsConfig(config)?.let {
|
|
43
|
-
collectors[nativeId] =
|
|
44
|
+
collectors[nativeId] = IBitmovinPlayerCollector.create(it, context)
|
|
44
45
|
}
|
|
45
46
|
}
|
|
46
47
|
}
|
|
@@ -106,8 +107,20 @@ class AnalyticsModule(private val context: ReactApplicationContext) : ReactConte
|
|
|
106
107
|
@ReactMethod
|
|
107
108
|
fun setCustomData(nativeId: NativeId, playerId: NativeId?, json: ReadableMap?) {
|
|
108
109
|
uiManager()?.addUIBlock { _ ->
|
|
109
|
-
|
|
110
|
-
|
|
110
|
+
val source = playerModule()?.getPlayer(playerId)?.source
|
|
111
|
+
val collector = collectors[nativeId]
|
|
112
|
+
val customData = JsonConverter.toAnalyticsCustomData(json)
|
|
113
|
+
when {
|
|
114
|
+
source == null -> Log.d(
|
|
115
|
+
"[AnalyticsModule]", "Could not find source for player ($playerId)"
|
|
116
|
+
)
|
|
117
|
+
collector == null -> Log.d(
|
|
118
|
+
"[AnalyticsModule]", "Could not find analytics collector ($nativeId)"
|
|
119
|
+
)
|
|
120
|
+
customData == null -> Log.d(
|
|
121
|
+
"[AnalyticsModule]", "Could not convert custom data, thus they are not applied to the active source for the player ($playerId) with the collector ($nativeId)"
|
|
122
|
+
)
|
|
123
|
+
else -> collector.setCustomData(source, customData)
|
|
111
124
|
}
|
|
112
125
|
}
|
|
113
126
|
}
|
|
@@ -120,8 +133,16 @@ class AnalyticsModule(private val context: ReactApplicationContext) : ReactConte
|
|
|
120
133
|
@ReactMethod
|
|
121
134
|
fun getCustomData(nativeId: NativeId, playerId: NativeId?, promise: Promise) {
|
|
122
135
|
uiManager()?.addUIBlock { _ ->
|
|
123
|
-
|
|
124
|
-
|
|
136
|
+
val source = playerModule()?.getPlayer(playerId)?.source
|
|
137
|
+
val collector = collectors[nativeId]
|
|
138
|
+
when {
|
|
139
|
+
source == null -> promise.reject(
|
|
140
|
+
"[AnalyticsModule]", "Could not find source for player ($playerId)"
|
|
141
|
+
)
|
|
142
|
+
collector == null -> promise.reject(
|
|
143
|
+
"[AnalyticsModule]", "Could not find analytics collector ($nativeId)"
|
|
144
|
+
)
|
|
145
|
+
else -> promise.resolve(JsonConverter.fromAnalyticsCustomData(collector.getCustomData(source)))
|
|
125
146
|
}
|
|
126
147
|
}
|
|
127
148
|
}
|
|
@@ -129,9 +150,20 @@ class AnalyticsModule(private val context: ReactApplicationContext) : ReactConte
|
|
|
129
150
|
@ReactMethod
|
|
130
151
|
fun addSourceMetadata(nativeId: NativeId, playerId: NativeId?, json: ReadableMap?) {
|
|
131
152
|
uiManager()?.addUIBlock { _ ->
|
|
132
|
-
val
|
|
133
|
-
|
|
134
|
-
|
|
153
|
+
val source = playerModule()?.getPlayer(playerId)?.source
|
|
154
|
+
val collector = collectors[nativeId]
|
|
155
|
+
val sourceMetadata = JsonConverter.toAnalyticsSourceMetadata(json)
|
|
156
|
+
when {
|
|
157
|
+
source == null -> Log.d(
|
|
158
|
+
"[AnalyticsModule]", "Could not find source for player ($playerId)"
|
|
159
|
+
)
|
|
160
|
+
collector == null -> Log.d(
|
|
161
|
+
"[AnalyticsModule]", "Could not find analytics collector ($nativeId)"
|
|
162
|
+
)
|
|
163
|
+
sourceMetadata == null -> Log.d(
|
|
164
|
+
"[AnalyticsModule]", "Could not convert source metadata, thus they are not applied to the collector ($nativeId)"
|
|
165
|
+
)
|
|
166
|
+
else -> collector.addSourceMetadata(source, sourceMetadata)
|
|
135
167
|
}
|
|
136
168
|
}
|
|
137
169
|
}
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
package com.bitmovin.player.reactnative
|
|
2
|
+
|
|
3
|
+
import com.bitmovin.player.api.offline.options.OfflineOptionEntryState
|
|
4
|
+
import com.bitmovin.player.reactnative.converter.JsonConverter
|
|
5
|
+
import com.bitmovin.player.reactnative.extensions.toList
|
|
6
|
+
import com.bitmovin.player.reactnative.offline.OfflineDownloadRequest
|
|
7
|
+
import com.bitmovin.player.reactnative.offline.OfflineContentManagerBridge
|
|
8
|
+
import com.facebook.react.bridge.*
|
|
9
|
+
import com.facebook.react.module.annotations.ReactModule
|
|
10
|
+
import com.facebook.react.uimanager.UIManagerModule
|
|
11
|
+
|
|
12
|
+
private const val OFFLINE_MODULE = "BitmovinOfflineModule"
|
|
13
|
+
|
|
14
|
+
@ReactModule(name = OFFLINE_MODULE)
|
|
15
|
+
class OfflineModule(private val context: ReactApplicationContext) : ReactContextBaseJavaModule(context) {
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* In-memory mapping from `nativeId`s to `OfflineManager` instances.
|
|
19
|
+
*/
|
|
20
|
+
private val offlineContentManagerBridges: Registry<OfflineContentManagerBridge> = mutableMapOf()
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* JS exported module name.
|
|
24
|
+
*/
|
|
25
|
+
override fun getName() = OFFLINE_MODULE
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Fetches the `OfflineManager` instance associated with `nativeId` from the internal offline managers.
|
|
29
|
+
* @param nativeId `OfflineManager` instance ID.
|
|
30
|
+
* @return The associated `OfflineManager` instance or `null`.
|
|
31
|
+
*/
|
|
32
|
+
fun getOfflineContentManagerBridge(nativeId: NativeId?): OfflineContentManagerBridge? {
|
|
33
|
+
if (nativeId == null) {
|
|
34
|
+
return null
|
|
35
|
+
}
|
|
36
|
+
return offlineContentManagerBridges[nativeId]
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Callback when a new NativeEventEmitter is created from the Typescript layer.
|
|
41
|
+
*/
|
|
42
|
+
@ReactMethod
|
|
43
|
+
fun addListener(eventName: String?) {
|
|
44
|
+
// NO-OP
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Callback when a NativeEventEmitter is removed from the Typescript layer.
|
|
49
|
+
*/
|
|
50
|
+
@ReactMethod
|
|
51
|
+
fun removeListeners(count: Int?) {
|
|
52
|
+
// NO-OP
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Creates a new `OfflineManager` instance inside the internal offline managers using the provided `config` object.
|
|
57
|
+
* @param config `ReadableMap` object received from JS. Should contain a sourceConfig and location.
|
|
58
|
+
*/
|
|
59
|
+
@ReactMethod
|
|
60
|
+
fun initWithConfig(nativeId: NativeId, config: ReadableMap?, drmNativeId: NativeId?, promise: Promise) {
|
|
61
|
+
uiManager()?.addUIBlock {
|
|
62
|
+
if (!offlineContentManagerBridges.containsKey(nativeId)) {
|
|
63
|
+
val identifier = config?.getString("identifier")
|
|
64
|
+
val sourceConfig = JsonConverter.toSourceConfig(config?.getMap("sourceConfig"))
|
|
65
|
+
sourceConfig?.drmConfig = drmModule()?.getConfig(drmNativeId)
|
|
66
|
+
|
|
67
|
+
if (identifier.isNullOrEmpty() || sourceConfig == null) {
|
|
68
|
+
promise.reject(IllegalArgumentException("Identifier and SourceConfig may not be null"))
|
|
69
|
+
return@addUIBlock
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
offlineContentManagerBridges[nativeId] = OfflineContentManagerBridge(nativeId, context, identifier, sourceConfig, context.cacheDir.path)
|
|
73
|
+
}
|
|
74
|
+
promise.resolve(null)
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
@ReactMethod
|
|
79
|
+
fun getState(nativeId: NativeId, promise: Promise) {
|
|
80
|
+
safeOfflineContentManager(nativeId, promise) {
|
|
81
|
+
promise.resolve(state.name)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Starts the `OfflineContentManager`'s asynchronous process of fetching the `OfflineContentOptions`.
|
|
87
|
+
* When the options are loaded a device event will be fired where the event type is `BitmovinOfflineEvent` and the data has an event type of `onOptionsAvailable`.
|
|
88
|
+
* @param nativeId Target offline manager.
|
|
89
|
+
*/
|
|
90
|
+
@ReactMethod
|
|
91
|
+
fun getOptions(nativeId: NativeId, promise: Promise) {
|
|
92
|
+
safeOfflineContentManager(nativeId, promise) {
|
|
93
|
+
getOptions()
|
|
94
|
+
promise.resolve(null)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Enqueues downloads according to the `OfflineDownloadRequest`.
|
|
100
|
+
* The promise will reject in the event of null or invalid request parameters.
|
|
101
|
+
* The promise will reject an `IllegalOperationException` when selecting an `OfflineOptionEntry` to download that is not compatible with the current state.
|
|
102
|
+
* @param nativeId Target offline manager.
|
|
103
|
+
* @param request `ReadableMap` that contains the `OfflineManager.OfflineOptionType`, id, and `OfflineOptionEntryAction` necessary to set the new action.
|
|
104
|
+
*/
|
|
105
|
+
@ReactMethod
|
|
106
|
+
fun download(nativeId: NativeId, request: ReadableMap?, promise: Promise) {
|
|
107
|
+
if (request == null) {
|
|
108
|
+
promise.reject(IllegalArgumentException("Request may not be null"))
|
|
109
|
+
return
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
safeOfflineContentManager(nativeId, promise) {
|
|
113
|
+
try {
|
|
114
|
+
when (state) {
|
|
115
|
+
OfflineOptionEntryState.Downloaded -> {
|
|
116
|
+
promise.reject(IllegalStateException("Download already completed"))
|
|
117
|
+
return@safeOfflineContentManager
|
|
118
|
+
}
|
|
119
|
+
OfflineOptionEntryState.Downloading,
|
|
120
|
+
OfflineOptionEntryState.Failed -> {
|
|
121
|
+
promise.reject(IllegalStateException("Download already in progress"))
|
|
122
|
+
return@safeOfflineContentManager
|
|
123
|
+
}
|
|
124
|
+
OfflineOptionEntryState.Suspended -> {
|
|
125
|
+
promise.reject(IllegalStateException("Download is suspended"))
|
|
126
|
+
return@safeOfflineContentManager
|
|
127
|
+
}
|
|
128
|
+
else -> {}
|
|
129
|
+
}
|
|
130
|
+
val minimumBitRate = if(request.hasKey("minimumBitrate")) request.getInt("minimumBitrate") else null
|
|
131
|
+
if (minimumBitRate != null && minimumBitRate < 0) {
|
|
132
|
+
promise.reject(IllegalArgumentException("Invalid download request"))
|
|
133
|
+
return@safeOfflineContentManager
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
val audioOptionIds = request.getArray("audioOptionIds")?.toList<String>()?.filterNotNull()
|
|
137
|
+
val textOptionIds = request.getArray("textOptionIds")?.toList<String>()?.filterNotNull()
|
|
138
|
+
|
|
139
|
+
getOfflineContentManagerBridge(nativeId)?.process(OfflineDownloadRequest(minimumBitRate, audioOptionIds, textOptionIds))
|
|
140
|
+
promise.resolve(null)
|
|
141
|
+
} catch (e: Exception) {
|
|
142
|
+
promise.reject(e)
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Resumes all suspended actions.
|
|
149
|
+
* @param nativeId Target offline manager.
|
|
150
|
+
*/
|
|
151
|
+
@ReactMethod
|
|
152
|
+
fun resume(nativeId: NativeId, promise: Promise) {
|
|
153
|
+
safeOfflineContentManager(nativeId, promise) {
|
|
154
|
+
resume()
|
|
155
|
+
promise.resolve(null)
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Suspends all active actions.
|
|
161
|
+
* @param nativeId Target offline manager.
|
|
162
|
+
*/
|
|
163
|
+
@ReactMethod
|
|
164
|
+
fun suspend(nativeId: NativeId, promise: Promise) {
|
|
165
|
+
safeOfflineContentManager(nativeId, promise) {
|
|
166
|
+
suspend()
|
|
167
|
+
promise.resolve(null)
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Cancels and deletes the current download.
|
|
173
|
+
* @param nativeId Target offline manager.
|
|
174
|
+
*/
|
|
175
|
+
@ReactMethod
|
|
176
|
+
fun cancelDownload(nativeId: NativeId, promise: Promise) {
|
|
177
|
+
safeOfflineContentManager(nativeId, promise) {
|
|
178
|
+
cancelDownload()
|
|
179
|
+
promise.resolve(null)
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Resolve `nativeId`'s current `usedStorage`.
|
|
185
|
+
* @param nativeId Target offline manager.
|
|
186
|
+
*/
|
|
187
|
+
@ReactMethod
|
|
188
|
+
fun usedStorage(nativeId: NativeId, promise: Promise) {
|
|
189
|
+
safeOfflineContentManager(nativeId, promise) {
|
|
190
|
+
promise.resolve(offlineContentManager.usedStorage.toDouble())
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Deletes everything related to the related content ID.
|
|
196
|
+
* @param nativeId Target offline manager.
|
|
197
|
+
*/
|
|
198
|
+
@ReactMethod
|
|
199
|
+
fun deleteAll(nativeId: NativeId, promise: Promise) {
|
|
200
|
+
safeOfflineContentManager(nativeId, promise) {
|
|
201
|
+
deleteAll()
|
|
202
|
+
promise.resolve(null)
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Downloads the offline license.
|
|
208
|
+
* When finished successfully a device event will be fired where the event type is `BitmovinOfflineEvent` and the data has an event type of `onDrmLicenseUpdated`.
|
|
209
|
+
* Errors are transmitted by a device event will be fired where the event type is `BitmovinOfflineEvent` and the data has an event type of `onError`.
|
|
210
|
+
* @param nativeId Target offline manager.
|
|
211
|
+
*/
|
|
212
|
+
@ReactMethod
|
|
213
|
+
fun downloadLicense(nativeId: NativeId, promise: Promise) {
|
|
214
|
+
safeOfflineContentManager(nativeId, promise) {
|
|
215
|
+
downloadLicense()
|
|
216
|
+
promise.resolve(null)
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Releases the currently held offline license.
|
|
222
|
+
* When finished successfully a device event will be fired where the event type is `BitmovinOfflineEvent` and the data has an event type of `onDrmLicenseUpdated`.
|
|
223
|
+
* Errors are transmitted by a device event will be fired where the event type is `BitmovinOfflineEvent` and the data has an event type of `onError`.
|
|
224
|
+
* @param nativeId Target offline manager.
|
|
225
|
+
*/
|
|
226
|
+
@ReactMethod
|
|
227
|
+
fun releaseLicense(nativeId: NativeId, promise: Promise) {
|
|
228
|
+
safeOfflineContentManager(nativeId, promise) {
|
|
229
|
+
releaseLicense()
|
|
230
|
+
promise.resolve(null)
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Renews the already downloaded DRM license.
|
|
236
|
+
* When finished successfully a device event will be fired where the event type is `BitmovinOfflineEvent` and the data has an event type of `onDrmLicenseUpdated`.
|
|
237
|
+
* Errors are transmitted by a device event will be fired where the event type is `BitmovinOfflineEvent` and the data has an event type of `onError`.
|
|
238
|
+
* @param nativeId Target offline manager.
|
|
239
|
+
*/
|
|
240
|
+
@ReactMethod
|
|
241
|
+
fun renewOfflineLicense(nativeId: NativeId, promise: Promise) {
|
|
242
|
+
safeOfflineContentManager(nativeId, promise) {
|
|
243
|
+
renewOfflineLicense()
|
|
244
|
+
promise.resolve(null)
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Call `.release()` on `nativeId`'s offline manager.
|
|
250
|
+
* IMPORTANT: Call this when the component, in which it was created, is destroyed.
|
|
251
|
+
* The `OfflineManager` should not be used after calling this method.
|
|
252
|
+
* @param nativeId Target player Id.
|
|
253
|
+
*/
|
|
254
|
+
@ReactMethod
|
|
255
|
+
fun release(nativeId: NativeId, promise: Promise) {
|
|
256
|
+
safeOfflineContentManager(nativeId, promise) {
|
|
257
|
+
release()
|
|
258
|
+
offlineContentManagerBridges.remove(nativeId)
|
|
259
|
+
promise.resolve(null)
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
private fun safeOfflineContentManager(nativeId: NativeId, promise: Promise, runBlock: OfflineContentManagerBridge.() -> Unit) {
|
|
264
|
+
getOfflineContentManagerBridge(nativeId)?.let(runBlock)
|
|
265
|
+
?: promise.reject(IllegalArgumentException("Could not find the offline module instance"))
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Helper function that returns the initialized `DrmModule` instance.
|
|
270
|
+
*/
|
|
271
|
+
private fun drmModule(): DrmModule? =
|
|
272
|
+
context.getNativeModule(DrmModule::class.java)
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Helper function that returns the initialized `UIManager` instance.
|
|
276
|
+
*/
|
|
277
|
+
private fun uiManager(): UIManagerModule? =
|
|
278
|
+
context.getNativeModule(UIManagerModule::class.java)
|
|
279
|
+
}
|
|
@@ -50,7 +50,7 @@ class PlayerModule(private val context: ReactApplicationContext) : ReactContextB
|
|
|
50
50
|
/**
|
|
51
51
|
* Load the source of the given `nativeId` with `config` options from JS.
|
|
52
52
|
* @param nativeId Target player.
|
|
53
|
-
* @param
|
|
53
|
+
* @param sourceNativeId Target source.
|
|
54
54
|
*/
|
|
55
55
|
@ReactMethod
|
|
56
56
|
fun loadSource(nativeId: NativeId, sourceNativeId: String) {
|
|
@@ -61,6 +61,24 @@ class PlayerModule(private val context: ReactApplicationContext) : ReactContextB
|
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Load the `offlineSourceConfig` for the player with `nativeId` and offline source module with `offlineModuleNativeId`.
|
|
66
|
+
* @param nativeId Target player.
|
|
67
|
+
* @param offlineContentManagerBridgeId Target offline module.
|
|
68
|
+
* @param options Source configuration options from JS.
|
|
69
|
+
*/
|
|
70
|
+
@ReactMethod
|
|
71
|
+
fun loadOfflineContent(nativeId: NativeId, offlineContentManagerBridgeId: String, options: ReadableMap?) {
|
|
72
|
+
uiManager()?.addUIBlock {
|
|
73
|
+
val offlineSourceConfig = offlineModule()?.getOfflineContentManagerBridge(offlineContentManagerBridgeId)
|
|
74
|
+
?.offlineContentManager?.offlineSourceConfig
|
|
75
|
+
|
|
76
|
+
if (offlineSourceConfig != null) {
|
|
77
|
+
players[nativeId]?.load(offlineSourceConfig)
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
64
82
|
/**
|
|
65
83
|
* Call `.unload()` on `nativeId`'s player.
|
|
66
84
|
* @param nativeId Target player Id.
|
|
@@ -273,6 +291,18 @@ class PlayerModule(private val context: ReactApplicationContext) : ReactContextB
|
|
|
273
291
|
}
|
|
274
292
|
}
|
|
275
293
|
|
|
294
|
+
/**
|
|
295
|
+
* Resolve `nativeId`'s currently selected audio track.
|
|
296
|
+
* @param nativeId Target player Id.
|
|
297
|
+
* @param promise JS promise object.
|
|
298
|
+
*/
|
|
299
|
+
@ReactMethod
|
|
300
|
+
fun getAudioTrack(nativeId: NativeId, promise: Promise) {
|
|
301
|
+
uiManager()?.addUIBlock {
|
|
302
|
+
promise.resolve(JsonConverter.fromAudioTrack(players[nativeId]?.source?.selectedAudioTrack))
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
276
306
|
/**
|
|
277
307
|
* Resolve `nativeId`'s player available audio tracks.
|
|
278
308
|
* @param nativeId Target player Id.
|
|
@@ -305,6 +335,18 @@ class PlayerModule(private val context: ReactApplicationContext) : ReactContextB
|
|
|
305
335
|
}
|
|
306
336
|
}
|
|
307
337
|
|
|
338
|
+
/**
|
|
339
|
+
* Resolve `nativeId`'s currently selected subtitle track.
|
|
340
|
+
* @param nativeId Target player Id.
|
|
341
|
+
* @param promise JS promise object.
|
|
342
|
+
*/
|
|
343
|
+
@ReactMethod
|
|
344
|
+
fun getSubtitleTrack(nativeId: NativeId, promise: Promise) {
|
|
345
|
+
uiManager()?.addUIBlock {
|
|
346
|
+
promise.resolve(JsonConverter.fromSubtitleTrack(players[nativeId]?.source?.selectedSubtitleTrack))
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
308
350
|
/**
|
|
309
351
|
* Resolve `nativeId`'s player available subtitle tracks.
|
|
310
352
|
* @param nativeId Target player Id.
|
|
@@ -398,6 +440,30 @@ class PlayerModule(private val context: ReactApplicationContext) : ReactContextB
|
|
|
398
440
|
}
|
|
399
441
|
}
|
|
400
442
|
|
|
443
|
+
/**
|
|
444
|
+
* Sets the max selectable bitrate for the player.
|
|
445
|
+
* @param nativeId Target player id.
|
|
446
|
+
* @param maxSelectableBitrate The desired max bitrate limit.
|
|
447
|
+
*/
|
|
448
|
+
@ReactMethod
|
|
449
|
+
fun setMaxSelectableBitrate(nativeId: NativeId, maxSelectableBitrate: Int) {
|
|
450
|
+
uiManager()?.addUIBlock {
|
|
451
|
+
players[nativeId]?.setMaxSelectableVideoBitrate(maxSelectableBitrate.takeUnless { it == -1 } ?: Integer.MAX_VALUE)
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* Returns the thumbnail image for the active `Source` at a certain time.
|
|
457
|
+
* @param nativeId Target player id.
|
|
458
|
+
* @param time Playback time for the thumbnail.
|
|
459
|
+
*/
|
|
460
|
+
@ReactMethod
|
|
461
|
+
fun getThumbnail(nativeId: NativeId, time: Double, promise: Promise) {
|
|
462
|
+
uiManager()?.addUIBlock {
|
|
463
|
+
promise.resolve(JsonConverter.fromThumbnail(players[nativeId]?.source?.getThumbnail(time)))
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
401
467
|
/**
|
|
402
468
|
* Helper function that returns the initialized `UIManager` instance.
|
|
403
469
|
*/
|
|
@@ -409,4 +475,10 @@ class PlayerModule(private val context: ReactApplicationContext) : ReactContextB
|
|
|
409
475
|
*/
|
|
410
476
|
private fun sourceModule(): SourceModule? =
|
|
411
477
|
context.getNativeModule(SourceModule::class.java)
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* Helper function that returns the initialized `OfflineModule` instance.
|
|
481
|
+
*/
|
|
482
|
+
private fun offlineModule(): OfflineModule? =
|
|
483
|
+
context.getNativeModule(OfflineModule::class.java)
|
|
412
484
|
}
|
|
@@ -19,6 +19,7 @@ class RNPlayerViewPackage : ReactPackage {
|
|
|
19
19
|
*/
|
|
20
20
|
override fun createNativeModules(reactContext: ReactApplicationContext): MutableList<NativeModule> {
|
|
21
21
|
return mutableListOf(
|
|
22
|
+
OfflineModule(reactContext),
|
|
22
23
|
UuidModule(reactContext),
|
|
23
24
|
PlayerModule(reactContext),
|
|
24
25
|
SourceModule(reactContext),
|
|
@@ -140,7 +140,6 @@ class SourceModule(private val context: ReactApplicationContext) : ReactContextB
|
|
|
140
140
|
/**
|
|
141
141
|
* Set the metadata for a loaded `nativeId` source.
|
|
142
142
|
* @param nativeId Source `nativeId`.
|
|
143
|
-
* @param promise: JS promise object.
|
|
144
143
|
*/
|
|
145
144
|
@ReactMethod
|
|
146
145
|
fun setMetadata(nativeId: NativeId, metadata: ReadableMap?) {
|
|
@@ -149,6 +148,18 @@ class SourceModule(private val context: ReactApplicationContext) : ReactContextB
|
|
|
149
148
|
}
|
|
150
149
|
}
|
|
151
150
|
|
|
151
|
+
/**
|
|
152
|
+
* Returns the thumbnail image for the `Source` at a certain time.
|
|
153
|
+
* @param nativeId Target player id.
|
|
154
|
+
* @param time Playback time for the thumbnail.
|
|
155
|
+
*/
|
|
156
|
+
@ReactMethod
|
|
157
|
+
fun getThumbnail(nativeId: NativeId, time: Double, promise: Promise) {
|
|
158
|
+
uiManager()?.addUIBlock {
|
|
159
|
+
promise.resolve(JsonConverter.fromThumbnail(sources[nativeId]?.getThumbnail(time)))
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
152
163
|
/**
|
|
153
164
|
* Helper method that converts a React `ReadableMap` into a kotlin String -> String map.
|
|
154
165
|
*/
|