bitmovin-player-react-native 0.1.0 → 0.2.1
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/README.md +163 -1
- package/RNBitmovinPlayer.podspec +3 -3
- package/android/src/main/java/com/bitmovin/player/reactnative/DrmModule.kt +191 -0
- package/android/src/main/java/com/bitmovin/player/reactnative/PlayerModule.kt +116 -101
- package/android/src/main/java/com/bitmovin/player/reactnative/RNPlayerView.kt +69 -38
- package/android/src/main/java/com/bitmovin/player/reactnative/RNPlayerViewManager.kt +10 -26
- package/android/src/main/java/com/bitmovin/player/reactnative/RNPlayerViewPackage.kt +3 -0
- package/android/src/main/java/com/bitmovin/player/reactnative/Registry.kt +11 -0
- package/android/src/main/java/com/bitmovin/player/reactnative/SourceModule.kt +178 -0
- package/android/src/main/java/com/bitmovin/player/reactnative/UuidModule.kt +20 -0
- package/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt +128 -1
- package/android/src/main/java/com/bitmovin/player/reactnative/extensions/Events.kt +11 -2
- package/ios/DrmModule.m +16 -0
- package/ios/DrmModule.swift +442 -0
- package/ios/Event+JSON.swift +31 -0
- package/ios/PlayerModule.m +21 -25
- package/ios/PlayerModule.swift +122 -120
- package/ios/RCTConvert+BitmovinPlayer.swift +131 -12
- package/ios/RNPlayerView+PlayerListener.swift +12 -0
- package/ios/RNPlayerView.swift +5 -3
- package/ios/RNPlayerViewManager.m +3 -1
- package/ios/RNPlayerViewManager.swift +4 -21
- package/ios/Registry.swift +5 -0
- package/ios/SourceModule.m +30 -0
- package/ios/SourceModule.swift +187 -0
- package/ios/UuidModule.m +9 -0
- package/ios/UuidModule.swift +23 -0
- package/lib/index.d.ts +670 -235
- package/lib/index.js +257 -106
- package/lib/index.mjs +260 -112
- package/package.json +5 -4
- package/src/components/PlayerView/events.ts +24 -18
- package/src/components/PlayerView/index.tsx +29 -26
- package/src/drm/fairplayConfig.ts +90 -0
- package/src/drm/index.ts +178 -0
- package/src/drm/widevineConfig.ts +37 -0
- package/src/events.ts +67 -6
- package/src/hooks/useProxy.ts +19 -15
- package/src/index.ts +5 -3
- package/src/nativeInstance.ts +64 -0
- package/src/player.ts +51 -42
- package/src/source.ts +88 -8
- package/src/subtitleTrack.ts +60 -0
- package/src/utils.ts +15 -0
package/lib/index.mjs
CHANGED
|
@@ -5,15 +5,253 @@ var __publicField = (obj, key, value) => {
|
|
|
5
5
|
return value;
|
|
6
6
|
};
|
|
7
7
|
|
|
8
|
-
// src/
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
// src/components/PlayerView/index.tsx
|
|
9
|
+
import React, { useRef, useEffect } from "react";
|
|
10
|
+
import {
|
|
11
|
+
Platform,
|
|
12
|
+
UIManager,
|
|
13
|
+
StyleSheet,
|
|
14
|
+
findNodeHandle as findNodeHandle2
|
|
15
|
+
} from "react-native";
|
|
16
|
+
|
|
17
|
+
// src/components/PlayerView/native.ts
|
|
18
|
+
import { requireNativeComponent } from "react-native";
|
|
19
|
+
var NativePlayerView = requireNativeComponent("NativePlayerView");
|
|
20
|
+
|
|
21
|
+
// src/hooks/useProxy.ts
|
|
22
|
+
import omit from "lodash.omit";
|
|
23
|
+
import { useCallback } from "react";
|
|
24
|
+
import { findNodeHandle } from "react-native";
|
|
25
|
+
function unwrapNativeEvent(event) {
|
|
26
|
+
return omit(event.nativeEvent, ["target"]);
|
|
27
|
+
}
|
|
28
|
+
function useProxy(viewRef) {
|
|
29
|
+
return useCallback((callback) => (event) => {
|
|
30
|
+
const node = event.target._nativeTag;
|
|
31
|
+
if (node === findNodeHandle(viewRef.current)) {
|
|
32
|
+
callback?.(unwrapNativeEvent(event));
|
|
33
|
+
}
|
|
34
|
+
}, [viewRef]);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// src/components/PlayerView/index.tsx
|
|
38
|
+
var styles = StyleSheet.create({
|
|
39
|
+
baseStyle: {
|
|
40
|
+
alignSelf: "stretch"
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
function dispatch(command, node, playerId) {
|
|
44
|
+
const commandId = Platform.OS === "android" ? UIManager.NativePlayerView.Commands[command].toString() : UIManager.getViewManagerConfig("NativePlayerView").Commands[command];
|
|
45
|
+
UIManager.dispatchViewManagerCommand(node, commandId, Platform.select({
|
|
46
|
+
ios: [playerId],
|
|
47
|
+
android: [node, playerId]
|
|
48
|
+
}));
|
|
49
|
+
}
|
|
50
|
+
function PlayerView(props) {
|
|
51
|
+
const nativeView = useRef(null);
|
|
52
|
+
const proxy = useProxy(nativeView);
|
|
53
|
+
const style = StyleSheet.flatten([styles.baseStyle, props.style]);
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
props.player.initialize();
|
|
56
|
+
const node = findNodeHandle2(nativeView.current);
|
|
57
|
+
dispatch("attachPlayer", node, props.player.nativeId);
|
|
58
|
+
}, [props.player]);
|
|
59
|
+
return /* @__PURE__ */ React.createElement(NativePlayerView, {
|
|
60
|
+
ref: nativeView,
|
|
61
|
+
style,
|
|
62
|
+
onDestroy: proxy(props.onDestroy),
|
|
63
|
+
onEvent: proxy(props.onEvent),
|
|
64
|
+
onMuted: proxy(props.onMuted),
|
|
65
|
+
onPaused: proxy(props.onPaused),
|
|
66
|
+
onPlay: proxy(props.onPlay),
|
|
67
|
+
onPlaybackFinished: proxy(props.onPlaybackFinished),
|
|
68
|
+
onPlayerActive: proxy(props.onPlayerActive),
|
|
69
|
+
onPlayerError: proxy(props.onPlayerError),
|
|
70
|
+
onPlayerWarning: proxy(props.onPlayerWarning),
|
|
71
|
+
onPlaying: proxy(props.onPlaying),
|
|
72
|
+
onReady: proxy(props.onReady),
|
|
73
|
+
onSeek: proxy(props.onSeek),
|
|
74
|
+
onSeeked: proxy(props.onSeeked),
|
|
75
|
+
onSourceError: proxy(props.onSourceError),
|
|
76
|
+
onSourceLoad: proxy(props.onSourceLoad),
|
|
77
|
+
onSourceLoaded: proxy(props.onSourceLoaded),
|
|
78
|
+
onSourceUnloaded: proxy(props.onSourceUnloaded),
|
|
79
|
+
onSourceWarning: proxy(props.onSourceWarning),
|
|
80
|
+
onSubtitleAdded: proxy(props.onSubtitleAdded),
|
|
81
|
+
onSubtitleChanged: proxy(props.onSubtitleChanged),
|
|
82
|
+
onSubtitleRemoved: proxy(props.onSubtitleRemoved),
|
|
83
|
+
onTimeChanged: proxy(props.onTimeChanged),
|
|
84
|
+
onUnmuted: proxy(props.onUnmuted)
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// src/drm/index.ts
|
|
89
|
+
import { NativeModules as NativeModules2, Platform as Platform2 } from "react-native";
|
|
90
|
+
import BatchedBridge from "react-native/Libraries/BatchedBridge/BatchedBridge";
|
|
91
|
+
|
|
92
|
+
// src/nativeInstance.ts
|
|
93
|
+
import { NativeModules } from "react-native";
|
|
94
|
+
var Uuid = NativeModules.UuidModule;
|
|
95
|
+
var NativeInstance = class {
|
|
12
96
|
constructor(config) {
|
|
13
97
|
__publicField(this, "nativeId");
|
|
14
98
|
__publicField(this, "config");
|
|
15
|
-
|
|
16
|
-
|
|
99
|
+
this.config = config;
|
|
100
|
+
this.nativeId = config?.nativeId ?? Uuid.generate();
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
// src/drm/index.ts
|
|
105
|
+
var DrmModule = NativeModules2.DrmModule;
|
|
106
|
+
var Drm = class extends NativeInstance {
|
|
107
|
+
constructor() {
|
|
108
|
+
super(...arguments);
|
|
109
|
+
__publicField(this, "isInitialized", false);
|
|
110
|
+
__publicField(this, "isDestroyed", false);
|
|
111
|
+
__publicField(this, "initialize", () => {
|
|
112
|
+
if (!this.isInitialized) {
|
|
113
|
+
BatchedBridge.registerCallableModule(`DRM-${this.nativeId}`, this);
|
|
114
|
+
DrmModule.initWithConfig(this.nativeId, this.config);
|
|
115
|
+
this.isInitialized = true;
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
__publicField(this, "destroy", () => {
|
|
119
|
+
if (!this.isDestroyed) {
|
|
120
|
+
DrmModule.destroy(this.nativeId);
|
|
121
|
+
this.isDestroyed = true;
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
__publicField(this, "onPrepareCertificate", (certificate) => {
|
|
125
|
+
if (this.config?.fairplay?.prepareCertificate) {
|
|
126
|
+
DrmModule.setPreparedCertificate(this.nativeId, this.config?.fairplay?.prepareCertificate?.(certificate));
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
__publicField(this, "onPrepareMessage", (message, assetId) => {
|
|
130
|
+
const config = Platform2.OS === "ios" ? this.config?.fairplay : this.config?.widevine;
|
|
131
|
+
if (config && config.prepareMessage) {
|
|
132
|
+
DrmModule.setPreparedMessage(this.nativeId, Platform2.OS === "ios" ? config.prepareMessage?.(message, assetId) : config.prepareMessage?.(message));
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
__publicField(this, "onPrepareSyncMessage", (syncMessage, assetId) => {
|
|
136
|
+
if (this.config?.fairplay?.prepareSyncMessage) {
|
|
137
|
+
DrmModule.setPreparedSyncMessage(this.nativeId, this.config?.fairplay?.prepareSyncMessage?.(syncMessage, assetId));
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
__publicField(this, "onPrepareLicense", (license) => {
|
|
141
|
+
const prepareLicense = Platform2.OS === "ios" ? this.config?.fairplay?.prepareLicense : this.config?.widevine?.prepareLicense;
|
|
142
|
+
if (prepareLicense) {
|
|
143
|
+
DrmModule.setPreparedLicense(this.nativeId, prepareLicense(license));
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
__publicField(this, "onPrepareLicenseServerUrl", (licenseServerUrl) => {
|
|
147
|
+
if (this.config?.fairplay?.prepareLicenseServerUrl) {
|
|
148
|
+
DrmModule.setPreparedLicenseServerUrl(this.nativeId, this.config?.fairplay?.prepareLicenseServerUrl?.(licenseServerUrl));
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
__publicField(this, "onPrepareContentId", (contentId) => {
|
|
152
|
+
if (this.config?.fairplay?.prepareContentId) {
|
|
153
|
+
DrmModule.setPreparedContentId(this.nativeId, this.config?.fairplay?.prepareContentId?.(contentId));
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
// src/hooks/usePlayer.ts
|
|
160
|
+
import { useRef as useRef2 } from "react";
|
|
161
|
+
|
|
162
|
+
// src/player.ts
|
|
163
|
+
import { NativeModules as NativeModules4, Platform as Platform3 } from "react-native";
|
|
164
|
+
|
|
165
|
+
// src/source.ts
|
|
166
|
+
import { NativeModules as NativeModules3 } from "react-native";
|
|
167
|
+
var SourceModule = NativeModules3.SourceModule;
|
|
168
|
+
var SourceType = /* @__PURE__ */ ((SourceType2) => {
|
|
169
|
+
SourceType2["NONE"] = "none";
|
|
170
|
+
SourceType2["HLS"] = "hls";
|
|
171
|
+
SourceType2["DASH"] = "dash";
|
|
172
|
+
SourceType2["PROGRESSIVE"] = "progressive";
|
|
173
|
+
return SourceType2;
|
|
174
|
+
})(SourceType || {});
|
|
175
|
+
var LoadingState = /* @__PURE__ */ ((LoadingState2) => {
|
|
176
|
+
LoadingState2[LoadingState2["UNLOADED"] = 0] = "UNLOADED";
|
|
177
|
+
LoadingState2[LoadingState2["LOADING"] = 1] = "LOADING";
|
|
178
|
+
LoadingState2[LoadingState2["LOADED"] = 2] = "LOADED";
|
|
179
|
+
return LoadingState2;
|
|
180
|
+
})(LoadingState || {});
|
|
181
|
+
var Source = class extends NativeInstance {
|
|
182
|
+
constructor() {
|
|
183
|
+
super(...arguments);
|
|
184
|
+
__publicField(this, "drm");
|
|
185
|
+
__publicField(this, "isInitialized", false);
|
|
186
|
+
__publicField(this, "isDestroyed", false);
|
|
187
|
+
__publicField(this, "initialize", () => {
|
|
188
|
+
if (!this.isInitialized) {
|
|
189
|
+
if (this.config?.drmConfig) {
|
|
190
|
+
this.drm = new Drm(this.config.drmConfig);
|
|
191
|
+
this.drm.initialize();
|
|
192
|
+
SourceModule.initWithDrmConfig(this.nativeId, this.drm.nativeId, this.config);
|
|
193
|
+
} else {
|
|
194
|
+
SourceModule.initWithConfig(this.nativeId, this.config);
|
|
195
|
+
}
|
|
196
|
+
this.isInitialized = true;
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
__publicField(this, "destroy", () => {
|
|
200
|
+
if (!this.isDestroyed) {
|
|
201
|
+
SourceModule.destroy(this.nativeId);
|
|
202
|
+
this.drm?.destroy();
|
|
203
|
+
this.isDestroyed = true;
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
__publicField(this, "duration", async () => {
|
|
207
|
+
return SourceModule.duration(this.nativeId);
|
|
208
|
+
});
|
|
209
|
+
__publicField(this, "isActive", async () => {
|
|
210
|
+
return SourceModule.isActive(this.nativeId);
|
|
211
|
+
});
|
|
212
|
+
__publicField(this, "isAttachedToPlayer", async () => {
|
|
213
|
+
return SourceModule.isAttachedToPlayer(this.nativeId);
|
|
214
|
+
});
|
|
215
|
+
__publicField(this, "metadata", async () => {
|
|
216
|
+
return SourceModule.getMetadata(this.nativeId);
|
|
217
|
+
});
|
|
218
|
+
__publicField(this, "setMetadata", (metadata) => {
|
|
219
|
+
SourceModule.setMetadata(this.nativeId, metadata);
|
|
220
|
+
});
|
|
221
|
+
__publicField(this, "loadingState", async () => {
|
|
222
|
+
return SourceModule.loadingState(this.nativeId);
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
// src/player.ts
|
|
228
|
+
var PlayerModule = NativeModules4.PlayerModule;
|
|
229
|
+
var Player = class extends NativeInstance {
|
|
230
|
+
constructor() {
|
|
231
|
+
super(...arguments);
|
|
232
|
+
__publicField(this, "source");
|
|
233
|
+
__publicField(this, "isInitialized", false);
|
|
234
|
+
__publicField(this, "isDestroyed", false);
|
|
235
|
+
__publicField(this, "initialize", () => {
|
|
236
|
+
if (!this.isInitialized) {
|
|
237
|
+
PlayerModule.initWithConfig(this.nativeId, this.config);
|
|
238
|
+
this.isInitialized = true;
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
__publicField(this, "destroy", () => {
|
|
242
|
+
if (!this.isDestroyed) {
|
|
243
|
+
PlayerModule.destroy(this.nativeId);
|
|
244
|
+
this.source?.destroy();
|
|
245
|
+
this.isDestroyed = true;
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
__publicField(this, "load", (sourceConfig) => {
|
|
249
|
+
this.loadSource(new Source(sourceConfig));
|
|
250
|
+
});
|
|
251
|
+
__publicField(this, "loadSource", (source) => {
|
|
252
|
+
source.initialize();
|
|
253
|
+
this.source = source;
|
|
254
|
+
PlayerModule.loadSource(this.nativeId, source.nativeId);
|
|
17
255
|
});
|
|
18
256
|
__publicField(this, "unload", () => {
|
|
19
257
|
PlayerModule.unload(this.nativeId);
|
|
@@ -33,15 +271,9 @@ var Player = class {
|
|
|
33
271
|
__publicField(this, "unmute", () => {
|
|
34
272
|
PlayerModule.unmute(this.nativeId);
|
|
35
273
|
});
|
|
36
|
-
__publicField(this, "destroy", () => {
|
|
37
|
-
PlayerModule.destroy(this.nativeId);
|
|
38
|
-
});
|
|
39
274
|
__publicField(this, "setVolume", (volume) => {
|
|
40
275
|
PlayerModule.setVolume(this.nativeId, volume);
|
|
41
276
|
});
|
|
42
|
-
__publicField(this, "getSource", async () => {
|
|
43
|
-
return PlayerModule.source(this.nativeId);
|
|
44
|
-
});
|
|
45
277
|
__publicField(this, "getVolume", async () => {
|
|
46
278
|
return PlayerModule.getVolume(this.nativeId);
|
|
47
279
|
});
|
|
@@ -64,128 +296,44 @@ var Player = class {
|
|
|
64
296
|
return PlayerModule.isLive(this.nativeId);
|
|
65
297
|
});
|
|
66
298
|
__publicField(this, "isAirPlayActive", async () => {
|
|
67
|
-
if (
|
|
299
|
+
if (Platform3.OS === "android") {
|
|
68
300
|
console.warn(`[Player ${this.nativeId}] Method isAirPlayActive is not available for Android. Only iOS devices.`);
|
|
69
301
|
return false;
|
|
70
302
|
}
|
|
71
303
|
return PlayerModule.isAirPlayActive(this.nativeId);
|
|
72
304
|
});
|
|
73
305
|
__publicField(this, "isAirPlayAvailable", async () => {
|
|
74
|
-
if (
|
|
306
|
+
if (Platform3.OS === "android") {
|
|
75
307
|
console.warn(`[Player ${this.nativeId}] Method isAirPlayAvailable is not available for Android. Only iOS devices.`);
|
|
76
308
|
return false;
|
|
77
309
|
}
|
|
78
310
|
return PlayerModule.isAirPlayAvailable(this.nativeId);
|
|
79
311
|
});
|
|
80
|
-
this
|
|
81
|
-
|
|
82
|
-
|
|
312
|
+
__publicField(this, "getAvailableSubtitles", async () => {
|
|
313
|
+
return PlayerModule.getAvailableSubtitles(this.nativeId);
|
|
314
|
+
});
|
|
83
315
|
}
|
|
84
316
|
};
|
|
85
317
|
|
|
86
|
-
// src/source.ts
|
|
87
|
-
var SourceType = /* @__PURE__ */ ((SourceType2) => {
|
|
88
|
-
SourceType2["NONE"] = "none";
|
|
89
|
-
SourceType2["HLS"] = "hls";
|
|
90
|
-
SourceType2["DASH"] = "dash";
|
|
91
|
-
SourceType2["PROGRESSIVE"] = "progressive";
|
|
92
|
-
return SourceType2;
|
|
93
|
-
})(SourceType || {});
|
|
94
|
-
var LoadingState = /* @__PURE__ */ ((LoadingState2) => {
|
|
95
|
-
LoadingState2[LoadingState2["UNLOADED"] = 0] = "UNLOADED";
|
|
96
|
-
LoadingState2[LoadingState2["LOADING"] = 1] = "LOADING";
|
|
97
|
-
LoadingState2[LoadingState2["LOADED"] = 2] = "LOADED";
|
|
98
|
-
return LoadingState2;
|
|
99
|
-
})(LoadingState || {});
|
|
100
|
-
|
|
101
318
|
// src/hooks/usePlayer.ts
|
|
102
|
-
import { useRef } from "react";
|
|
103
319
|
function usePlayer(config) {
|
|
104
|
-
return
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// src/components/PlayerView/index.tsx
|
|
108
|
-
import React, { useRef as useRef3, useEffect } from "react";
|
|
109
|
-
import {
|
|
110
|
-
Platform as Platform2,
|
|
111
|
-
UIManager,
|
|
112
|
-
StyleSheet,
|
|
113
|
-
findNodeHandle as findNodeHandle2
|
|
114
|
-
} from "react-native";
|
|
115
|
-
|
|
116
|
-
// src/components/PlayerView/native.ts
|
|
117
|
-
import { requireNativeComponent } from "react-native";
|
|
118
|
-
var NativePlayerView = requireNativeComponent("NativePlayerView");
|
|
119
|
-
|
|
120
|
-
// src/hooks/useProxy.ts
|
|
121
|
-
import omit from "lodash.omit";
|
|
122
|
-
import { useCallback, useRef as useRef2 } from "react";
|
|
123
|
-
import { findNodeHandle } from "react-native";
|
|
124
|
-
function unwrapNativeEvent(event) {
|
|
125
|
-
return omit(event.nativeEvent, ["target"]);
|
|
126
|
-
}
|
|
127
|
-
function useProxy(viewRef, proxy) {
|
|
128
|
-
const proxyRef = useRef2(proxy);
|
|
129
|
-
return useCallback((event) => {
|
|
130
|
-
const node = event.target._nativeTag;
|
|
131
|
-
if (node === findNodeHandle(viewRef.current)) {
|
|
132
|
-
proxyRef.current?.(unwrapNativeEvent(event));
|
|
133
|
-
}
|
|
134
|
-
}, [viewRef]);
|
|
320
|
+
return useRef2(new Player(config)).current;
|
|
135
321
|
}
|
|
136
322
|
|
|
137
|
-
// src/
|
|
138
|
-
var
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
const commandId = Platform2.OS === "android" ? UIManager.NativePlayerView.Commands[command].toString() : UIManager.getViewManagerConfig("NativePlayerView").Commands[command];
|
|
145
|
-
UIManager.dispatchViewManagerCommand(node, commandId, Platform2.select({
|
|
146
|
-
ios: [playerId],
|
|
147
|
-
android: [node, playerId]
|
|
148
|
-
}));
|
|
149
|
-
}
|
|
150
|
-
function PlayerView(props) {
|
|
151
|
-
const nativeView = useRef3(null);
|
|
152
|
-
const style = StyleSheet.flatten([styles.baseStyle, props.style]);
|
|
153
|
-
useEffect(() => {
|
|
154
|
-
const node = findNodeHandle2(nativeView.current);
|
|
155
|
-
dispatch("attachPlayer", node, props.player.nativeId);
|
|
156
|
-
return () => {
|
|
157
|
-
dispatch("detachPlayer", node, props.player.nativeId);
|
|
158
|
-
};
|
|
159
|
-
}, [props.player.nativeId]);
|
|
160
|
-
return /* @__PURE__ */ React.createElement(NativePlayerView, {
|
|
161
|
-
ref: nativeView,
|
|
162
|
-
style,
|
|
163
|
-
onEvent: useProxy(nativeView, props.onEvent),
|
|
164
|
-
onPlayerActive: useProxy(nativeView, props.onPlayerActive),
|
|
165
|
-
onPlayerError: useProxy(nativeView, props.onPlayerError),
|
|
166
|
-
onPlayerWarning: useProxy(nativeView, props.onPlayerWarning),
|
|
167
|
-
onDestroy: useProxy(nativeView, props.onDestroy),
|
|
168
|
-
onMuted: useProxy(nativeView, props.onMuted),
|
|
169
|
-
onUnmuted: useProxy(nativeView, props.onUnmuted),
|
|
170
|
-
onReady: useProxy(nativeView, props.onReady),
|
|
171
|
-
onPaused: useProxy(nativeView, props.onPaused),
|
|
172
|
-
onPlay: useProxy(nativeView, props.onPlay),
|
|
173
|
-
onPlaying: useProxy(nativeView, props.onPlaying),
|
|
174
|
-
onPlaybackFinished: useProxy(nativeView, props.onPlaybackFinished),
|
|
175
|
-
onSeek: useProxy(nativeView, props.onSeek),
|
|
176
|
-
onSeeked: useProxy(nativeView, props.onSeeked),
|
|
177
|
-
onTimeChanged: useProxy(nativeView, props.onTimeChanged),
|
|
178
|
-
onSourceLoad: useProxy(nativeView, props.onSourceLoad),
|
|
179
|
-
onSourceLoaded: useProxy(nativeView, props.onSourceLoaded),
|
|
180
|
-
onSourceUnloaded: useProxy(nativeView, props.onSourceUnloaded),
|
|
181
|
-
onSourceError: useProxy(nativeView, props.onSourceError),
|
|
182
|
-
onSourceWarning: useProxy(nativeView, props.onSourceWarning)
|
|
183
|
-
});
|
|
184
|
-
}
|
|
323
|
+
// src/subtitleTrack.ts
|
|
324
|
+
var SubtitleFormat = /* @__PURE__ */ ((SubtitleFormat2) => {
|
|
325
|
+
SubtitleFormat2["CEA"] = "cea";
|
|
326
|
+
SubtitleFormat2["TTML"] = "ttml";
|
|
327
|
+
SubtitleFormat2["VTT"] = "vtt";
|
|
328
|
+
return SubtitleFormat2;
|
|
329
|
+
})(SubtitleFormat || {});
|
|
185
330
|
export {
|
|
331
|
+
Drm,
|
|
186
332
|
LoadingState,
|
|
187
333
|
Player,
|
|
188
334
|
PlayerView,
|
|
335
|
+
Source,
|
|
189
336
|
SourceType,
|
|
337
|
+
SubtitleFormat,
|
|
190
338
|
usePlayer
|
|
191
339
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bitmovin-player-react-native",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Official React Native bindings for Bitmovin's mobile Player SDKs.",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"module": "lib/index.mjs",
|
|
@@ -29,7 +29,8 @@
|
|
|
29
29
|
"build": "tsup ./src/index.ts --dts --target es2020 --format cjs,esm -d lib",
|
|
30
30
|
"example": "yarn --cwd example",
|
|
31
31
|
"pods": "cd example && pod-install --quiet",
|
|
32
|
-
"bootstrap": "yarn && yarn example && yarn pods"
|
|
32
|
+
"bootstrap": "yarn && yarn example && yarn pods",
|
|
33
|
+
"prepare": "husky install"
|
|
33
34
|
},
|
|
34
35
|
"keywords": [
|
|
35
36
|
"react-native",
|
|
@@ -48,8 +49,8 @@
|
|
|
48
49
|
"@react-native-community/eslint-config": "3.0.2",
|
|
49
50
|
"@types/jest": "26.0.24",
|
|
50
51
|
"@types/lodash.omit": "4.5.0",
|
|
51
|
-
"@types/react": "
|
|
52
|
-
"@types/react-native": "0.
|
|
52
|
+
"@types/react": "18.0.15",
|
|
53
|
+
"@types/react-native": "0.69.2",
|
|
53
54
|
"commitlint": "11.0.0",
|
|
54
55
|
"eslint": "8.18.0",
|
|
55
56
|
"eslint-config-prettier": "8.5.0",
|
|
@@ -1,25 +1,28 @@
|
|
|
1
1
|
import { NativeSyntheticEvent } from 'react-native';
|
|
2
2
|
import {
|
|
3
|
-
Event,
|
|
4
|
-
PlayerActiveEvent,
|
|
5
|
-
PlayerErrorEvent,
|
|
6
|
-
PlayerWarningEvent,
|
|
7
3
|
DestroyEvent,
|
|
4
|
+
Event,
|
|
8
5
|
MutedEvent,
|
|
9
|
-
UnmutedEvent,
|
|
10
|
-
ReadyEvent,
|
|
11
6
|
PausedEvent,
|
|
12
7
|
PlayEvent,
|
|
13
|
-
PlayingEvent,
|
|
14
8
|
PlaybackFinishedEvent,
|
|
9
|
+
PlayerActiveEvent,
|
|
10
|
+
PlayerErrorEvent,
|
|
11
|
+
PlayerWarningEvent,
|
|
12
|
+
PlayingEvent,
|
|
13
|
+
ReadyEvent,
|
|
15
14
|
SeekEvent,
|
|
16
15
|
SeekedEvent,
|
|
17
|
-
|
|
16
|
+
SourceErrorEvent,
|
|
18
17
|
SourceLoadEvent,
|
|
19
18
|
SourceLoadedEvent,
|
|
20
19
|
SourceUnloadedEvent,
|
|
21
|
-
SourceErrorEvent,
|
|
22
20
|
SourceWarningEvent,
|
|
21
|
+
SubtitleAddedEvent,
|
|
22
|
+
SubtitleChangedEvent,
|
|
23
|
+
SubtitleRemovedEvent,
|
|
24
|
+
TimeChangedEvent,
|
|
25
|
+
UnmutedEvent,
|
|
23
26
|
} from '../../events';
|
|
24
27
|
|
|
25
28
|
/**
|
|
@@ -27,26 +30,29 @@ import {
|
|
|
27
30
|
* Used to generate the specific events interface for each component.
|
|
28
31
|
*/
|
|
29
32
|
interface EventProps {
|
|
30
|
-
onEvent: Event;
|
|
31
|
-
onPlayerActive: PlayerActiveEvent;
|
|
32
|
-
onPlayerError: PlayerErrorEvent;
|
|
33
|
-
onPlayerWarning: PlayerWarningEvent;
|
|
34
33
|
onDestroy: DestroyEvent;
|
|
34
|
+
onEvent: Event;
|
|
35
35
|
onMuted: MutedEvent;
|
|
36
|
-
onUnmuted: UnmutedEvent;
|
|
37
|
-
onReady: ReadyEvent;
|
|
38
36
|
onPaused: PausedEvent;
|
|
39
37
|
onPlay: PlayEvent;
|
|
40
|
-
onPlaying: PlayingEvent;
|
|
41
38
|
onPlaybackFinished: PlaybackFinishedEvent;
|
|
39
|
+
onPlayerActive: PlayerActiveEvent;
|
|
40
|
+
onPlayerError: PlayerErrorEvent;
|
|
41
|
+
onPlayerWarning: PlayerWarningEvent;
|
|
42
|
+
onPlaying: PlayingEvent;
|
|
43
|
+
onReady: ReadyEvent;
|
|
42
44
|
onSeek: SeekEvent;
|
|
43
45
|
onSeeked: SeekedEvent;
|
|
44
|
-
|
|
46
|
+
onSourceError: SourceErrorEvent;
|
|
45
47
|
onSourceLoad: SourceLoadEvent;
|
|
46
48
|
onSourceLoaded: SourceLoadedEvent;
|
|
47
49
|
onSourceUnloaded: SourceUnloadedEvent;
|
|
48
|
-
onSourceError: SourceErrorEvent;
|
|
49
50
|
onSourceWarning: SourceWarningEvent;
|
|
51
|
+
onSubtitleAdded: SubtitleAddedEvent;
|
|
52
|
+
onSubtitleChanged: SubtitleChangedEvent;
|
|
53
|
+
onSubtitleRemoved: SubtitleRemovedEvent;
|
|
54
|
+
onTimeChanged: TimeChangedEvent;
|
|
55
|
+
onUnmuted: UnmutedEvent;
|
|
50
56
|
}
|
|
51
57
|
|
|
52
58
|
/**
|
|
@@ -66,41 +66,44 @@ function dispatch(command: string, node: number | null, playerId: string) {
|
|
|
66
66
|
export function PlayerView(props: PlayerViewProps) {
|
|
67
67
|
// Native view reference.
|
|
68
68
|
const nativeView = useRef(null);
|
|
69
|
+
// Native events proxy helper.
|
|
70
|
+
const proxy = useProxy(nativeView);
|
|
69
71
|
// Style resulting from merging `baseStyle` and `props.style`.
|
|
70
72
|
const style = StyleSheet.flatten([styles.baseStyle, props.style]);
|
|
71
73
|
useEffect(() => {
|
|
72
|
-
//
|
|
74
|
+
// Initialize native player instance if needed.
|
|
75
|
+
props.player.initialize();
|
|
76
|
+
// Attach native player to native `PlayerView`.
|
|
73
77
|
const node = findNodeHandle(nativeView.current);
|
|
74
78
|
dispatch('attachPlayer', node, props.player.nativeId);
|
|
75
|
-
|
|
76
|
-
// Detach `props.player` from native `PlayerView`.
|
|
77
|
-
dispatch('detachPlayer', node, props.player.nativeId);
|
|
78
|
-
};
|
|
79
|
-
}, [props.player.nativeId]);
|
|
79
|
+
}, [props.player]);
|
|
80
80
|
return (
|
|
81
81
|
<NativePlayerView
|
|
82
82
|
ref={nativeView}
|
|
83
83
|
style={style}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
84
|
+
onDestroy={proxy(props.onDestroy)}
|
|
85
|
+
onEvent={proxy(props.onEvent)}
|
|
86
|
+
onMuted={proxy(props.onMuted)}
|
|
87
|
+
onPaused={proxy(props.onPaused)}
|
|
88
|
+
onPlay={proxy(props.onPlay)}
|
|
89
|
+
onPlaybackFinished={proxy(props.onPlaybackFinished)}
|
|
90
|
+
onPlayerActive={proxy(props.onPlayerActive)}
|
|
91
|
+
onPlayerError={proxy(props.onPlayerError)}
|
|
92
|
+
onPlayerWarning={proxy(props.onPlayerWarning)}
|
|
93
|
+
onPlaying={proxy(props.onPlaying)}
|
|
94
|
+
onReady={proxy(props.onReady)}
|
|
95
|
+
onSeek={proxy(props.onSeek)}
|
|
96
|
+
onSeeked={proxy(props.onSeeked)}
|
|
97
|
+
onSourceError={proxy(props.onSourceError)}
|
|
98
|
+
onSourceLoad={proxy(props.onSourceLoad)}
|
|
99
|
+
onSourceLoaded={proxy(props.onSourceLoaded)}
|
|
100
|
+
onSourceUnloaded={proxy(props.onSourceUnloaded)}
|
|
101
|
+
onSourceWarning={proxy(props.onSourceWarning)}
|
|
102
|
+
onSubtitleAdded={proxy(props.onSubtitleAdded)}
|
|
103
|
+
onSubtitleChanged={proxy(props.onSubtitleChanged)}
|
|
104
|
+
onSubtitleRemoved={proxy(props.onSubtitleRemoved)}
|
|
105
|
+
onTimeChanged={proxy(props.onTimeChanged)}
|
|
106
|
+
onUnmuted={proxy(props.onUnmuted)}
|
|
104
107
|
/>
|
|
105
108
|
);
|
|
106
109
|
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents a FairPlay Streaming DRM config.
|
|
3
|
+
*/
|
|
4
|
+
export interface FairplayConfig {
|
|
5
|
+
/**
|
|
6
|
+
* The DRM license acquisition URL.
|
|
7
|
+
*/
|
|
8
|
+
licenseUrl: string;
|
|
9
|
+
/**
|
|
10
|
+
* The URL to the FairPlay Streaming certificate of the license server.
|
|
11
|
+
*/
|
|
12
|
+
certificateUrl?: string;
|
|
13
|
+
/**
|
|
14
|
+
* A dictionary to specify custom HTTP headers for the license request.
|
|
15
|
+
*/
|
|
16
|
+
licenseRequestHeaders?: Record<string, string>;
|
|
17
|
+
/**
|
|
18
|
+
* A dictionary to specify custom HTTP headers for the certificate request.
|
|
19
|
+
*/
|
|
20
|
+
certificateRequestHeaders?: Record<string, string>;
|
|
21
|
+
/**
|
|
22
|
+
* A block to prepare the loaded certificate before building SPC data and passing it into the
|
|
23
|
+
* system. This is needed if the server responds with anything else than the certificate, e.g. if
|
|
24
|
+
* the certificate is wrapped into a JSON object. The server response for the certificate request
|
|
25
|
+
* is passed as parameter “as is”.
|
|
26
|
+
*
|
|
27
|
+
* Note that both the passed `certificate` data and this block return value should be a Base64
|
|
28
|
+
* string. So use whatever solution suits you best to handle Base64 in React Native.
|
|
29
|
+
*
|
|
30
|
+
* @param certificate - Base64 encoded certificate data.
|
|
31
|
+
* @returns The processed Base64 encoded certificate.
|
|
32
|
+
*/
|
|
33
|
+
prepareCertificate?: (certificate: string) => string;
|
|
34
|
+
/**
|
|
35
|
+
* A block to prepare the data which is sent as the body of the POST license request.
|
|
36
|
+
* As many DRM providers expect different, vendor-specific messages, this can be done using
|
|
37
|
+
* this user-defined block.
|
|
38
|
+
*
|
|
39
|
+
* Note that both the passed `message` data and this block return value should be a Base64 string.
|
|
40
|
+
* So use whatever solution suits you best to handle Base64 in React Native.
|
|
41
|
+
*
|
|
42
|
+
* @param message - Base64 encoded message data.
|
|
43
|
+
* @param assetId - Stream asset ID.
|
|
44
|
+
* @returns The processed Base64 encoded message.
|
|
45
|
+
*/
|
|
46
|
+
prepareMessage?: (message: string, assetId: string) => string;
|
|
47
|
+
/**
|
|
48
|
+
* A block to prepare the data which is sent as the body of the POST request for syncing the DRM
|
|
49
|
+
* license information.
|
|
50
|
+
*
|
|
51
|
+
* Note that both the passed `syncMessage` data and this block return value should be a Base64
|
|
52
|
+
* string. So use whatever solution suits you best to handle Base64 in React Native.
|
|
53
|
+
*
|
|
54
|
+
* @param message - Base64 encoded message data.
|
|
55
|
+
* @param assetId - Asset ID.
|
|
56
|
+
* @returns The processed Base64 encoded sync message.
|
|
57
|
+
*/
|
|
58
|
+
prepareSyncMessage?: (syncMessage: string, assetId: string) => string;
|
|
59
|
+
/**
|
|
60
|
+
* A block to prepare the loaded CKC Data before passing it to the system. This is needed if the
|
|
61
|
+
* server responds with anything else than the license, e.g. if the license is wrapped into a JSON
|
|
62
|
+
* object.
|
|
63
|
+
*
|
|
64
|
+
* Note that both the passed `license` data and this block return value should be a Base64 string.
|
|
65
|
+
* So use whatever solution suits you best to handle Base64 in React Native.
|
|
66
|
+
*
|
|
67
|
+
* @param license - Base64 encoded license data.
|
|
68
|
+
* @returns The processed Base64 encoded license.
|
|
69
|
+
*/
|
|
70
|
+
prepareLicense?: (license: string) => string;
|
|
71
|
+
/**
|
|
72
|
+
* A block to prepare the URI (without the skd://) from the HLS manifest before passing it to the
|
|
73
|
+
* system.
|
|
74
|
+
*
|
|
75
|
+
* @param licenseServerUrl - License server URL string.
|
|
76
|
+
* @returns The processed license server URL string.
|
|
77
|
+
*/
|
|
78
|
+
prepareLicenseServerUrl?: (licenseServerUrl: string) => string;
|
|
79
|
+
/**
|
|
80
|
+
* A block to prepare the `contentId`, which is sent to the FairPlay Streaming license server as
|
|
81
|
+
* request body, and which is used to build the SPC data. As many DRM providers expect different,
|
|
82
|
+
* vendor-specific messages, this can be done using this user-defined block. The parameter is the
|
|
83
|
+
* skd:// URI extracted from the HLS manifest (m3u8) and the return value should be the contentID
|
|
84
|
+
* as string.
|
|
85
|
+
*
|
|
86
|
+
* @param contentId - Extracted content id string.
|
|
87
|
+
* @returns The processed contentId.
|
|
88
|
+
*/
|
|
89
|
+
prepareContentId?: (contentId: string) => string;
|
|
90
|
+
}
|