bitmovin-player-react-native 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.
Files changed (36) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +274 -0
  3. package/RNBitmovinPlayer.podspec +23 -0
  4. package/android/build.gradle +55 -0
  5. package/android/src/main/AndroidManifest.xml +4 -0
  6. package/android/src/main/java/com/bitmovin/player/reactnative/PlayerModule.kt +279 -0
  7. package/android/src/main/java/com/bitmovin/player/reactnative/RNPlayerView.kt +264 -0
  8. package/android/src/main/java/com/bitmovin/player/reactnative/RNPlayerViewManager.kt +139 -0
  9. package/android/src/main/java/com/bitmovin/player/reactnative/RNPlayerViewPackage.kt +33 -0
  10. package/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt +162 -0
  11. package/android/src/main/java/com/bitmovin/player/reactnative/extensions/Events.kt +15 -0
  12. package/ios/Event+JSON.swift +132 -0
  13. package/ios/PlayerModule.m +61 -0
  14. package/ios/PlayerModule.swift +347 -0
  15. package/ios/RCTConvert+BitmovinPlayer.swift +79 -0
  16. package/ios/RNBitmovinPlayer.h +7 -0
  17. package/ios/RNBitmovinPlayer.xcodeproj/project.pbxproj +303 -0
  18. package/ios/RNPlayerView+PlayerListener.swift +83 -0
  19. package/ios/RNPlayerView.swift +50 -0
  20. package/ios/RNPlayerViewManager.m +29 -0
  21. package/ios/RNPlayerViewManager.swift +60 -0
  22. package/lib/index.d.ts +486 -0
  23. package/lib/index.js +218 -0
  24. package/lib/index.mjs +191 -0
  25. package/package.json +82 -0
  26. package/src/components/PlayerView/events.ts +69 -0
  27. package/src/components/PlayerView/index.tsx +106 -0
  28. package/src/components/PlayerView/native.ts +17 -0
  29. package/src/components/index.ts +1 -0
  30. package/src/events.ts +184 -0
  31. package/src/hooks/index.ts +1 -0
  32. package/src/hooks/usePlayer.ts +10 -0
  33. package/src/hooks/useProxy.ts +36 -0
  34. package/src/index.ts +5 -0
  35. package/src/player.ts +229 -0
  36. package/src/source.ts +95 -0
@@ -0,0 +1,36 @@
1
+ import omit from 'lodash.omit';
2
+ import { useCallback, useRef, RefObject } from 'react';
3
+ import { NativeSyntheticEvent, findNodeHandle } from 'react-native';
4
+ import { Event } from '../events';
5
+
6
+ /**
7
+ * Returns the actual event payload without RN's bubbling data.
8
+ */
9
+ function unwrapNativeEvent<E extends Event>(event: NativeSyntheticEvent<E>): E {
10
+ return omit(event.nativeEvent, ['target']) as E;
11
+ }
12
+
13
+ /**
14
+ * Proxies a native event that receives a `NativeSyntheticEvent` using
15
+ * a function that takes the `unwrapped` event version. Intented to be
16
+ * used when proxying native events of a native React component.
17
+ *
18
+ * @param viewRef - Reference to native component instance.
19
+ * @param proxy - Function that takes the `unwrapped` event.
20
+ * @returns React callback that can be passed as a native event prop.
21
+ */
22
+ export function useProxy<E extends Event>(
23
+ viewRef: RefObject<any>,
24
+ proxy?: (event: E) => void
25
+ ): (nativeEvent: NativeSyntheticEvent<E>) => void {
26
+ const proxyRef = useRef(proxy);
27
+ return useCallback(
28
+ (event) => {
29
+ const node: number = (event.target as any)._nativeTag;
30
+ if (node === findNodeHandle(viewRef.current)) {
31
+ proxyRef.current?.(unwrapNativeEvent(event));
32
+ }
33
+ },
34
+ [viewRef]
35
+ );
36
+ }
package/src/index.ts ADDED
@@ -0,0 +1,5 @@
1
+ export * from './player';
2
+ export * from './source';
3
+ export * from './events';
4
+ export * from './hooks';
5
+ export * from './components';
package/src/player.ts ADDED
@@ -0,0 +1,229 @@
1
+ import { NativeModules, Platform } from 'react-native';
2
+ import { SourceConfig, Source } from './source';
3
+
4
+ const PlayerModule = NativeModules.PlayerModule;
5
+
6
+ /**
7
+ * Object used to configure a new `Player` instance.
8
+ */
9
+ export interface PlayerConfig {
10
+ /**
11
+ * Optionally user-defined string `id` for the native `Player` instances. Used to access a certain native `Player` instance from any point in the source code then call methods/properties on it.
12
+ *
13
+ * When left empty, a random `UUIDv4` is generated for it.
14
+ * @example
15
+ * Accessing or creating the `Player` with `nativeId` equal to `my-player`:
16
+ * ```
17
+ * const player = new Player({ nativeId: 'my-player' })
18
+ * player.play(); // call methods and properties...
19
+ * ```
20
+ */
21
+ nativeId?: string;
22
+ /**
23
+ * Bitmovin license key that can be found in the Bitmovin portal.
24
+ * If a license key is set here, it will be used instead of the license key found in the `Info.plist` and `AndroidManifest.xml`.
25
+ * @example
26
+ * Configuring the player license key from source code:
27
+ * ```
28
+ * const player = new Player({
29
+ * licenseKey: '\<LICENSE-KEY-CODE\>',
30
+ * });
31
+ * ```
32
+ * @example
33
+ * `licenseKey` can be safely omitted from source code if it has
34
+ * been configured in Info.plist/AndroidManifest.xml.
35
+ * ```
36
+ * const player = new Player(); // omit `licenseKey`
37
+ * player.play(); // call methods and properties...
38
+ * ```
39
+ */
40
+ licenseKey?: string;
41
+ }
42
+
43
+ /**
44
+ * Loads, controls and renders audio and video content represented through `Source`s. A player
45
+ * instance can be created via the `usePlayer` hook and will idle until one or more `Source`s are
46
+ * loaded. Once `load` is called, the player becomes active and initiates necessary downloads to
47
+ * start playback of the loaded source(s).
48
+ *
49
+ * Can be attached to `PlayerView` component in order to use Bitmovin's Player Web UI.
50
+ * @see PlayerView
51
+ */
52
+ export class Player {
53
+ /**
54
+ * User-defined `nativeId` string or random `UUIDv4` identifying this `Player` in the native side.
55
+ */
56
+ readonly nativeId: string;
57
+
58
+ /**
59
+ * Configuration object used to initialize this `Player`.
60
+ */
61
+ readonly config: PlayerConfig | null;
62
+
63
+ constructor(config?: PlayerConfig) {
64
+ this.config = config ?? null;
65
+ this.nativeId = config?.nativeId ?? PlayerModule.generateUUIDv4();
66
+ PlayerModule.initWithConfig(this.nativeId, this.config);
67
+ }
68
+
69
+ /**
70
+ * Loads a new `Source` into the player.
71
+ */
72
+ load = (source: SourceConfig) => {
73
+ PlayerModule.loadSource(this.nativeId, source);
74
+ };
75
+
76
+ /**
77
+ * Unloads all `Source`s from the player.
78
+ */
79
+ unload = () => {
80
+ PlayerModule.unload(this.nativeId);
81
+ };
82
+
83
+ /**
84
+ * Starts or resumes playback after being paused. Has no effect if the player is already playing.
85
+ */
86
+ play = () => {
87
+ PlayerModule.play(this.nativeId);
88
+ };
89
+
90
+ /**
91
+ * Pauses the video if it is playing. Has no effect if the player is already paused.
92
+ */
93
+ pause = () => {
94
+ PlayerModule.pause(this.nativeId);
95
+ };
96
+
97
+ /**
98
+ * Seeks to the given playback time specified by the parameter `time` in seconds. Must not be
99
+ * greater than the total duration of the video. Has no effect when watching a live stream since
100
+ * seeking is not possible.
101
+ *
102
+ * @param time - The time to seek to in seconds.
103
+ */
104
+ seek = (time: number) => {
105
+ PlayerModule.seek(this.nativeId, time);
106
+ };
107
+
108
+ /**
109
+ * Mutes the player if an audio track is available. Has no effect if the player is already muted.
110
+ */
111
+ mute = () => {
112
+ PlayerModule.mute(this.nativeId);
113
+ };
114
+
115
+ /**
116
+ * Unmutes the player if it is muted. Has no effect if the player is already unmuted.
117
+ */
118
+ unmute = () => {
119
+ PlayerModule.unmute(this.nativeId);
120
+ };
121
+
122
+ /**
123
+ * Destroys the player and releases all of its allocated resources.
124
+ * The player instance must not be used after calling this method.
125
+ */
126
+ destroy = () => {
127
+ PlayerModule.destroy(this.nativeId);
128
+ };
129
+
130
+ /**
131
+ * Sets the player's volume between 0 (silent) and 100 (max volume).
132
+ *
133
+ * @param volume - The volume level to set.
134
+ */
135
+ setVolume = (volume: number) => {
136
+ PlayerModule.setVolume(this.nativeId, volume);
137
+ };
138
+
139
+ /**
140
+ * @returns The currently active source or null if no source is active.
141
+ */
142
+ getSource = async (): Promise<Source> => {
143
+ return PlayerModule.source(this.nativeId);
144
+ };
145
+
146
+ /**
147
+ * @returns The player's current volume level.
148
+ */
149
+ getVolume = async (): Promise<number> => {
150
+ return PlayerModule.getVolume(this.nativeId);
151
+ };
152
+
153
+ /**
154
+ * @returns The current playback time in seconds.
155
+ *
156
+ * For VoD streams the returned time ranges between 0 and the duration of the asset.
157
+ *
158
+ * For live streams it can be specified if an absolute UNIX timestamp or a value
159
+ * relative to the playback start should be returned.
160
+ *
161
+ * @param mode - The time mode to specify: an absolute UNIX timestamp ('absolute') or relative time ('relative').
162
+ */
163
+ getCurrentTime = async (mode?: 'relative' | 'absolute'): Promise<number> => {
164
+ return PlayerModule.currentTime(this.nativeId, mode);
165
+ };
166
+
167
+ /**
168
+ * @returns The total duration in seconds of the current video or INFINITY if it’s a live stream.
169
+ */
170
+ getDuration = async (): Promise<number> => {
171
+ return PlayerModule.duration(this.nativeId);
172
+ };
173
+
174
+ /**
175
+ * @returns `true` if the player is muted.
176
+ */
177
+ isMuted = async (): Promise<boolean> => {
178
+ return PlayerModule.isMuted(this.nativeId);
179
+ };
180
+
181
+ /**
182
+ * @returns `true` if the player is currently playing, i.e. has started and is not paused.
183
+ */
184
+ isPlaying = async (): Promise<boolean> => {
185
+ return PlayerModule.isPlaying(this.nativeId);
186
+ };
187
+
188
+ /**
189
+ * @returns `true` if the player has started playback but it's currently paused.
190
+ */
191
+ isPaused = async (): Promise<boolean> => {
192
+ return PlayerModule.isPaused(this.nativeId);
193
+ };
194
+
195
+ /**
196
+ * @returns `true` if the displayed video is a live stream.
197
+ */
198
+ isLive = async (): Promise<boolean> => {
199
+ return PlayerModule.isLive(this.nativeId);
200
+ };
201
+
202
+ /**
203
+ * @remarks Only available for iOS devices.
204
+ * @returns `true` when media is played externally using AirPlay.
205
+ */
206
+ isAirPlayActive = async (): Promise<boolean> => {
207
+ if (Platform.OS === 'android') {
208
+ console.warn(
209
+ `[Player ${this.nativeId}] Method isAirPlayActive is not available for Android. Only iOS devices.`
210
+ );
211
+ return false;
212
+ }
213
+ return PlayerModule.isAirPlayActive(this.nativeId);
214
+ };
215
+
216
+ /**
217
+ * @remarks Only available for iOS devices.
218
+ * @returns `true` when AirPlay is available.
219
+ */
220
+ isAirPlayAvailable = async (): Promise<boolean> => {
221
+ if (Platform.OS === 'android') {
222
+ console.warn(
223
+ `[Player ${this.nativeId}] Method isAirPlayAvailable is not available for Android. Only iOS devices.`
224
+ );
225
+ return false;
226
+ }
227
+ return PlayerModule.isAirPlayAvailable(this.nativeId);
228
+ };
229
+ }
package/src/source.ts ADDED
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Types of media that can be handled by the player.
3
+ */
4
+ export enum SourceType {
5
+ /**
6
+ * Indicates a missing source type.
7
+ */
8
+ NONE = 'none',
9
+ /**
10
+ * Indicates media type HLS.
11
+ */
12
+ HLS = 'hls',
13
+ /**
14
+ * Indicates media type DASH.
15
+ */
16
+ DASH = 'dash',
17
+ /**
18
+ * Indicates media type Progressive MP4.
19
+ */
20
+ PROGRESSIVE = 'progressive',
21
+ }
22
+
23
+ /**
24
+ * The different loading states a `Source` instance can be in.
25
+ */
26
+ export enum LoadingState {
27
+ /**
28
+ * The source is unloaded.
29
+ */
30
+ UNLOADED = 0,
31
+ /**
32
+ * The source is currently loading.
33
+ */
34
+ LOADING = 1,
35
+ /**
36
+ * The source is loaded.
37
+ */
38
+ LOADED = 2,
39
+ }
40
+
41
+ /**
42
+ * Represents a source configuration that be loaded into a player instance.
43
+ */
44
+ export interface SourceConfig {
45
+ /**
46
+ * The url for this source configuration.
47
+ */
48
+ url: string;
49
+ /**
50
+ * The `SourceType` for this configuration.
51
+ */
52
+ type?: SourceType;
53
+ /**
54
+ * The title of the video source.
55
+ */
56
+ title?: string;
57
+ /**
58
+ * The URL to a preview image displayed until the video starts.
59
+ */
60
+ poster?: string;
61
+ /**
62
+ * Indicates whether to show the poster image during playback.
63
+ * Useful, for example, for audio-only streams.
64
+ */
65
+ isPosterPersistent?: boolean;
66
+ }
67
+
68
+ /**
69
+ * Represents audio and video content that can be loaded into a player.
70
+ */
71
+ export interface Source {
72
+ /**
73
+ * The duration of the source in seconds if it’s a VoD or `INFINITY` if it’s a live stream.
74
+ * Default value is `0` if the duration is not available or not known.
75
+ */
76
+ duration: number;
77
+ /**
78
+ * Whether the source is currently active in a player (i.e. playing back or paused).
79
+ * Only one source can be active in the same player instance at any time.
80
+ */
81
+ isActive: boolean;
82
+ /**
83
+ * Whether the source is currently attached to a player instance.
84
+ */
85
+ isAttachedToPlayer: boolean;
86
+ /**
87
+ * Metadata for the currently loaded source.
88
+ * Setting the metadata value for a source is not supported yet.
89
+ */
90
+ metadata?: Record<string, any>;
91
+ /**
92
+ * The current `LoadingState` of the source.
93
+ */
94
+ loadingState?: LoadingState;
95
+ }