@mux/mux-react-native-player 0.1.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/MuxReactNativePlayer.podspec +37 -0
- package/README.md +134 -0
- package/android/build.gradle +33 -0
- package/android/src/main/AndroidManifest.xml +1 -0
- package/android/src/main/java/com/mux/reactnativeplayer/MuxReactNativePlayerModule.kt +135 -0
- package/android/src/main/java/com/mux/reactnativeplayer/MuxVideoRecords.kt +174 -0
- package/android/src/main/java/com/mux/reactnativeplayer/MuxVideoView.kt +452 -0
- package/android/src/main/res/layout/mux_video_player_view.xml +6 -0
- package/assets/MuxRobot_02.gif +0 -0
- package/assets/MuxRobot_02@2x.gif +0 -0
- package/assets/MuxRobot_03.gif +0 -0
- package/assets/MuxRobot_03@2x.gif +0 -0
- package/assets/MuxRobot_04.gif +0 -0
- package/assets/MuxRobot_04@2x.gif +0 -0
- package/assets/MuxRobot_05.gif +0 -0
- package/assets/MuxRobot_05@2x.gif +0 -0
- package/build/MuxVideoControls.d.ts +21 -0
- package/build/MuxVideoControls.d.ts.map +1 -0
- package/build/MuxVideoControls.js +1032 -0
- package/build/MuxVideoPlayer.d.ts +59 -0
- package/build/MuxVideoPlayer.d.ts.map +1 -0
- package/build/MuxVideoPlayer.js +265 -0
- package/build/MuxVideoView.d.ts +39 -0
- package/build/MuxVideoView.d.ts.map +1 -0
- package/build/MuxVideoView.js +254 -0
- package/build/NativeMuxVideoView.d.ts +5 -0
- package/build/NativeMuxVideoView.d.ts.map +1 -0
- package/build/NativeMuxVideoView.js +4 -0
- package/build/index.d.ts +6 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +3 -0
- package/build/normalizeSource.d.ts +7 -0
- package/build/normalizeSource.d.ts.map +1 -0
- package/build/normalizeSource.js +76 -0
- package/build/screenOrientation.d.ts +3 -0
- package/build/screenOrientation.d.ts.map +1 -0
- package/build/screenOrientation.js +38 -0
- package/build/types.d.ts +170 -0
- package/build/types.d.ts.map +1 -0
- package/build/types.js +1 -0
- package/expo-module.config.json +13 -0
- package/ios/MuxReactNativePlayerModule.swift +139 -0
- package/ios/MuxVideoRecords.swift +212 -0
- package/ios/MuxVideoView.swift +502 -0
- package/package.json +69 -0
- package/plugin/index.d.ts +11 -0
- package/plugin/index.js +1 -0
- package/plugin/withMuxReactNativePlayer.js +203 -0
- package/src/MuxVideoControls.tsx +1772 -0
- package/src/MuxVideoPlayer.ts +338 -0
- package/src/MuxVideoView.tsx +412 -0
- package/src/NativeMuxVideoView.ts +15 -0
- package/src/index.ts +32 -0
- package/src/normalizeSource.ts +101 -0
- package/src/screenOrientation.ts +46 -0
- package/src/types.ts +228 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
const MIN_RESOLUTION_ORDER = ['480p', '540p', '720p', '1080p', '1440p', '2160p'];
|
|
2
|
+
const MAX_RESOLUTION_ORDER = ['720p', '1080p', '1440p', '2160p'];
|
|
3
|
+
const CUSTOM_DATA_KEYS = Array.from({ length: 10 }, (_, index) => `customData${index + 1}`);
|
|
4
|
+
export function normalizeMuxVideoSource(source) {
|
|
5
|
+
const input = typeof source === 'string' ? { playbackId: source } : source;
|
|
6
|
+
const playbackId = input.playbackId?.trim();
|
|
7
|
+
if (!playbackId) {
|
|
8
|
+
throw new Error('Mux video source requires a non-empty playbackId.');
|
|
9
|
+
}
|
|
10
|
+
if (input.drmToken && !input.playbackToken) {
|
|
11
|
+
throw new Error('Mux DRM playback requires both drmToken and playbackToken.');
|
|
12
|
+
}
|
|
13
|
+
validateResolutionWindow(input.minResolution, input.maxResolution);
|
|
14
|
+
validateClipping(input.clipping?.assetStartTime, input.clipping?.assetEndTime);
|
|
15
|
+
return {
|
|
16
|
+
...input,
|
|
17
|
+
playbackId,
|
|
18
|
+
renditionOrder: input.renditionOrder ?? 'default',
|
|
19
|
+
metadata: input.metadata
|
|
20
|
+
? {
|
|
21
|
+
...input.metadata,
|
|
22
|
+
customData: normalizeCustomData(input.metadata.customData),
|
|
23
|
+
}
|
|
24
|
+
: undefined,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function validateResolutionWindow(minResolution, maxResolution) {
|
|
28
|
+
if (!minResolution || !maxResolution) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const minPixels = Number(minResolution.replace('p', ''));
|
|
32
|
+
const maxPixels = Number(maxResolution.replace('p', ''));
|
|
33
|
+
if (minPixels > maxPixels) {
|
|
34
|
+
throw new Error(`Mux video source minResolution (${minResolution}) cannot exceed maxResolution (${maxResolution}).`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function validateClipping(assetStartTime, assetEndTime) {
|
|
38
|
+
if (assetStartTime != null && (!Number.isFinite(assetStartTime) || assetStartTime < 0)) {
|
|
39
|
+
throw new Error('Mux video source clipping.assetStartTime must be a non-negative finite number.');
|
|
40
|
+
}
|
|
41
|
+
if (assetEndTime != null && (!Number.isFinite(assetEndTime) || assetEndTime < 0)) {
|
|
42
|
+
throw new Error('Mux video source clipping.assetEndTime must be a non-negative finite number.');
|
|
43
|
+
}
|
|
44
|
+
if (assetStartTime != null && assetEndTime != null && assetStartTime >= assetEndTime) {
|
|
45
|
+
throw new Error('Mux video source clipping.assetStartTime must be less than clipping.assetEndTime.');
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function normalizeCustomData(customData) {
|
|
49
|
+
if (!customData) {
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
const out = {};
|
|
53
|
+
const directKeys = Object.keys(customData).filter(key => CUSTOM_DATA_KEYS.includes(key));
|
|
54
|
+
for (const key of directKeys) {
|
|
55
|
+
const value = customData[key];
|
|
56
|
+
if (typeof value === 'string') {
|
|
57
|
+
out[key] = value;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
const remainingValues = Object.entries(customData)
|
|
61
|
+
.filter(([key, value]) => !CUSTOM_DATA_KEYS.includes(key) && typeof value === 'string')
|
|
62
|
+
.map(([, value]) => value);
|
|
63
|
+
for (const key of CUSTOM_DATA_KEYS) {
|
|
64
|
+
if (remainingValues.length === 0) {
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
if (out[key] == null) {
|
|
68
|
+
out[key] = remainingValues.shift();
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return Object.keys(out).length > 0 ? out : undefined;
|
|
72
|
+
}
|
|
73
|
+
export const muxResolutionSupport = {
|
|
74
|
+
min: MIN_RESOLUTION_ORDER,
|
|
75
|
+
max: MAX_RESOLUTION_ORDER,
|
|
76
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"screenOrientation.d.ts","sourceRoot":"","sources":["../src/screenOrientation.ts"],"names":[],"mappings":"AAuBA,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,IAAI,CAAC,CAU9D;AAED,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAUvD"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { requireOptionalNativeModule } from 'expo-modules-core';
|
|
2
|
+
let cached;
|
|
3
|
+
function loadModule() {
|
|
4
|
+
if (cached !== undefined) {
|
|
5
|
+
return cached;
|
|
6
|
+
}
|
|
7
|
+
try {
|
|
8
|
+
cached = requireOptionalNativeModule('MuxReactNativePlayer');
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
cached = null;
|
|
12
|
+
}
|
|
13
|
+
return cached;
|
|
14
|
+
}
|
|
15
|
+
export async function lockOrientationLandscape() {
|
|
16
|
+
const mod = loadModule();
|
|
17
|
+
if (!mod) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
try {
|
|
21
|
+
await mod.lockFullscreenLandscape?.();
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
// Locking can fail on devices that don't support orientation changes.
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export async function unlockOrientation() {
|
|
28
|
+
const mod = loadModule();
|
|
29
|
+
if (!mod) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
await mod.unlockFullscreenOrientation?.();
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
// ignore
|
|
37
|
+
}
|
|
38
|
+
}
|
package/build/types.d.ts
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import type { NativeSyntheticEvent, ViewProps } from 'react-native';
|
|
2
|
+
export type MuxMaxResolution = '720p' | '1080p' | '1440p' | '2160p';
|
|
3
|
+
export type MuxMinResolution = '480p' | '540p' | '720p' | '1080p' | '1440p' | '2160p';
|
|
4
|
+
export type MuxRenditionOrder = 'default' | 'desc';
|
|
5
|
+
export type MuxContentFit = 'contain' | 'cover' | 'fill';
|
|
6
|
+
export type MuxVideoControls = 'native' | 'custom' | 'none';
|
|
7
|
+
export type MuxCustomData = Partial<Record<'customData1' | 'customData2' | 'customData3' | 'customData4' | 'customData5' | 'customData6' | 'customData7' | 'customData8' | 'customData9' | 'customData10', string>> & Record<string, string | undefined>;
|
|
8
|
+
export type MuxVideoMetadata = {
|
|
9
|
+
envKey?: string;
|
|
10
|
+
playerName?: string;
|
|
11
|
+
playerVersion?: string;
|
|
12
|
+
videoTitle?: string;
|
|
13
|
+
videoId?: string;
|
|
14
|
+
videoSeries?: string;
|
|
15
|
+
viewerUserId?: string;
|
|
16
|
+
customData?: MuxCustomData;
|
|
17
|
+
};
|
|
18
|
+
export type MuxVideoClipping = {
|
|
19
|
+
assetStartTime?: number;
|
|
20
|
+
assetEndTime?: number;
|
|
21
|
+
};
|
|
22
|
+
export type MuxVideoSourceObject = {
|
|
23
|
+
playbackId: string;
|
|
24
|
+
assetId?: string;
|
|
25
|
+
playbackToken?: string;
|
|
26
|
+
drmToken?: string;
|
|
27
|
+
customDomain?: string;
|
|
28
|
+
minResolution?: MuxMinResolution;
|
|
29
|
+
maxResolution?: MuxMaxResolution;
|
|
30
|
+
renditionOrder?: MuxRenditionOrder;
|
|
31
|
+
clipping?: MuxVideoClipping;
|
|
32
|
+
metadata?: MuxVideoMetadata;
|
|
33
|
+
};
|
|
34
|
+
export type MuxVideoSource = string | MuxVideoSourceObject;
|
|
35
|
+
export type NormalizedMuxVideoSource = MuxVideoSourceObject & {
|
|
36
|
+
playbackId: string;
|
|
37
|
+
renditionOrder: MuxRenditionOrder;
|
|
38
|
+
};
|
|
39
|
+
export type MuxPlaybackStatus = 'idle' | 'loading' | 'ready' | 'buffering' | 'playing' | 'paused' | 'ended' | 'error';
|
|
40
|
+
export type MuxPlayerStatus = {
|
|
41
|
+
status: MuxPlaybackStatus;
|
|
42
|
+
currentTime: number;
|
|
43
|
+
duration: number;
|
|
44
|
+
bufferedPosition: number;
|
|
45
|
+
muted: boolean;
|
|
46
|
+
volume: number;
|
|
47
|
+
loop: boolean;
|
|
48
|
+
playbackRate: number;
|
|
49
|
+
captionTracks?: MuxVideoCaptionTrack[];
|
|
50
|
+
selectedCaptionTrackId?: string | null;
|
|
51
|
+
error?: string;
|
|
52
|
+
};
|
|
53
|
+
export type MuxStatusChangeEvent = MuxPlayerStatus;
|
|
54
|
+
export type MuxPlayingChangeEvent = {
|
|
55
|
+
isPlaying: boolean;
|
|
56
|
+
};
|
|
57
|
+
export type MuxTimeUpdateEvent = {
|
|
58
|
+
currentTime: number;
|
|
59
|
+
duration: number;
|
|
60
|
+
bufferedPosition: number;
|
|
61
|
+
};
|
|
62
|
+
export type MuxVideoRobotsContext = {
|
|
63
|
+
assetId: string;
|
|
64
|
+
duration: number;
|
|
65
|
+
currentTime: number;
|
|
66
|
+
};
|
|
67
|
+
export type MuxVideoSummary = {
|
|
68
|
+
title: string;
|
|
69
|
+
description: string;
|
|
70
|
+
tags?: string[];
|
|
71
|
+
};
|
|
72
|
+
export type MuxVideoChapter = {
|
|
73
|
+
startTime: number;
|
|
74
|
+
title: string;
|
|
75
|
+
};
|
|
76
|
+
export type MuxVideoKeyMoment = {
|
|
77
|
+
startTime: number;
|
|
78
|
+
endTime: number;
|
|
79
|
+
title: string;
|
|
80
|
+
description?: string;
|
|
81
|
+
score?: number;
|
|
82
|
+
};
|
|
83
|
+
export type MuxVideoRobotsConfig = {
|
|
84
|
+
enabled?: boolean;
|
|
85
|
+
assetId?: string;
|
|
86
|
+
summary?: MuxVideoSummary;
|
|
87
|
+
chapters?: MuxVideoChapter[];
|
|
88
|
+
keyMoments?: MuxVideoKeyMoment[];
|
|
89
|
+
onSummarize?: (context: MuxVideoRobotsContext) => Promise<MuxVideoSummary>;
|
|
90
|
+
onGenerateChapters?: (context: MuxVideoRobotsContext) => Promise<MuxVideoChapter[]>;
|
|
91
|
+
onFindKeyMoments?: (context: MuxVideoRobotsContext) => Promise<MuxVideoKeyMoment[]>;
|
|
92
|
+
};
|
|
93
|
+
export type MuxSourceLoadEvent = {
|
|
94
|
+
playbackId: string;
|
|
95
|
+
duration: number;
|
|
96
|
+
captionTracks?: MuxVideoCaptionTrack[];
|
|
97
|
+
selectedCaptionTrackId?: string | null;
|
|
98
|
+
};
|
|
99
|
+
export type MuxSourceErrorEvent = {
|
|
100
|
+
playbackId?: string;
|
|
101
|
+
message: string;
|
|
102
|
+
code?: string;
|
|
103
|
+
};
|
|
104
|
+
export type MuxNativeViewRef = {
|
|
105
|
+
play: () => Promise<void>;
|
|
106
|
+
pause: () => Promise<void>;
|
|
107
|
+
replay: () => Promise<void>;
|
|
108
|
+
seekBy: (seconds: number) => Promise<void>;
|
|
109
|
+
seekTo: (seconds: number) => Promise<void>;
|
|
110
|
+
setMuted: (muted: boolean) => Promise<void>;
|
|
111
|
+
setVolume: (volume: number) => Promise<void>;
|
|
112
|
+
setLoop: (loop: boolean) => Promise<void>;
|
|
113
|
+
setPlaybackRate: (rate: number) => Promise<void>;
|
|
114
|
+
setCaptionTrack: (trackId: string | null) => Promise<void>;
|
|
115
|
+
preload: () => Promise<void>;
|
|
116
|
+
release: () => Promise<void>;
|
|
117
|
+
};
|
|
118
|
+
export type MuxVideoCaptionTrack = {
|
|
119
|
+
id: string;
|
|
120
|
+
label: string;
|
|
121
|
+
language?: string;
|
|
122
|
+
kind?: 'subtitles' | 'captions' | 'forced' | string;
|
|
123
|
+
};
|
|
124
|
+
export type MuxVideoControlsTheme = {
|
|
125
|
+
accentColor?: string;
|
|
126
|
+
backgroundColor?: string;
|
|
127
|
+
buttonBackgroundColor?: string;
|
|
128
|
+
buttonTextColor?: string;
|
|
129
|
+
buttonSize?: number;
|
|
130
|
+
playButtonSize?: number;
|
|
131
|
+
fullscreenButtonSize?: number;
|
|
132
|
+
progressTrackColor?: string;
|
|
133
|
+
bufferedTrackColor?: string;
|
|
134
|
+
trackColor?: string;
|
|
135
|
+
trackHeight?: number;
|
|
136
|
+
textColor?: string;
|
|
137
|
+
seekSeconds?: number;
|
|
138
|
+
};
|
|
139
|
+
export type MuxVideoViewProps = ViewProps & {
|
|
140
|
+
player: import('./MuxVideoPlayer').MuxVideoPlayer;
|
|
141
|
+
controls?: MuxVideoControls;
|
|
142
|
+
controlsTheme?: MuxVideoControlsTheme;
|
|
143
|
+
robots?: MuxVideoRobotsConfig;
|
|
144
|
+
nativeControls?: boolean;
|
|
145
|
+
contentFit?: MuxContentFit;
|
|
146
|
+
allowsFullscreen?: boolean;
|
|
147
|
+
allowsPictureInPicture?: boolean;
|
|
148
|
+
timeUpdateEventInterval?: number;
|
|
149
|
+
startupBufferDuration?: number;
|
|
150
|
+
onStatusChange?: (event: MuxStatusChangeEvent) => void;
|
|
151
|
+
onPlayingChange?: (event: MuxPlayingChangeEvent) => void;
|
|
152
|
+
onTimeUpdate?: (event: MuxTimeUpdateEvent) => void;
|
|
153
|
+
onSourceLoad?: (event: MuxSourceLoadEvent) => void;
|
|
154
|
+
onSourceError?: (event: MuxSourceErrorEvent) => void;
|
|
155
|
+
onFullscreenChange?: (isFullscreen: boolean) => void;
|
|
156
|
+
};
|
|
157
|
+
export type NativeMuxVideoViewProps = Omit<MuxVideoViewProps, 'player' | 'controls' | 'controlsTheme' | 'robots' | 'onStatusChange' | 'onPlayingChange' | 'onTimeUpdate' | 'onSourceLoad' | 'onSourceError' | 'onFullscreenChange'> & {
|
|
158
|
+
source?: NormalizedMuxVideoSource;
|
|
159
|
+
playWhenReady: boolean;
|
|
160
|
+
muted: boolean;
|
|
161
|
+
volume: number;
|
|
162
|
+
loop: boolean;
|
|
163
|
+
playbackRate: number;
|
|
164
|
+
onStatusChange?: (event: NativeSyntheticEvent<MuxStatusChangeEvent>) => void;
|
|
165
|
+
onPlayingChange?: (event: NativeSyntheticEvent<MuxPlayingChangeEvent>) => void;
|
|
166
|
+
onTimeUpdate?: (event: NativeSyntheticEvent<MuxTimeUpdateEvent>) => void;
|
|
167
|
+
onSourceLoad?: (event: NativeSyntheticEvent<MuxSourceLoadEvent>) => void;
|
|
168
|
+
onSourceError?: (event: NativeSyntheticEvent<MuxSourceErrorEvent>) => void;
|
|
169
|
+
};
|
|
170
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/build/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"platforms": ["ios", "android"],
|
|
3
|
+
"apple": {
|
|
4
|
+
"modules": ["MuxReactNativePlayerModule"],
|
|
5
|
+
"podspecPath": "MuxReactNativePlayer.podspec"
|
|
6
|
+
},
|
|
7
|
+
"ios": {
|
|
8
|
+
"modules": ["MuxReactNativePlayerModule"]
|
|
9
|
+
},
|
|
10
|
+
"android": {
|
|
11
|
+
"modules": ["com.mux.reactnativeplayer.MuxReactNativePlayerModule"]
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import ExpoModulesCore
|
|
2
|
+
import UIKit
|
|
3
|
+
|
|
4
|
+
public final class MuxReactNativePlayerModule: Module {
|
|
5
|
+
public func definition() -> ModuleDefinition {
|
|
6
|
+
Name("MuxReactNativePlayer")
|
|
7
|
+
|
|
8
|
+
AsyncFunction("lockFullscreenLandscape") {
|
|
9
|
+
DispatchQueue.main.async {
|
|
10
|
+
Self.requestOrientation(.landscapeRight, mask: .landscape)
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
AsyncFunction("unlockFullscreenOrientation") {
|
|
15
|
+
DispatchQueue.main.async {
|
|
16
|
+
Self.requestOrientation(.portrait, mask: .allButUpsideDown)
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
View(MuxVideoView.self) {
|
|
21
|
+
Events(
|
|
22
|
+
"onStatusChange",
|
|
23
|
+
"onPlayingChange",
|
|
24
|
+
"onTimeUpdate",
|
|
25
|
+
"onSourceLoad",
|
|
26
|
+
"onSourceError"
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
Prop("source") { (view: MuxVideoView, source: MuxVideoSourceRecord?) in
|
|
30
|
+
view.setSource(source)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
Prop("nativeControls") { (view: MuxVideoView, enabled: Bool) in
|
|
34
|
+
view.setNativeControls(enabled)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
Prop("contentFit") { (view: MuxVideoView, contentFit: String) in
|
|
38
|
+
view.setContentFit(contentFit)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
Prop("allowsFullscreen") { (_: MuxVideoView, _: Bool) in
|
|
42
|
+
// Fullscreen is managed by the React Native wrapper for custom controls.
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
Prop("allowsPictureInPicture") { (view: MuxVideoView, enabled: Bool) in
|
|
46
|
+
view.setAllowsPictureInPicture(enabled)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
Prop("timeUpdateEventInterval") { (view: MuxVideoView, interval: Double) in
|
|
50
|
+
view.setTimeUpdateEventInterval(interval)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
Prop("startupBufferDuration") { (view: MuxVideoView, duration: Double) in
|
|
54
|
+
view.setStartupBufferDuration(duration)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
Prop("playWhenReady") { (view: MuxVideoView, playWhenReady: Bool) in
|
|
58
|
+
view.setPlayWhenReady(playWhenReady)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
Prop("muted") { (view: MuxVideoView, muted: Bool) in
|
|
62
|
+
view.setMuted(muted)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
Prop("volume") { (view: MuxVideoView, volume: Double) in
|
|
66
|
+
view.setVolume(volume)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
Prop("loop") { (view: MuxVideoView, loop: Bool) in
|
|
70
|
+
view.setLoop(loop)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
Prop("playbackRate") { (view: MuxVideoView, rate: Double) in
|
|
74
|
+
view.setPlaybackRate(rate)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
AsyncFunction("play") { (view: MuxVideoView) in
|
|
78
|
+
view.play()
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
AsyncFunction("pause") { (view: MuxVideoView) in
|
|
82
|
+
view.pause()
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
AsyncFunction("replay") { (view: MuxVideoView) in
|
|
86
|
+
view.replay()
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
AsyncFunction("seekBy") { (view: MuxVideoView, seconds: Double) in
|
|
90
|
+
view.seekBy(seconds)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
AsyncFunction("seekTo") { (view: MuxVideoView, seconds: Double) in
|
|
94
|
+
view.seekTo(seconds)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
AsyncFunction("setMuted") { (view: MuxVideoView, muted: Bool) in
|
|
98
|
+
view.setMuted(muted)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
AsyncFunction("setVolume") { (view: MuxVideoView, volume: Double) in
|
|
102
|
+
view.setVolume(volume)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
AsyncFunction("setLoop") { (view: MuxVideoView, loop: Bool) in
|
|
106
|
+
view.setLoop(loop)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
AsyncFunction("setPlaybackRate") { (view: MuxVideoView, rate: Double) in
|
|
110
|
+
view.setPlaybackRate(rate)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
AsyncFunction("setCaptionTrack") { (view: MuxVideoView, trackId: String?) in
|
|
114
|
+
view.setCaptionTrack(trackId)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
AsyncFunction("release") { (view: MuxVideoView) in
|
|
118
|
+
view.release()
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
private static func requestOrientation(_ orientation: UIInterfaceOrientation, mask: UIInterfaceOrientationMask) {
|
|
124
|
+
guard let windowScene = UIApplication.shared.connectedScenes
|
|
125
|
+
.compactMap({ $0 as? UIWindowScene })
|
|
126
|
+
.first(where: { $0.activationState == .foregroundActive })
|
|
127
|
+
?? UIApplication.shared.connectedScenes.compactMap({ $0 as? UIWindowScene }).first else {
|
|
128
|
+
return
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if #available(iOS 16.0, *) {
|
|
132
|
+
windowScene.windows.first?.rootViewController?.setNeedsUpdateOfSupportedInterfaceOrientations()
|
|
133
|
+
windowScene.requestGeometryUpdate(.iOS(interfaceOrientations: mask)) { _ in }
|
|
134
|
+
} else {
|
|
135
|
+
UIDevice.current.setValue(orientation.rawValue, forKey: "orientation")
|
|
136
|
+
UIViewController.attemptRotationToDeviceOrientation()
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import ExpoModulesCore
|
|
2
|
+
import Foundation
|
|
3
|
+
import MuxCore
|
|
4
|
+
import MuxPlayerSwift
|
|
5
|
+
|
|
6
|
+
struct MuxVideoClippingRecord: Record {
|
|
7
|
+
@Field var assetStartTime: Double?
|
|
8
|
+
@Field var assetEndTime: Double?
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
struct MuxVideoMetadataRecord: Record {
|
|
12
|
+
@Field var envKey: String?
|
|
13
|
+
@Field var playerName: String?
|
|
14
|
+
@Field var playerVersion: String?
|
|
15
|
+
@Field var videoTitle: String?
|
|
16
|
+
@Field var videoId: String?
|
|
17
|
+
@Field var videoSeries: String?
|
|
18
|
+
@Field var viewerUserId: String?
|
|
19
|
+
@Field var customData: [String: String]?
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
struct MuxVideoSourceRecord: Record {
|
|
23
|
+
@Field var playbackId: String = ""
|
|
24
|
+
@Field var playbackToken: String?
|
|
25
|
+
@Field var drmToken: String?
|
|
26
|
+
@Field var customDomain: String?
|
|
27
|
+
@Field var minResolution: String?
|
|
28
|
+
@Field var maxResolution: String?
|
|
29
|
+
@Field var renditionOrder: String = "default"
|
|
30
|
+
@Field var clipping: MuxVideoClippingRecord?
|
|
31
|
+
@Field var metadata: MuxVideoMetadataRecord?
|
|
32
|
+
|
|
33
|
+
var fingerprint: String {
|
|
34
|
+
var values: [String] = []
|
|
35
|
+
values.append(playbackId)
|
|
36
|
+
values.append(playbackToken ?? "")
|
|
37
|
+
values.append(drmToken ?? "")
|
|
38
|
+
values.append(customDomain ?? "")
|
|
39
|
+
values.append(minResolution ?? "")
|
|
40
|
+
values.append(maxResolution ?? "")
|
|
41
|
+
values.append(renditionOrder)
|
|
42
|
+
values.append(clipping?.assetStartTime.map { String($0) } ?? "")
|
|
43
|
+
values.append(clipping?.assetEndTime.map { String($0) } ?? "")
|
|
44
|
+
values.append(metadata?.envKey ?? "")
|
|
45
|
+
values.append(metadata?.playerName ?? "")
|
|
46
|
+
values.append(metadata?.playerVersion ?? "")
|
|
47
|
+
values.append(metadata?.videoTitle ?? "")
|
|
48
|
+
values.append(metadata?.videoId ?? "")
|
|
49
|
+
values.append(metadata?.videoSeries ?? "")
|
|
50
|
+
values.append(metadata?.viewerUserId ?? "")
|
|
51
|
+
let customDataFingerprint = metadata?.customData?
|
|
52
|
+
.sorted { $0.key < $1.key }
|
|
53
|
+
.map { "\($0.key):\($0.value)" }
|
|
54
|
+
.joined(separator: ",") ?? ""
|
|
55
|
+
values.append(customDataFingerprint)
|
|
56
|
+
|
|
57
|
+
return values.joined(separator: "|")
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
func toPlaybackOptions() -> PlaybackOptions {
|
|
61
|
+
if let playbackToken, let drmToken {
|
|
62
|
+
return PlaybackOptions(
|
|
63
|
+
playbackToken: playbackToken,
|
|
64
|
+
drmToken: drmToken,
|
|
65
|
+
customDomain: blankToNil(customDomain)
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if let customDomain = blankToNil(customDomain), let playbackToken {
|
|
70
|
+
return PlaybackOptions(customDomain: customDomain, playbackToken: playbackToken)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if let playbackToken {
|
|
74
|
+
return PlaybackOptions(playbackToken: playbackToken)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if let customDomain = blankToNil(customDomain) {
|
|
78
|
+
return PlaybackOptions(
|
|
79
|
+
customDomain: customDomain,
|
|
80
|
+
maximumResolutionTier: maxResolution.toMaxResolutionTier(),
|
|
81
|
+
minimumResolutionTier: minResolution.toMinResolutionTier(),
|
|
82
|
+
renditionOrder: renditionOrder.toRenditionOrder()
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if let clipping = clipping?.toInstantClipping() {
|
|
87
|
+
return PlaybackOptions(
|
|
88
|
+
maximumResolutionTier: maxResolution.toMaxResolutionTier(),
|
|
89
|
+
minimumResolutionTier: minResolution.toMinResolutionTier(),
|
|
90
|
+
renditionOrder: renditionOrder.toRenditionOrder(),
|
|
91
|
+
clipping: clipping
|
|
92
|
+
)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return PlaybackOptions(
|
|
96
|
+
maximumResolutionTier: maxResolution.toMaxResolutionTier(),
|
|
97
|
+
minimumResolutionTier: minResolution.toMinResolutionTier(),
|
|
98
|
+
renditionOrder: renditionOrder.toRenditionOrder()
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
func toMonitoringOptions() -> MonitoringOptions {
|
|
103
|
+
let customerData = toCustomerData()
|
|
104
|
+
let playerName = blankToNil(metadata?.playerName) ?? "MuxReactNativePlayer"
|
|
105
|
+
return MonitoringOptions(
|
|
106
|
+
customerData: customerData,
|
|
107
|
+
playerName: playerName,
|
|
108
|
+
automaticErrorTracking: true
|
|
109
|
+
)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
func toCustomerData() -> MUXSDKCustomerData {
|
|
113
|
+
let customerData = MUXSDKCustomerData()
|
|
114
|
+
|
|
115
|
+
let customerPlayerData = MUXSDKCustomerPlayerData()
|
|
116
|
+
customerPlayerData.environmentKey = blankToNil(metadata?.envKey)
|
|
117
|
+
customerPlayerData.playerName = blankToNil(metadata?.playerName) ?? "MuxReactNativePlayer"
|
|
118
|
+
customerPlayerData.playerVersion = blankToNil(metadata?.playerVersion)
|
|
119
|
+
customerPlayerData.viewerUserId = blankToNil(metadata?.viewerUserId)
|
|
120
|
+
customerData.customerPlayerData = customerPlayerData
|
|
121
|
+
|
|
122
|
+
let customerVideoData = MUXSDKCustomerVideoData()
|
|
123
|
+
customerVideoData.videoTitle = blankToNil(metadata?.videoTitle)
|
|
124
|
+
customerVideoData.videoId = blankToNil(metadata?.videoId)
|
|
125
|
+
customerVideoData.videoSeries = blankToNil(metadata?.videoSeries)
|
|
126
|
+
customerData.customerVideoData = customerVideoData
|
|
127
|
+
|
|
128
|
+
let customData = MUXSDKCustomData()
|
|
129
|
+
customData.customData1 = metadata?.customData?["customData1"]
|
|
130
|
+
customData.customData2 = metadata?.customData?["customData2"]
|
|
131
|
+
customData.customData3 = metadata?.customData?["customData3"]
|
|
132
|
+
customData.customData4 = metadata?.customData?["customData4"]
|
|
133
|
+
customData.customData5 = metadata?.customData?["customData5"]
|
|
134
|
+
customData.customData6 = metadata?.customData?["customData6"]
|
|
135
|
+
customData.customData7 = metadata?.customData?["customData7"]
|
|
136
|
+
customData.customData8 = metadata?.customData?["customData8"]
|
|
137
|
+
customData.customData9 = metadata?.customData?["customData9"]
|
|
138
|
+
customData.customData10 = metadata?.customData?["customData10"]
|
|
139
|
+
customerData.customData = customData
|
|
140
|
+
|
|
141
|
+
return customerData
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
private func blankToNil(_ value: String?) -> String? {
|
|
146
|
+
guard let value, !value.isEmpty else {
|
|
147
|
+
return nil
|
|
148
|
+
}
|
|
149
|
+
return value
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
private extension MuxVideoClippingRecord {
|
|
153
|
+
func toInstantClipping() -> InstantClipping? {
|
|
154
|
+
switch (assetStartTime, assetEndTime) {
|
|
155
|
+
case let (start?, end?):
|
|
156
|
+
return InstantClipping(assetStartTimeInSeconds: start, assetEndTimeInSeconds: end)
|
|
157
|
+
case let (start?, nil):
|
|
158
|
+
return InstantClipping(assetStartTimeInSeconds: start)
|
|
159
|
+
case let (nil, end?):
|
|
160
|
+
return InstantClipping(assetEndTimeInSeconds: end)
|
|
161
|
+
default:
|
|
162
|
+
return nil
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
private extension Optional where Wrapped == String {
|
|
168
|
+
func toMaxResolutionTier() -> MaxResolutionTier {
|
|
169
|
+
switch self {
|
|
170
|
+
case "720p":
|
|
171
|
+
return .upTo720p
|
|
172
|
+
case "1080p":
|
|
173
|
+
return .upTo1080p
|
|
174
|
+
case "1440p":
|
|
175
|
+
return .upTo1440p
|
|
176
|
+
case "2160p":
|
|
177
|
+
return .upTo2160p
|
|
178
|
+
default:
|
|
179
|
+
return .default
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
func toMinResolutionTier() -> MinResolutionTier {
|
|
184
|
+
switch self {
|
|
185
|
+
case "480p":
|
|
186
|
+
return .atLeast480p
|
|
187
|
+
case "540p":
|
|
188
|
+
return .atLeast540p
|
|
189
|
+
case "720p":
|
|
190
|
+
return .atLeast720p
|
|
191
|
+
case "1080p":
|
|
192
|
+
return .atLeast1080p
|
|
193
|
+
case "1440p":
|
|
194
|
+
return .atLeast1440p
|
|
195
|
+
case "2160p":
|
|
196
|
+
return .atLeast2160p
|
|
197
|
+
default:
|
|
198
|
+
return .default
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
private extension String {
|
|
204
|
+
func toRenditionOrder() -> RenditionOrder {
|
|
205
|
+
switch self {
|
|
206
|
+
case "desc":
|
|
207
|
+
return .descending
|
|
208
|
+
default:
|
|
209
|
+
return .default
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|