@granite-js/video 1.0.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/CHANGELOG.md +7 -0
- package/GraniteVideo.podspec +72 -0
- package/android/README.md +232 -0
- package/android/build.gradle +117 -0
- package/android/gradle.properties +8 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/run/granite/video/GraniteVideoModule.kt +70 -0
- package/android/src/main/java/run/granite/video/GraniteVideoPackage.kt +43 -0
- package/android/src/main/java/run/granite/video/GraniteVideoView.kt +384 -0
- package/android/src/main/java/run/granite/video/GraniteVideoViewManager.kt +318 -0
- package/android/src/main/java/run/granite/video/event/GraniteVideoEvents.kt +273 -0
- package/android/src/main/java/run/granite/video/event/VideoEventDispatcher.kt +66 -0
- package/android/src/main/java/run/granite/video/event/VideoEventListenerAdapter.kt +157 -0
- package/android/src/main/java/run/granite/video/provider/GraniteVideoProvider.kt +346 -0
- package/android/src/media3/AndroidManifest.xml +9 -0
- package/android/src/media3/java/run/granite/video/provider/media3/ExoPlayerProvider.kt +386 -0
- package/android/src/media3/java/run/granite/video/provider/media3/Media3ContentProvider.kt +29 -0
- package/android/src/media3/java/run/granite/video/provider/media3/Media3Initializer.kt +25 -0
- package/android/src/media3/java/run/granite/video/provider/media3/factory/ExoPlayerFactory.kt +32 -0
- package/android/src/media3/java/run/granite/video/provider/media3/factory/MediaSourceFactory.kt +61 -0
- package/android/src/media3/java/run/granite/video/provider/media3/factory/TrackSelectorFactory.kt +26 -0
- package/android/src/media3/java/run/granite/video/provider/media3/factory/VideoSurfaceFactory.kt +62 -0
- package/android/src/media3/java/run/granite/video/provider/media3/listener/ExoPlayerEventListener.kt +104 -0
- package/android/src/media3/java/run/granite/video/provider/media3/scheduler/ProgressScheduler.kt +56 -0
- package/android/src/test/java/run/granite/video/GraniteVideoViewRobolectricTest.kt +598 -0
- package/android/src/test/java/run/granite/video/event/VideoEventListenerAdapterTest.kt +319 -0
- package/android/src/test/java/run/granite/video/helpers/FakeGraniteVideoProvider.kt +161 -0
- package/android/src/test/java/run/granite/video/helpers/TestProgressScheduler.kt +42 -0
- package/android/src/test/java/run/granite/video/provider/GraniteVideoRegistryTest.kt +232 -0
- package/android/src/test/java/run/granite/video/provider/ProviderContractTest.kt +174 -0
- package/android/src/test/java/run/granite/video/provider/media3/listener/ExoPlayerEventListenerTest.kt +243 -0
- package/android/src/test/resources/kotest.properties +2 -0
- package/dist/module/GraniteVideo.js +458 -0
- package/dist/module/GraniteVideo.js.map +1 -0
- package/dist/module/GraniteVideoNativeComponent.ts +265 -0
- package/dist/module/index.js +7 -0
- package/dist/module/index.js.map +1 -0
- package/dist/module/package.json +1 -0
- package/dist/module/types.js +4 -0
- package/dist/module/types.js.map +1 -0
- package/dist/typescript/GraniteVideo.d.ts +12 -0
- package/dist/typescript/GraniteVideoNativeComponent.d.ts +189 -0
- package/dist/typescript/index.d.ts +5 -0
- package/dist/typescript/types.d.ts +328 -0
- package/ios/GraniteVideoComponentsProvider.h +10 -0
- package/ios/GraniteVideoProvider.swift +280 -0
- package/ios/GraniteVideoView.h +15 -0
- package/ios/GraniteVideoView.mm +661 -0
- package/ios/Providers/AVPlayerProvider.swift +541 -0
- package/package.json +106 -0
- package/src/GraniteVideo.tsx +575 -0
- package/src/GraniteVideoNativeComponent.ts +265 -0
- package/src/index.ts +8 -0
- package/src/types.ts +464 -0
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
import type { StyleProp, ViewStyle, ImageSourcePropType } from 'react-native';
|
|
2
|
+
import type { OnVideoLoadStartEvent, OnVideoLoadEvent, OnVideoProgressEvent, OnVideoSeekEvent, OnVideoBufferEvent, OnVideoBandwidthUpdateEvent, OnVideoPlaybackStateChangedEvent, OnVideoPlaybackRateChangeEvent, OnVideoVolumeChangeEvent, OnVideoAudioFocusChangedEvent, OnVideoPictureInPictureStatusChangedEvent, OnVideoControlsVisibilityChangeEvent, OnVideoExternalPlaybackChangeEvent, OnVideoAspectRatioEvent, OnVideoErrorEvent } from './GraniteVideoNativeComponent';
|
|
3
|
+
export interface VideoSourceHeaders {
|
|
4
|
+
[key: string]: string;
|
|
5
|
+
}
|
|
6
|
+
export interface DrmConfig {
|
|
7
|
+
type: 'widevine' | 'playready' | 'clearkey' | 'fairplay';
|
|
8
|
+
licenseServer?: string;
|
|
9
|
+
headers?: VideoSourceHeaders;
|
|
10
|
+
contentId?: string;
|
|
11
|
+
certificateUrl?: string;
|
|
12
|
+
base64Certificate?: boolean;
|
|
13
|
+
multiDrm?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export interface TextTrack {
|
|
16
|
+
title: string;
|
|
17
|
+
language: string;
|
|
18
|
+
type: 'application/x-subrip' | 'text/vtt' | 'application/ttml+xml';
|
|
19
|
+
uri: string;
|
|
20
|
+
}
|
|
21
|
+
export interface BufferConfig {
|
|
22
|
+
minBufferMs?: number;
|
|
23
|
+
maxBufferMs?: number;
|
|
24
|
+
bufferForPlaybackMs?: number;
|
|
25
|
+
bufferForPlaybackAfterRebufferMs?: number;
|
|
26
|
+
backBufferDurationMs?: number;
|
|
27
|
+
cacheSizeMB?: number;
|
|
28
|
+
live?: {
|
|
29
|
+
maxPlaybackSpeed?: number;
|
|
30
|
+
minPlaybackSpeed?: number;
|
|
31
|
+
maxOffsetMs?: number;
|
|
32
|
+
minOffsetMs?: number;
|
|
33
|
+
targetOffsetMs?: number;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export interface VideoSource {
|
|
37
|
+
uri?: string;
|
|
38
|
+
type?: string;
|
|
39
|
+
mainVer?: number;
|
|
40
|
+
patchVer?: number;
|
|
41
|
+
headers?: VideoSourceHeaders;
|
|
42
|
+
startPosition?: number;
|
|
43
|
+
cropStart?: number;
|
|
44
|
+
cropEnd?: number;
|
|
45
|
+
drm?: DrmConfig;
|
|
46
|
+
textTracks?: TextTrack[];
|
|
47
|
+
metadata?: VideoMetadata;
|
|
48
|
+
}
|
|
49
|
+
export interface VideoMetadata {
|
|
50
|
+
title?: string;
|
|
51
|
+
subtitle?: string;
|
|
52
|
+
description?: string;
|
|
53
|
+
artist?: string;
|
|
54
|
+
imageUri?: string;
|
|
55
|
+
}
|
|
56
|
+
export type SelectedTrackType = 'system' | 'disabled' | 'title' | 'language' | 'index';
|
|
57
|
+
export type SelectedVideoTrackType = 'auto' | 'disabled' | 'resolution' | 'index';
|
|
58
|
+
export interface SelectedTrack {
|
|
59
|
+
type: SelectedTrackType;
|
|
60
|
+
value?: string | number;
|
|
61
|
+
}
|
|
62
|
+
export interface SelectedVideoTrack {
|
|
63
|
+
type: SelectedVideoTrackType;
|
|
64
|
+
value?: number;
|
|
65
|
+
}
|
|
66
|
+
export type ResizeMode = 'contain' | 'cover' | 'stretch' | 'none';
|
|
67
|
+
export type ViewType = 'surface' | 'texture';
|
|
68
|
+
export interface PosterSource {
|
|
69
|
+
uri?: string;
|
|
70
|
+
}
|
|
71
|
+
export type Poster = ImageSourcePropType | PosterSource;
|
|
72
|
+
export type OnLoadData = OnVideoLoadEvent & {
|
|
73
|
+
naturalSize: OnVideoLoadEvent['naturalSize'] & {
|
|
74
|
+
orientation: 'portrait' | 'landscape';
|
|
75
|
+
};
|
|
76
|
+
audioTracks: AudioTrack[];
|
|
77
|
+
textTracks: TextTrackInfo[];
|
|
78
|
+
videoTracks: VideoTrackInfo[];
|
|
79
|
+
};
|
|
80
|
+
export interface AudioTrack {
|
|
81
|
+
index: number;
|
|
82
|
+
title?: string;
|
|
83
|
+
language?: string;
|
|
84
|
+
bitrate?: number;
|
|
85
|
+
type?: string;
|
|
86
|
+
selected?: boolean;
|
|
87
|
+
}
|
|
88
|
+
export interface TextTrackInfo {
|
|
89
|
+
index: number;
|
|
90
|
+
title?: string;
|
|
91
|
+
language?: string;
|
|
92
|
+
type?: string;
|
|
93
|
+
selected?: boolean;
|
|
94
|
+
}
|
|
95
|
+
export interface VideoTrackInfo {
|
|
96
|
+
index: number;
|
|
97
|
+
trackId?: string;
|
|
98
|
+
codecs?: string;
|
|
99
|
+
width?: number;
|
|
100
|
+
height?: number;
|
|
101
|
+
bitrate?: number;
|
|
102
|
+
selected?: boolean;
|
|
103
|
+
}
|
|
104
|
+
export type OnSeekData = OnVideoSeekEvent & {
|
|
105
|
+
target?: number;
|
|
106
|
+
};
|
|
107
|
+
export interface OnTimedMetadataData {
|
|
108
|
+
metadata: Array<{
|
|
109
|
+
value: string;
|
|
110
|
+
identifier: string;
|
|
111
|
+
}>;
|
|
112
|
+
}
|
|
113
|
+
export interface OnAudioTracksData {
|
|
114
|
+
audioTracks: AudioTrack[];
|
|
115
|
+
}
|
|
116
|
+
export interface OnTextTracksData {
|
|
117
|
+
textTracks: TextTrackInfo[];
|
|
118
|
+
}
|
|
119
|
+
export interface OnTextTrackDataChangedData {
|
|
120
|
+
subtitleTracks: string;
|
|
121
|
+
}
|
|
122
|
+
export interface OnVideoTracksData {
|
|
123
|
+
videoTracks: VideoTrackInfo[];
|
|
124
|
+
}
|
|
125
|
+
export interface OnReceiveAdEventData {
|
|
126
|
+
event: string;
|
|
127
|
+
data?: {
|
|
128
|
+
[key: string]: string | number | boolean;
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
export interface OnTransferEndData {
|
|
132
|
+
uri: string;
|
|
133
|
+
bytesTransferred: number;
|
|
134
|
+
}
|
|
135
|
+
export interface VideoRef {
|
|
136
|
+
seek: (time: number, tolerance?: number) => void;
|
|
137
|
+
pause: () => void;
|
|
138
|
+
resume: () => void;
|
|
139
|
+
setVolume: (volume: number) => void;
|
|
140
|
+
setFullScreen: (fullscreen: boolean) => void;
|
|
141
|
+
presentFullscreenPlayer: () => void;
|
|
142
|
+
dismissFullscreenPlayer: () => void;
|
|
143
|
+
enterPictureInPicture: () => void;
|
|
144
|
+
exitPictureInPicture: () => void;
|
|
145
|
+
setSource: (source: VideoSource) => void;
|
|
146
|
+
getCurrentPosition: () => Promise<number>;
|
|
147
|
+
save: (options?: {
|
|
148
|
+
type?: string;
|
|
149
|
+
}) => Promise<{
|
|
150
|
+
uri: string;
|
|
151
|
+
}>;
|
|
152
|
+
restoreUserInterfaceForPictureInPictureStopCompleted: (restored: boolean) => void;
|
|
153
|
+
}
|
|
154
|
+
export interface VideoProps {
|
|
155
|
+
testID?: string;
|
|
156
|
+
style?: StyleProp<ViewStyle>;
|
|
157
|
+
progressUpdateInterval?: number;
|
|
158
|
+
source: VideoSource | number;
|
|
159
|
+
/**
|
|
160
|
+
* **NOTE**
|
|
161
|
+
*
|
|
162
|
+
* Value: string with a URL for the poster is deprecated, use poster as an object instead.
|
|
163
|
+
*/
|
|
164
|
+
poster?: Poster | string;
|
|
165
|
+
posterResizeMode?: ResizeMode;
|
|
166
|
+
paused?: boolean;
|
|
167
|
+
muted?: boolean;
|
|
168
|
+
volume?: number;
|
|
169
|
+
rate?: number;
|
|
170
|
+
repeat?: boolean;
|
|
171
|
+
playInBackground?: boolean;
|
|
172
|
+
playWhenInactive?: boolean;
|
|
173
|
+
automaticallyWaitsToMinimizeStalling?: boolean;
|
|
174
|
+
shutterColor?: string;
|
|
175
|
+
resizeMode?: ResizeMode;
|
|
176
|
+
viewType?: ViewType;
|
|
177
|
+
useTextureView?: boolean;
|
|
178
|
+
useSecureView?: boolean;
|
|
179
|
+
bufferConfig?: BufferConfig;
|
|
180
|
+
minLoadRetryCount?: number;
|
|
181
|
+
maxBitRate?: number;
|
|
182
|
+
preferredForwardBufferDuration?: number;
|
|
183
|
+
selectedAudioTrack?: SelectedTrack;
|
|
184
|
+
selectedTextTrack?: SelectedTrack;
|
|
185
|
+
selectedVideoTrack?: SelectedVideoTrack;
|
|
186
|
+
textTracks?: TextTrack[];
|
|
187
|
+
drm?: DrmConfig;
|
|
188
|
+
localSourceEncryptionKeyScheme?: string;
|
|
189
|
+
adTagUrl?: string;
|
|
190
|
+
adLanguage?: string;
|
|
191
|
+
controls?: boolean;
|
|
192
|
+
showNotificationControls?: boolean;
|
|
193
|
+
disableFocus?: boolean;
|
|
194
|
+
disableDisconnectError?: boolean;
|
|
195
|
+
focusable?: boolean;
|
|
196
|
+
hideShutterView?: boolean;
|
|
197
|
+
preventsDisplaySleepDuringVideoPlayback?: boolean;
|
|
198
|
+
fullscreen?: boolean;
|
|
199
|
+
fullscreenAutorotate?: boolean;
|
|
200
|
+
fullscreenOrientation?: 'all' | 'landscape' | 'portrait';
|
|
201
|
+
pictureInPicture?: boolean;
|
|
202
|
+
contentStartTime?: number;
|
|
203
|
+
allowsExternalPlayback?: boolean;
|
|
204
|
+
audioOutput?: 'speaker' | 'earpiece';
|
|
205
|
+
ignoreSilentSwitch?: 'inherit' | 'ignore' | 'obey';
|
|
206
|
+
mixWithOthers?: 'inherit' | 'mix' | 'duck';
|
|
207
|
+
debug?: {
|
|
208
|
+
enable?: boolean;
|
|
209
|
+
thread?: boolean;
|
|
210
|
+
};
|
|
211
|
+
/**
|
|
212
|
+
* Callback when video starts loading
|
|
213
|
+
*/
|
|
214
|
+
onLoadStart?: (data: OnVideoLoadStartEvent) => void;
|
|
215
|
+
/**
|
|
216
|
+
* Callback when video is loaded
|
|
217
|
+
*/
|
|
218
|
+
onLoad?: (data: OnLoadData) => void;
|
|
219
|
+
/**
|
|
220
|
+
* Callback when video fails to load
|
|
221
|
+
*/
|
|
222
|
+
onError?: (data: OnVideoErrorEvent) => void;
|
|
223
|
+
/**
|
|
224
|
+
* Callback during video playback progress
|
|
225
|
+
*/
|
|
226
|
+
onProgress?: (data: OnVideoProgressEvent) => void;
|
|
227
|
+
/**
|
|
228
|
+
* Callback when video seek completes
|
|
229
|
+
*/
|
|
230
|
+
onSeek?: (data: OnSeekData) => void;
|
|
231
|
+
/**
|
|
232
|
+
* Callback when video ends
|
|
233
|
+
*/
|
|
234
|
+
onEnd?: () => void;
|
|
235
|
+
/**
|
|
236
|
+
* Callback when video buffering state changes
|
|
237
|
+
*/
|
|
238
|
+
onBuffer?: (data: OnVideoBufferEvent) => void;
|
|
239
|
+
/**
|
|
240
|
+
* Callback when video bandwidth updates
|
|
241
|
+
*/
|
|
242
|
+
onBandwidthUpdate?: (data: OnVideoBandwidthUpdateEvent) => void;
|
|
243
|
+
/**
|
|
244
|
+
* Callback when playback state changes
|
|
245
|
+
*/
|
|
246
|
+
onPlaybackStateChanged?: (data: OnVideoPlaybackStateChangedEvent) => void;
|
|
247
|
+
/**
|
|
248
|
+
* Callback when playback rate changes
|
|
249
|
+
*/
|
|
250
|
+
onPlaybackRateChange?: (data: OnVideoPlaybackRateChangeEvent) => void;
|
|
251
|
+
/**
|
|
252
|
+
* Callback when volume changes
|
|
253
|
+
*/
|
|
254
|
+
onVolumeChange?: (data: OnVideoVolumeChangeEvent) => void;
|
|
255
|
+
/**
|
|
256
|
+
* Callback when video becomes idle
|
|
257
|
+
*/
|
|
258
|
+
onIdle?: () => void;
|
|
259
|
+
/**
|
|
260
|
+
* Callback when video is ready for display
|
|
261
|
+
*/
|
|
262
|
+
onReadyForDisplay?: () => void;
|
|
263
|
+
onPlaybackResume?: () => void;
|
|
264
|
+
onPlaybackStalled?: () => void;
|
|
265
|
+
onAudioTracks?: (data: OnAudioTracksData) => void;
|
|
266
|
+
onTextTracks?: (data: OnTextTracksData) => void;
|
|
267
|
+
onTextTrackDataChanged?: (data: OnTextTrackDataChangedData) => void;
|
|
268
|
+
onVideoTracks?: (data: OnVideoTracksData) => void;
|
|
269
|
+
onTimedMetadata?: (data: OnTimedMetadataData) => void;
|
|
270
|
+
/**
|
|
271
|
+
* Callback when video aspect ratio changes
|
|
272
|
+
*/
|
|
273
|
+
onAspectRatio?: (data: OnVideoAspectRatioEvent) => void;
|
|
274
|
+
/**
|
|
275
|
+
* Callback when audio focus changes
|
|
276
|
+
*/
|
|
277
|
+
onAudioFocusChanged?: (data: OnVideoAudioFocusChangedEvent) => void;
|
|
278
|
+
/**
|
|
279
|
+
* Callback when audio becomes noisy
|
|
280
|
+
*/
|
|
281
|
+
onAudioBecomingNoisy?: () => void;
|
|
282
|
+
/**
|
|
283
|
+
* Callback before fullscreen player presents
|
|
284
|
+
*/
|
|
285
|
+
onFullscreenPlayerWillPresent?: () => void;
|
|
286
|
+
/**
|
|
287
|
+
* Callback after fullscreen player presents
|
|
288
|
+
*/
|
|
289
|
+
onFullscreenPlayerDidPresent?: () => void;
|
|
290
|
+
/**
|
|
291
|
+
* Callback before fullscreen player dismisses
|
|
292
|
+
*/
|
|
293
|
+
onFullscreenPlayerWillDismiss?: () => void;
|
|
294
|
+
/**
|
|
295
|
+
* Callback after fullscreen player dismisses
|
|
296
|
+
*/
|
|
297
|
+
onFullscreenPlayerDidDismiss?: () => void;
|
|
298
|
+
/**
|
|
299
|
+
* Callback when picture-in-picture status changes
|
|
300
|
+
*/
|
|
301
|
+
onPictureInPictureStatusChanged?: (data: OnVideoPictureInPictureStatusChangedEvent) => void;
|
|
302
|
+
/**
|
|
303
|
+
* Callback to restore user interface for picture-in-picture stop
|
|
304
|
+
*/
|
|
305
|
+
onRestoreUserInterfaceForPictureInPictureStop?: () => void;
|
|
306
|
+
/**
|
|
307
|
+
* Callback when controls visibility changes
|
|
308
|
+
*/
|
|
309
|
+
onControlsVisibilityChange?: (data: OnVideoControlsVisibilityChangeEvent) => void;
|
|
310
|
+
/**
|
|
311
|
+
* Callback when external playback changes
|
|
312
|
+
*/
|
|
313
|
+
onExternalPlaybackChange?: (data: OnVideoExternalPlaybackChangeEvent) => void;
|
|
314
|
+
/**
|
|
315
|
+
* Callback when receive ad event occurs
|
|
316
|
+
*/
|
|
317
|
+
onReceiveAdEvent?: (data: OnReceiveAdEventData) => void;
|
|
318
|
+
/**
|
|
319
|
+
* Callback when transfer end event occurs
|
|
320
|
+
*/
|
|
321
|
+
onTransferEnd?: (data: OnTransferEndData) => void;
|
|
322
|
+
}
|
|
323
|
+
export interface VideoStatic {
|
|
324
|
+
clearCache: () => Promise<void>;
|
|
325
|
+
getWidevineLevel: () => Promise<number>;
|
|
326
|
+
isCodecSupported: (mimeType: string, width: number, height: number) => Promise<boolean>;
|
|
327
|
+
isHEVCSupported: () => Promise<boolean>;
|
|
328
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#import <Foundation/Foundation.h>
|
|
2
|
+
|
|
3
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
4
|
+
|
|
5
|
+
// Forward declaration to avoid pulling in React C++ headers
|
|
6
|
+
// The actual implementation is in the .mm file
|
|
7
|
+
@protocol RCTComponentViewProtocol;
|
|
8
|
+
Class<RCTComponentViewProtocol> GraniteVideoViewCls(void) __attribute__((used));
|
|
9
|
+
|
|
10
|
+
NS_ASSUME_NONNULL_END
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import UIKit
|
|
2
|
+
import AVFoundation
|
|
3
|
+
|
|
4
|
+
// ============================================================
|
|
5
|
+
// MARK: - Enums
|
|
6
|
+
// ============================================================
|
|
7
|
+
|
|
8
|
+
@objc public enum GraniteVideoResizeMode: Int {
|
|
9
|
+
case contain = 0
|
|
10
|
+
case cover = 1
|
|
11
|
+
case stretch = 2
|
|
12
|
+
case none = 3
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
@objc public enum GraniteVideoDrmType: Int {
|
|
16
|
+
case none = 0
|
|
17
|
+
case fairplay = 1
|
|
18
|
+
case widevine = 2
|
|
19
|
+
case playready = 3
|
|
20
|
+
case clearkey = 4
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@objc public enum GraniteVideoAudioOutput: Int {
|
|
24
|
+
case speaker = 0
|
|
25
|
+
case earpiece = 1
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@objc public enum GraniteVideoIgnoreSilentSwitch: Int {
|
|
29
|
+
case inherit = 0
|
|
30
|
+
case ignore = 1
|
|
31
|
+
case obey = 2
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
@objc public enum GraniteVideoMixWithOthers: Int {
|
|
35
|
+
case inherit = 0
|
|
36
|
+
case mix = 1
|
|
37
|
+
case duck = 2
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// ============================================================
|
|
41
|
+
// MARK: - Data Types
|
|
42
|
+
// ============================================================
|
|
43
|
+
|
|
44
|
+
@objc public class GraniteVideoDrmConfig: NSObject {
|
|
45
|
+
@objc public var type: GraniteVideoDrmType = .none
|
|
46
|
+
@objc public var licenseServer: String?
|
|
47
|
+
@objc public var headers: [String: String]?
|
|
48
|
+
@objc public var contentID: String?
|
|
49
|
+
@objc public var certificateURL: String?
|
|
50
|
+
@objc public var base64Certificate: Bool = false
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
@objc public class GraniteVideoSource: NSObject {
|
|
54
|
+
@objc public var uri: String?
|
|
55
|
+
@objc public var type: String?
|
|
56
|
+
@objc public var startPosition: Double = 0
|
|
57
|
+
@objc public var cropStart: Double = 0
|
|
58
|
+
@objc public var cropEnd: Double = 0
|
|
59
|
+
@objc public var headers: [String: String]?
|
|
60
|
+
@objc public var drm: GraniteVideoDrmConfig?
|
|
61
|
+
|
|
62
|
+
@objc public override init() {
|
|
63
|
+
super.init()
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
@objc public convenience init(uri: String) {
|
|
67
|
+
self.init()
|
|
68
|
+
self.uri = uri
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
@objc public class GraniteVideoBufferConfig: NSObject {
|
|
73
|
+
@objc public var minBufferMs: Int = 15000
|
|
74
|
+
@objc public var maxBufferMs: Int = 50000
|
|
75
|
+
@objc public var bufferForPlaybackMs: Int = 2500
|
|
76
|
+
@objc public var bufferForPlaybackAfterRebufferMs: Int = 5000
|
|
77
|
+
@objc public var cacheSizeMB: Int = 0
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
@objc public class GraniteVideoSelectedTrack: NSObject {
|
|
81
|
+
@objc public var type: String = "system"
|
|
82
|
+
@objc public var value: String?
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// ============================================================
|
|
86
|
+
// MARK: - Event Data Types
|
|
87
|
+
// ============================================================
|
|
88
|
+
|
|
89
|
+
@objc public class GraniteVideoLoadData: NSObject {
|
|
90
|
+
@objc public var currentTime: Double = 0
|
|
91
|
+
@objc public var duration: Double = 0
|
|
92
|
+
@objc public var naturalWidth: Double = 0
|
|
93
|
+
@objc public var naturalHeight: Double = 0
|
|
94
|
+
@objc public var orientation: String = "landscape"
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
@objc public class GraniteVideoProgressData: NSObject {
|
|
98
|
+
@objc public var currentTime: Double = 0
|
|
99
|
+
@objc public var playableDuration: Double = 0
|
|
100
|
+
@objc public var seekableDuration: Double = 0
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
@objc public class GraniteVideoErrorData: NSObject {
|
|
104
|
+
@objc public var code: Int = 0
|
|
105
|
+
@objc public var domain: String = ""
|
|
106
|
+
@objc public var localizedDescription_: String = ""
|
|
107
|
+
@objc public var localizedFailureReason_: String = ""
|
|
108
|
+
@objc public var localizedRecoverySuggestion_: String = ""
|
|
109
|
+
|
|
110
|
+
@objc public override init() {
|
|
111
|
+
super.init()
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
@objc public convenience init(error: Error) {
|
|
115
|
+
self.init()
|
|
116
|
+
let nsError = error as NSError
|
|
117
|
+
self.code = nsError.code
|
|
118
|
+
self.domain = nsError.domain
|
|
119
|
+
self.localizedDescription_ = nsError.localizedDescription
|
|
120
|
+
self.localizedFailureReason_ = nsError.localizedFailureReason ?? ""
|
|
121
|
+
self.localizedRecoverySuggestion_ = nsError.localizedRecoverySuggestion ?? ""
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// ============================================================
|
|
126
|
+
// MARK: - Delegate Protocol
|
|
127
|
+
// ============================================================
|
|
128
|
+
|
|
129
|
+
@objc public protocol GraniteVideoDelegate: AnyObject {
|
|
130
|
+
@objc optional func videoDidLoadStart(isNetwork: Bool, type: String, uri: String)
|
|
131
|
+
@objc optional func videoDidLoad(data: GraniteVideoLoadData)
|
|
132
|
+
@objc optional func videoDidFail(error: GraniteVideoErrorData)
|
|
133
|
+
@objc optional func videoDidUpdateProgress(data: GraniteVideoProgressData)
|
|
134
|
+
@objc optional func videoDidSeek(currentTime: Double, seekTime: Double)
|
|
135
|
+
@objc optional func videoDidEnd()
|
|
136
|
+
@objc optional func videoBufferingStateChanged(isBuffering: Bool)
|
|
137
|
+
@objc optional func videoBandwidthDidUpdate(bitrate: Double, width: Int, height: Int)
|
|
138
|
+
@objc optional func videoPlaybackStateChanged(isPlaying: Bool, isSeeking: Bool, isLooping: Bool)
|
|
139
|
+
@objc optional func videoPlaybackRateChanged(rate: Float)
|
|
140
|
+
@objc optional func videoVolumeChanged(volume: Float)
|
|
141
|
+
@objc optional func videoDidBecomeIdle()
|
|
142
|
+
@objc optional func videoReadyForDisplay()
|
|
143
|
+
@objc optional func videoAudioBecomingNoisy()
|
|
144
|
+
@objc optional func videoFullscreenPlayerWillPresent()
|
|
145
|
+
@objc optional func videoFullscreenPlayerDidPresent()
|
|
146
|
+
@objc optional func videoFullscreenPlayerWillDismiss()
|
|
147
|
+
@objc optional func videoFullscreenPlayerDidDismiss()
|
|
148
|
+
@objc optional func videoPictureInPictureStatusChanged(isActive: Bool)
|
|
149
|
+
@objc optional func videoRestoreUserInterfaceForPictureInPictureStop()
|
|
150
|
+
@objc optional func videoControlsVisibilityChanged(isVisible: Bool)
|
|
151
|
+
@objc optional func videoExternalPlaybackChanged(isActive: Bool)
|
|
152
|
+
@objc optional func videoAspectRatioChanged(width: Double, height: Double)
|
|
153
|
+
@objc optional func videoTransferEnd(uri: String, bytesTransferred: Double)
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// ============================================================
|
|
157
|
+
// MARK: - Provider Protocol
|
|
158
|
+
// ============================================================
|
|
159
|
+
|
|
160
|
+
@objc public protocol GraniteVideoProvidable: NSObjectProtocol {
|
|
161
|
+
// Required - View Creation
|
|
162
|
+
@objc func createPlayerView() -> UIView
|
|
163
|
+
|
|
164
|
+
// Required - Source Loading
|
|
165
|
+
@objc func loadSource(_ source: GraniteVideoSource)
|
|
166
|
+
@objc func unload()
|
|
167
|
+
|
|
168
|
+
// Required - Playback Control
|
|
169
|
+
@objc func play()
|
|
170
|
+
@objc func pause()
|
|
171
|
+
@objc func seek(to time: Double, toleranceBefore: Double, toleranceAfter: Double)
|
|
172
|
+
|
|
173
|
+
// Required - Properties
|
|
174
|
+
@objc weak var delegate: GraniteVideoDelegate? { get set }
|
|
175
|
+
@objc var currentTime: Double { get }
|
|
176
|
+
@objc var duration: Double { get }
|
|
177
|
+
@objc var isPlaying: Bool { get }
|
|
178
|
+
|
|
179
|
+
// Optional - Volume
|
|
180
|
+
@objc optional func setVolume(_ volume: Float)
|
|
181
|
+
@objc optional func setMuted(_ muted: Bool)
|
|
182
|
+
|
|
183
|
+
// Optional - Rate
|
|
184
|
+
@objc optional func setRate(_ rate: Float)
|
|
185
|
+
|
|
186
|
+
// Optional - Repeat
|
|
187
|
+
@objc optional func setRepeat(_ shouldRepeat: Bool)
|
|
188
|
+
|
|
189
|
+
// Optional - Resize Mode
|
|
190
|
+
@objc optional func setResizeMode(_ mode: GraniteVideoResizeMode)
|
|
191
|
+
|
|
192
|
+
// Optional - Background Playback
|
|
193
|
+
@objc optional func setPlayInBackground(_ enabled: Bool)
|
|
194
|
+
@objc optional func setPlayWhenInactive(_ enabled: Bool)
|
|
195
|
+
|
|
196
|
+
// Optional - Audio Session
|
|
197
|
+
@objc optional func setAudioOutput(_ output: GraniteVideoAudioOutput)
|
|
198
|
+
@objc optional func setIgnoreSilentSwitch(_ mode: GraniteVideoIgnoreSilentSwitch)
|
|
199
|
+
@objc optional func setMixWithOthers(_ mode: GraniteVideoMixWithOthers)
|
|
200
|
+
|
|
201
|
+
// Optional - Fullscreen
|
|
202
|
+
@objc optional func setFullscreen(_ fullscreen: Bool, animated: Bool)
|
|
203
|
+
@objc optional func setFullscreenAutorotate(_ autorotate: Bool)
|
|
204
|
+
@objc optional func setFullscreenOrientation(_ orientation: String)
|
|
205
|
+
|
|
206
|
+
// Optional - Picture in Picture
|
|
207
|
+
@objc optional func setPictureInPictureEnabled(_ enabled: Bool)
|
|
208
|
+
@objc optional func enterPictureInPicture()
|
|
209
|
+
@objc optional func exitPictureInPicture()
|
|
210
|
+
|
|
211
|
+
// Optional - Controls
|
|
212
|
+
@objc optional func setControlsEnabled(_ enabled: Bool)
|
|
213
|
+
@objc optional func setPreventsDisplaySleepDuringVideoPlayback(_ prevents: Bool)
|
|
214
|
+
|
|
215
|
+
// Optional - Buffer Config
|
|
216
|
+
@objc optional func setBufferConfig(_ config: GraniteVideoBufferConfig)
|
|
217
|
+
@objc optional func setMaxBitRate(_ bitRate: Int)
|
|
218
|
+
@objc optional func setPreferredForwardBufferDuration(_ duration: Double)
|
|
219
|
+
@objc optional func setAutomaticallyWaitsToMinimizeStalling(_ waits: Bool)
|
|
220
|
+
|
|
221
|
+
// Optional - Track Selection
|
|
222
|
+
@objc optional func setSelectedAudioTrack(_ track: GraniteVideoSelectedTrack)
|
|
223
|
+
@objc optional func setSelectedTextTrack(_ track: GraniteVideoSelectedTrack)
|
|
224
|
+
@objc optional func setSelectedVideoTrack(type: String, value: Int)
|
|
225
|
+
|
|
226
|
+
// Optional - External Playback
|
|
227
|
+
@objc optional func setAllowsExternalPlayback(_ allows: Bool)
|
|
228
|
+
|
|
229
|
+
// Optional - DRM
|
|
230
|
+
@objc optional func setDrmConfig(_ config: GraniteVideoDrmConfig)
|
|
231
|
+
|
|
232
|
+
// Optional - Poster
|
|
233
|
+
@objc optional func setPoster(_ url: String, resizeMode: GraniteVideoResizeMode)
|
|
234
|
+
|
|
235
|
+
// Optional - Save
|
|
236
|
+
@objc optional func save(type: String, completion: @escaping (String?, Error?) -> Void)
|
|
237
|
+
|
|
238
|
+
// Optional - Cache Management
|
|
239
|
+
@objc optional func clearCache()
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// ============================================================
|
|
243
|
+
// MARK: - Registry
|
|
244
|
+
// ============================================================
|
|
245
|
+
|
|
246
|
+
public typealias GraniteVideoProviderFactory = () -> GraniteVideoProvidable
|
|
247
|
+
|
|
248
|
+
@objc public class GraniteVideoRegistry: NSObject {
|
|
249
|
+
@objc public static let shared = GraniteVideoRegistry()
|
|
250
|
+
|
|
251
|
+
private var internalProvider: GraniteVideoProvidable?
|
|
252
|
+
private var providerFactory: GraniteVideoProviderFactory?
|
|
253
|
+
|
|
254
|
+
private override init() {
|
|
255
|
+
super.init()
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
@objc public var provider: GraniteVideoProvidable? {
|
|
259
|
+
return internalProvider
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
@objc public func register(provider: GraniteVideoProvidable) {
|
|
263
|
+
internalProvider = provider
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
@objc public func register(factory: @escaping GraniteVideoProviderFactory) {
|
|
267
|
+
providerFactory = factory
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
@objc public func createProvider() -> GraniteVideoProvidable? {
|
|
271
|
+
if let factory = providerFactory {
|
|
272
|
+
return factory()
|
|
273
|
+
}
|
|
274
|
+
return internalProvider
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
@objc public func hasProvider() -> Bool {
|
|
278
|
+
return internalProvider != nil || providerFactory != nil
|
|
279
|
+
}
|
|
280
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#import <UIKit/UIKit.h>
|
|
2
|
+
|
|
3
|
+
#ifndef GraniteVideoViewNativeComponent_h
|
|
4
|
+
#define GraniteVideoViewNativeComponent_h
|
|
5
|
+
|
|
6
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
7
|
+
|
|
8
|
+
// Forward declare to avoid pulling in C++ headers
|
|
9
|
+
// RCTViewComponentView import is in the .mm file
|
|
10
|
+
@interface GraniteVideoView : UIView
|
|
11
|
+
@end
|
|
12
|
+
|
|
13
|
+
NS_ASSUME_NONNULL_END
|
|
14
|
+
|
|
15
|
+
#endif /* GraniteVideoViewNativeComponent_h */
|