2020-01-28 15:21:21 -07:00
|
|
|
import React, { Component } from 'react';
|
2017-08-04 12:53:53 -06:00
|
|
|
import PropTypes from 'prop-types';
|
2022-05-04 13:34:28 -06:00
|
|
|
import { StyleSheet, requireNativeComponent, NativeModules, UIManager, View, Image, Platform, findNodeHandle } from 'react-native';
|
2022-06-13 09:26:40 -06:00
|
|
|
import { ViewPropTypes, ImagePropTypes } from 'deprecated-react-native-prop-types';
|
2016-06-22 07:52:12 -06:00
|
|
|
import resolveAssetSource from 'react-native/Libraries/Image/resolveAssetSource';
|
2018-06-12 22:04:15 -06:00
|
|
|
import TextTrackType from './TextTrackType';
|
2018-11-06 07:38:28 -07:00
|
|
|
import FilterType from './FilterType';
|
Add iOS and Android basic DRM support (#1445)
This PR adds support for DRM streams on iOS (Fairplay) and Android (Playready, Widevine, Clearkey)
I am neither Android nor iOS developer, so feel free to provide feedback to improve this PR.
**Test stream for ANDROID:**
```
testStream = {
uri: 'http://profficialsite.origin.mediaservices.windows.net/c51358ea-9a5e-4322-8951-897d640fdfd7/tearsofsteel_4k.ism/manifest(format=mpd-time-csf)',
type: 'mpd',
drm: {
type: DRMType.PLAYREADY,
licenseServer: 'http://test.playready.microsoft.com/service/rightsmanager.asmx?cfg=(persist:false,sl:150)'
}
};
```
or
```
{
uri: 'https://media.axprod.net/TestVectors/v7-MultiDRM-SingleKey/Manifest_1080p.mpd',
drm: {
type: 'widevine', //or DRMType.WIDEVINE
licenseServer: 'https://drm-widevine-licensing.axtest.net/AcquireLicense',
headers: {
'X-AxDRM-Message': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2ZXJzaW9uIjoxLCJjb21fa2V5X2lkIjoiYjMzNjRlYjUtNTFmNi00YWUzLThjOTgtMzNjZWQ1ZTMxYzc4IiwibWVzc2FnZSI6eyJ0eXBlIjoiZW50aXRsZW1lbnRfbWVzc2FnZSIsImZpcnN0X3BsYXlfZXhwaXJhdGlvbiI6NjAsInBsYXlyZWFkeSI6eyJyZWFsX3RpbWVfZXhwaXJhdGlvbiI6dHJ1ZX0sImtleXMiOlt7ImlkIjoiOWViNDA1MGQtZTQ0Yi00ODAyLTkzMmUtMjdkNzUwODNlMjY2IiwiZW5jcnlwdGVkX2tleSI6ImxLM09qSExZVzI0Y3Iya3RSNzRmbnc9PSJ9XX19.FAbIiPxX8BHi9RwfzD7Yn-wugU19ghrkBFKsaCPrZmU'
},
}
}
```
**Test stream for iOS:**
Sorry but I can not provide free streams to test. If anyone can provide test streams, or found some we can use, please let me know to also test them.
It has been tested with a private provider and they work, at least with the `getLicense` override method. (An example implementation is provided in the README)
2020-08-12 19:56:21 -06:00
|
|
|
import DRMType from './DRMType';
|
2016-01-31 20:35:18 -07:00
|
|
|
import VideoResizeMode from './VideoResizeMode.js';
|
|
|
|
|
2015-10-29 18:26:28 -06:00
|
|
|
const styles = StyleSheet.create({
|
|
|
|
base: {
|
|
|
|
overflow: 'hidden',
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
2023-09-18 03:46:39 -06:00
|
|
|
const { VideoDecoderProperties } = NativeModules;
|
|
|
|
export { TextTrackType, FilterType, DRMType, VideoDecoderProperties };
|
2018-06-12 22:04:15 -06:00
|
|
|
|
2016-01-31 20:35:18 -07:00
|
|
|
export default class Video extends Component {
|
2015-10-29 18:26:28 -06:00
|
|
|
|
2016-12-05 14:57:35 -07:00
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
|
|
|
|
|
|
|
this.state = {
|
2020-01-28 15:21:21 -07:00
|
|
|
showPoster: !!props.poster,
|
2016-12-05 14:57:35 -07:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2015-11-09 18:55:39 -07:00
|
|
|
setNativeProps(nativeProps) {
|
|
|
|
this._root.setNativeProps(nativeProps);
|
|
|
|
}
|
2020-01-28 15:21:21 -07:00
|
|
|
|
2018-01-13 13:28:24 -07:00
|
|
|
toTypeString(x) {
|
|
|
|
switch (typeof x) {
|
2020-02-22 11:56:31 -07:00
|
|
|
case 'object':
|
2020-01-28 15:21:21 -07:00
|
|
|
return x instanceof Date
|
|
|
|
? x.toISOString()
|
2018-01-13 13:28:24 -07:00
|
|
|
: JSON.stringify(x); // object, null
|
2020-02-22 11:56:31 -07:00
|
|
|
case 'undefined':
|
|
|
|
return '';
|
2018-01-13 13:28:24 -07:00
|
|
|
default: // boolean, number, string
|
2020-01-28 15:21:21 -07:00
|
|
|
return x.toString();
|
2018-01-13 13:28:24 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
stringsOnlyObject(obj) {
|
|
|
|
const strObj = {};
|
|
|
|
|
|
|
|
Object.keys(obj).forEach(x => {
|
|
|
|
strObj[x] = this.toTypeString(obj[x]);
|
|
|
|
});
|
|
|
|
|
|
|
|
return strObj;
|
|
|
|
}
|
2015-11-09 18:55:39 -07:00
|
|
|
|
2018-06-20 23:09:45 -06:00
|
|
|
seek = (time, tolerance = 100) => {
|
2020-02-22 11:56:31 -07:00
|
|
|
if (isNaN(time)) {throw new Error('Specified time is not a number');}
|
2020-01-28 15:21:21 -07:00
|
|
|
|
2018-06-20 23:09:45 -06:00
|
|
|
if (Platform.OS === 'ios') {
|
|
|
|
this.setNativeProps({
|
|
|
|
seek: {
|
|
|
|
time,
|
2020-02-22 11:56:31 -07:00
|
|
|
tolerance,
|
|
|
|
},
|
2018-06-20 23:09:45 -06:00
|
|
|
});
|
|
|
|
} else {
|
|
|
|
this.setNativeProps({ seek: time });
|
|
|
|
}
|
2016-06-22 08:28:54 -06:00
|
|
|
};
|
2016-01-31 20:35:18 -07:00
|
|
|
|
2016-06-22 08:28:54 -06:00
|
|
|
presentFullscreenPlayer = () => {
|
2016-03-31 12:36:39 -06:00
|
|
|
this.setNativeProps({ fullscreen: true });
|
2016-06-22 08:28:54 -06:00
|
|
|
};
|
2016-03-31 12:36:39 -06:00
|
|
|
|
2016-06-22 08:28:54 -06:00
|
|
|
dismissFullscreenPlayer = () => {
|
2016-04-01 03:12:50 -06:00
|
|
|
this.setNativeProps({ fullscreen: false });
|
2016-06-22 08:28:54 -06:00
|
|
|
};
|
2016-04-01 03:12:50 -06:00
|
|
|
|
2023-07-23 10:08:26 -06:00
|
|
|
save = async (options) => {
|
2018-10-26 07:21:41 -06:00
|
|
|
return await NativeModules.VideoManager.save(options, findNodeHandle(this._root));
|
|
|
|
}
|
|
|
|
|
2023-09-18 03:46:39 -06:00
|
|
|
pause = async () => {
|
2023-09-20 23:25:21 -06:00
|
|
|
await this.setPlayerPauseState(false);
|
2023-09-18 03:46:39 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
play = async () => {
|
2023-09-20 23:25:21 -06:00
|
|
|
await this.setPlayerPauseState(true);
|
2023-09-18 03:46:39 -06:00
|
|
|
};
|
|
|
|
|
2023-09-20 23:25:21 -06:00
|
|
|
setPlayerPauseState = async (shouldPlay) => {
|
|
|
|
return await NativeModules.VideoManager.setPlayerPauseState(shouldPlay, findNodeHandle(this._root));
|
2023-09-18 03:46:39 -06:00
|
|
|
};
|
|
|
|
|
2018-11-26 15:23:04 -07:00
|
|
|
restoreUserInterfaceForPictureInPictureStopCompleted = (restored) => {
|
|
|
|
this.setNativeProps({ restoreUserInterfaceForPIPStopCompletionHandler: restored });
|
2018-10-26 14:33:03 -06:00
|
|
|
};
|
|
|
|
|
2016-06-22 08:28:54 -06:00
|
|
|
_assignRoot = (component) => {
|
2016-01-31 20:35:18 -07:00
|
|
|
this._root = component;
|
2016-06-22 08:28:54 -06:00
|
|
|
};
|
2015-11-11 14:34:41 -07:00
|
|
|
|
2019-06-19 05:00:57 -06:00
|
|
|
_hidePoster = () => {
|
2019-06-20 02:24:12 -06:00
|
|
|
if (this.state.showPoster) {
|
2020-01-28 15:21:21 -07:00
|
|
|
this.setState({ showPoster: false });
|
2019-06-20 02:24:12 -06:00
|
|
|
}
|
2019-06-19 05:00:57 -06:00
|
|
|
}
|
|
|
|
|
2016-06-22 08:28:54 -06:00
|
|
|
_onLoadStart = (event) => {
|
2016-01-31 20:35:18 -07:00
|
|
|
if (this.props.onLoadStart) {
|
|
|
|
this.props.onLoadStart(event.nativeEvent);
|
|
|
|
}
|
2016-06-22 08:28:54 -06:00
|
|
|
};
|
2015-11-17 20:15:07 -07:00
|
|
|
|
2022-04-19 10:12:47 -06:00
|
|
|
_onPlaybackStateChanged = (event) => {
|
|
|
|
if (this.props.onPlaybackStateChanged) {
|
|
|
|
this.props.onPlaybackStateChanged(event.nativeEvent);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-06-22 08:28:54 -06:00
|
|
|
_onLoad = (event) => {
|
2019-06-20 02:24:12 -06:00
|
|
|
// Need to hide poster here for windows as onReadyForDisplay is not implemented
|
|
|
|
if (Platform.OS === 'windows') {
|
|
|
|
this._hidePoster();
|
|
|
|
}
|
2016-01-31 20:35:18 -07:00
|
|
|
if (this.props.onLoad) {
|
|
|
|
this.props.onLoad(event.nativeEvent);
|
|
|
|
}
|
2016-06-22 08:28:54 -06:00
|
|
|
};
|
2015-11-17 20:15:07 -07:00
|
|
|
|
2022-08-06 04:05:07 -06:00
|
|
|
_onAudioTracks = (event) => {
|
|
|
|
if (this.props.onAudioTracks) {
|
|
|
|
this.props.onAudioTracks(event.nativeEvent);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
_onTextTracks = (event) => {
|
|
|
|
if (this.props.onTextTracks) {
|
|
|
|
this.props.onTextTracks(event.nativeEvent);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
_onVideoTracks = (event) => {
|
|
|
|
if (this.props.onVideoTracks) {
|
|
|
|
this.props.onVideoTracks(event.nativeEvent);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-06-22 08:28:54 -06:00
|
|
|
_onError = (event) => {
|
2016-01-31 20:35:18 -07:00
|
|
|
if (this.props.onError) {
|
|
|
|
this.props.onError(event.nativeEvent);
|
|
|
|
}
|
2016-06-22 08:28:54 -06:00
|
|
|
};
|
2015-11-17 20:15:07 -07:00
|
|
|
|
2016-06-22 08:28:54 -06:00
|
|
|
_onProgress = (event) => {
|
2016-01-31 20:35:18 -07:00
|
|
|
if (this.props.onProgress) {
|
|
|
|
this.props.onProgress(event.nativeEvent);
|
|
|
|
}
|
2016-06-22 08:28:54 -06:00
|
|
|
};
|
2015-11-17 20:15:07 -07:00
|
|
|
|
2018-08-25 10:23:11 -06:00
|
|
|
_onBandwidthUpdate = (event) => {
|
|
|
|
if (this.props.onBandwidthUpdate) {
|
|
|
|
this.props.onBandwidthUpdate(event.nativeEvent);
|
|
|
|
}
|
2020-01-28 15:21:21 -07:00
|
|
|
};
|
2018-08-25 10:23:11 -06:00
|
|
|
|
2016-06-22 08:28:54 -06:00
|
|
|
_onSeek = (event) => {
|
2016-01-31 20:35:18 -07:00
|
|
|
if (this.props.onSeek) {
|
|
|
|
this.props.onSeek(event.nativeEvent);
|
|
|
|
}
|
2016-06-22 08:28:54 -06:00
|
|
|
};
|
2015-11-17 20:15:07 -07:00
|
|
|
|
2016-06-22 08:28:54 -06:00
|
|
|
_onEnd = (event) => {
|
2016-01-31 20:35:18 -07:00
|
|
|
if (this.props.onEnd) {
|
|
|
|
this.props.onEnd(event.nativeEvent);
|
|
|
|
}
|
2016-06-22 08:28:54 -06:00
|
|
|
};
|
2015-11-17 20:15:07 -07:00
|
|
|
|
2017-02-13 19:38:02 -07:00
|
|
|
_onTimedMetadata = (event) => {
|
|
|
|
if (this.props.onTimedMetadata) {
|
|
|
|
this.props.onTimedMetadata(event.nativeEvent);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-06-22 08:28:54 -06:00
|
|
|
_onFullscreenPlayerWillPresent = (event) => {
|
2016-03-31 13:35:10 -06:00
|
|
|
if (this.props.onFullscreenPlayerWillPresent) {
|
|
|
|
this.props.onFullscreenPlayerWillPresent(event.nativeEvent);
|
|
|
|
}
|
2016-06-22 08:28:54 -06:00
|
|
|
};
|
2016-03-31 13:35:10 -06:00
|
|
|
|
2016-06-22 08:28:54 -06:00
|
|
|
_onFullscreenPlayerDidPresent = (event) => {
|
2016-03-31 13:40:49 -06:00
|
|
|
if (this.props.onFullscreenPlayerDidPresent) {
|
2016-03-31 13:35:10 -06:00
|
|
|
this.props.onFullscreenPlayerDidPresent(event.nativeEvent);
|
|
|
|
}
|
2016-06-22 08:28:54 -06:00
|
|
|
};
|
2016-03-31 13:35:10 -06:00
|
|
|
|
2016-06-22 08:28:54 -06:00
|
|
|
_onFullscreenPlayerWillDismiss = (event) => {
|
2016-03-31 13:40:49 -06:00
|
|
|
if (this.props.onFullscreenPlayerWillDismiss) {
|
2016-03-31 13:35:10 -06:00
|
|
|
this.props.onFullscreenPlayerWillDismiss(event.nativeEvent);
|
|
|
|
}
|
2016-06-22 08:28:54 -06:00
|
|
|
};
|
2016-03-31 13:35:10 -06:00
|
|
|
|
2016-06-22 08:28:54 -06:00
|
|
|
_onFullscreenPlayerDidDismiss = (event) => {
|
2016-03-31 13:35:10 -06:00
|
|
|
if (this.props.onFullscreenPlayerDidDismiss) {
|
|
|
|
this.props.onFullscreenPlayerDidDismiss(event.nativeEvent);
|
|
|
|
}
|
2016-06-22 08:28:54 -06:00
|
|
|
};
|
2015-11-17 20:15:07 -07:00
|
|
|
|
2016-06-22 08:28:54 -06:00
|
|
|
_onReadyForDisplay = (event) => {
|
2019-11-26 12:40:03 -07:00
|
|
|
if (!this.props.audioOnly) {
|
|
|
|
this._hidePoster();
|
|
|
|
}
|
2020-02-22 11:56:31 -07:00
|
|
|
|
2016-04-28 06:42:44 -06:00
|
|
|
if (this.props.onReadyForDisplay) {
|
|
|
|
this.props.onReadyForDisplay(event.nativeEvent);
|
|
|
|
}
|
2016-06-22 08:28:54 -06:00
|
|
|
};
|
2016-04-28 06:42:44 -06:00
|
|
|
|
2016-06-22 08:28:54 -06:00
|
|
|
_onPlaybackStalled = (event) => {
|
2016-04-28 06:42:44 -06:00
|
|
|
if (this.props.onPlaybackStalled) {
|
|
|
|
this.props.onPlaybackStalled(event.nativeEvent);
|
|
|
|
}
|
2016-06-22 08:28:54 -06:00
|
|
|
};
|
2016-04-28 06:42:44 -06:00
|
|
|
|
2016-06-22 08:28:54 -06:00
|
|
|
_onPlaybackResume = (event) => {
|
2016-04-28 06:42:44 -06:00
|
|
|
if (this.props.onPlaybackResume) {
|
|
|
|
this.props.onPlaybackResume(event.nativeEvent);
|
|
|
|
}
|
2016-06-22 08:28:54 -06:00
|
|
|
};
|
2016-04-28 06:42:44 -06:00
|
|
|
|
2016-06-22 08:28:54 -06:00
|
|
|
_onPlaybackRateChange = (event) => {
|
2016-04-28 06:42:44 -06:00
|
|
|
if (this.props.onPlaybackRateChange) {
|
|
|
|
this.props.onPlaybackRateChange(event.nativeEvent);
|
|
|
|
}
|
2016-06-22 08:28:54 -06:00
|
|
|
};
|
2020-01-28 15:21:21 -07:00
|
|
|
|
2018-09-13 06:06:12 -06:00
|
|
|
_onExternalPlaybackChange = (event) => {
|
|
|
|
if (this.props.onExternalPlaybackChange) {
|
|
|
|
this.props.onExternalPlaybackChange(event.nativeEvent);
|
|
|
|
}
|
|
|
|
}
|
2016-04-28 06:42:44 -06:00
|
|
|
|
2017-01-11 05:51:45 -07:00
|
|
|
_onAudioBecomingNoisy = () => {
|
|
|
|
if (this.props.onAudioBecomingNoisy) {
|
|
|
|
this.props.onAudioBecomingNoisy();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-11-26 15:23:04 -07:00
|
|
|
_onPictureInPictureStatusChanged = (event) => {
|
|
|
|
if (this.props.onPictureInPictureStatusChanged) {
|
|
|
|
this.props.onPictureInPictureStatusChanged(event.nativeEvent);
|
2018-10-26 14:33:03 -06:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-11-26 15:23:04 -07:00
|
|
|
_onRestoreUserInterfaceForPictureInPictureStop = (event) => {
|
2020-01-28 15:21:21 -07:00
|
|
|
if (this.props.onRestoreUserInterfaceForPictureInPictureStop) {
|
2018-11-26 15:23:04 -07:00
|
|
|
this.props.onRestoreUserInterfaceForPictureInPictureStop();
|
2018-10-26 14:33:03 -06:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-01-11 05:51:45 -07:00
|
|
|
_onAudioFocusChanged = (event) => {
|
|
|
|
if (this.props.onAudioFocusChanged) {
|
|
|
|
this.props.onAudioFocusChanged(event.nativeEvent);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
_onBuffer = (event) => {
|
|
|
|
if (this.props.onBuffer) {
|
|
|
|
this.props.onBuffer(event.nativeEvent);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
Add iOS and Android basic DRM support (#1445)
This PR adds support for DRM streams on iOS (Fairplay) and Android (Playready, Widevine, Clearkey)
I am neither Android nor iOS developer, so feel free to provide feedback to improve this PR.
**Test stream for ANDROID:**
```
testStream = {
uri: 'http://profficialsite.origin.mediaservices.windows.net/c51358ea-9a5e-4322-8951-897d640fdfd7/tearsofsteel_4k.ism/manifest(format=mpd-time-csf)',
type: 'mpd',
drm: {
type: DRMType.PLAYREADY,
licenseServer: 'http://test.playready.microsoft.com/service/rightsmanager.asmx?cfg=(persist:false,sl:150)'
}
};
```
or
```
{
uri: 'https://media.axprod.net/TestVectors/v7-MultiDRM-SingleKey/Manifest_1080p.mpd',
drm: {
type: 'widevine', //or DRMType.WIDEVINE
licenseServer: 'https://drm-widevine-licensing.axtest.net/AcquireLicense',
headers: {
'X-AxDRM-Message': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2ZXJzaW9uIjoxLCJjb21fa2V5X2lkIjoiYjMzNjRlYjUtNTFmNi00YWUzLThjOTgtMzNjZWQ1ZTMxYzc4IiwibWVzc2FnZSI6eyJ0eXBlIjoiZW50aXRsZW1lbnRfbWVzc2FnZSIsImZpcnN0X3BsYXlfZXhwaXJhdGlvbiI6NjAsInBsYXlyZWFkeSI6eyJyZWFsX3RpbWVfZXhwaXJhdGlvbiI6dHJ1ZX0sImtleXMiOlt7ImlkIjoiOWViNDA1MGQtZTQ0Yi00ODAyLTkzMmUtMjdkNzUwODNlMjY2IiwiZW5jcnlwdGVkX2tleSI6ImxLM09qSExZVzI0Y3Iya3RSNzRmbnc9PSJ9XX19.FAbIiPxX8BHi9RwfzD7Yn-wugU19ghrkBFKsaCPrZmU'
},
}
}
```
**Test stream for iOS:**
Sorry but I can not provide free streams to test. If anyone can provide test streams, or found some we can use, please let me know to also test them.
It has been tested with a private provider and they work, at least with the `getLicense` override method. (An example implementation is provided in the README)
2020-08-12 19:56:21 -06:00
|
|
|
_onGetLicense = (event) => {
|
|
|
|
if (this.props.drm && this.props.drm.getLicense instanceof Function) {
|
|
|
|
const data = event.nativeEvent;
|
2021-01-13 03:18:01 -07:00
|
|
|
if (data && data.spcBase64) {
|
|
|
|
const getLicenseOverride = this.props.drm.getLicense(data.spcBase64, data.contentId, data.licenseUrl);
|
Add iOS and Android basic DRM support (#1445)
This PR adds support for DRM streams on iOS (Fairplay) and Android (Playready, Widevine, Clearkey)
I am neither Android nor iOS developer, so feel free to provide feedback to improve this PR.
**Test stream for ANDROID:**
```
testStream = {
uri: 'http://profficialsite.origin.mediaservices.windows.net/c51358ea-9a5e-4322-8951-897d640fdfd7/tearsofsteel_4k.ism/manifest(format=mpd-time-csf)',
type: 'mpd',
drm: {
type: DRMType.PLAYREADY,
licenseServer: 'http://test.playready.microsoft.com/service/rightsmanager.asmx?cfg=(persist:false,sl:150)'
}
};
```
or
```
{
uri: 'https://media.axprod.net/TestVectors/v7-MultiDRM-SingleKey/Manifest_1080p.mpd',
drm: {
type: 'widevine', //or DRMType.WIDEVINE
licenseServer: 'https://drm-widevine-licensing.axtest.net/AcquireLicense',
headers: {
'X-AxDRM-Message': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2ZXJzaW9uIjoxLCJjb21fa2V5X2lkIjoiYjMzNjRlYjUtNTFmNi00YWUzLThjOTgtMzNjZWQ1ZTMxYzc4IiwibWVzc2FnZSI6eyJ0eXBlIjoiZW50aXRsZW1lbnRfbWVzc2FnZSIsImZpcnN0X3BsYXlfZXhwaXJhdGlvbiI6NjAsInBsYXlyZWFkeSI6eyJyZWFsX3RpbWVfZXhwaXJhdGlvbiI6dHJ1ZX0sImtleXMiOlt7ImlkIjoiOWViNDA1MGQtZTQ0Yi00ODAyLTkzMmUtMjdkNzUwODNlMjY2IiwiZW5jcnlwdGVkX2tleSI6ImxLM09qSExZVzI0Y3Iya3RSNzRmbnc9PSJ9XX19.FAbIiPxX8BHi9RwfzD7Yn-wugU19ghrkBFKsaCPrZmU'
},
}
}
```
**Test stream for iOS:**
Sorry but I can not provide free streams to test. If anyone can provide test streams, or found some we can use, please let me know to also test them.
It has been tested with a private provider and they work, at least with the `getLicense` override method. (An example implementation is provided in the README)
2020-08-12 19:56:21 -06:00
|
|
|
const getLicensePromise = Promise.resolve(getLicenseOverride); // Handles both scenarios, getLicenseOverride being a promise and not.
|
|
|
|
getLicensePromise.then((result => {
|
|
|
|
if (result !== undefined) {
|
|
|
|
NativeModules.VideoManager.setLicenseResult(result, findNodeHandle(this._root));
|
|
|
|
} else {
|
|
|
|
NativeModules.VideoManager.setLicenseError && NativeModules.VideoManager.setLicenseError('Empty license result', findNodeHandle(this._root));
|
|
|
|
}
|
|
|
|
})).catch((error) => {
|
|
|
|
NativeModules.VideoManager.setLicenseError && NativeModules.VideoManager.setLicenseError(error, findNodeHandle(this._root));
|
|
|
|
});
|
|
|
|
} else {
|
2022-02-04 13:32:34 -07:00
|
|
|
NativeModules.VideoManager.setLicenseError && NativeModules.VideoManager.setLicenseError('No spc received', findNodeHandle(this._root));
|
Add iOS and Android basic DRM support (#1445)
This PR adds support for DRM streams on iOS (Fairplay) and Android (Playready, Widevine, Clearkey)
I am neither Android nor iOS developer, so feel free to provide feedback to improve this PR.
**Test stream for ANDROID:**
```
testStream = {
uri: 'http://profficialsite.origin.mediaservices.windows.net/c51358ea-9a5e-4322-8951-897d640fdfd7/tearsofsteel_4k.ism/manifest(format=mpd-time-csf)',
type: 'mpd',
drm: {
type: DRMType.PLAYREADY,
licenseServer: 'http://test.playready.microsoft.com/service/rightsmanager.asmx?cfg=(persist:false,sl:150)'
}
};
```
or
```
{
uri: 'https://media.axprod.net/TestVectors/v7-MultiDRM-SingleKey/Manifest_1080p.mpd',
drm: {
type: 'widevine', //or DRMType.WIDEVINE
licenseServer: 'https://drm-widevine-licensing.axtest.net/AcquireLicense',
headers: {
'X-AxDRM-Message': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2ZXJzaW9uIjoxLCJjb21fa2V5X2lkIjoiYjMzNjRlYjUtNTFmNi00YWUzLThjOTgtMzNjZWQ1ZTMxYzc4IiwibWVzc2FnZSI6eyJ0eXBlIjoiZW50aXRsZW1lbnRfbWVzc2FnZSIsImZpcnN0X3BsYXlfZXhwaXJhdGlvbiI6NjAsInBsYXlyZWFkeSI6eyJyZWFsX3RpbWVfZXhwaXJhdGlvbiI6dHJ1ZX0sImtleXMiOlt7ImlkIjoiOWViNDA1MGQtZTQ0Yi00ODAyLTkzMmUtMjdkNzUwODNlMjY2IiwiZW5jcnlwdGVkX2tleSI6ImxLM09qSExZVzI0Y3Iya3RSNzRmbnc9PSJ9XX19.FAbIiPxX8BHi9RwfzD7Yn-wugU19ghrkBFKsaCPrZmU'
},
}
}
```
**Test stream for iOS:**
Sorry but I can not provide free streams to test. If anyone can provide test streams, or found some we can use, please let me know to also test them.
It has been tested with a private provider and they work, at least with the `getLicense` override method. (An example implementation is provided in the README)
2020-08-12 19:56:21 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-07-26 07:11:37 -06:00
|
|
|
|
|
|
|
_onReceiveAdEvent = (event) => {
|
|
|
|
if (this.props.onReceiveAdEvent) {
|
|
|
|
this.props.onReceiveAdEvent(event.nativeEvent);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-02-18 04:17:20 -07:00
|
|
|
getViewManagerConfig = viewManagerName => {
|
2021-11-15 16:57:24 -07:00
|
|
|
if (!UIManager.getViewManagerConfig) {
|
|
|
|
return UIManager[viewManagerName];
|
2019-02-18 04:17:20 -07:00
|
|
|
}
|
2021-11-15 16:57:24 -07:00
|
|
|
return UIManager.getViewManagerConfig(viewManagerName);
|
2019-02-18 04:17:20 -07:00
|
|
|
};
|
|
|
|
|
2015-10-29 18:26:28 -06:00
|
|
|
render() {
|
2016-06-22 07:52:12 -06:00
|
|
|
const resizeMode = this.props.resizeMode;
|
|
|
|
const source = resolveAssetSource(this.props.source) || {};
|
2020-02-22 11:56:31 -07:00
|
|
|
const shouldCache = !source.__packager_asset;
|
2015-10-29 18:26:28 -06:00
|
|
|
|
2017-01-28 18:46:30 -07:00
|
|
|
let uri = source.uri || '';
|
2015-10-29 18:26:28 -06:00
|
|
|
if (uri && uri.match(/^\//)) {
|
2016-01-31 20:35:18 -07:00
|
|
|
uri = `file://${uri}`;
|
2015-10-29 18:26:28 -06:00
|
|
|
}
|
2020-01-28 15:21:21 -07:00
|
|
|
|
2019-02-18 22:36:17 -07:00
|
|
|
if (!uri) {
|
2022-09-14 13:57:37 -06:00
|
|
|
console.log('Trying to load empty source.');
|
2019-02-18 22:36:17 -07:00
|
|
|
}
|
2015-10-29 18:26:28 -06:00
|
|
|
|
2022-09-14 13:57:37 -06:00
|
|
|
const isNetwork = !!(uri && uri.match(/^https?:/i));
|
|
|
|
const isAsset = !!(uri && uri.match(/^(assets-library|ph|ipod-library|file|content|ms-appx|ms-appdata):/i));
|
|
|
|
|
2022-10-02 13:33:03 -06:00
|
|
|
if ((uri || uri === '') && !isNetwork && !isAsset) {
|
2022-09-14 13:57:37 -06:00
|
|
|
if (this.props.onError) {
|
|
|
|
this.props.onError({error: {errorString: 'invalid url, player will stop', errorCode: 'INVALID_URL'}});
|
|
|
|
}
|
|
|
|
}
|
2015-10-29 18:26:28 -06:00
|
|
|
|
|
|
|
let nativeResizeMode;
|
2019-02-18 04:17:20 -07:00
|
|
|
const RCTVideoInstance = this.getViewManagerConfig('RCTVideo');
|
|
|
|
|
2015-10-29 18:26:28 -06:00
|
|
|
if (resizeMode === VideoResizeMode.stretch) {
|
2019-02-18 04:17:20 -07:00
|
|
|
nativeResizeMode = RCTVideoInstance.Constants.ScaleToFill;
|
2015-10-29 18:26:28 -06:00
|
|
|
} else if (resizeMode === VideoResizeMode.contain) {
|
2019-02-18 04:17:20 -07:00
|
|
|
nativeResizeMode = RCTVideoInstance.Constants.ScaleAspectFit;
|
2015-10-29 18:26:28 -06:00
|
|
|
} else if (resizeMode === VideoResizeMode.cover) {
|
2019-02-18 04:17:20 -07:00
|
|
|
nativeResizeMode = RCTVideoInstance.Constants.ScaleAspectFill;
|
2015-10-29 18:26:28 -06:00
|
|
|
} else {
|
2019-02-18 04:17:20 -07:00
|
|
|
nativeResizeMode = RCTVideoInstance.Constants.ScaleNone;
|
2015-10-29 18:26:28 -06:00
|
|
|
}
|
|
|
|
|
2015-11-03 21:27:38 -07:00
|
|
|
const nativeProps = Object.assign({}, this.props);
|
2015-10-29 18:26:28 -06:00
|
|
|
Object.assign(nativeProps, {
|
2016-01-31 20:35:18 -07:00
|
|
|
style: [styles.base, nativeProps.style],
|
2015-10-29 18:26:28 -06:00
|
|
|
resizeMode: nativeResizeMode,
|
|
|
|
src: {
|
2016-01-31 20:35:18 -07:00
|
|
|
uri,
|
2015-10-29 18:26:28 -06:00
|
|
|
isNetwork,
|
|
|
|
isAsset,
|
2019-01-24 05:15:58 -07:00
|
|
|
shouldCache,
|
2017-01-28 18:46:30 -07:00
|
|
|
type: source.type || '',
|
2016-09-14 05:28:06 -06:00
|
|
|
mainVer: source.mainVer || 0,
|
|
|
|
patchVer: source.patchVer || 0,
|
2020-02-22 11:56:31 -07:00
|
|
|
requestHeaders: source.headers ? this.stringsOnlyObject(source.headers) : {},
|
2023-03-13 08:14:04 -06:00
|
|
|
startTime: source.startTime || 0,
|
2023-08-12 16:01:27 -06:00
|
|
|
endTime: source.endTime,
|
|
|
|
// Custom Metadata
|
|
|
|
title: source.title,
|
|
|
|
subtitle: source.subtitle,
|
|
|
|
description: source.description,
|
2015-10-29 18:26:28 -06:00
|
|
|
},
|
2015-11-11 14:34:41 -07:00
|
|
|
onVideoLoadStart: this._onLoadStart,
|
2022-04-19 10:12:47 -06:00
|
|
|
onVideoPlaybackStateChanged: this._onPlaybackStateChanged,
|
2015-10-29 18:26:28 -06:00
|
|
|
onVideoLoad: this._onLoad,
|
2022-08-06 04:05:07 -06:00
|
|
|
onAudioTracks: this._onAudioTracks,
|
|
|
|
onTextTracks: this._onTextTracks,
|
|
|
|
onVideoTracks: this._onVideoTracks,
|
2015-11-11 14:34:41 -07:00
|
|
|
onVideoError: this._onError,
|
2015-10-29 18:26:28 -06:00
|
|
|
onVideoProgress: this._onProgress,
|
2015-11-11 14:34:41 -07:00
|
|
|
onVideoSeek: this._onSeek,
|
2015-10-29 18:26:28 -06:00
|
|
|
onVideoEnd: this._onEnd,
|
2017-01-11 05:51:45 -07:00
|
|
|
onVideoBuffer: this._onBuffer,
|
2018-11-01 10:11:57 -06:00
|
|
|
onVideoBandwidthUpdate: this._onBandwidthUpdate,
|
2017-02-13 19:38:02 -07:00
|
|
|
onTimedMetadata: this._onTimedMetadata,
|
2018-07-12 22:48:58 -06:00
|
|
|
onVideoAudioBecomingNoisy: this._onAudioBecomingNoisy,
|
2018-10-07 16:59:10 -06:00
|
|
|
onVideoExternalPlaybackChange: this._onExternalPlaybackChange,
|
2016-03-31 13:35:10 -06:00
|
|
|
onVideoFullscreenPlayerWillPresent: this._onFullscreenPlayerWillPresent,
|
|
|
|
onVideoFullscreenPlayerDidPresent: this._onFullscreenPlayerDidPresent,
|
|
|
|
onVideoFullscreenPlayerWillDismiss: this._onFullscreenPlayerWillDismiss,
|
|
|
|
onVideoFullscreenPlayerDidDismiss: this._onFullscreenPlayerDidDismiss,
|
2016-04-28 06:42:44 -06:00
|
|
|
onReadyForDisplay: this._onReadyForDisplay,
|
|
|
|
onPlaybackStalled: this._onPlaybackStalled,
|
|
|
|
onPlaybackResume: this._onPlaybackResume,
|
|
|
|
onPlaybackRateChange: this._onPlaybackRateChange,
|
2017-01-11 05:51:45 -07:00
|
|
|
onAudioFocusChanged: this._onAudioFocusChanged,
|
|
|
|
onAudioBecomingNoisy: this._onAudioBecomingNoisy,
|
Add iOS and Android basic DRM support (#1445)
This PR adds support for DRM streams on iOS (Fairplay) and Android (Playready, Widevine, Clearkey)
I am neither Android nor iOS developer, so feel free to provide feedback to improve this PR.
**Test stream for ANDROID:**
```
testStream = {
uri: 'http://profficialsite.origin.mediaservices.windows.net/c51358ea-9a5e-4322-8951-897d640fdfd7/tearsofsteel_4k.ism/manifest(format=mpd-time-csf)',
type: 'mpd',
drm: {
type: DRMType.PLAYREADY,
licenseServer: 'http://test.playready.microsoft.com/service/rightsmanager.asmx?cfg=(persist:false,sl:150)'
}
};
```
or
```
{
uri: 'https://media.axprod.net/TestVectors/v7-MultiDRM-SingleKey/Manifest_1080p.mpd',
drm: {
type: 'widevine', //or DRMType.WIDEVINE
licenseServer: 'https://drm-widevine-licensing.axtest.net/AcquireLicense',
headers: {
'X-AxDRM-Message': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2ZXJzaW9uIjoxLCJjb21fa2V5X2lkIjoiYjMzNjRlYjUtNTFmNi00YWUzLThjOTgtMzNjZWQ1ZTMxYzc4IiwibWVzc2FnZSI6eyJ0eXBlIjoiZW50aXRsZW1lbnRfbWVzc2FnZSIsImZpcnN0X3BsYXlfZXhwaXJhdGlvbiI6NjAsInBsYXlyZWFkeSI6eyJyZWFsX3RpbWVfZXhwaXJhdGlvbiI6dHJ1ZX0sImtleXMiOlt7ImlkIjoiOWViNDA1MGQtZTQ0Yi00ODAyLTkzMmUtMjdkNzUwODNlMjY2IiwiZW5jcnlwdGVkX2tleSI6ImxLM09qSExZVzI0Y3Iya3RSNzRmbnc9PSJ9XX19.FAbIiPxX8BHi9RwfzD7Yn-wugU19ghrkBFKsaCPrZmU'
},
}
}
```
**Test stream for iOS:**
Sorry but I can not provide free streams to test. If anyone can provide test streams, or found some we can use, please let me know to also test them.
It has been tested with a private provider and they work, at least with the `getLicense` override method. (An example implementation is provided in the README)
2020-08-12 19:56:21 -06:00
|
|
|
onGetLicense: nativeProps.drm && nativeProps.drm.getLicense && this._onGetLicense,
|
2018-11-26 15:23:04 -07:00
|
|
|
onPictureInPictureStatusChanged: this._onPictureInPictureStatusChanged,
|
|
|
|
onRestoreUserInterfaceForPictureInPictureStop: this._onRestoreUserInterfaceForPictureInPictureStop,
|
2021-07-26 07:11:37 -06:00
|
|
|
onReceiveAdEvent: this._onReceiveAdEvent,
|
2015-10-29 18:26:28 -06:00
|
|
|
});
|
|
|
|
|
2018-08-04 15:28:33 -06:00
|
|
|
const posterStyle = {
|
|
|
|
...StyleSheet.absoluteFillObject,
|
|
|
|
resizeMode: this.props.posterResizeMode || 'contain',
|
|
|
|
};
|
2016-12-05 14:57:35 -07:00
|
|
|
|
2015-11-09 18:55:39 -07:00
|
|
|
return (
|
2020-06-11 08:44:13 -06:00
|
|
|
<View style={nativeProps.style}>
|
2019-06-19 03:39:35 -06:00
|
|
|
<RCTVideo
|
|
|
|
ref={this._assignRoot}
|
|
|
|
{...nativeProps}
|
|
|
|
style={StyleSheet.absoluteFill}
|
|
|
|
/>
|
2019-06-19 05:00:57 -06:00
|
|
|
{this.state.showPoster && (
|
2019-06-19 07:19:06 -06:00
|
|
|
<Image style={posterStyle} source={{ uri: this.props.poster }} />
|
2019-06-19 03:39:35 -06:00
|
|
|
)}
|
|
|
|
</View>
|
2015-11-09 18:55:39 -07:00
|
|
|
);
|
2015-10-29 18:26:28 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Video.propTypes = {
|
2018-11-06 07:38:28 -07:00
|
|
|
filter: PropTypes.oneOf([
|
2020-01-28 15:21:21 -07:00
|
|
|
FilterType.NONE,
|
|
|
|
FilterType.INVERT,
|
|
|
|
FilterType.MONOCHROME,
|
|
|
|
FilterType.POSTERIZE,
|
|
|
|
FilterType.FALSE,
|
|
|
|
FilterType.MAXIMUMCOMPONENT,
|
|
|
|
FilterType.MINIMUMCOMPONENT,
|
|
|
|
FilterType.CHROME,
|
|
|
|
FilterType.FADE,
|
|
|
|
FilterType.INSTANT,
|
|
|
|
FilterType.MONO,
|
|
|
|
FilterType.NOIR,
|
|
|
|
FilterType.PROCESS,
|
|
|
|
FilterType.TONAL,
|
|
|
|
FilterType.TRANSFER,
|
2020-02-22 11:56:31 -07:00
|
|
|
FilterType.SEPIA,
|
2018-11-06 07:38:28 -07:00
|
|
|
]),
|
2018-12-13 20:30:38 -07:00
|
|
|
filterEnabled: PropTypes.bool,
|
2016-12-12 17:16:11 -07:00
|
|
|
onVideoLoadStart: PropTypes.func,
|
|
|
|
onVideoLoad: PropTypes.func,
|
2017-01-11 05:51:45 -07:00
|
|
|
onVideoBuffer: PropTypes.func,
|
2016-12-12 17:16:11 -07:00
|
|
|
onVideoError: PropTypes.func,
|
|
|
|
onVideoProgress: PropTypes.func,
|
2018-11-01 10:11:57 -06:00
|
|
|
onVideoBandwidthUpdate: PropTypes.func,
|
2016-12-12 17:16:11 -07:00
|
|
|
onVideoSeek: PropTypes.func,
|
|
|
|
onVideoEnd: PropTypes.func,
|
2017-02-13 19:38:02 -07:00
|
|
|
onTimedMetadata: PropTypes.func,
|
2018-07-12 22:48:58 -06:00
|
|
|
onVideoAudioBecomingNoisy: PropTypes.func,
|
2018-10-07 16:59:10 -06:00
|
|
|
onVideoExternalPlaybackChange: PropTypes.func,
|
2016-12-12 17:16:11 -07:00
|
|
|
onVideoFullscreenPlayerWillPresent: PropTypes.func,
|
|
|
|
onVideoFullscreenPlayerDidPresent: PropTypes.func,
|
|
|
|
onVideoFullscreenPlayerWillDismiss: PropTypes.func,
|
|
|
|
onVideoFullscreenPlayerDidDismiss: PropTypes.func,
|
2015-10-29 18:26:28 -06:00
|
|
|
|
|
|
|
/* Wrapper component */
|
2016-06-22 07:52:12 -06:00
|
|
|
source: PropTypes.oneOfType([
|
|
|
|
PropTypes.shape({
|
2020-02-22 11:56:31 -07:00
|
|
|
uri: PropTypes.string,
|
2016-06-22 07:52:12 -06:00
|
|
|
}),
|
|
|
|
// Opaque type returned by require('./video.mp4')
|
2020-02-22 11:56:31 -07:00
|
|
|
PropTypes.number,
|
2016-06-22 07:52:12 -06:00
|
|
|
]),
|
Add iOS and Android basic DRM support (#1445)
This PR adds support for DRM streams on iOS (Fairplay) and Android (Playready, Widevine, Clearkey)
I am neither Android nor iOS developer, so feel free to provide feedback to improve this PR.
**Test stream for ANDROID:**
```
testStream = {
uri: 'http://profficialsite.origin.mediaservices.windows.net/c51358ea-9a5e-4322-8951-897d640fdfd7/tearsofsteel_4k.ism/manifest(format=mpd-time-csf)',
type: 'mpd',
drm: {
type: DRMType.PLAYREADY,
licenseServer: 'http://test.playready.microsoft.com/service/rightsmanager.asmx?cfg=(persist:false,sl:150)'
}
};
```
or
```
{
uri: 'https://media.axprod.net/TestVectors/v7-MultiDRM-SingleKey/Manifest_1080p.mpd',
drm: {
type: 'widevine', //or DRMType.WIDEVINE
licenseServer: 'https://drm-widevine-licensing.axtest.net/AcquireLicense',
headers: {
'X-AxDRM-Message': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2ZXJzaW9uIjoxLCJjb21fa2V5X2lkIjoiYjMzNjRlYjUtNTFmNi00YWUzLThjOTgtMzNjZWQ1ZTMxYzc4IiwibWVzc2FnZSI6eyJ0eXBlIjoiZW50aXRsZW1lbnRfbWVzc2FnZSIsImZpcnN0X3BsYXlfZXhwaXJhdGlvbiI6NjAsInBsYXlyZWFkeSI6eyJyZWFsX3RpbWVfZXhwaXJhdGlvbiI6dHJ1ZX0sImtleXMiOlt7ImlkIjoiOWViNDA1MGQtZTQ0Yi00ODAyLTkzMmUtMjdkNzUwODNlMjY2IiwiZW5jcnlwdGVkX2tleSI6ImxLM09qSExZVzI0Y3Iya3RSNzRmbnc9PSJ9XX19.FAbIiPxX8BHi9RwfzD7Yn-wugU19ghrkBFKsaCPrZmU'
},
}
}
```
**Test stream for iOS:**
Sorry but I can not provide free streams to test. If anyone can provide test streams, or found some we can use, please let me know to also test them.
It has been tested with a private provider and they work, at least with the `getLicense` override method. (An example implementation is provided in the README)
2020-08-12 19:56:21 -06:00
|
|
|
drm: PropTypes.shape({
|
|
|
|
type: PropTypes.oneOf([
|
2022-02-04 13:32:34 -07:00
|
|
|
DRMType.CLEARKEY, DRMType.FAIRPLAY, DRMType.WIDEVINE, DRMType.PLAYREADY,
|
Add iOS and Android basic DRM support (#1445)
This PR adds support for DRM streams on iOS (Fairplay) and Android (Playready, Widevine, Clearkey)
I am neither Android nor iOS developer, so feel free to provide feedback to improve this PR.
**Test stream for ANDROID:**
```
testStream = {
uri: 'http://profficialsite.origin.mediaservices.windows.net/c51358ea-9a5e-4322-8951-897d640fdfd7/tearsofsteel_4k.ism/manifest(format=mpd-time-csf)',
type: 'mpd',
drm: {
type: DRMType.PLAYREADY,
licenseServer: 'http://test.playready.microsoft.com/service/rightsmanager.asmx?cfg=(persist:false,sl:150)'
}
};
```
or
```
{
uri: 'https://media.axprod.net/TestVectors/v7-MultiDRM-SingleKey/Manifest_1080p.mpd',
drm: {
type: 'widevine', //or DRMType.WIDEVINE
licenseServer: 'https://drm-widevine-licensing.axtest.net/AcquireLicense',
headers: {
'X-AxDRM-Message': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2ZXJzaW9uIjoxLCJjb21fa2V5X2lkIjoiYjMzNjRlYjUtNTFmNi00YWUzLThjOTgtMzNjZWQ1ZTMxYzc4IiwibWVzc2FnZSI6eyJ0eXBlIjoiZW50aXRsZW1lbnRfbWVzc2FnZSIsImZpcnN0X3BsYXlfZXhwaXJhdGlvbiI6NjAsInBsYXlyZWFkeSI6eyJyZWFsX3RpbWVfZXhwaXJhdGlvbiI6dHJ1ZX0sImtleXMiOlt7ImlkIjoiOWViNDA1MGQtZTQ0Yi00ODAyLTkzMmUtMjdkNzUwODNlMjY2IiwiZW5jcnlwdGVkX2tleSI6ImxLM09qSExZVzI0Y3Iya3RSNzRmbnc9PSJ9XX19.FAbIiPxX8BHi9RwfzD7Yn-wugU19ghrkBFKsaCPrZmU'
},
}
}
```
**Test stream for iOS:**
Sorry but I can not provide free streams to test. If anyone can provide test streams, or found some we can use, please let me know to also test them.
It has been tested with a private provider and they work, at least with the `getLicense` override method. (An example implementation is provided in the README)
2020-08-12 19:56:21 -06:00
|
|
|
]),
|
|
|
|
licenseServer: PropTypes.string,
|
|
|
|
headers: PropTypes.shape({}),
|
|
|
|
base64Certificate: PropTypes.bool,
|
|
|
|
certificateUrl: PropTypes.string,
|
|
|
|
getLicense: PropTypes.func,
|
|
|
|
}),
|
2022-05-19 07:29:25 -06:00
|
|
|
localSourceEncryptionKeyScheme: PropTypes.string,
|
2019-02-10 20:21:02 -07:00
|
|
|
minLoadRetryCount: PropTypes.number,
|
2018-11-26 15:50:31 -07:00
|
|
|
maxBitRate: PropTypes.number,
|
2015-10-29 18:26:28 -06:00
|
|
|
resizeMode: PropTypes.string,
|
2016-12-05 14:57:35 -07:00
|
|
|
poster: PropTypes.string,
|
2022-06-13 09:26:40 -06:00
|
|
|
posterResizeMode: ImagePropTypes.resizeMode,
|
2015-10-29 18:26:28 -06:00
|
|
|
repeat: PropTypes.bool,
|
2019-08-22 02:10:39 -06:00
|
|
|
automaticallyWaitsToMinimizeStalling: PropTypes.bool,
|
2018-06-05 20:22:19 -06:00
|
|
|
allowsExternalPlayback: PropTypes.bool,
|
2018-07-17 15:14:21 -06:00
|
|
|
selectedAudioTrack: PropTypes.shape({
|
|
|
|
type: PropTypes.string.isRequired,
|
|
|
|
value: PropTypes.oneOfType([
|
|
|
|
PropTypes.string,
|
2020-02-22 11:56:31 -07:00
|
|
|
PropTypes.number,
|
|
|
|
]),
|
2018-07-17 15:14:21 -06:00
|
|
|
}),
|
2018-08-24 04:03:46 -06:00
|
|
|
selectedVideoTrack: PropTypes.shape({
|
|
|
|
type: PropTypes.string.isRequired,
|
|
|
|
value: PropTypes.oneOfType([
|
|
|
|
PropTypes.string,
|
2020-02-22 11:56:31 -07:00
|
|
|
PropTypes.number,
|
|
|
|
]),
|
2020-01-28 15:21:21 -07:00
|
|
|
}),
|
2018-06-02 03:24:13 -06:00
|
|
|
selectedTextTrack: PropTypes.shape({
|
|
|
|
type: PropTypes.string.isRequired,
|
|
|
|
value: PropTypes.oneOfType([
|
|
|
|
PropTypes.string,
|
2020-02-22 11:56:31 -07:00
|
|
|
PropTypes.number,
|
|
|
|
]),
|
2018-06-02 03:24:13 -06:00
|
|
|
}),
|
2018-06-12 22:04:15 -06:00
|
|
|
textTracks: PropTypes.arrayOf(
|
|
|
|
PropTypes.shape({
|
|
|
|
title: PropTypes.string,
|
|
|
|
uri: PropTypes.string.isRequired,
|
|
|
|
type: PropTypes.oneOf([
|
|
|
|
TextTrackType.SRT,
|
|
|
|
TextTrackType.TTML,
|
|
|
|
TextTrackType.VTT,
|
|
|
|
]),
|
2020-02-22 11:56:31 -07:00
|
|
|
language: PropTypes.string.isRequired,
|
2018-06-12 22:04:15 -06:00
|
|
|
})
|
|
|
|
),
|
2023-08-12 16:01:27 -06:00
|
|
|
chapters: PropTypes.arrayOf(
|
|
|
|
PropTypes.shape({
|
|
|
|
title: PropTypes.string,
|
|
|
|
startTime: PropTypes.number.isRequired,
|
|
|
|
endTime: PropTypes.number.isRequired,
|
|
|
|
})
|
|
|
|
),
|
2015-10-29 18:26:28 -06:00
|
|
|
paused: PropTypes.bool,
|
|
|
|
muted: PropTypes.bool,
|
|
|
|
volume: PropTypes.number,
|
2018-08-02 01:20:08 -06:00
|
|
|
bufferConfig: PropTypes.shape({
|
2018-08-01 07:58:02 -06:00
|
|
|
minBufferMs: PropTypes.number,
|
|
|
|
maxBufferMs: PropTypes.number,
|
|
|
|
bufferForPlaybackMs: PropTypes.number,
|
|
|
|
bufferForPlaybackAfterRebufferMs: PropTypes.number,
|
2021-11-04 11:54:43 -06:00
|
|
|
maxHeapAllocationPercent: PropTypes.number,
|
2018-08-01 07:58:02 -06:00
|
|
|
}),
|
2015-10-29 18:26:28 -06:00
|
|
|
rate: PropTypes.number,
|
2018-11-26 15:23:04 -07:00
|
|
|
pictureInPicture: PropTypes.bool,
|
2015-12-16 05:53:04 -07:00
|
|
|
playInBackground: PropTypes.bool,
|
2020-05-15 01:25:19 -06:00
|
|
|
preferredForwardBufferDuration: PropTypes.number,
|
2016-04-29 05:55:34 -06:00
|
|
|
playWhenInactive: PropTypes.bool,
|
2017-04-20 12:10:06 -06:00
|
|
|
ignoreSilentSwitch: PropTypes.oneOf(['ignore', 'obey']),
|
2018-08-25 10:23:11 -06:00
|
|
|
reportBandwidth: PropTypes.bool,
|
2021-11-09 05:22:32 -07:00
|
|
|
contentStartTime: PropTypes.number,
|
2017-01-11 05:51:45 -07:00
|
|
|
disableFocus: PropTypes.bool,
|
2022-09-25 18:51:18 -06:00
|
|
|
focusable: PropTypes.bool,
|
2021-03-18 04:58:04 -06:00
|
|
|
disableBuffering: PropTypes.bool,
|
2015-12-22 16:39:04 -07:00
|
|
|
controls: PropTypes.bool,
|
2018-06-20 17:52:48 -06:00
|
|
|
audioOnly: PropTypes.bool,
|
2023-04-02 12:02:56 -06:00
|
|
|
audioOutput: PropTypes.oneOf(['earpiece', 'speaker']),
|
2018-10-18 16:21:46 -06:00
|
|
|
fullscreenAutorotate: PropTypes.bool,
|
2020-01-28 15:21:21 -07:00
|
|
|
fullscreenOrientation: PropTypes.oneOf(['all', 'landscape', 'portrait']),
|
2016-10-01 12:23:50 -06:00
|
|
|
progressUpdateInterval: PropTypes.number,
|
2022-07-05 15:58:30 -06:00
|
|
|
subtitleStyle: PropTypes.shape({
|
|
|
|
paddingTop: PropTypes.number,
|
|
|
|
paddingBottom: PropTypes.number,
|
|
|
|
paddingLeft: PropTypes.number,
|
|
|
|
paddingRight: PropTypes.number,
|
|
|
|
fontSize: PropTypes.number,
|
|
|
|
}),
|
2018-06-08 01:01:13 -06:00
|
|
|
useTextureView: PropTypes.bool,
|
2022-02-14 18:17:22 -07:00
|
|
|
useSecureView: PropTypes.bool,
|
2018-11-28 05:56:58 -07:00
|
|
|
hideShutterView: PropTypes.bool,
|
2023-07-23 10:08:26 -06:00
|
|
|
shutterColor: PropTypes.string,
|
2015-10-29 18:26:28 -06:00
|
|
|
onLoadStart: PropTypes.func,
|
2022-04-19 10:12:47 -06:00
|
|
|
onPlaybackStateChanged: PropTypes.func,
|
2015-10-29 18:26:28 -06:00
|
|
|
onLoad: PropTypes.func,
|
2022-08-06 04:05:07 -06:00
|
|
|
onAudioTracks: PropTypes.func,
|
|
|
|
onTextTracks: PropTypes.func,
|
|
|
|
onVideoTracks: PropTypes.func,
|
2017-01-11 05:51:45 -07:00
|
|
|
onBuffer: PropTypes.func,
|
2015-10-29 18:26:28 -06:00
|
|
|
onError: PropTypes.func,
|
|
|
|
onProgress: PropTypes.func,
|
2018-11-01 10:11:57 -06:00
|
|
|
onBandwidthUpdate: PropTypes.func,
|
2015-11-11 14:34:41 -07:00
|
|
|
onSeek: PropTypes.func,
|
2015-10-29 18:26:28 -06:00
|
|
|
onEnd: PropTypes.func,
|
2016-03-31 13:35:10 -06:00
|
|
|
onFullscreenPlayerWillPresent: PropTypes.func,
|
|
|
|
onFullscreenPlayerDidPresent: PropTypes.func,
|
|
|
|
onFullscreenPlayerWillDismiss: PropTypes.func,
|
|
|
|
onFullscreenPlayerDidDismiss: PropTypes.func,
|
2016-04-28 06:42:44 -06:00
|
|
|
onReadyForDisplay: PropTypes.func,
|
|
|
|
onPlaybackStalled: PropTypes.func,
|
|
|
|
onPlaybackResume: PropTypes.func,
|
|
|
|
onPlaybackRateChange: PropTypes.func,
|
2017-01-11 05:51:45 -07:00
|
|
|
onAudioFocusChanged: PropTypes.func,
|
|
|
|
onAudioBecomingNoisy: PropTypes.func,
|
2018-11-26 15:23:04 -07:00
|
|
|
onPictureInPictureStatusChanged: PropTypes.func,
|
2018-09-13 06:06:12 -06:00
|
|
|
onExternalPlaybackChange: PropTypes.func,
|
2022-11-14 03:49:15 -07:00
|
|
|
adTagUrl: PropTypes.string,
|
2022-11-16 04:11:28 -07:00
|
|
|
onReceiveAdEvent: PropTypes.func,
|
2015-10-29 18:26:28 -06:00
|
|
|
|
|
|
|
/* Required by react-native */
|
2017-11-03 12:38:37 -06:00
|
|
|
...ViewPropTypes,
|
2015-10-29 18:26:28 -06:00
|
|
|
};
|
|
|
|
|
2023-03-09 01:41:11 -07:00
|
|
|
const RCTVideo = requireNativeComponent('RCTVideo');
|