@applicaster/quick-brick-player 12.0.0-alpha.4620237415 → 12.0.0-alpha.4739493702
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/package.json +7 -7
- package/src/CellPlayer/ContextProvider.tsx +3 -3
- package/src/Player/index.tsx +67 -1057
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applicaster/quick-brick-player",
|
|
3
|
-
"version": "12.0.0-alpha.
|
|
3
|
+
"version": "12.0.0-alpha.4739493702",
|
|
4
4
|
"description": "Quick Brick Player",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -38,17 +38,17 @@
|
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"@applicaster/quick-brick-mobile-transport-controls": "12.0.0-rc.118",
|
|
40
40
|
"@applicaster/quick-brick-tv-transport-controls": "12.0.0-rc.112",
|
|
41
|
-
"@applicaster/zapp-react-native-tvos-app": "12.0.0-alpha.
|
|
42
|
-
"@applicaster/zapp-react-native-ui-components": "12.0.0-alpha.
|
|
43
|
-
"@applicaster/zapp-react-native-utils": "12.0.0-alpha.
|
|
41
|
+
"@applicaster/zapp-react-native-tvos-app": "12.0.0-alpha.4739493702",
|
|
42
|
+
"@applicaster/zapp-react-native-ui-components": "12.0.0-alpha.4739493702",
|
|
43
|
+
"@applicaster/zapp-react-native-utils": "12.0.0-alpha.4739493702",
|
|
44
44
|
"keymirror": "^0.1.1",
|
|
45
45
|
"query-string": "7.1.3",
|
|
46
46
|
"react-native-web-linear-gradient": "1.1.2",
|
|
47
47
|
"shaka-player": "4.3.5",
|
|
48
48
|
"typeface-montserrat": "^0.0.54",
|
|
49
|
-
"video.js": "
|
|
50
|
-
"videojs-contrib-eme": "^
|
|
51
|
-
"videojs-contrib-quality-levels": "
|
|
49
|
+
"video.js": "8.21.0",
|
|
50
|
+
"videojs-contrib-eme": "^5.5.1",
|
|
51
|
+
"videojs-contrib-quality-levels": "^4.1.0"
|
|
52
52
|
},
|
|
53
53
|
"peerDependencies": {
|
|
54
54
|
"@applicaster/quick-brick-xray": "*",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from "react";
|
|
2
2
|
import { LiveImageManager } from "@applicaster/zapp-react-native-ui-components/Components/VideoLive/LiveImageManager";
|
|
3
3
|
|
|
4
4
|
import { Context } from "./Context";
|
|
@@ -86,7 +86,7 @@ const initialEntryState = () => ({
|
|
|
86
86
|
});
|
|
87
87
|
|
|
88
88
|
export function ContextProvider(Component: ReactComponent<any>) {
|
|
89
|
-
return
|
|
89
|
+
return function DefaultPlayerProvider({
|
|
90
90
|
children,
|
|
91
91
|
}: CellActionContextProviderProps) {
|
|
92
92
|
const contextValue = React.useMemo(
|
|
@@ -104,5 +104,5 @@ export function ContextProvider(Component: ReactComponent<any>) {
|
|
|
104
104
|
<Component>{children}</Component>
|
|
105
105
|
</Context.Provider>
|
|
106
106
|
);
|
|
107
|
-
}
|
|
107
|
+
};
|
|
108
108
|
}
|
package/src/Player/index.tsx
CHANGED
|
@@ -2,74 +2,32 @@
|
|
|
2
2
|
/* eslint-disable react-native/no-color-literals */
|
|
3
3
|
|
|
4
4
|
import React from "react";
|
|
5
|
-
import
|
|
5
|
+
import videojs from "video.js";
|
|
6
6
|
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import TransportControlsTV from "@applicaster/quick-brick-tv-transport-controls";
|
|
7
|
+
import "video.js/dist/video-js.css";
|
|
8
|
+
import "videojs-contrib-eme";
|
|
10
9
|
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
isAndroidPlatform,
|
|
14
|
-
isApplePlatform,
|
|
15
|
-
isTV,
|
|
16
|
-
isTvOSPlatform,
|
|
17
|
-
isWeb,
|
|
18
|
-
} from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
10
|
+
import { View } from "react-native";
|
|
11
|
+
import { isWeb } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
19
12
|
|
|
20
|
-
|
|
13
|
+
const STREAM_TYPES = {
|
|
14
|
+
m3u8: "application/x-mpegURL",
|
|
15
|
+
mpd: "application/dash+xml",
|
|
16
|
+
};
|
|
21
17
|
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
const getStreamType = (url) => {
|
|
19
|
+
const extension = url.split(".").pop();
|
|
24
20
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
import { parseLanguageTracks } from "@applicaster/zapp-react-native-utils/playerUtils/configurationUtils";
|
|
28
|
-
import { DEFAULT_COLORS, SEEK_TIME } from "../utils/const";
|
|
29
|
-
import { AudioPlayerWrapper } from "./AudioLayer/AudioPlayerWrapper";
|
|
30
|
-
import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils";
|
|
31
|
-
import { getAllAccessibilityProps } from "@applicaster/zapp-react-native-utils/configurationUtils";
|
|
32
|
-
import { PlayNextData } from "@applicaster/zapp-react-native-ui-components/Components/PlayerContainer/PlayerContainer";
|
|
33
|
-
import { getTargetScreenDataFromEntry } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useTargetScreenData";
|
|
34
|
-
import { isAppleTV } from "@applicaster/zapp-react-native-ui-components/Helpers/Platform";
|
|
35
|
-
import {
|
|
36
|
-
AnimationComponent,
|
|
37
|
-
ComponentAnimationType,
|
|
38
|
-
} from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
|
|
39
|
-
import { PlayerAnalyticsManager } from "@applicaster/zapp-react-native-utils/analyticsUtils/PlayerAnalyticsManager";
|
|
40
|
-
import { PlayerAnalyticsTrackerI } from "@applicaster/zapp-react-native-utils/analyticsUtils/playerAnalyticsTracker";
|
|
41
|
-
|
|
42
|
-
import { RNPlayerManager } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/nativePlayerManager";
|
|
43
|
-
|
|
44
|
-
const styles = StyleSheet.create({
|
|
45
|
-
container: { flex: 1 },
|
|
46
|
-
playerContainerBlack: { backgroundColor: DEFAULT_COLORS.black },
|
|
47
|
-
playerContainerTransparent: { backgroundColor: DEFAULT_COLORS.transparent }, // android
|
|
48
|
-
audio: {
|
|
49
|
-
overflow: "hidden",
|
|
50
|
-
position: "absolute",
|
|
51
|
-
zIndex: 1,
|
|
52
|
-
},
|
|
53
|
-
playerSize: { width: "100%", height: "100%" },
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
const logger = createLogger({
|
|
57
|
-
category: Categories.PLAYER,
|
|
58
|
-
subsystem: Subsystem,
|
|
59
|
-
});
|
|
21
|
+
return STREAM_TYPES[extension];
|
|
22
|
+
};
|
|
60
23
|
|
|
61
24
|
export default class VideoPlayer extends React.Component<
|
|
62
25
|
QuickBrickPlayer.PlayerProps,
|
|
63
26
|
QuickBrickPlayer.NativePlayerState
|
|
64
27
|
> {
|
|
65
|
-
public static propTypes = {};
|
|
66
28
|
_root: any;
|
|
67
29
|
playerPluginId: string;
|
|
68
30
|
takeParentStyle: Record<any, any>;
|
|
69
|
-
playbackStarted = false;
|
|
70
|
-
needToResumeOnForeground: boolean = null;
|
|
71
|
-
private onVideoLoadCalled: boolean;
|
|
72
|
-
playNextData: PlayNextData;
|
|
73
31
|
|
|
74
32
|
state: QuickBrickPlayer.NativePlayerState = {
|
|
75
33
|
audioTrackId: null,
|
|
@@ -94,20 +52,8 @@ export default class VideoPlayer extends React.Component<
|
|
|
94
52
|
duration: 0,
|
|
95
53
|
};
|
|
96
54
|
|
|
97
|
-
private _tracker: PlayerAnalyticsTrackerI;
|
|
98
|
-
get analyticsTracker() {
|
|
99
|
-
if (!this._tracker) {
|
|
100
|
-
this._tracker = PlayerAnalyticsManager.getInstance().getTracker(
|
|
101
|
-
this.props.playerId
|
|
102
|
-
);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
return this._tracker;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
55
|
constructor(props) {
|
|
109
56
|
super(props);
|
|
110
|
-
this.onVideoLoadCalled = false; // android
|
|
111
57
|
|
|
112
58
|
this.takeParentStyle = isWeb()
|
|
113
59
|
? { width: "100%", flex: "1 1 auto", objectFit: "contain" }
|
|
@@ -116,59 +62,58 @@ export default class VideoPlayer extends React.Component<
|
|
|
116
62
|
this.playerPluginId = this.props?.playerPluginIdentifier;
|
|
117
63
|
}
|
|
118
64
|
|
|
119
|
-
componentWillUnmount() {
|
|
120
|
-
this.playbackStarted = false;
|
|
121
|
-
|
|
122
|
-
this.analyticsTracker.handleAnalyticEvent(GENERAL_EVENT.session_end);
|
|
123
|
-
this.onPlayerClosed();
|
|
124
|
-
|
|
125
|
-
if (isAndroidPlatform()) {
|
|
126
|
-
this.disablePiP();
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
65
|
componentDidMount() {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
66
|
+
const {
|
|
67
|
+
content: { src, type },
|
|
68
|
+
extensions: { drm },
|
|
69
|
+
} = this.props.entry;
|
|
70
|
+
|
|
71
|
+
const options = {
|
|
72
|
+
height: 1080,
|
|
73
|
+
width: 1920,
|
|
74
|
+
playsinline: undefined,
|
|
75
|
+
autoplay: true,
|
|
76
|
+
retryOnError: true,
|
|
77
|
+
defaultVolume: 1,
|
|
78
|
+
preload: "metadata",
|
|
79
|
+
html5: {
|
|
80
|
+
nativeTextTracks: false,
|
|
81
|
+
nativeVideoTracks: false,
|
|
82
|
+
nativeAudioTracks: false,
|
|
83
|
+
vhs: {
|
|
84
|
+
limitRenditionByPlayerDimensions: true,
|
|
85
|
+
useDevicePixelRatio: true,
|
|
86
|
+
overrideNative: true,
|
|
87
|
+
enableLowInitialPlaylist: true,
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
};
|
|
134
91
|
|
|
135
|
-
|
|
136
|
-
const srcPath = ["entry", "content", "src"];
|
|
92
|
+
const player = videojs(this._root, options);
|
|
137
93
|
|
|
138
|
-
|
|
139
|
-
// null when trying to exit the player. This prevents a crash in that scenario
|
|
140
|
-
return !(R.path(srcPath, this.props) && !R.path(srcPath, nextProps));
|
|
141
|
-
}
|
|
94
|
+
let keySystems;
|
|
142
95
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
this.props.castAction?.state?.connected &&
|
|
146
|
-
!this.state.isCastConnected
|
|
147
|
-
) {
|
|
148
|
-
this.stopBackgroundPlayback();
|
|
149
|
-
this.setState({ isCastConnected: true });
|
|
150
|
-
}
|
|
96
|
+
if (drm) {
|
|
97
|
+
player.eme();
|
|
151
98
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
99
|
+
keySystems = {
|
|
100
|
+
"com.widevine.alpha": {
|
|
101
|
+
audioRobustness: "SW_SECURE_CRYPTO",
|
|
102
|
+
videoRobustness: "SW_SECURE_CRYPTO",
|
|
103
|
+
url: drm?.widevine?.license_url,
|
|
104
|
+
},
|
|
105
|
+
};
|
|
157
106
|
}
|
|
158
107
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
108
|
+
player.src([
|
|
109
|
+
{
|
|
110
|
+
src: src,
|
|
111
|
+
type: getStreamType(type),
|
|
112
|
+
keySystems,
|
|
113
|
+
},
|
|
114
|
+
]);
|
|
163
115
|
}
|
|
164
116
|
|
|
165
|
-
// For close button
|
|
166
|
-
public closeNativePlayer = () => {
|
|
167
|
-
this.stopBackgroundPlayback();
|
|
168
|
-
};
|
|
169
|
-
|
|
170
|
-
getPlayNextData = () => this.props.playNextData as PlayNextData;
|
|
171
|
-
|
|
172
117
|
/**
|
|
173
118
|
* Assigns root / ref of the player.
|
|
174
119
|
*/
|
|
@@ -176,953 +121,18 @@ export default class VideoPlayer extends React.Component<
|
|
|
176
121
|
this._root = component;
|
|
177
122
|
};
|
|
178
123
|
|
|
179
|
-
getPluginConfiguration = () => {
|
|
180
|
-
return this.props.pluginConfiguration;
|
|
181
|
-
};
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* This method is for the events that have no implementation in react but are being invoked by native
|
|
185
|
-
* When we get the synthetic event we need to pull the data in the nativeEvent object
|
|
186
|
-
* nativeEvent contains the return value from native
|
|
187
|
-
* Value could be null if nothing return
|
|
188
|
-
*/
|
|
189
|
-
unHandledEvent = (eventName) => {
|
|
190
|
-
return function dispatchUnhandledEvent({ nativeEvent = null }) {
|
|
191
|
-
logger.warning({
|
|
192
|
-
message:
|
|
193
|
-
"You have invoked an event that is being deprecated or unhandled",
|
|
194
|
-
data: { eventName, nativeEvent },
|
|
195
|
-
});
|
|
196
|
-
};
|
|
197
|
-
};
|
|
198
|
-
|
|
199
|
-
isReactNativeMethodsSupported = () =>
|
|
200
|
-
this.props.PlayerComponent === "QuickBrickDefaultPlayerView" ||
|
|
201
|
-
this.props.PlayerComponent === "PlayerModule";
|
|
202
|
-
|
|
203
|
-
pause = () => {
|
|
204
|
-
// TODO: Call player instance controller methods directly
|
|
205
|
-
// this._root was added here because chromecast,
|
|
206
|
-
// is checking player state for the pause
|
|
207
|
-
if (
|
|
208
|
-
this.isReactNativeMethodsSupported() &&
|
|
209
|
-
RNPlayerManager?.[this.playerPluginId]?.pause &&
|
|
210
|
-
this._root
|
|
211
|
-
) {
|
|
212
|
-
if (!this.state.paused) {
|
|
213
|
-
const node = findNodeHandle(this._root);
|
|
214
|
-
|
|
215
|
-
if (!node) {
|
|
216
|
-
return;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
RNPlayerManager?.[this.playerPluginId]?.pause(node);
|
|
220
|
-
}
|
|
221
|
-
} else {
|
|
222
|
-
this.setState({ paused: true });
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
// User invoked player pause action
|
|
226
|
-
this.needToResumeOnForeground = null;
|
|
227
|
-
};
|
|
228
|
-
|
|
229
|
-
play = () => {
|
|
230
|
-
// TODO: Call player instance controller methods directly
|
|
231
|
-
// this._root was added here because chromecast,
|
|
232
|
-
// is checking player state for the pause
|
|
233
|
-
if (
|
|
234
|
-
this.isReactNativeMethodsSupported() &&
|
|
235
|
-
RNPlayerManager?.[this.playerPluginId]?.play &&
|
|
236
|
-
this._root
|
|
237
|
-
) {
|
|
238
|
-
if (this.state.paused) {
|
|
239
|
-
const node = findNodeHandle(this._root);
|
|
240
|
-
|
|
241
|
-
if (!node) {
|
|
242
|
-
return;
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
RNPlayerManager?.[this.playerPluginId]?.play(node);
|
|
246
|
-
}
|
|
247
|
-
} else {
|
|
248
|
-
this.setState({ paused: false });
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
// User invoked player pause action
|
|
252
|
-
this.needToResumeOnForeground = null;
|
|
253
|
-
};
|
|
254
|
-
|
|
255
|
-
stopBackgroundPlayback = () => {
|
|
256
|
-
if (
|
|
257
|
-
this.isReactNativeMethodsSupported() &&
|
|
258
|
-
RNPlayerManager?.[this.playerPluginId]?.stopBackgroundPlayback
|
|
259
|
-
) {
|
|
260
|
-
RNPlayerManager?.[this.playerPluginId]?.stopBackgroundPlayback();
|
|
261
|
-
}
|
|
262
|
-
};
|
|
263
|
-
|
|
264
|
-
forward = (seekTime = SEEK_TIME) => {
|
|
265
|
-
const currentTime = this.state.currentTime;
|
|
266
|
-
|
|
267
|
-
const _duration = this.state.isLive
|
|
268
|
-
? this.state?.seekableDuration
|
|
269
|
-
: this.getDuration();
|
|
270
|
-
|
|
271
|
-
const _time = this.state.isLive
|
|
272
|
-
? R.clamp(0, _duration, currentTime - seekTime)
|
|
273
|
-
: R.clamp(0, _duration, currentTime + seekTime);
|
|
274
|
-
|
|
275
|
-
const seekTo = {
|
|
276
|
-
time: _time,
|
|
277
|
-
tolerance: 1,
|
|
278
|
-
};
|
|
279
|
-
|
|
280
|
-
this.setState({ seek: seekTo });
|
|
281
|
-
};
|
|
282
|
-
|
|
283
|
-
rewind = (seekTime = SEEK_TIME) => {
|
|
284
|
-
const currentTime = this.state.currentTime;
|
|
285
|
-
|
|
286
|
-
const _duration = this.state.isLive
|
|
287
|
-
? this.state?.seekableDuration
|
|
288
|
-
: this.getDuration();
|
|
289
|
-
|
|
290
|
-
const _time = this.state.isLive
|
|
291
|
-
? R.clamp(0, _duration, currentTime + seekTime)
|
|
292
|
-
: R.clamp(0, _duration, currentTime - seekTime);
|
|
293
|
-
|
|
294
|
-
const seekTo = {
|
|
295
|
-
time: _time,
|
|
296
|
-
tolerance: 1,
|
|
297
|
-
};
|
|
298
|
-
|
|
299
|
-
this.setState({ seek: seekTo });
|
|
300
|
-
};
|
|
301
|
-
|
|
302
|
-
seeking = (time, tolerance = 1) => {
|
|
303
|
-
if (isNaN(time)) {
|
|
304
|
-
logger.error({
|
|
305
|
-
message: `Specified time is not a number time: ${time}`,
|
|
306
|
-
});
|
|
307
|
-
|
|
308
|
-
return;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
// This hack was added, if send same value to seek two times like 0,
|
|
312
|
-
// It will not property change callback to native.
|
|
313
|
-
// TODO: This func must be refactored to View React method.
|
|
314
|
-
if (time === this.state.seek.time) {
|
|
315
|
-
this.setState({ seek: {} }, () => {
|
|
316
|
-
this.setState({ seek: { time, tolerance } });
|
|
317
|
-
});
|
|
318
|
-
} else {
|
|
319
|
-
this.setState({ seek: { time, tolerance } });
|
|
320
|
-
}
|
|
321
|
-
};
|
|
322
|
-
|
|
323
|
-
selectTrack = (selected) => {
|
|
324
|
-
const { trackType, id, language } = selected || {};
|
|
325
|
-
|
|
326
|
-
const isOff = language === "Off";
|
|
327
|
-
|
|
328
|
-
if (!id) {
|
|
329
|
-
logger.error({
|
|
330
|
-
message:
|
|
331
|
-
"Failed to set Audio or Text track. Language track is missing required parameter ID",
|
|
332
|
-
data: { selected },
|
|
333
|
-
});
|
|
334
|
-
|
|
335
|
-
return;
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
switch (trackType) {
|
|
339
|
-
case "text":
|
|
340
|
-
this.setState({
|
|
341
|
-
textTrackId: isOff ? null : id,
|
|
342
|
-
});
|
|
343
|
-
|
|
344
|
-
break;
|
|
345
|
-
case "audio":
|
|
346
|
-
this.setState({
|
|
347
|
-
audioTrackId: id,
|
|
348
|
-
});
|
|
349
|
-
|
|
350
|
-
break;
|
|
351
|
-
}
|
|
352
|
-
};
|
|
353
|
-
|
|
354
|
-
setPlaybackRate = (rate = 1.0) => {
|
|
355
|
-
this.setState({ rate });
|
|
356
|
-
};
|
|
357
|
-
|
|
358
|
-
getCurrentTime = () => {
|
|
359
|
-
return this.state.currentTime;
|
|
360
|
-
};
|
|
361
|
-
|
|
362
|
-
getDuration = () => {
|
|
363
|
-
return this.state.duration;
|
|
364
|
-
};
|
|
365
|
-
|
|
366
|
-
getState = () => {
|
|
367
|
-
return { ...this.state, fullscreen: Boolean(this.props?.fullscreen) };
|
|
368
|
-
};
|
|
369
|
-
|
|
370
|
-
/**
|
|
371
|
-
* Handles key events transmitted by the native
|
|
372
|
-
* Adds the key event to the playerState so that it can be consumed by interaction manager
|
|
373
|
-
* Needs for Android
|
|
374
|
-
*/
|
|
375
|
-
onKeyDown = (event) => {
|
|
376
|
-
this.setState({
|
|
377
|
-
keyEvent: event,
|
|
378
|
-
});
|
|
379
|
-
};
|
|
380
|
-
|
|
381
|
-
onPlayerPresented = () => {
|
|
382
|
-
this.analyticsTracker?.handleAnalyticEvent(GENERAL_EVENT.player_presented);
|
|
383
|
-
};
|
|
384
|
-
|
|
385
|
-
onPlayerClosed = () => {
|
|
386
|
-
this.analyticsTracker?.handleAnalyticEvent(GENERAL_EVENT.player_closed);
|
|
387
|
-
};
|
|
388
|
-
|
|
389
|
-
onVideoEnd = () => {
|
|
390
|
-
this.setState({ displayOverlay: !this.state.displayOverlay }, () => {
|
|
391
|
-
if (this.state?.displayOverlay) {
|
|
392
|
-
this.props?.listener?.onVideoEnd({});
|
|
393
|
-
}
|
|
394
|
-
});
|
|
395
|
-
};
|
|
396
|
-
|
|
397
|
-
// TODO: Should be unified on both platform
|
|
398
|
-
onVideoError = ({ nativeEvent }) => {
|
|
399
|
-
const { message } = nativeEvent;
|
|
400
|
-
|
|
401
|
-
return this.props?.listener?.onError(new Error(message));
|
|
402
|
-
};
|
|
403
|
-
|
|
404
|
-
onPlayerPause = ({ nativeEvent = null }) => {
|
|
405
|
-
this.setState({ paused: true });
|
|
406
|
-
this.props?.listener?.onPlayerPause(nativeEvent);
|
|
407
|
-
};
|
|
408
|
-
|
|
409
|
-
onPlayerResume = ({ nativeEvent = null }) => {
|
|
410
|
-
const { isAd, resume } = this.state;
|
|
411
|
-
const isNotAnAd = !isAd;
|
|
412
|
-
this.setState({ paused: false });
|
|
413
|
-
this.props?.listener?.onPlayerResume?.({ nativeEvent });
|
|
414
|
-
|
|
415
|
-
if (isNotAnAd && !resume) {
|
|
416
|
-
this.setState({ resume: true });
|
|
417
|
-
}
|
|
418
|
-
};
|
|
419
|
-
|
|
420
|
-
onPlayerSeekComplete = ({ nativeEvent }) => {
|
|
421
|
-
this.props?.listener?.onPlayerSeekComplete(nativeEvent);
|
|
422
|
-
};
|
|
423
|
-
|
|
424
|
-
onPlayerSeekStart = ({ nativeEvent }) => {
|
|
425
|
-
this.props?.listener?.onPlayerSeekStart(nativeEvent);
|
|
426
|
-
};
|
|
427
|
-
|
|
428
|
-
onBufferStart = ({ nativeEvent }) => {
|
|
429
|
-
this.props?.listener?.onBufferStart(nativeEvent);
|
|
430
|
-
};
|
|
431
|
-
|
|
432
|
-
onBufferComplete = ({ nativeEvent }) => {
|
|
433
|
-
this.props?.listener?.onBufferComplete(nativeEvent);
|
|
434
|
-
};
|
|
435
|
-
|
|
436
|
-
onAdBegin = ({ nativeEvent }) => {
|
|
437
|
-
this.setState({ isAd: true });
|
|
438
|
-
this.props.listener?.onAdBegin?.(nativeEvent);
|
|
439
|
-
};
|
|
440
|
-
|
|
441
|
-
onAdBreakBegin = ({ nativeEvent }) => {
|
|
442
|
-
this.setState({ isAd: true });
|
|
443
|
-
this.props.listener?.onAdBreakBegin?.(nativeEvent);
|
|
444
|
-
};
|
|
445
|
-
|
|
446
|
-
onAdBreakEnd = ({ nativeEvent }) => {
|
|
447
|
-
this.setState({ isAd: false });
|
|
448
|
-
this.props.listener?.onAdBreakEnd?.(nativeEvent);
|
|
449
|
-
};
|
|
450
|
-
|
|
451
|
-
onAdEnd = ({ nativeEvent }) => {
|
|
452
|
-
this.setState({ isAd: false });
|
|
453
|
-
this.props.listener?.onAdEnd?.(nativeEvent);
|
|
454
|
-
};
|
|
455
|
-
|
|
456
|
-
onAdError = ({ nativeEvent }) => {
|
|
457
|
-
this.setState({ isAd: false });
|
|
458
|
-
this.props.listener?.onAdError?.(nativeEvent);
|
|
459
|
-
};
|
|
460
|
-
|
|
461
|
-
onAdRequest = ({ nativeEvent }) => {
|
|
462
|
-
this.props.listener?.onAdRequest?.(nativeEvent);
|
|
463
|
-
};
|
|
464
|
-
|
|
465
|
-
onAdClicked = ({ nativeEvent }) => {
|
|
466
|
-
// Broadcast click event
|
|
467
|
-
this.props.playerEvent("ad-clicked", nativeEvent);
|
|
468
|
-
this.props.listener?.onAdClicked?.(nativeEvent);
|
|
469
|
-
};
|
|
470
|
-
|
|
471
|
-
onAdTapped = ({ nativeEvent }) => {
|
|
472
|
-
// Broadcast click event
|
|
473
|
-
this.props.playerEvent("ad-tapped", nativeEvent);
|
|
474
|
-
this.props.listener?.onAdTapped?.(nativeEvent);
|
|
475
|
-
};
|
|
476
|
-
|
|
477
|
-
onPlaybackStalled = () => {
|
|
478
|
-
return this.props?.updatePlayerState?.("stalled");
|
|
479
|
-
};
|
|
480
|
-
|
|
481
|
-
onPlayerAttached = ({ nativeEvent }) => {
|
|
482
|
-
this.props.listener?.onPlayerAttached?.(nativeEvent);
|
|
483
|
-
};
|
|
484
|
-
|
|
485
|
-
onPlayerDetached = ({ nativeEvent }) => {
|
|
486
|
-
this.props.listener?.onPlayerDetached?.(nativeEvent);
|
|
487
|
-
};
|
|
488
|
-
|
|
489
|
-
onVideoFullscreenPlayerDidDismiss = () => {
|
|
490
|
-
this.props.listener?.onVideoFullscreenPlayerDidDismiss?.();
|
|
491
|
-
};
|
|
492
|
-
|
|
493
|
-
onVideoFullscreenPlayerDidPresent = () => {
|
|
494
|
-
this.props.listener?.onVideoFullscreenPlayerDidPresent?.();
|
|
495
|
-
};
|
|
496
|
-
|
|
497
|
-
onVideoFullscreenPlayerWillDismiss = () => {
|
|
498
|
-
this.props.listener?.onVideoFullscreenPlayerWillDismiss?.();
|
|
499
|
-
};
|
|
500
|
-
|
|
501
|
-
onVideoFullscreenPlayerWillPresent = () => {
|
|
502
|
-
this.props.listener?.onVideoFullscreenPlayerWillPresent?.();
|
|
503
|
-
};
|
|
504
|
-
|
|
505
|
-
onPlayerClose = () => {
|
|
506
|
-
this.props.listener?.onPlayerClose?.();
|
|
507
|
-
};
|
|
508
|
-
|
|
509
|
-
onPiPEnter = () => {
|
|
510
|
-
this.setState({ piped: true });
|
|
511
|
-
this.props.openPiP();
|
|
512
|
-
};
|
|
513
|
-
|
|
514
|
-
onPiPExit = () => {
|
|
515
|
-
this.setState({ piped: false });
|
|
516
|
-
this.props.closePiP();
|
|
517
|
-
};
|
|
518
|
-
|
|
519
|
-
onPiPCloseByUser = () => {
|
|
520
|
-
if (this.state.piped) {
|
|
521
|
-
const node = findNodeHandle(this._root);
|
|
522
|
-
|
|
523
|
-
if (!node) {
|
|
524
|
-
return;
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
playerManager.close();
|
|
528
|
-
}
|
|
529
|
-
};
|
|
530
|
-
|
|
531
|
-
disablePiP = () => {
|
|
532
|
-
const node = findNodeHandle(this._root);
|
|
533
|
-
|
|
534
|
-
if (!node) {
|
|
535
|
-
return;
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
RNPlayerManager?.[this.playerPluginId]?.disablePiP?.(node);
|
|
539
|
-
// TODO: Remove after implementing play next for PiP
|
|
540
|
-
RNPlayerManager?.[this.playerPluginId]?.closePiP?.(node);
|
|
541
|
-
};
|
|
542
|
-
|
|
543
|
-
onVideoBuffer = ({ nativeEvent }) => {
|
|
544
|
-
// video buffer event is invoked from native side when asking the player to pause
|
|
545
|
-
// this causes the buffer animation to trigger and incorrectly request to update state
|
|
546
|
-
if (this.state.paused) {
|
|
547
|
-
return;
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
// TODO: This events must be called from native directly
|
|
551
|
-
if (nativeEvent?.isBuffering) {
|
|
552
|
-
this.onBufferStart({ nativeEvent });
|
|
553
|
-
} else {
|
|
554
|
-
this.onBufferComplete({ nativeEvent });
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
return this.props?.updatePlayerState?.("loadstart");
|
|
558
|
-
};
|
|
559
|
-
|
|
560
|
-
onVideoLoad = ({ nativeEvent }) => {
|
|
561
|
-
const duration = nativeEvent.duration;
|
|
562
|
-
const currentTime = nativeEvent.currentTime;
|
|
563
|
-
|
|
564
|
-
// check if content is loaded
|
|
565
|
-
if (duration < 0) {
|
|
566
|
-
return;
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
this.setState(
|
|
570
|
-
{
|
|
571
|
-
currentTime,
|
|
572
|
-
duration,
|
|
573
|
-
},
|
|
574
|
-
() => {
|
|
575
|
-
this.props?.listener?.onVideoLoad(nativeEvent);
|
|
576
|
-
|
|
577
|
-
if (!this.playbackStarted) {
|
|
578
|
-
this.playbackStarted = true;
|
|
579
|
-
// TODO: Remove not needed anymore, implemented on player.tsx
|
|
580
|
-
this.props?.listener?.onLoad(nativeEvent);
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
if (!this.state.isAd && !this.onVideoLoadCalled) {
|
|
584
|
-
// TODO: Hack, needs to remove
|
|
585
|
-
this.onVideoLoadCalled = true;
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
);
|
|
589
|
-
};
|
|
590
|
-
|
|
591
|
-
onTracksChanged = ({ nativeEvent }) => {
|
|
592
|
-
const { textTracks, audioTracks, audioTrackId, textTrackId } =
|
|
593
|
-
parseLanguageTracks(nativeEvent);
|
|
594
|
-
|
|
595
|
-
this.setState(
|
|
596
|
-
{
|
|
597
|
-
audioTrackId,
|
|
598
|
-
textTrackId,
|
|
599
|
-
},
|
|
600
|
-
() => {
|
|
601
|
-
this.props?.listener?.onTracksChanged?.({
|
|
602
|
-
textTracks,
|
|
603
|
-
audioTracks,
|
|
604
|
-
audioTrackId,
|
|
605
|
-
textTrackId,
|
|
606
|
-
});
|
|
607
|
-
}
|
|
608
|
-
);
|
|
609
|
-
};
|
|
610
|
-
|
|
611
|
-
onVideoProgress = ({ nativeEvent }) => {
|
|
612
|
-
const duration = nativeEvent.duration;
|
|
613
|
-
const currentTime = nativeEvent.currentTime;
|
|
614
|
-
const seekableDuration = nativeEvent.seekableDuration;
|
|
615
|
-
const isLive = nativeEvent.isLive;
|
|
616
|
-
|
|
617
|
-
// TODO: Delete states on view
|
|
618
|
-
this.setState({
|
|
619
|
-
currentTime,
|
|
620
|
-
duration,
|
|
621
|
-
resume: false,
|
|
622
|
-
seekableDuration,
|
|
623
|
-
isLive,
|
|
624
|
-
});
|
|
625
|
-
|
|
626
|
-
this.props?.listener?.onVideoProgress({
|
|
627
|
-
currentTime,
|
|
628
|
-
duration,
|
|
629
|
-
item: this.props?.entry,
|
|
630
|
-
seekableDuration,
|
|
631
|
-
isLive,
|
|
632
|
-
});
|
|
633
|
-
};
|
|
634
|
-
|
|
635
|
-
onPlaybackRateChange = ({ nativeEvent }) => {
|
|
636
|
-
if (nativeEvent.playbackRate !== this.state.rate) {
|
|
637
|
-
this.setState({ rate: nativeEvent.playbackRate });
|
|
638
|
-
|
|
639
|
-
if (this.props?.listener?.onPlaybackRateChange) {
|
|
640
|
-
this.props?.listener?.onPlaybackRateChange(nativeEvent);
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
if (nativeEvent?.playbackRate > 0) {
|
|
644
|
-
if (this.props?.listener?.onPlayerResume) {
|
|
645
|
-
this.props?.listener?.onPlayerResume(nativeEvent);
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
|
-
};
|
|
650
|
-
|
|
651
|
-
appStateChange = (appState, previousAppState) => {
|
|
652
|
-
const { pluginConfiguration } = this.props;
|
|
653
|
-
const shouldPauseOnExit = pluginConfiguration?.nowPlayingEnabled !== true;
|
|
654
|
-
|
|
655
|
-
// TODO: This const must be imported from upstate change of TS
|
|
656
|
-
const ACTIVE = "active";
|
|
657
|
-
const BACKGROUND = "background";
|
|
658
|
-
const INACTIVE = "inactive";
|
|
659
|
-
|
|
660
|
-
if (
|
|
661
|
-
previousAppState === ACTIVE &&
|
|
662
|
-
appState &&
|
|
663
|
-
(appState === BACKGROUND || appState === INACTIVE)
|
|
664
|
-
) {
|
|
665
|
-
if ((isTV() || shouldPauseOnExit) && this.props.mode !== "PIP") {
|
|
666
|
-
const wasPlaying = !this.state.paused;
|
|
667
|
-
this.pause();
|
|
668
|
-
this.needToResumeOnForeground = wasPlaying;
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
if (appState && appState === ACTIVE && previousAppState !== ACTIVE) {
|
|
673
|
-
if (this.needToResumeOnForeground) {
|
|
674
|
-
this.play();
|
|
675
|
-
this.needToResumeOnForeground = null;
|
|
676
|
-
}
|
|
677
|
-
}
|
|
678
|
-
};
|
|
679
|
-
|
|
680
|
-
childrenWithPlayNext = () => {
|
|
681
|
-
if (!isTvOSPlatform() || !this.getPlayNextData()) {
|
|
682
|
-
return this.props.children;
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
// tvos only
|
|
686
|
-
const { docked, entry } = this.props;
|
|
687
|
-
|
|
688
|
-
const children = R.pathOr([], "children", this.props);
|
|
689
|
-
|
|
690
|
-
return [
|
|
691
|
-
...children,
|
|
692
|
-
<PlayNextOverlay
|
|
693
|
-
key="play-next-overlay"
|
|
694
|
-
item={entry}
|
|
695
|
-
playerIsDocked={docked}
|
|
696
|
-
pluginConfiguration={this.getPluginConfiguration()}
|
|
697
|
-
playerId={this.props.playerId}
|
|
698
|
-
playNextData={this.getPlayNextData()}
|
|
699
|
-
setNextVideoPreloadThresholdPercentage={
|
|
700
|
-
this.props.setNextVideoPreloadThresholdPercentage
|
|
701
|
-
}
|
|
702
|
-
/>,
|
|
703
|
-
];
|
|
704
|
-
};
|
|
705
|
-
|
|
706
124
|
render() {
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
isTabletPortrait,
|
|
715
|
-
muted,
|
|
716
|
-
style,
|
|
717
|
-
castAction,
|
|
718
|
-
controller,
|
|
719
|
-
startComponentsAnimation,
|
|
720
|
-
} = this.props;
|
|
721
|
-
|
|
722
|
-
const supportNativeCast = controller.supportNativeCast();
|
|
723
|
-
|
|
724
|
-
const { audioTrackId, keyEvent, paused, seek, textTrackId, rate } =
|
|
725
|
-
this.state;
|
|
726
|
-
|
|
727
|
-
const isAudioItem =
|
|
728
|
-
entry?.content?.type?.includes?.("audio") ||
|
|
729
|
-
entry?.type?.value === "audio";
|
|
730
|
-
|
|
731
|
-
const getStyle = (dimensions) => {
|
|
732
|
-
const generalStyles = isAudioItem ? styles.audio : styles.video;
|
|
733
|
-
|
|
734
|
-
if (isAndroidPlatform() && isAudioItem) {
|
|
735
|
-
return generalStyles;
|
|
736
|
-
}
|
|
737
|
-
|
|
738
|
-
return { ...generalStyles, ...dimensions };
|
|
739
|
-
};
|
|
740
|
-
|
|
741
|
-
const getBackgroundImageStyle = (dimensions): any =>
|
|
742
|
-
Object.assign(
|
|
743
|
-
{},
|
|
744
|
-
isAudioItem ? styles.audio : { position: "absolute" },
|
|
745
|
-
dimensions
|
|
746
|
-
);
|
|
747
|
-
|
|
748
|
-
const nativeResizeMode = "ScaleAspectFit";
|
|
749
|
-
|
|
750
|
-
const nowPlayingEnabled =
|
|
751
|
-
this.props?.pluginConfiguration?.nowPlayingEnabled;
|
|
752
|
-
|
|
753
|
-
const enableAutoAudioTrackSelection =
|
|
754
|
-
this.props.pluginConfiguration?.enable_auto_audio_track_selection;
|
|
755
|
-
|
|
756
|
-
const minimumAllowedSeekableDurationInSeconds =
|
|
757
|
-
this.props?.pluginConfiguration?.minimumAllowedSeekableDurationInSeconds;
|
|
758
|
-
// In case no seeking duration or it less than 10 min we do not want to enable live seeking feature
|
|
759
|
-
|
|
760
|
-
const liveSeekingEnabled =
|
|
761
|
-
(this.props.pluginConfiguration?.liveSeekingEnabled &&
|
|
762
|
-
this.state?.seekableDuration >
|
|
763
|
-
minimumAllowedSeekableDurationInSeconds) ||
|
|
764
|
-
false;
|
|
765
|
-
|
|
766
|
-
// keep undefined if not present, since not all native players have the property
|
|
767
|
-
const liveCatchUpEnabled =
|
|
768
|
-
this.props.pluginConfiguration?.liveCatchUpEnabled;
|
|
769
|
-
|
|
770
|
-
// TODO: Get screen data more reliable way useCurrentScreenData
|
|
771
|
-
const screenData = getTargetScreenDataFromEntry(this.props.playableItem);
|
|
772
|
-
|
|
773
|
-
const isInlineTV = screenData?.ui_components?.length > 0 && isTV();
|
|
774
|
-
|
|
775
|
-
let platformSpecificProps: any = isApplePlatform()
|
|
776
|
-
? {
|
|
777
|
-
resizeMode: nativeResizeMode,
|
|
778
|
-
}
|
|
779
|
-
: {};
|
|
780
|
-
|
|
781
|
-
const supportsNativeControls =
|
|
782
|
-
!!this.props.controller?.supportsNativeControls?.();
|
|
783
|
-
|
|
784
|
-
const controls = isAppleTV()
|
|
785
|
-
? (supportsNativeControls && !isInlineTV) || !!this.getPlayNextData()
|
|
786
|
-
: supportsNativeControls && !this.getPlayNextData();
|
|
787
|
-
|
|
788
|
-
const shouldUseNativeControls =
|
|
789
|
-
controls &&
|
|
790
|
-
!startComponentsAnimation &&
|
|
791
|
-
!docked &&
|
|
792
|
-
!castAction?.state?.connected;
|
|
793
|
-
|
|
794
|
-
platformSpecificProps = {
|
|
795
|
-
...platformSpecificProps,
|
|
796
|
-
controls: shouldUseNativeControls,
|
|
797
|
-
};
|
|
798
|
-
|
|
799
|
-
const pictureInPictureEnabled =
|
|
800
|
-
this.props.pluginConfiguration?.pictureInPictureEnabled;
|
|
801
|
-
|
|
802
|
-
const nativeProps = {
|
|
803
|
-
entry, // Must be passed first in list
|
|
804
|
-
...platformSpecificProps,
|
|
805
|
-
audioTrackId,
|
|
806
|
-
docked,
|
|
807
|
-
enableAutoAudioTrackSelection,
|
|
808
|
-
fullscreen, // TODO: Check fullscreen params not crash
|
|
809
|
-
inline,
|
|
810
|
-
muted,
|
|
811
|
-
nowPlayingEnabled,
|
|
812
|
-
paused,
|
|
813
|
-
seek,
|
|
814
|
-
rate,
|
|
815
|
-
textTrackId,
|
|
816
|
-
liveSeekingEnabled,
|
|
817
|
-
liveCatchUpEnabled,
|
|
818
|
-
playerId: this.props.playerId,
|
|
819
|
-
pictureInPictureEnabled,
|
|
820
|
-
seekStep:
|
|
821
|
-
(this.props.pluginConfiguration?.seek_duration || SEEK_TIME) * 1000, // Only for Android
|
|
822
|
-
accessibilityProps: getAllAccessibilityProps(
|
|
823
|
-
this.getPluginConfiguration()
|
|
824
|
-
),
|
|
825
|
-
}; // rate temporary removed, because of bug with subtitles
|
|
826
|
-
|
|
827
|
-
if (
|
|
828
|
-
this.isReactNativeMethodsSupported() &&
|
|
829
|
-
RNPlayerManager?.[this.playerPluginId]?.play
|
|
830
|
-
) {
|
|
831
|
-
delete nativeProps["paused"];
|
|
832
|
-
}
|
|
833
|
-
|
|
834
|
-
const adEvents = {
|
|
835
|
-
onAdBegin: this.onAdBegin, // ad_start
|
|
836
|
-
onAdBreakBegin: this.onAdBreakBegin, // ad_break_start
|
|
837
|
-
onAdBreakEnd: this.onAdBreakEnd, // ad_break_completed
|
|
838
|
-
onAdEnd: this.onAdEnd, // ad_complete
|
|
839
|
-
onAdError: this.onAdError, // ad_error
|
|
840
|
-
onAdRequest: this.onAdRequest, // ad_request
|
|
841
|
-
onAdClicked: this.onAdClicked, // ad_clicked
|
|
842
|
-
onAdTapped: this.onAdTapped, // ad_tapped
|
|
843
|
-
};
|
|
844
|
-
|
|
845
|
-
const playbackEvents = {
|
|
846
|
-
onPlaybackRateChange: this.onPlaybackRateChange,
|
|
847
|
-
onPlayerPause: this.onPlayerPause, // pause
|
|
848
|
-
onPlayerResume: this.onPlayerResume, // play
|
|
849
|
-
onPlayerSeekComplete: this.onPlayerSeekComplete, // seek_complete
|
|
850
|
-
onPlayerSeekStart: this.onPlayerSeekStart, // seek_start
|
|
851
|
-
};
|
|
852
|
-
|
|
853
|
-
const lifecycleEvents = {
|
|
854
|
-
onReadyForDisplay: this.unHandledEvent("onReadyForDisplay"),
|
|
855
|
-
onVideoEnd: this.onVideoEnd, // complete
|
|
856
|
-
onVideoError: this.onVideoError, // error
|
|
857
|
-
onVideoProgress: this.onVideoProgress,
|
|
858
|
-
onVideoFullscreenPlayerDidDismiss: this.onVideoFullscreenPlayerDidDismiss,
|
|
859
|
-
onVideoFullscreenPlayerDidPresent: this.onVideoFullscreenPlayerDidPresent,
|
|
860
|
-
onVideoFullscreenPlayerWillDismiss:
|
|
861
|
-
this.onVideoFullscreenPlayerWillDismiss,
|
|
862
|
-
onVideoFullscreenPlayerWillPresent:
|
|
863
|
-
this.onVideoFullscreenPlayerWillPresent,
|
|
864
|
-
onVideoLoad: this.onVideoLoad,
|
|
865
|
-
onVideoLoadStart: this.unHandledEvent("onVideoLoadStart"),
|
|
866
|
-
onVideoBuffer: this.onVideoBuffer,
|
|
867
|
-
onPlaybackStalled: this.onPlaybackStalled,
|
|
868
|
-
onPlayerClose: this.onPlayerClose,
|
|
869
|
-
onPlayerAttached: this.onPlayerAttached,
|
|
870
|
-
onPlayerDetached: this.onPlayerDetached,
|
|
871
|
-
};
|
|
872
|
-
|
|
873
|
-
const androidLifecyclePiPEvents = isAndroidPlatform() && {
|
|
874
|
-
onPiPEnter: this.onPiPEnter,
|
|
875
|
-
onPiPExit: this.onPiPExit,
|
|
876
|
-
onPiPCloseByUser: this.onPiPCloseByUser,
|
|
877
|
-
};
|
|
878
|
-
|
|
879
|
-
const playerMetadataChangedEvents = {
|
|
880
|
-
onTimedMetadata: this.unHandledEvent("onTimedMetadata"),
|
|
881
|
-
onTracksChanged: this.onTracksChanged,
|
|
882
|
-
eventSubtitlesChange: this.unHandledEvent("eventSubtitlesChange"),
|
|
883
|
-
};
|
|
884
|
-
|
|
885
|
-
const playerSystemEvents = {
|
|
886
|
-
onAudioFocusChanged: this.unHandledEvent("onAudioFocusChanged"),
|
|
887
|
-
onVideoExternalPlaybackChange: this.unHandledEvent(
|
|
888
|
-
"onVideoExternalPlaybackChange"
|
|
889
|
-
),
|
|
890
|
-
onVideoAudioBecomingNoisy: this.unHandledEvent(
|
|
891
|
-
"onVideoAudioBecomingNoisy"
|
|
892
|
-
),
|
|
893
|
-
};
|
|
894
|
-
|
|
895
|
-
const androidPlayerEvents = {
|
|
896
|
-
onKeyChanged: keyEvent,
|
|
897
|
-
};
|
|
898
|
-
|
|
899
|
-
const unsupportedEvents = {
|
|
900
|
-
onBufferComplete: this.onBufferComplete, // buffer_complete
|
|
901
|
-
onBufferStart: this.onBufferStart, // buffer_start
|
|
902
|
-
};
|
|
903
|
-
|
|
904
|
-
const nativeEvents = {
|
|
905
|
-
...adEvents,
|
|
906
|
-
...androidPlayerEvents,
|
|
907
|
-
...lifecycleEvents,
|
|
908
|
-
...playerMetadataChangedEvents,
|
|
909
|
-
...playerSystemEvents,
|
|
910
|
-
...unsupportedEvents,
|
|
911
|
-
...playbackEvents,
|
|
912
|
-
...androidLifecyclePiPEvents,
|
|
913
|
-
};
|
|
914
|
-
|
|
915
|
-
const needToShowPlayNextOverlay =
|
|
916
|
-
isTV() && this.getPlayNextData() && !docked;
|
|
917
|
-
|
|
918
|
-
const needToShowDefaultControls = !(
|
|
919
|
-
(controls && !castAction?.state?.connected) ||
|
|
920
|
-
this.getPlayNextData()
|
|
921
|
-
);
|
|
922
|
-
|
|
923
|
-
const playerContainerStyles = isApplePlatform()
|
|
924
|
-
? styles.playerContainerBlack
|
|
925
|
-
: isTV() && isAudioItem
|
|
926
|
-
? styles.playerContainerTransparent
|
|
927
|
-
: styles.playerContainerBlack;
|
|
928
|
-
|
|
929
|
-
const isInline = () => {
|
|
930
|
-
if (isTV()) {
|
|
931
|
-
return inline;
|
|
932
|
-
}
|
|
933
|
-
|
|
934
|
-
// HACK: on mobile overwrite inline value if player is fullScreen
|
|
935
|
-
return fullscreen ? false : inline;
|
|
936
|
-
};
|
|
937
|
-
|
|
938
|
-
const renderTransportControls = (playerDimensions) => {
|
|
939
|
-
const needsToRender =
|
|
940
|
-
!hideTransportControls &&
|
|
941
|
-
!needToShowPlayNextOverlay &&
|
|
942
|
-
this.props.mode !== "PIP";
|
|
943
|
-
|
|
944
|
-
if (shouldUseNativeControls) {
|
|
945
|
-
return null;
|
|
946
|
-
}
|
|
947
|
-
|
|
948
|
-
const TransportControls = isTV()
|
|
949
|
-
? TransportControlsTV
|
|
950
|
-
: TransportControlsMobile;
|
|
951
|
-
|
|
952
|
-
return needsToRender ? (
|
|
953
|
-
<TransportControls
|
|
954
|
-
playerContent={entry}
|
|
955
|
-
configuration={this.getPluginConfiguration()}
|
|
956
|
-
playerDimensions={playerDimensions}
|
|
957
|
-
inline={isInline()}
|
|
958
|
-
docked={fullscreen ? false : docked}
|
|
959
|
-
isModal={isModal}
|
|
960
|
-
extraInfoText={castAction?.state?.friendlyStatus}
|
|
961
|
-
controlsAlwaysVisible={castAction?.state?.connected}
|
|
962
|
-
playNextData={this.getPlayNextData()}
|
|
963
|
-
needToShowDefaultControls={needToShowDefaultControls}
|
|
964
|
-
/>
|
|
965
|
-
) : null;
|
|
966
|
-
};
|
|
967
|
-
|
|
968
|
-
const isFullScreenAudioPlayer =
|
|
969
|
-
this.getPluginConfiguration()?.["full_screen_audio_player"] || false;
|
|
970
|
-
|
|
971
|
-
const sharedWrapperViewProps = {
|
|
972
|
-
style,
|
|
973
|
-
entry,
|
|
974
|
-
inline,
|
|
975
|
-
docked,
|
|
976
|
-
isModal,
|
|
977
|
-
pip: this.state.piped,
|
|
978
|
-
layoutState: {
|
|
979
|
-
inline,
|
|
980
|
-
docked,
|
|
981
|
-
isModal,
|
|
982
|
-
pip: this.state.piped,
|
|
983
|
-
},
|
|
984
|
-
configuration: this.getPluginConfiguration(),
|
|
985
|
-
fullscreen: fullscreen,
|
|
986
|
-
isTabletPortrait: isTabletPortrait,
|
|
987
|
-
playNextData: this.getPlayNextData(),
|
|
988
|
-
};
|
|
989
|
-
|
|
990
|
-
const containerStyle = { flex: 1 };
|
|
991
|
-
|
|
992
|
-
const backgroundImageKey =
|
|
993
|
-
this.getPluginConfiguration()?.player_preview_image_key;
|
|
994
|
-
|
|
995
|
-
const renderMobilePlayer = () => {
|
|
996
|
-
return isFullScreenAudioPlayer && isAudioItem ? (
|
|
997
|
-
<View style={containerStyle}>
|
|
998
|
-
{(!castAction?.state?.connected || supportNativeCast) && (
|
|
999
|
-
<this.props.PlayerComponent
|
|
1000
|
-
ref={this._assignRoot}
|
|
1001
|
-
{...nativeEvents}
|
|
1002
|
-
{...nativeProps}
|
|
1003
|
-
/>
|
|
1004
|
-
)}
|
|
1005
|
-
<AudioPlayerWrapper {...sharedWrapperViewProps} />
|
|
1006
|
-
</View>
|
|
1007
|
-
) : (
|
|
1008
|
-
<PlayerWrapper {...sharedWrapperViewProps}>
|
|
1009
|
-
{(playerDimensions) => {
|
|
1010
|
-
const shouldRenderBackground =
|
|
1011
|
-
!R.isNil(backgroundImageKey) &&
|
|
1012
|
-
backgroundImageKey.length > 0 &&
|
|
1013
|
-
!this.onVideoLoadCalled &&
|
|
1014
|
-
!this.state.isAd;
|
|
1015
|
-
|
|
1016
|
-
return (
|
|
1017
|
-
<View style={styles.container}>
|
|
1018
|
-
<View style={[playerContainerStyles, playerDimensions]}>
|
|
1019
|
-
{isAudioItem && (
|
|
1020
|
-
<AnimationComponent
|
|
1021
|
-
animationType={ComponentAnimationType.player}
|
|
1022
|
-
additionalData={{
|
|
1023
|
-
...playerDimensions,
|
|
1024
|
-
inlineAudioPlayer: true,
|
|
1025
|
-
}}
|
|
1026
|
-
style={getStyle(playerDimensions)}
|
|
1027
|
-
>
|
|
1028
|
-
<AudioPlayer
|
|
1029
|
-
style={
|
|
1030
|
-
isTV()
|
|
1031
|
-
? getStyle(playerDimensions)
|
|
1032
|
-
: styles.playerSize
|
|
1033
|
-
}
|
|
1034
|
-
audio_item={entry}
|
|
1035
|
-
plugin_configuration={this.getPluginConfiguration()}
|
|
1036
|
-
/>
|
|
1037
|
-
</AnimationComponent>
|
|
1038
|
-
)}
|
|
1039
|
-
|
|
1040
|
-
{shouldRenderBackground && (
|
|
1041
|
-
<PlayerImageBackground
|
|
1042
|
-
imageKey={backgroundImageKey}
|
|
1043
|
-
configuration={this.getPluginConfiguration()}
|
|
1044
|
-
entry={entry}
|
|
1045
|
-
style={getBackgroundImageStyle(playerDimensions)}
|
|
1046
|
-
/>
|
|
1047
|
-
)}
|
|
1048
|
-
|
|
1049
|
-
{(!castAction?.state?.connected || supportNativeCast) && (
|
|
1050
|
-
<AnimationComponent
|
|
1051
|
-
animationType={ComponentAnimationType.player}
|
|
1052
|
-
additionalData={playerDimensions}
|
|
1053
|
-
style={getStyle(playerDimensions)}
|
|
1054
|
-
>
|
|
1055
|
-
<this.props.PlayerComponent
|
|
1056
|
-
ref={this._assignRoot}
|
|
1057
|
-
{...nativeEvents}
|
|
1058
|
-
{...nativeProps}
|
|
1059
|
-
listener={this.props.listener}
|
|
1060
|
-
style={
|
|
1061
|
-
isTV()
|
|
1062
|
-
? getStyle(playerDimensions)
|
|
1063
|
-
: styles.playerSize
|
|
1064
|
-
}
|
|
1065
|
-
pluginConfiguration={this.getPluginConfiguration()}
|
|
1066
|
-
controller={this.props.controller}
|
|
1067
|
-
>
|
|
1068
|
-
{this.childrenWithPlayNext()}
|
|
1069
|
-
</this.props.PlayerComponent>
|
|
1070
|
-
</AnimationComponent>
|
|
1071
|
-
)}
|
|
1072
|
-
</View>
|
|
1073
|
-
|
|
1074
|
-
{renderTransportControls(playerDimensions)}
|
|
1075
|
-
{!this.state.piped && (
|
|
1076
|
-
<PlayNextOverlay
|
|
1077
|
-
item={entry}
|
|
1078
|
-
playerIsDocked={docked}
|
|
1079
|
-
pluginConfiguration={this.getPluginConfiguration()}
|
|
1080
|
-
playerId={this.props.playerId}
|
|
1081
|
-
playNextData={this.getPlayNextData()}
|
|
1082
|
-
setNextVideoPreloadThresholdPercentage={
|
|
1083
|
-
this.props.setNextVideoPreloadThresholdPercentage
|
|
1084
|
-
}
|
|
1085
|
-
/>
|
|
1086
|
-
)}
|
|
1087
|
-
</View>
|
|
1088
|
-
);
|
|
1089
|
-
}}
|
|
1090
|
-
</PlayerWrapper>
|
|
1091
|
-
);
|
|
1092
|
-
};
|
|
1093
|
-
|
|
1094
|
-
const renderTVPlayer = () => {
|
|
1095
|
-
return (
|
|
1096
|
-
<View style={this.takeParentStyle} testID={"player-view"}>
|
|
1097
|
-
<this.props.PlayerComponent
|
|
125
|
+
return (
|
|
126
|
+
<View style={this.takeParentStyle} testID={"player-view"}>
|
|
127
|
+
<div data-vjs-player>
|
|
128
|
+
<video
|
|
129
|
+
className="video-js vjs-big-play-centered fullscreen"
|
|
130
|
+
autoPlay
|
|
131
|
+
controls
|
|
1098
132
|
ref={this._assignRoot}
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
pluginConfiguration={this.getPluginConfiguration()}
|
|
1104
|
-
controller={this.props.controller}
|
|
1105
|
-
>
|
|
1106
|
-
{this.childrenWithPlayNext()}
|
|
1107
|
-
</this.props.PlayerComponent>
|
|
1108
|
-
|
|
1109
|
-
{renderTransportControls(this.takeParentStyle)}
|
|
1110
|
-
{!isTvOSPlatform() && (
|
|
1111
|
-
<PlayNextOverlay
|
|
1112
|
-
item={entry}
|
|
1113
|
-
playerIsDocked={docked}
|
|
1114
|
-
pluginConfiguration={this.getPluginConfiguration()}
|
|
1115
|
-
playerId={this.props.playerId}
|
|
1116
|
-
playNextData={this.getPlayNextData()}
|
|
1117
|
-
setNextVideoPreloadThresholdPercentage={
|
|
1118
|
-
this.props.setNextVideoPreloadThresholdPercentage
|
|
1119
|
-
}
|
|
1120
|
-
/>
|
|
1121
|
-
)}
|
|
1122
|
-
</View>
|
|
1123
|
-
);
|
|
1124
|
-
};
|
|
1125
|
-
|
|
1126
|
-
return isTV() ? renderTVPlayer() : renderMobilePlayer();
|
|
133
|
+
></video>
|
|
134
|
+
</div>
|
|
135
|
+
</View>
|
|
136
|
+
);
|
|
1127
137
|
}
|
|
1128
138
|
}
|