@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,37 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
|
|
3
|
+
package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
|
|
4
|
+
|
|
5
|
+
Pod::Spec.new do |s|
|
|
6
|
+
s.name = 'MuxReactNativePlayer'
|
|
7
|
+
s.version = package['version']
|
|
8
|
+
s.summary = package['description']
|
|
9
|
+
s.description = 'React Native bindings for Mux Player Swift and Mux Player Android.'
|
|
10
|
+
s.license = package['license']
|
|
11
|
+
s.author = 'Mux, Inc.'
|
|
12
|
+
s.homepage = 'https://github.com/muxinc/mux-react-native-player'
|
|
13
|
+
s.source = { :git => 'https://github.com/muxinc/mux-react-native-player.git', :tag => "#{s.version}" }
|
|
14
|
+
s.platforms = { :ios => '15.0' }
|
|
15
|
+
s.swift_version = '5.9'
|
|
16
|
+
s.static_framework = true
|
|
17
|
+
|
|
18
|
+
s.source_files = 'ios/*.{h,m,mm,swift}'
|
|
19
|
+
s.dependency 'ExpoModulesCore'
|
|
20
|
+
|
|
21
|
+
if respond_to?(:spm_dependency, true)
|
|
22
|
+
spm_dependency(
|
|
23
|
+
s,
|
|
24
|
+
url: 'https://github.com/muxinc/mux-player-swift.git',
|
|
25
|
+
requirement: {
|
|
26
|
+
kind: 'upToNextMajorVersion',
|
|
27
|
+
minimumVersion: '1.5.0'
|
|
28
|
+
},
|
|
29
|
+
products: ['MuxPlayerSwift']
|
|
30
|
+
)
|
|
31
|
+
else
|
|
32
|
+
raise <<~MSG
|
|
33
|
+
MuxReactNativePlayer requires React Native's spm_dependency Podfile helper to consume MuxPlayerSwift.
|
|
34
|
+
Upgrade React Native to 0.75 or newer, or add MuxPlayerSwift to the app target manually and patch this podspec.
|
|
35
|
+
MSG
|
|
36
|
+
end
|
|
37
|
+
end
|
package/README.md
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# Mux React Native Player
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<img src="assets/player_screenshot.png" alt="Mux React Native Player" width="320" />
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
A React native video player with built-in Mux Data and Mux Robots integrations. Native playback is delegated to:
|
|
8
|
+
|
|
9
|
+
- iOS: [`muxinc/mux-player-swift`](https://github.com/muxinc/mux-player-swift)
|
|
10
|
+
- Android: [`muxinc/mux-player-android`](https://github.com/muxinc/mux-player-android)
|
|
11
|
+
|
|
12
|
+
## Requirements
|
|
13
|
+
|
|
14
|
+
- React Native 0.75+ with Expo Modules
|
|
15
|
+
- iOS 15+, Android minSdk 23+
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
npm install @mux/mux-react-native-player
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
```json
|
|
24
|
+
{
|
|
25
|
+
"expo": {
|
|
26
|
+
"plugins": [
|
|
27
|
+
[
|
|
28
|
+
"@mux/mux-react-native-player/plugin",
|
|
29
|
+
{ "enablePictureInPicture": true }
|
|
30
|
+
]
|
|
31
|
+
]
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
npx expo prebuild
|
|
38
|
+
npx expo run:ios
|
|
39
|
+
npx expo run:android
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Usage
|
|
43
|
+
|
|
44
|
+
```tsx
|
|
45
|
+
import { MuxVideoView, useMuxVideoPlayer } from "@mux/mux-react-native-player";
|
|
46
|
+
|
|
47
|
+
export default function Player() {
|
|
48
|
+
const player = useMuxVideoPlayer({
|
|
49
|
+
playbackId: "qxb01i6T202018GFS02vp9RIe01icTcDCjVzQpmaB00CUisJ4",
|
|
50
|
+
metadata: {
|
|
51
|
+
envKey: "YOUR_MUX_DATA_ENV_KEY",
|
|
52
|
+
playerName: "MuxReactNativePlayerExample",
|
|
53
|
+
videoTitle: "Mux playback in React Native",
|
|
54
|
+
viewerUserId: "user-123",
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<MuxVideoView
|
|
60
|
+
player={player}
|
|
61
|
+
controls="custom"
|
|
62
|
+
contentFit="contain"
|
|
63
|
+
style={{ width: "100%", aspectRatio: 16 / 9, backgroundColor: "black" }}
|
|
64
|
+
/>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`controls`: `"native"` for platform controls, `"custom"` for the shared cross-platform JS controls, `"none"` for the bare video surface.
|
|
70
|
+
|
|
71
|
+
## Source Options
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
type MuxVideoSource = {
|
|
75
|
+
playbackId: string;
|
|
76
|
+
assetId?: string;
|
|
77
|
+
playbackToken?: string;
|
|
78
|
+
drmToken?: string;
|
|
79
|
+
customDomain?: string;
|
|
80
|
+
minResolution?: "480p" | "540p" | "720p" | "1080p" | "1440p" | "2160p";
|
|
81
|
+
maxResolution?: "720p" | "1080p" | "1440p" | "2160p";
|
|
82
|
+
renditionOrder?: "default" | "desc";
|
|
83
|
+
clipping?: { assetStartTime?: number; assetEndTime?: number };
|
|
84
|
+
metadata?: {
|
|
85
|
+
envKey?: string;
|
|
86
|
+
playerName?: string;
|
|
87
|
+
videoTitle?: string;
|
|
88
|
+
videoId?: string;
|
|
89
|
+
viewerUserId?: string;
|
|
90
|
+
customData?: Record<string, string>;
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
- `metadata.envKey` enables Mux Data.
|
|
96
|
+
- `drmToken` requires `playbackToken`.
|
|
97
|
+
- The source is mutable — pass it from state and the player will reload when it changes.
|
|
98
|
+
|
|
99
|
+
## Player Commands
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
await player.play();
|
|
103
|
+
await player.pause();
|
|
104
|
+
await player.seekTo(12);
|
|
105
|
+
await player.seekBy(10);
|
|
106
|
+
await player.replay();
|
|
107
|
+
await player.setMuted(true);
|
|
108
|
+
await player.setVolume(0.5);
|
|
109
|
+
await player.setLoop(true);
|
|
110
|
+
await player.setPlaybackRate(1.25);
|
|
111
|
+
player.replace({ playbackId: "NEW_PLAYBACK_ID" });
|
|
112
|
+
await player.release();
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Mux Robots UI
|
|
116
|
+
|
|
117
|
+
When using `controls="custom"`, you can add Mux Robots buttons (summary, chapters, key moments). Keep `MUX_TOKEN_ID` / `MUX_TOKEN_SECRET` on a backend and pass callbacks:
|
|
118
|
+
|
|
119
|
+
```tsx
|
|
120
|
+
<MuxVideoView
|
|
121
|
+
player={player}
|
|
122
|
+
controls="custom"
|
|
123
|
+
robots={{
|
|
124
|
+
onSummarize: ({ assetId }) =>
|
|
125
|
+
fetchJson("/mux/robots/summarize", { assetId }),
|
|
126
|
+
onGenerateChapters: ({ assetId }) =>
|
|
127
|
+
fetchJson("/mux/robots/chapters", { assetId }),
|
|
128
|
+
onFindKeyMoments: ({ assetId }) =>
|
|
129
|
+
fetchJson("/mux/robots/key-moments", { assetId }),
|
|
130
|
+
}}
|
|
131
|
+
/>
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Buttons appear only for actions with a callback. Chapters render as timeline markers; key moments render as highlighted ranges. Selecting either seeks to its start time.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
apply plugin: 'com.android.library'
|
|
2
|
+
apply plugin: 'org.jetbrains.kotlin.android'
|
|
3
|
+
apply plugin: 'expo-module-gradle-plugin'
|
|
4
|
+
|
|
5
|
+
group = 'com.mux.reactnativeplayer'
|
|
6
|
+
version = '0.1.0'
|
|
7
|
+
|
|
8
|
+
def safeExtGet(prop, fallback) {
|
|
9
|
+
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
android {
|
|
13
|
+
namespace 'com.mux.reactnativeplayer'
|
|
14
|
+
compileSdkVersion safeExtGet('compileSdkVersion', 36)
|
|
15
|
+
|
|
16
|
+
defaultConfig {
|
|
17
|
+
minSdkVersion safeExtGet('minSdkVersion', 23)
|
|
18
|
+
targetSdkVersion safeExtGet('targetSdkVersion', 36)
|
|
19
|
+
versionCode 1
|
|
20
|
+
versionName "0.1.0"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
repositories {
|
|
25
|
+
google()
|
|
26
|
+
mavenCentral()
|
|
27
|
+
maven { url = uri("https://muxinc.jfrog.io/artifactory/default-maven-release-local") }
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
dependencies {
|
|
31
|
+
implementation project(':expo-modules-core')
|
|
32
|
+
implementation "com.mux.player:android:1.5.4"
|
|
33
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android" />
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
package com.mux.reactnativeplayer
|
|
2
|
+
|
|
3
|
+
import android.app.Activity
|
|
4
|
+
import android.content.pm.ActivityInfo
|
|
5
|
+
import expo.modules.kotlin.modules.Module
|
|
6
|
+
import expo.modules.kotlin.modules.ModuleDefinition
|
|
7
|
+
|
|
8
|
+
class MuxReactNativePlayerModule : Module() {
|
|
9
|
+
override fun definition() = ModuleDefinition {
|
|
10
|
+
Name("MuxReactNativePlayer")
|
|
11
|
+
|
|
12
|
+
AsyncFunction("lockFullscreenLandscape") {
|
|
13
|
+
runOnActivity { activity ->
|
|
14
|
+
activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
AsyncFunction("unlockFullscreenOrientation") {
|
|
19
|
+
runOnActivity { activity ->
|
|
20
|
+
activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
View(MuxVideoView::class) {
|
|
25
|
+
OnViewDestroys { view: MuxVideoView ->
|
|
26
|
+
view.release()
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
Events(
|
|
30
|
+
"onStatusChange",
|
|
31
|
+
"onPlayingChange",
|
|
32
|
+
"onTimeUpdate",
|
|
33
|
+
"onSourceLoad",
|
|
34
|
+
"onSourceError"
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
Prop("source") { view: MuxVideoView, source: MuxVideoSourceRecord? ->
|
|
38
|
+
view.setSource(source)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
Prop("nativeControls", true) { view: MuxVideoView, enabled: Boolean ->
|
|
42
|
+
view.setNativeControls(enabled)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
Prop("contentFit", "contain") { view: MuxVideoView, contentFit: String ->
|
|
46
|
+
view.setContentFit(contentFit)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
Prop("allowsFullscreen", true) { _: MuxVideoView, _: Boolean ->
|
|
50
|
+
// Android Media3 PlayerView exposes fullscreen through app UI; accepted for API parity.
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
Prop("allowsPictureInPicture", false) { _: MuxVideoView, _: Boolean ->
|
|
54
|
+
// PiP requires host Activity integration and is intentionally left to a future pass.
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
Prop("timeUpdateEventInterval", 0.5) { view: MuxVideoView, interval: Double ->
|
|
58
|
+
view.setTimeUpdateEventInterval(interval)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
Prop("startupBufferDuration", 0.0) { view: MuxVideoView, duration: Double ->
|
|
62
|
+
view.setStartupBufferDuration(duration)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
Prop("playWhenReady", false) { view: MuxVideoView, playWhenReady: Boolean ->
|
|
66
|
+
view.setPlayWhenReady(playWhenReady)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
Prop("muted", false) { view: MuxVideoView, muted: Boolean ->
|
|
70
|
+
view.setMuted(muted)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
Prop("volume", 1.0) { view: MuxVideoView, volume: Double ->
|
|
74
|
+
view.setVolume(volume)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
Prop("loop", false) { view: MuxVideoView, loop: Boolean ->
|
|
78
|
+
view.setLoop(loop)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
Prop("playbackRate", 1.0) { view: MuxVideoView, rate: Double ->
|
|
82
|
+
view.setPlaybackRate(rate)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
AsyncFunction("play") { view: MuxVideoView ->
|
|
86
|
+
view.play()
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
AsyncFunction("pause") { view: MuxVideoView ->
|
|
90
|
+
view.pause()
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
AsyncFunction("replay") { view: MuxVideoView ->
|
|
94
|
+
view.replay()
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
AsyncFunction("seekBy") { view: MuxVideoView, seconds: Double ->
|
|
98
|
+
view.seekBy(seconds)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
AsyncFunction("seekTo") { view: MuxVideoView, seconds: Double ->
|
|
102
|
+
view.seekTo(seconds)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
AsyncFunction("setMuted") { view: MuxVideoView, muted: Boolean ->
|
|
106
|
+
view.setMuted(muted)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
AsyncFunction("setVolume") { view: MuxVideoView, volume: Double ->
|
|
110
|
+
view.setVolume(volume)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
AsyncFunction("setLoop") { view: MuxVideoView, loop: Boolean ->
|
|
114
|
+
view.setLoop(loop)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
AsyncFunction("setPlaybackRate") { view: MuxVideoView, rate: Double ->
|
|
118
|
+
view.setPlaybackRate(rate)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
AsyncFunction("setCaptionTrack") { view: MuxVideoView, trackId: String? ->
|
|
122
|
+
view.setCaptionTrack(trackId)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
AsyncFunction("release") { view: MuxVideoView ->
|
|
126
|
+
view.release()
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
private fun runOnActivity(block: (Activity) -> Unit) {
|
|
132
|
+
val activity = appContext.activityProvider?.currentActivity ?: return
|
|
133
|
+
activity.runOnUiThread { block(activity) }
|
|
134
|
+
}
|
|
135
|
+
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
package com.mux.reactnativeplayer
|
|
2
|
+
|
|
3
|
+
import androidx.media3.common.MediaItem
|
|
4
|
+
import androidx.media3.common.MediaMetadata
|
|
5
|
+
import com.mux.player.media.MediaItems
|
|
6
|
+
import com.mux.player.media.PlaybackResolution
|
|
7
|
+
import com.mux.player.media.RenditionOrder
|
|
8
|
+
import com.mux.stats.sdk.core.model.CustomData
|
|
9
|
+
import com.mux.stats.sdk.core.model.CustomerData
|
|
10
|
+
import com.mux.stats.sdk.core.model.CustomerPlayerData
|
|
11
|
+
import com.mux.stats.sdk.core.model.CustomerVideoData
|
|
12
|
+
import expo.modules.kotlin.records.Field
|
|
13
|
+
import expo.modules.kotlin.records.Record
|
|
14
|
+
|
|
15
|
+
class MuxVideoClippingRecord : Record {
|
|
16
|
+
@Field
|
|
17
|
+
var assetStartTime: Double? = null
|
|
18
|
+
|
|
19
|
+
@Field
|
|
20
|
+
var assetEndTime: Double? = null
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
class MuxVideoMetadataRecord : Record {
|
|
24
|
+
@Field
|
|
25
|
+
var envKey: String? = null
|
|
26
|
+
|
|
27
|
+
@Field
|
|
28
|
+
var playerName: String? = null
|
|
29
|
+
|
|
30
|
+
@Field
|
|
31
|
+
var playerVersion: String? = null
|
|
32
|
+
|
|
33
|
+
@Field
|
|
34
|
+
var videoTitle: String? = null
|
|
35
|
+
|
|
36
|
+
@Field
|
|
37
|
+
var videoId: String? = null
|
|
38
|
+
|
|
39
|
+
@Field
|
|
40
|
+
var videoSeries: String? = null
|
|
41
|
+
|
|
42
|
+
@Field
|
|
43
|
+
var viewerUserId: String? = null
|
|
44
|
+
|
|
45
|
+
@Field
|
|
46
|
+
var customData: Map<String, String>? = null
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
class MuxVideoSourceRecord : Record {
|
|
50
|
+
@Field
|
|
51
|
+
var playbackId: String = ""
|
|
52
|
+
|
|
53
|
+
@Field
|
|
54
|
+
var playbackToken: String? = null
|
|
55
|
+
|
|
56
|
+
@Field
|
|
57
|
+
var drmToken: String? = null
|
|
58
|
+
|
|
59
|
+
@Field
|
|
60
|
+
var customDomain: String? = null
|
|
61
|
+
|
|
62
|
+
@Field
|
|
63
|
+
var minResolution: String? = null
|
|
64
|
+
|
|
65
|
+
@Field
|
|
66
|
+
var maxResolution: String? = null
|
|
67
|
+
|
|
68
|
+
@Field
|
|
69
|
+
var renditionOrder: String = "default"
|
|
70
|
+
|
|
71
|
+
@Field
|
|
72
|
+
var clipping: MuxVideoClippingRecord? = null
|
|
73
|
+
|
|
74
|
+
@Field
|
|
75
|
+
var metadata: MuxVideoMetadataRecord? = null
|
|
76
|
+
|
|
77
|
+
val fingerprint: String
|
|
78
|
+
get() = listOf(
|
|
79
|
+
playbackId,
|
|
80
|
+
playbackToken.orEmpty(),
|
|
81
|
+
drmToken.orEmpty(),
|
|
82
|
+
customDomain.orEmpty(),
|
|
83
|
+
minResolution.orEmpty(),
|
|
84
|
+
maxResolution.orEmpty(),
|
|
85
|
+
renditionOrder,
|
|
86
|
+
clipping?.assetStartTime?.toString().orEmpty(),
|
|
87
|
+
clipping?.assetEndTime?.toString().orEmpty(),
|
|
88
|
+
metadata?.envKey.orEmpty(),
|
|
89
|
+
metadata?.playerName.orEmpty(),
|
|
90
|
+
metadata?.playerVersion.orEmpty(),
|
|
91
|
+
metadata?.videoTitle.orEmpty(),
|
|
92
|
+
metadata?.videoId.orEmpty(),
|
|
93
|
+
metadata?.videoSeries.orEmpty(),
|
|
94
|
+
metadata?.viewerUserId.orEmpty(),
|
|
95
|
+
metadata?.customData?.toSortedMap()?.entries?.joinToString { "${it.key}:${it.value}" }.orEmpty(),
|
|
96
|
+
).joinToString("|")
|
|
97
|
+
|
|
98
|
+
fun toMediaItem(): MediaItem {
|
|
99
|
+
val builder = MediaItems.builderFromMuxPlaybackId(
|
|
100
|
+
playbackId = playbackId,
|
|
101
|
+
maxResolution = maxResolution.toPlaybackResolution(),
|
|
102
|
+
minResolution = minResolution.toPlaybackResolution(),
|
|
103
|
+
renditionOrder = renditionOrder.toRenditionOrder(),
|
|
104
|
+
assetStartTime = clipping?.assetStartTime,
|
|
105
|
+
assetEndTime = clipping?.assetEndTime,
|
|
106
|
+
domain = customDomain,
|
|
107
|
+
playbackToken = playbackToken,
|
|
108
|
+
drmToken = drmToken,
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
metadata?.videoTitle?.let { title ->
|
|
112
|
+
builder.setMediaMetadata(
|
|
113
|
+
MediaMetadata.Builder()
|
|
114
|
+
.setTitle(title)
|
|
115
|
+
.build()
|
|
116
|
+
)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return builder.build()
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
fun toCustomerData(): CustomerData {
|
|
123
|
+
val metadata = metadata
|
|
124
|
+
return CustomerData().apply {
|
|
125
|
+
customerPlayerData = CustomerPlayerData().apply {
|
|
126
|
+
environmentKey = metadata?.envKey
|
|
127
|
+
playerName = metadata?.playerName ?: "MuxReactNativePlayer"
|
|
128
|
+
playerVersion = metadata?.playerVersion
|
|
129
|
+
viewerUserId = metadata?.viewerUserId
|
|
130
|
+
}
|
|
131
|
+
customerVideoData = CustomerVideoData().apply {
|
|
132
|
+
videoTitle = metadata?.videoTitle
|
|
133
|
+
videoId = metadata?.videoId
|
|
134
|
+
videoSeries = metadata?.videoSeries
|
|
135
|
+
}
|
|
136
|
+
customData = CustomData().apply {
|
|
137
|
+
applyCustomData(metadata?.customData)
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
private fun String?.toPlaybackResolution(): PlaybackResolution? {
|
|
144
|
+
return when (this) {
|
|
145
|
+
"480p" -> PlaybackResolution.LD_480
|
|
146
|
+
"540p" -> PlaybackResolution.LD_540
|
|
147
|
+
"720p" -> PlaybackResolution.HD_720
|
|
148
|
+
"1080p" -> PlaybackResolution.FHD_1080
|
|
149
|
+
"1440p" -> PlaybackResolution.QHD_1440
|
|
150
|
+
"2160p" -> PlaybackResolution.FOUR_K_2160
|
|
151
|
+
else -> null
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
private fun String?.toRenditionOrder(): RenditionOrder? {
|
|
156
|
+
return when (this) {
|
|
157
|
+
"desc" -> RenditionOrder.Descending
|
|
158
|
+
"default" -> RenditionOrder.Default
|
|
159
|
+
else -> null
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
private fun CustomData.applyCustomData(values: Map<String, String>?) {
|
|
164
|
+
customData1 = values?.get("customData1")
|
|
165
|
+
customData2 = values?.get("customData2")
|
|
166
|
+
customData3 = values?.get("customData3")
|
|
167
|
+
customData4 = values?.get("customData4")
|
|
168
|
+
customData5 = values?.get("customData5")
|
|
169
|
+
customData6 = values?.get("customData6")
|
|
170
|
+
customData7 = values?.get("customData7")
|
|
171
|
+
customData8 = values?.get("customData8")
|
|
172
|
+
customData9 = values?.get("customData9")
|
|
173
|
+
customData10 = values?.get("customData10")
|
|
174
|
+
}
|