docs: update structure (#4454)
* [Preview] docs: update (#9) Co-authored-by: Bart Widlarz <bart@thewidlarzgroup.com> * docs: update links * docs: fix naming * docs: update footer * docs: update content * docs: refine grammar * fix(docs): update typo * docs: update url * refactor: sdk name * docs: add issue boost link * docs: add new roadmap to readme * lint code --------- Co-authored-by: Bart Widlarz <bart@thewidlarzgroup.com> Co-authored-by: Kamil <moskalakamil07@gmail.com>
This commit is contained in:
@@ -50,6 +50,9 @@ var styles = StyleSheet.create({
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Roadmap
|
||||||
|
You can follow our work on the library at [Roadmap](https://github.com/orgs/TheWidlarzGroup/projects/6).
|
||||||
|
|
||||||
## Community support
|
## Community support
|
||||||
We have an discord server where you can ask questions and get help. [Join the discord server](https://discord.gg/WXuM4Tgb9X)
|
We have an discord server where you can ask questions and get help. [Join the discord server](https://discord.gg/WXuM4Tgb9X)
|
||||||
|
|
||||||
|
|||||||
@@ -7,29 +7,39 @@
|
|||||||
"type": "separator",
|
"type": "separator",
|
||||||
"title": ""
|
"title": ""
|
||||||
},
|
},
|
||||||
"updating": "Updating",
|
|
||||||
"changelog": {
|
|
||||||
"title": "Changelog",
|
|
||||||
"newWindow": true,
|
|
||||||
"href": "https://github.com/TheWidlarzGroup/react-native-video/blob/master/CHANGELOG.md"
|
|
||||||
},
|
|
||||||
"separator_community": {
|
|
||||||
"type": "separator",
|
|
||||||
"title": ""
|
|
||||||
},
|
|
||||||
"example_apps": {
|
"example_apps": {
|
||||||
"title": "Example Apps",
|
"title": "Example Apps",
|
||||||
"newWindow": true,
|
"newWindow": true,
|
||||||
"href": "https://github.com/TheWidlarzGroup/react-native-video/tree/master/examples"
|
"href": "https://github.com/TheWidlarzGroup/react-native-video/tree/master/examples"
|
||||||
},
|
},
|
||||||
"projects": "Useful projects",
|
"projects": "Useful projects",
|
||||||
"separator_enterprise": {
|
"separator_community": {
|
||||||
"type": "separator",
|
"type": "separator",
|
||||||
"title": ""
|
"title": ""
|
||||||
},
|
},
|
||||||
|
"video_offline_sdk": {
|
||||||
|
"title": "Offline Video SDK",
|
||||||
|
"newWindow": true,
|
||||||
|
"href": "https://www.thewidlarzgroup.com/offline-video-sdk/?utm_source=rnv&utm_medium=docs&utm_campaign=sidebar&utm_id=offline-video-sdk-button"
|
||||||
|
},
|
||||||
"enterprise_support": {
|
"enterprise_support": {
|
||||||
"title": "Enterprise Support",
|
"title": "Enterprise Support",
|
||||||
"newWindow": true,
|
"newWindow": true,
|
||||||
"href": "https://www.thewidlarzgroup.com/?utm_source=rnv&utm_medium=docs&utm_campaign=navbar&utm_id=enterprise#Contact"
|
"href": "https://www.thewidlarzgroup.com/?utm_source=rnv&utm_medium=docs#Contact"
|
||||||
|
},
|
||||||
|
"issue_boost": {
|
||||||
|
"title": "Boost Your Issue",
|
||||||
|
"newWindow": true,
|
||||||
|
"href": "https://www.thewidlarzgroup.com/issue-boost/?utm_source=rnv&utm_medium=docs&utm_campaign=sidebar&utm_id=issue-boost-button"
|
||||||
|
},
|
||||||
|
"separator_enterprise": {
|
||||||
|
"type": "separator",
|
||||||
|
"title": ""
|
||||||
|
},
|
||||||
|
"updating": "Updating",
|
||||||
|
"changelog": {
|
||||||
|
"title": "Changelog",
|
||||||
|
"newWindow": true,
|
||||||
|
"href": "https://github.com/TheWidlarzGroup/react-native-video/blob/master/CHANGELOG.md"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,26 @@
|
|||||||
# Ads
|
# Ads
|
||||||
|
|
||||||
## IMA SDK
|
## IMA SDK
|
||||||
`react-native-video` has built-in support for Google IMA SDK for Android and iOS. To enable it please refer to [installation section](/installation)
|
|
||||||
|
`react-native-video` includes built-in support for Google IMA SDK on Android and iOS. To enable it, refer to the [installation section](/installation).
|
||||||
|
|
||||||
### Usage
|
### Usage
|
||||||
To use AVOD, you need to pass `adTagUrl` prop to `Video` component. `adTagUrl` is a VAST uri.
|
|
||||||
|
|
||||||
Example:
|
To use AVOD (Ad-Supported Video on Demand), pass the `adTagUrl` prop to the `Video` component. The `adTagUrl` should be a VAST-compliant URI.
|
||||||
```
|
|
||||||
|
#### Example:
|
||||||
|
|
||||||
|
```jsx
|
||||||
adTagUrl="https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/vmap_ad_samples&sz=640x480&cust_params=sample_ar%3Dpremidpostoptimizedpodbumper&ciu_szs=300x250&gdfp_req=1&ad_rule=1&output=vmap&unviewed_position_start=1&env=vp&impl=s&cmsid=496&vid=short_onecue&correlator="
|
adTagUrl="https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/vmap_ad_samples&sz=640x480&cust_params=sample_ar%3Dpremidpostoptimizedpodbumper&ciu_szs=300x250&gdfp_req=1&ad_rule=1&output=vmap&unviewed_position_start=1&env=vp&impl=s&cmsid=496&vid=short_onecue&correlator="
|
||||||
```
|
```
|
||||||
|
|
||||||
> NOTE: Video ads cannot start when you are using the PIP on iOS (more info available at [Google IMA SDK Docs](https://developers.google.com/interactive-media-ads/docs/sdks/ios/client-side/picture_in_picture?hl=en#starting_ads)). If you are using custom controls, you must hide your PIP button when you receive the ```STARTED``` event from ```onReceiveAdEvent``` and show it again when you receive the ```ALL_ADS_COMPLETED``` event.
|
> **Note:** Video ads cannot start when Picture-in-Picture (PiP) mode is active on iOS. More details are available in the [Google IMA SDK Docs](https://developers.google.com/interactive-media-ads/docs/sdks/ios/client-side/picture_in_picture?hl=en#starting_ads). If you are using custom controls, hide the PiP button when receiving the `STARTED` event from `onReceiveAdEvent` and show it again when receiving the `ALL_ADS_COMPLETED` event.
|
||||||
|
|
||||||
### Events
|
### Events
|
||||||
To receive events from IMA SDK, you need to pass `onReceiveAdEvent` prop to `Video` component. List of events, you can find [here](https://github.com/TheWidlarzGroup/react-native-video/blob/master/src/types/Ads.ts)
|
|
||||||
|
|
||||||
Example:
|
To receive events from the IMA SDK, pass the `onReceiveAdEvent` prop to the `Video` component. The full list of supported events is available [here](https://github.com/TheWidlarzGroup/react-native-video/blob/master/src/types/Ads.ts).
|
||||||
|
|
||||||
|
#### Example:
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
...
|
...
|
||||||
@@ -25,11 +29,12 @@ onReceiveAdEvent={event => console.log(event)}
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Localization
|
### Localization
|
||||||
To change the language of the IMA SDK, you need to pass `adLanguage` prop to `Video` component. List of supported languages, you can find [here](https://developers.google.com/interactive-media-ads/docs/sdks/android/client-side/localization#locale-codes)
|
|
||||||
|
|
||||||
By default, ios will use system language and android will use `en`
|
To change the language of the IMA SDK, pass the `adLanguage` prop to the `Video` component. The list of supported languages is available [here](https://developers.google.com/interactive-media-ads/docs/sdks/android/client-side/localization#locale-codes).
|
||||||
|
|
||||||
Example:
|
- By default, **iOS** uses the system language, and **Android** defaults to `en` (English).
|
||||||
|
|
||||||
|
#### Example:
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
...
|
...
|
||||||
|
|||||||
@@ -4,57 +4,59 @@ import PlatformsList from '../../components/PlatformsList/PlatformsList.tsx';
|
|||||||
|
|
||||||
## DRM Example
|
## DRM Example
|
||||||
|
|
||||||
We have available example for DRM usage in the [example app](https://github.com/TheWidlarzGroup/react-native-video/blob/master/examples/bare/src/DRMExample.tsx).
|
We provide a sample implementation in the [example app](https://github.com/TheWidlarzGroup/react-native-video/blob/master/examples/bare/src/DRMExample.tsx) demonstrating how to use DRM with `react-native-video`. You’ll need a valid token—visit [our site](https://www.thewidlarzgroup.com/services/free-drm-token-generator-for-video?utm_source=drm&utm_medium=docs) to obtain a **free 24-hour token**.
|
||||||
To get token needed for DRM playback you can go to [our site](https://www.thewidlarzgroup.com/services/free-drm-token-generator-for-video?utm_source=rnv&utm_medium=docs&utm_campaign=drm&utm_id=text) and get it.
|
|
||||||
|
|
||||||
## Provide DRM data (only tested with http/https assets)
|
## DRM Offline
|
||||||
|
|
||||||
You can provide some configuration to allow DRM playback.
|
If you need DRM-protected content available offline, our [Offline Video SDK](https://www.thewidlarzgroup.com/offline-video-sdk/?utm_source=rnv&utm_medium=docs&utm_campaign=drm&utm_id=offline-video-sdk-link) enables downloading, storing, and managing streams with and without DRM. It also handles many edge cases you may encounter over time.
|
||||||
This feature will disable the use of `TextureView` on Android.
|
|
||||||
|
|
||||||
DRM object allows this members:
|
### Prerequisites:
|
||||||
|
- Use `react-native-video` v6 or v7. If you're still on v5 or lower, [contact us](https://www.thewidlarzgroup.com/?utm_source=rnv&utm_medium=docs&utm_campaign=drm&utm_id=contact#Contact) for assistance.
|
||||||
|
|
||||||
|
> Supporting our software kits helps maintain this open-source project. Thank you!
|
||||||
|
|
||||||
|
## Providing DRM Data (Tested with HTTP/HTTPS Assets)
|
||||||
|
|
||||||
|
You can configure DRM playback by providing a DRM object with the following properties. This feature disables the use of `TextureView` on Android.
|
||||||
|
|
||||||
|
### DRM Properties
|
||||||
|
|
||||||
### `base64Certificate`
|
### `base64Certificate`
|
||||||
|
|
||||||
<PlatformsList types={['iOS', 'visionOS']} />
|
<PlatformsList types={['iOS', 'visionOS']} />
|
||||||
|
|
||||||
Type: bool\
|
**Type:** boolean
|
||||||
Default: false
|
**Default:** `false`
|
||||||
|
|
||||||
Whether or not the certificate url returns it on base64.
|
Indicates whether the certificate URL returns data in Base64 format.
|
||||||
|
|
||||||
### `certificateUrl`
|
### `certificateUrl`
|
||||||
|
|
||||||
<PlatformsList types={['iOS', 'visionOS']} />
|
<PlatformsList types={['iOS', 'visionOS']} />
|
||||||
|
|
||||||
Type: string\
|
**Type:** string
|
||||||
Default: undefined
|
**Default:** `undefined`
|
||||||
|
|
||||||
URL to fetch a valid certificate for FairPlay.
|
The URL used to fetch a valid certificate for FairPlay.
|
||||||
|
|
||||||
### `getLicense`
|
### `getLicense`
|
||||||
|
|
||||||
<PlatformsList types={['iOS', 'visionOS']} />
|
<PlatformsList types={['iOS', 'visionOS']} />
|
||||||
|
|
||||||
Type: function\
|
**Type:** function
|
||||||
Default: undefined
|
**Default:** `undefined`
|
||||||
|
|
||||||
Rather than setting the `licenseServer` url to get the license, you can manually get the license on the JS part, and send the result to the native part to configure FairplayDRM for the stream
|
Instead of setting `licenseServer`, you can manually acquire the license in JavaScript and send the result to the native module for FairPlay DRM configuration.
|
||||||
|
|
||||||
`licenseServer` and `headers` will be ignored. You will obtain as argument the `SPC`
|
The following parameters are available in `getLicense`:
|
||||||
(as ASCII string, you will probably need to convert it to base 64) obtained from
|
- `contentId`: The content ID from the DRM object or `loadingRequest.request.url?.host`
|
||||||
your `contentId` + the provided certificate via `objc [loadingRequest streamingContentKeyRequestDataForApp:certificateData
|
- `loadedLicenseUrl`: The URL retrieved from `loadingRequest.request.URL.absoluteString`, starting with `skd://` or `clearkey://`
|
||||||
contentIdentifier:contentIdData options:nil error:&spcError]; `
|
- `licenseServer`: The URL passed in the DRM object
|
||||||
|
- `spcString`: The SPC used for DRM validation
|
||||||
|
|
||||||
Also, you will receive following parameter of getLicense:
|
You should return a Base64-encoded CKC response, either directly or as a `Promise`.
|
||||||
* `contentId` contentId if passed to `drm` object or loadingRequest.request.url?.host
|
|
||||||
* `loadedLicenseUrl` URL defined as `loadingRequest.request.URL.absoluteString`, this url starts with `skd://` or `clearkey://`
|
|
||||||
* `licenseServer` prop if prop is passed to `drm` object.
|
|
||||||
* `spcString` the SPC used to validate playback with drm server
|
|
||||||
|
|
||||||
You should return on this method a `CKC` in Base64, either by just returning it or returning a `Promise` that resolves with the `CKC`.
|
#### Example:
|
||||||
|
|
||||||
With this prop you can override the license acquisition flow, as an example:
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
getLicense: (spcString, contentId, licenseUrl, loadedLicenseUrl) => {
|
getLicense: (spcString, contentId, licenseUrl, loadedLicenseUrl) => {
|
||||||
@@ -64,19 +66,14 @@ getLicense: (spcString, contentId, licenseUrl, loadedLicenseUrl) => {
|
|||||||
return fetch(`https://license.pallycon.com/ri/licenseManager.do`, {
|
return fetch(`https://license.pallycon.com/ri/licenseManager.do`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'pallycon-customdata-v2':
|
'pallycon-customdata-v2': 'your-custom-header',
|
||||||
'd2VpcmRiYXNlNjRzdHJpbmcgOlAgRGFuaWVsIE1hcmnxbyB3YXMgaGVyZQ==',
|
|
||||||
'Content-Type': 'application/x-www-form-urlencoded',
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
},
|
},
|
||||||
body: formData,
|
body: formData,
|
||||||
})
|
})
|
||||||
.then((response) => response.text())
|
.then((response) => response.text())
|
||||||
.then((response) => {
|
.then((response) => response)
|
||||||
return response;
|
.catch((error) => console.error('Error', error));
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.error('Error', error);
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -84,100 +81,103 @@ getLicense: (spcString, contentId, licenseUrl, loadedLicenseUrl) => {
|
|||||||
|
|
||||||
<PlatformsList types={['iOS', 'visionOS']} />
|
<PlatformsList types={['iOS', 'visionOS']} />
|
||||||
|
|
||||||
Type: string\
|
**Type:** string
|
||||||
Default: undefined
|
**Default:** `undefined`
|
||||||
|
|
||||||
Specify the content id of the stream, otherwise it will take the host value from `loadingRequest.request.URL.host` (f.e: `skd://testAsset` -> will take `testAsset`)
|
Sets the content ID for the stream. If not specified, the system uses the host value from `loadingRequest.request.URL.host`.
|
||||||
|
|
||||||
### `headers`
|
### `headers`
|
||||||
|
|
||||||
<PlatformsList types={['Android', 'iOS', 'visionOS']} />
|
<PlatformsList types={['Android', 'iOS', 'visionOS']} />
|
||||||
|
|
||||||
Type: Object\
|
**Type:** Object
|
||||||
Default: undefined
|
**Default:** `undefined`
|
||||||
|
|
||||||
You can customize headers send to the licenseServer.
|
Custom headers for the license server request.
|
||||||
|
|
||||||
Example:
|
#### Example:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
source={{
|
drm: {
|
||||||
uri: 'https://media.axprod.net/TestVectors/v7-MultiDRM-SingleKey/Manifest_1080p.mpd',
|
|
||||||
}}
|
|
||||||
drm={{
|
|
||||||
type: DRMType.WIDEVINE,
|
type: DRMType.WIDEVINE,
|
||||||
licenseServer: 'https://drm-widevine-licensing.axtest.net/AcquireLicense',
|
licenseServer: 'https://drm-widevine-licensing.axtest.net/AcquireLicense',
|
||||||
headers: {
|
headers: {
|
||||||
'X-AxDRM-Message': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2ZXJzaW9uIjoxLCJjb21fa2V5X2lkIjoiYjMzNjRlYjUtNTFmNi00YWUzLThjOTgtMzNjZWQ1ZTMxYzc4IiwibWVzc2FnZSI6eyJ0eXBlIjoiZW50aXRsZW1lbnRfbWVzc2FnZSIsImZpcnN0X3BsYXlfZXhwaXJhdGlvbiI6NjAsInBsYXlyZWFkeSI6eyJyZWFsX3RpbWVfZXhwaXJhdGlvbiI6dHJ1ZX0sImtleXMiOlt7ImlkIjoiOWViNDA1MGQtZTQ0Yi00ODAyLTkzMmUtMjdkNzUwODNlMjY2IiwiZW5jcnlwdGVkX2tleSI6ImxLM09qSExZVzI0Y3Iya3RSNzRmbnc9PSJ9XX19.FAbIiPxX8BHi9RwfzD7Yn-wugU19ghrkBFKsaCPrZmU'
|
'X-AxDRM-Message': 'your-drm-header',
|
||||||
},
|
},
|
||||||
}}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### `licenseServer`
|
### `licenseServer`
|
||||||
|
|
||||||
<PlatformsList types={['Android', 'iOS', 'visionOS']} />
|
<PlatformsList types={['Android', 'iOS', 'visionOS']} />
|
||||||
|
|
||||||
Type: string\
|
**Type:** string
|
||||||
Default: false
|
**Default:** `undefined`
|
||||||
|
|
||||||
The URL pointing to the licenseServer that will provide the authorization to play the protected stream.
|
The license server URL that authorizes protected content playback.
|
||||||
|
|
||||||
### `multiDrm`
|
### `multiDrm`
|
||||||
<PlatformsList types={['Android']} />
|
|
||||||
Type: boolean\
|
|
||||||
Default: false
|
|
||||||
|
|
||||||
Indicates that drm system shall support key rotation, see: https://developer.android.google.cn/media/media3/exoplayer/drm?hl=en#key-rotation
|
<PlatformsList types={['Android']} />
|
||||||
|
|
||||||
|
**Type:** boolean
|
||||||
|
**Default:** `false`
|
||||||
|
|
||||||
|
Indicates whether the DRM system should support key rotation. See [Android Developer Docs](https://developer.android.google.cn/media/media3/exoplayer/drm?hl=en#key-rotation) for more details.
|
||||||
|
|
||||||
### `type`
|
### `type`
|
||||||
|
|
||||||
<PlatformsList types={['Android', 'iOS']} />
|
<PlatformsList types={['Android', 'iOS']} />
|
||||||
|
|
||||||
Type: DRMType\
|
**Type:** DRMType
|
||||||
Default: undefined
|
**Default:** `undefined`
|
||||||
|
|
||||||
You can specify the DRM type, either by string or using the exported DRMType enum.
|
Defines the DRM type:
|
||||||
Valid values are, for Android: DRMType.WIDEVINE / DRMType.PLAYREADY / DRMType.CLEARKEY.
|
- **Android:** `DRMType.WIDEVINE`, `DRMType.PLAYREADY`, `DRMType.CLEARKEY`
|
||||||
for iOS: DRMType.FAIRPLAY
|
- **iOS:** `DRMType.FAIRPLAY`
|
||||||
|
|
||||||
### `localSourceEncryptionKeyScheme`
|
### `localSourceEncryptionKeyScheme`
|
||||||
|
|
||||||
<PlatformsList types={['iOS', 'visionOS']} />
|
<PlatformsList types={['iOS', 'visionOS']} />
|
||||||
|
|
||||||
Set the url scheme for stream encryption key for local assets
|
**Type:** string
|
||||||
|
|
||||||
Type: String
|
Sets the URL scheme for stream encryption keys used in local assets.
|
||||||
|
|
||||||
Example:
|
#### Example:
|
||||||
|
|
||||||
```
|
```js
|
||||||
localSourceEncryptionKeyScheme="my-offline-key"
|
localSourceEncryptionKeyScheme="my-offline-key"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Common Usage Scenarios
|
## Common Usage Scenarios
|
||||||
|
|
||||||
### Send cookies to license server
|
### Sending Cookies to the License Server
|
||||||
|
|
||||||
You can send Cookies to the license server via `headers` prop. Example:
|
You can send cookies using the `headers` prop.
|
||||||
|
|
||||||
|
#### Example:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
drm: {
|
drm: {
|
||||||
type: DRMType.WIDEVINE
|
type: DRMType.WIDEVINE,
|
||||||
licenseServer: 'https://drm-widevine-licensing.axtest.net/AcquireLicense',
|
licenseServer: 'https://drm-widevine-licensing.axtest.net/AcquireLicense',
|
||||||
headers: {
|
headers: {
|
||||||
'Cookie': 'PHPSESSID=etcetc; csrftoken=mytoken; _gat=1; foo=bar'
|
'Cookie': 'PHPSESSID=your-session-id; csrftoken=mytoken; _gat=1; foo=bar'
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Custom License Acquisition (only iOS for now)
|
### Custom License Acquisition (iOS Only)
|
||||||
|
|
||||||
|
#### Example:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
drm: {
|
drm: {
|
||||||
type: DRMType.FAIRPLAY,
|
type: DRMType.FAIRPLAY,
|
||||||
getLicense: (spcString) => {
|
getLicense: (spcString) => {
|
||||||
const base64spc = Base64.encode(spcString);
|
const base64spc = Base64.encode(spcString);
|
||||||
return fetch('YOUR LICENSE SERVER HERE', {
|
return fetch('YOUR_LICENSE_SERVER_URL', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
@@ -192,15 +192,12 @@ drm: {
|
|||||||
})
|
})
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (response && response.getFairplayLicenseResponse
|
if (response?.getFairplayLicenseResponse?.ckcResponse) {
|
||||||
&& response.getFairplayLicenseResponse.ckcResponse) {
|
|
||||||
return response.getFairplayLicenseResponse.ckcResponse;
|
return response.getFairplayLicenseResponse.ckcResponse;
|
||||||
}
|
}
|
||||||
throw new Error('No correct response');
|
throw new Error('No valid response');
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => console.error('CKC error', error));
|
||||||
console.error('CKC error', error);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import PlatformsList from '../../components/PlatformsList/PlatformsList.tsx';
|
|||||||
|
|
||||||
# Events
|
# Events
|
||||||
|
|
||||||
This page shows the list of available callbacks to handle player notifications
|
This page lists all available callbacks for handling player notifications.
|
||||||
|
|
||||||
## Details
|
## Details
|
||||||
|
|
||||||
@@ -10,233 +10,240 @@ This page shows the list of available callbacks to handle player notifications
|
|||||||
|
|
||||||
<PlatformsList types={['Android', 'iOS']} />
|
<PlatformsList types={['Android', 'iOS']} />
|
||||||
|
|
||||||
Callback function that is called when the audio is about to become 'noisy' due to
|
Triggered when audio output changes (e.g., switching from headphones to speakers). It's recommended to pause the media when this event occurs.
|
||||||
a change in audio outputs. Typically this is called when audio output is being switched
|
|
||||||
from an external source like headphones back to the internal speaker. It's a good
|
|
||||||
idea to pause the media when this happens so the speaker doesn't start blasting sound.
|
|
||||||
|
|
||||||
Payload: none
|
**Payload:** _none_
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### `onAudioFocusChanged`
|
### `onAudioFocusChanged`
|
||||||
|
|
||||||
<PlatformsList types={['Android']} />
|
<PlatformsList types={['Android']} />
|
||||||
|
|
||||||
Callback function that is called when the audio focus changes. This is called when the audio focus is gained or lost. This is useful for determining if the media should be paused or not.
|
Called when audio focus is gained or lost.
|
||||||
|
|
||||||
Payload:
|
**Payload:**
|
||||||
Property | Type | Description
|
| Property | Type | Description |
|
||||||
--- | --- | ---
|
|---------------|--------|----------------------------------------------|
|
||||||
hasAudioFocus | boolean | Boolean indicating whether the media has audio focus
|
| hasAudioFocus | boolean | `true` if media has audio focus, `false` otherwise |
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
|
**Example:**
|
||||||
```javascript
|
```javascript
|
||||||
{
|
{
|
||||||
hasAudioFocus: true;
|
hasAudioFocus: true
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### `onAudioTracks`
|
### `onAudioTracks`
|
||||||
|
|
||||||
<PlatformsList types={['Android', 'iOS']} />
|
<PlatformsList types={['Android', 'iOS']} />
|
||||||
|
|
||||||
Callback function that is called when audio tracks change
|
Triggered when available audio tracks change.
|
||||||
|
|
||||||
Payload:
|
**Payload:** _Array of objects with track details_
|
||||||
|
|
||||||
An **array** of
|
|
||||||
| Property | Type | Description |
|
| Property | Type | Description |
|
||||||
| -------- | ------- | ---------------------------------------------------------------------------------------------------------- |
|
|----------|--------|-----------------------------------------------------------------------------|
|
||||||
| index | number | Internal track ID |
|
| index | number | Internal track ID |
|
||||||
| title | string | Descriptive name for the track |
|
| title | string | Descriptive track name |
|
||||||
| language | string | 2 letter [ISO 639-1 code](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) representing the language |
|
| language | string | [ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) language code |
|
||||||
| bitrate | number | bitrate of track |
|
| bitrate | number | Track bitrate |
|
||||||
| type | string | Mime type of track |
|
| type | string | Track MIME type |
|
||||||
| selected | boolean | true if track is playing |
|
| selected | boolean | `true` if track is currently playing |
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
|
**Example:**
|
||||||
```javascript
|
```javascript
|
||||||
{
|
{
|
||||||
audioTracks: [
|
audioTracks: [
|
||||||
{ language: 'es', title: 'Spanish', type: 'audio/mpeg', index: 0, selected: true },
|
{ language: 'es', title: 'Spanish', type: 'audio/mpeg', index: 0, selected: true },
|
||||||
{ language: 'en', title: 'English', type: 'audio/mpeg', index: 1 }
|
{ language: 'en', title: 'English', type: 'audio/mpeg', index: 1 }
|
||||||
];
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### `onBandwidthUpdate`
|
### `onBandwidthUpdate`
|
||||||
|
|
||||||
<PlatformsList types={['Android', 'iOS']} />
|
<PlatformsList types={['Android', 'iOS']} />
|
||||||
|
|
||||||
Callback function that is called when the available bandwidth changes.
|
Called when available bandwidth changes.
|
||||||
|
|
||||||
Payload:
|
|
||||||
|
|
||||||
|
**Payload:**
|
||||||
| Property | Type | Description |
|
| Property | Type | Description |
|
||||||
| -------- | ------ | ---------------------------------------------- |
|
|----------|--------|-----------------------------------------------|
|
||||||
| bitrate | number | The estimated bitrate in bits/sec |
|
| bitrate | number | Estimated bitrate in bits/sec |
|
||||||
| width | number | The width of the video (android only) |
|
| width | number | Video width (Android only) |
|
||||||
| height | number | The height of the video (android only) |
|
| height | number | Video height (Android only) |
|
||||||
| trackId | string | The track ID of the video track (android only) |
|
| trackId | string | Video track ID (Android only) |
|
||||||
|
|
||||||
Example on iOS:
|
|
||||||
|
|
||||||
|
**Example (iOS):**
|
||||||
```javascript
|
```javascript
|
||||||
{
|
{
|
||||||
bitrate: 1000000;
|
bitrate: 1000000
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Example on Android:
|
**Example (Android):**
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
{
|
{
|
||||||
bitrate: 1000000;
|
bitrate: 1000000,
|
||||||
width: 1920;
|
width: 1920,
|
||||||
height: 1080;
|
height: 1080,
|
||||||
trackId: 'some-track-id';
|
trackId: 'some-track-id'
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Note: On Android, you must set the [reportBandwidth](#reportbandwidth) prop to enable this event. This is due to the high volume of events generated.
|
> **Note:** On Android, set the [`reportBandwidth`](#reportbandwidth) prop to enable this event.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### `onBuffer`
|
### `onBuffer`
|
||||||
|
|
||||||
<PlatformsList types={['Android', 'iOS', 'web']} />
|
<PlatformsList types={['Android', 'iOS', 'web']} />
|
||||||
|
|
||||||
Callback function that is called when the player buffers.
|
Triggered when buffering starts or stops.
|
||||||
|
|
||||||
Payload:
|
|
||||||
|
|
||||||
|
**Payload:**
|
||||||
| Property | Type | Description |
|
| Property | Type | Description |
|
||||||
| ----------- | ------- | ---------------------------------------------- |
|
|------------|--------|---------------------------------|
|
||||||
| isBuffering | boolean | Boolean indicating whether buffering is active |
|
| isBuffering | boolean | `true` if buffering is active |
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
|
**Example:**
|
||||||
```javascript
|
```javascript
|
||||||
{
|
{
|
||||||
isBuffering: true;
|
isBuffering: true
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### `onControlsVisibilityChange`
|
### `onControlsVisibilityChange`
|
||||||
|
|
||||||
<PlatformsList types={['Android']} />
|
<PlatformsList types={['Android']} />
|
||||||
|
|
||||||
Callback function that is called when the controls are hidden or shown. Not possible on iOS.
|
Triggered when the video player controls become visible or hidden.
|
||||||
|
|
||||||
Payload:
|
|
||||||
|
|
||||||
|
**Payload:**
|
||||||
| Property | Type | Description |
|
| Property | Type | Description |
|
||||||
| ----------- | ------- | ---------------------------------------------- |
|
|----------|--------|-------------------------------------|
|
||||||
| isVisible | boolean | Boolean indicating whether controls are visible |
|
| isVisible | boolean | `true` if controls are visible |
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
|
**Example:**
|
||||||
```javascript
|
```javascript
|
||||||
{
|
{
|
||||||
isVisible: true;
|
isVisible: true
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### `onEnd`
|
### `onEnd`
|
||||||
|
|
||||||
<PlatformsList types={['All']} />
|
<PlatformsList types={['All']} />
|
||||||
|
|
||||||
Callback function that is called when the player reaches the end of the media.
|
Triggered when the media reaches the end.
|
||||||
|
|
||||||
Payload: none
|
**Payload:** _none_
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### `onError`
|
### `onError`
|
||||||
|
|
||||||
<PlatformsList types={['All']} />
|
<PlatformsList types={['All']} />
|
||||||
|
|
||||||
Callback function that is called when the player experiences a playback error.
|
Called when a playback error occurs.
|
||||||
|
|
||||||
Payload:
|
|
||||||
|
|
||||||
|
**Payload:**
|
||||||
| Property | Type | Description |
|
| Property | Type | Description |
|
||||||
| -------- | ------ | ------------------------------------------------------------- |
|
|---------|--------|---------------------------|
|
||||||
| error | object | Object containing properties with information about the error |
|
| error | object | Error details |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### `onExternalPlaybackChange`
|
### `onExternalPlaybackChange`
|
||||||
|
|
||||||
<PlatformsList types={['iOS']} />
|
<PlatformsList types={['iOS']} />
|
||||||
|
|
||||||
Callback function that is called when external playback mode for current playing video has changed. Mostly useful when connecting/disconnecting to Apple TV – it's called on connection/disconnection.
|
Called when external playback mode changes (e.g., Apple TV connection/disconnection).
|
||||||
|
|
||||||
Payload:
|
|
||||||
|
|
||||||
|
**Payload:**
|
||||||
| Property | Type | Description |
|
| Property | Type | Description |
|
||||||
| ------------------------ | ------- | ----------------------------------------------------------- |
|
|-------------------------|--------|--------------------------------------------|
|
||||||
| isExternalPlaybackActive | boolean | Boolean indicating whether external playback mode is active |
|
| isExternalPlaybackActive | boolean | `true` if external playback is active |
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
|
**Example:**
|
||||||
```javascript
|
```javascript
|
||||||
{
|
{
|
||||||
isExternalPlaybackActive: true;
|
isExternalPlaybackActive: true
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### `onFullscreenPlayerWillPresent`
|
### `onFullscreenPlayerWillPresent`
|
||||||
|
|
||||||
<PlatformsList types={['Android', 'iOS', 'visionOS']} />
|
<PlatformsList types={['Android', 'iOS', 'visionOS']} />
|
||||||
|
|
||||||
Callback function that is called when the player is about to enter fullscreen mode.
|
Called before entering fullscreen mode.
|
||||||
|
|
||||||
Payload: none
|
**Payload:** _none_
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### `onFullscreenPlayerDidPresent`
|
### `onFullscreenPlayerDidPresent`
|
||||||
|
|
||||||
<PlatformsList types={['Android', 'iOS', 'visionOS']} />
|
<PlatformsList types={['Android', 'iOS', 'visionOS']} />
|
||||||
|
|
||||||
Callback function that is called when the player has entered fullscreen mode.
|
Called when fullscreen mode is active.
|
||||||
|
|
||||||
Payload: none
|
**Payload:** _none_
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### `onFullscreenPlayerWillDismiss`
|
### `onFullscreenPlayerWillDismiss`
|
||||||
|
|
||||||
<PlatformsList types={['Android', 'iOS', 'visionOS']} />
|
<PlatformsList types={['Android', 'iOS', 'visionOS']} />
|
||||||
|
|
||||||
Callback function that is called when the player is about to exit fullscreen mode.
|
Called before exiting fullscreen mode.
|
||||||
|
|
||||||
Payload: none
|
**Payload:** _none_
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### `onFullscreenPlayerDidDismiss`
|
### `onFullscreenPlayerDidDismiss`
|
||||||
|
|
||||||
<PlatformsList types={['Android', 'iOS', 'visionOS']} />
|
<PlatformsList types={['Android', 'iOS', 'visionOS']} />
|
||||||
|
|
||||||
Callback function that is called when the player has exited fullscreen mode.
|
Called when fullscreen mode is exited.
|
||||||
|
|
||||||
Payload: none
|
**Payload:** _none_
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### `onLoad`
|
### `onLoad`
|
||||||
|
|
||||||
<PlatformsList types={['All']} />
|
<PlatformsList types={['All']} />
|
||||||
|
|
||||||
Callback function that is called when the media is loaded and ready to play.
|
Triggered when the media is loaded and ready to play.
|
||||||
|
|
||||||
|
### Payload:
|
||||||
NOTE: tracks (`audioTracks`, `textTracks` & `videoTracks`) are not available on the web.
|
|
||||||
|
|
||||||
Payload:
|
|
||||||
|
|
||||||
| Property | Type | Description |
|
| Property | Type | Description |
|
||||||
|-------------|--------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|-------------|--------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| currentTime | number | Time in seconds where the media will start |
|
| currentTime | number | Time in seconds where the media will start |
|
||||||
| duration | number | Length of the media in seconds |
|
| duration | number | Length of the media in seconds |
|
||||||
| naturalSize | object | Properties:<br/> _ width - Width in pixels that the video was encoded at<br/> _ height - Height in pixels that the video was encoded at<br/> \* orientation - "portrait", "landscape" or "square" |
|
| naturalSize | object | Properties:<br/>   width - Width in pixels that the video was encoded at<br/>   height - Height in pixels that the video was encoded at<br/>   orientation - "portrait", "landscape" or "square" |
|
||||||
| audioTracks | array | An array of audio track info objects with the following properties:<br/> _ index - Index number<br/> _ title - Description of the track<br/> _ language - 2 letter [ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) or 3 letter [ISO639-2](https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes) language code<br/> _ type - Mime type of track |
|
| audioTracks | array | An array of audio track info objects with the following properties:<br/>   index - Index number<br/>   title - Description of the track<br/>   language - 2 letter [ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) or 3 letter [ISO639-2](https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes) language code<br/>   type - Mime type of track |
|
||||||
| textTracks | array | An array of text track info objects with the following properties:<br/> _ index - Index number<br/> _ title - Description of the track<br/> _ language - 2 letter [ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) or 3 letter [ISO 639-2](https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes) language code<br/> _ type - Mime type of track |
|
| textTracks | array | An array of text track info objects with the following properties:<br/>   index - Index number<br/>   title - Description of the track<br/>   language - 2 letter [ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) or 3 letter [ISO 639-2](https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes) language code<br/>   type - Mime type of track |
|
||||||
| videoTracks | array | An array of video track info objects with the following properties:<br/> _ trackId - ID for the track<br/> _ bitrate - Bit rate in bits per second<br/> _ codecs - Comma separated list of codecs<br/> _ height - Height of the video<br/> \* width - Width of the video |
|
| videoTracks | array | An array of video track info objects with the following properties:<br/>   trackId - ID for the track<br/>   bitrate - Bit rate in bits per second<br/>   codecs - Comma separated list of codecs<br/>   height - Height of the video<br/>   width - Width of the video |
|
||||||
| trackId | string | Provide key information about the video track, typically including: `Resolution`, `Bitrate`. |
|
| trackId | string | Provide key information about the video track, typically including: `Resolution`, `Bitrate`. |
|
||||||
|
|
||||||
Example:
|
**Example:**
|
||||||
|
|
||||||
```javascript
|
```js
|
||||||
{
|
{
|
||||||
canPlaySlowForward: true,
|
canPlaySlowForward: true,
|
||||||
canPlayReverse: false,
|
canPlayReverse: false,
|
||||||
@@ -265,49 +272,51 @@ Example:
|
|||||||
{ index: 1, bitrate: 7981888, codecs: "avc1.640028", height: 1080, trackId: "f2-v1-x3", width: 1920 },
|
{ index: 1, bitrate: 7981888, codecs: "avc1.640028", height: 1080, trackId: "f2-v1-x3", width: 1920 },
|
||||||
{ index: 2, bitrate: 1994979, codecs: "avc1.4d401f", height: 480, trackId: "f3-v1-x3", width: 848 }
|
{ index: 2, bitrate: 1994979, codecs: "avc1.4d401f", height: 480, trackId: "f3-v1-x3", width: 848 }
|
||||||
],
|
],
|
||||||
trackId: "720p 2400kbps"
|
trackId: "720p 2400kbps",
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> **Note:** `audioTracks`, `textTracks`, and `videoTracks` are not available on the web.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### `onLoadStart`
|
### `onLoadStart`
|
||||||
|
|
||||||
<PlatformsList types={['All']} />
|
<PlatformsList types={['All']} />
|
||||||
|
|
||||||
Callback function that is called when the media starts loading.
|
Triggered when media starts loading.
|
||||||
|
|
||||||
Payload:
|
|
||||||
|
|
||||||
|
**Payload:**
|
||||||
| Property | Type | Description |
|
| Property | Type | Description |
|
||||||
| --------- | ----------- | ---------------------------------------------------------------- |
|
|----------|--------|-------------------------------------|
|
||||||
| isNetwork | boolean | Boolean indicating if the media is being loaded from the network |
|
| isNetwork | boolean | `true` if media is loaded from a network |
|
||||||
| type | string | Type of the media. Not available on Windows |
|
| type | string | Media type (not available on Windows) |
|
||||||
| uri | string | URI for the media source. Not available on Windows |
|
| uri | string | Media source URI (not available on Windows) |
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
|
**Example:**
|
||||||
```javascript
|
```javascript
|
||||||
{
|
{
|
||||||
isNetwork: true,
|
isNetwork: true,
|
||||||
type: '',
|
type: '',
|
||||||
uri: 'https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u8'
|
uri: 'https://example.com/video.mp4'
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### `onPlaybackStateChanged`
|
### `onPlaybackStateChanged`
|
||||||
|
|
||||||
<PlatformsList types={['Android', 'iOS', 'visionOS', 'web']} />
|
<PlatformsList types={['Android', 'iOS', 'visionOS', 'web']} />
|
||||||
|
|
||||||
Callback function that is called when the playback state changes.
|
Triggered when playback state changes.
|
||||||
|
|
||||||
Payload:
|
|
||||||
|
|
||||||
|
**Payload:**
|
||||||
| Property | Type | Description |
|
| Property | Type | Description |
|
||||||
| --------- | ----------- | -------------------------------------------------- |
|
|----------|--------|-------------------------------------|
|
||||||
| isPlaying | boolean | Boolean indicating if the media is playing or not |
|
| isPlaying | boolean | `true` if media is playing |
|
||||||
| isSeeking | boolean | Boolean indicating if the player is seeking or not |
|
| isSeeking | boolean | `true` if seeking is in progress |
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
|
**Example:**
|
||||||
```javascript
|
```javascript
|
||||||
{
|
{
|
||||||
isPlaying: true,
|
isPlaying: true,
|
||||||
@@ -315,56 +324,62 @@ Example:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### `onPictureInPictureStatusChanged`
|
### `onPictureInPictureStatusChanged`
|
||||||
|
|
||||||
<PlatformsList types={['iOS', 'Android', 'web']} />
|
<PlatformsList types={['iOS', 'Android', 'web']} />
|
||||||
|
|
||||||
Callback function that is called when picture in picture becomes active or inactive.
|
Triggered when Picture-in-Picture (PiP) mode is activated or deactivated.
|
||||||
|
|
||||||
|
**Payload:**
|
||||||
| Property | Type | Description |
|
| Property | Type | Description |
|
||||||
| -------- | ------- | ------------------------------------------------------- |
|
|----------|--------|----------------------------------|
|
||||||
| isActive | boolean | Boolean indicating whether picture in picture is active |
|
| isActive | boolean | `true` if PiP mode is active |
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
|
**Example:**
|
||||||
```javascript
|
```javascript
|
||||||
{
|
{
|
||||||
isActive: true;
|
isActive: true
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### `onPlaybackRateChange`
|
### `onPlaybackRateChange`
|
||||||
|
|
||||||
<PlatformsList types={['All']} />
|
<PlatformsList types={['All']} />
|
||||||
|
|
||||||
Callback function that is called when the rate of playback changes - either paused or starts/resumes.
|
Triggered when playback speed changes.
|
||||||
|
|
||||||
|
**Payload:**
|
||||||
| Property | Type | Description |
|
| Property | Type | Description |
|
||||||
| ------------ | ------ | --------------------------------------------------------------------------------------------------------------- |
|
|-------------|--------|---------------------------------|
|
||||||
| playbackRate | number | 0 when playback is paused, 1 when playing at normal speed. Other values when playback is slowed down or sped up |
|
| playbackRate | number | `0` (paused), `1` (normal speed), other values indicate speed changes |
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
|
**Example:**
|
||||||
```javascript
|
```javascript
|
||||||
{
|
{
|
||||||
playbackRate: 0, // indicates paused
|
playbackRate: 0 // indicates paused
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### `onProgress`
|
### `onProgress`
|
||||||
|
|
||||||
<PlatformsList types={['All']} />
|
<PlatformsList types={['All']} />
|
||||||
|
|
||||||
Callback function that is called every progressUpdateInterval milliseconds with info about which position the media is currently playing.
|
Triggered every `progressUpdateInterval` milliseconds, providing information about the current playback position.
|
||||||
|
|
||||||
|
**Payload:**
|
||||||
| Property | Type | Description |
|
| Property | Type | Description |
|
||||||
| ---------------- | ------ | ------------------------------------------------------------------------------------------------- |
|
|----------------|--------|-------------------------------------------------------------------------|
|
||||||
| currentTime | number | Current position in seconds |
|
| currentTime | number | Current playback position (seconds) |
|
||||||
| playableDuration | number | Position to where the media can be played to using just the buffer in seconds |
|
| playableDuration | number | Duration that can be played using only the buffer (seconds) |
|
||||||
| seekableDuration | number | Position to where the media can be seeked to in seconds. Typically, the total length of the media |
|
| seekableDuration | number | Duration that can be seeked to (usually the total length of the media) |
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
|
**Example:**
|
||||||
```javascript
|
```javascript
|
||||||
{
|
{
|
||||||
currentTime: 5.2,
|
currentTime: 5.2,
|
||||||
@@ -373,27 +388,31 @@ Example:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### `onReadyForDisplay`
|
### `onReadyForDisplay`
|
||||||
|
|
||||||
<PlatformsList types={['Android', 'iOS', 'Web']} />
|
<PlatformsList types={['Android', 'iOS', 'Web']} />
|
||||||
|
|
||||||
Callback function that is called when the first video frame is ready for display. This is when the poster is removed.
|
Triggered when the first video frame is ready to be displayed. This is when the poster is removed.
|
||||||
|
|
||||||
Payload: none
|
**Payload:** _none_
|
||||||
|
|
||||||
- iOS: [readyForDisplay](https://developer.apple.com/documentation/avkit/avplayerviewcontroller/1615830-readyfordisplay?language=objc)
|
- iOS: [`readyForDisplay`](https://developer.apple.com/documentation/avkit/avplayerviewcontroller/1615830-readyfordisplay?language=objc)
|
||||||
- Android [STATE_READY](https://exoplayer.dev/doc/reference/com/google/android/exoplayer2/Player.html#STATE_READY)
|
- Android: [`STATE_READY`](https://exoplayer.dev/doc/reference/com/google/android/exoplayer2/Player.html#STATE_READY)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### `onReceiveAdEvent`
|
### `onReceiveAdEvent`
|
||||||
|
|
||||||
<PlatformsList types={['Android', 'iOS']} />
|
<PlatformsList types={['Android', 'iOS']} />
|
||||||
|
|
||||||
Callback function that is called when an AdEvent is received from the IMA's SDK.
|
Triggered when an AdEvent is received from the IMA SDK.
|
||||||
|
|
||||||
Enum `AdEvent` possible values for [Android](https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/reference/js/google.ima.AdEvent) and [iOS](https://developers.google.com/interactive-media-ads/docs/sdks/ios/client-side/reference/Enums/IMAAdEventType):
|
Enum `AdEvent` possible values for [Android](https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/reference/js/google.ima.AdEvent) and [iOS](https://developers.google.com/interactive-media-ads/docs/sdks/ios/client-side/reference/Enums/IMAAdEventType):
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>Events</summary>
|
<summary>AdEvent</summary>
|
||||||
|
|
||||||
| Event | Platform | Description |
|
| Event | Platform | Description |
|
||||||
| -------------------------- | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| -------------------------- | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
@@ -438,15 +457,13 @@ Enum `AdEvent` possible values for [Android](https://developers.google.com/inter
|
|||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
Payload:
|
**Payload:**
|
||||||
|
|
||||||
| Property | Type | Description |
|
| Property | Type | Description |
|
||||||
| -------- | ----------------------------------------- | --------------------- |
|
|----------|-----------------------------------------|---------------------|
|
||||||
| event | AdEvent | The ad event received |
|
| event | AdEvent | The ad event received |
|
||||||
| data | Record<string, string> \| undefined | The ad event data |
|
| data | Record<string, string> \| undefined | Additional ad event data |
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
|
**Example:**
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"data": {
|
"data": {
|
||||||
@@ -456,173 +473,172 @@ Example:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### `onRestoreUserInterfaceForPictureInPictureStop`
|
### `onRestoreUserInterfaceForPictureInPictureStop`
|
||||||
|
|
||||||
<PlatformsList types={['iOS', 'visionOS']} />
|
<PlatformsList types={['iOS', 'visionOS']} />
|
||||||
|
|
||||||
Callback function that corresponds to Apple's [`restoreUserInterfaceForPictureInPictureStopWithCompletionHandler`](https://developer.apple.com/documentation/avkit/avpictureinpicturecontrollerdelegate/1614703-pictureinpicturecontroller?language=objc). Call `restoreUserInterfaceForPictureInPictureStopCompleted` inside of this function when done restoring the user interface.
|
Corresponds to Apple's [`restoreUserInterfaceForPictureInPictureStopWithCompletionHandler`](https://developer.apple.com/documentation/avkit/avpictureinpicturecontrollerdelegate/1614703-pictureinpicturecontroller?language=objc).
|
||||||
|
Call `restoreUserInterfaceForPictureInPictureStopCompleted` inside this function when the UI is restored.
|
||||||
|
|
||||||
Payload: none
|
**Payload:** _none_
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### `onSeek`
|
### `onSeek`
|
||||||
|
|
||||||
<PlatformsList types={['Android', 'iOS', 'Windows UWP', 'web']} />
|
<PlatformsList types={['Android', 'iOS', 'Windows UWP', 'web']} />
|
||||||
|
|
||||||
Callback function that is called when a seek completes.
|
Triggered when a seek operation completes.
|
||||||
|
|
||||||
Payload:
|
|
||||||
|
|
||||||
|
**Payload:**
|
||||||
| Property | Type | Description |
|
| Property | Type | Description |
|
||||||
| ----------- | ------ | ------------------------------- |
|
|------------|--------|---------------------------------|
|
||||||
| currentTime | number | The current time after the seek |
|
| currentTime | number | Current time after seeking |
|
||||||
| seekTime | number | The requested time |
|
| seekTime | number | Requested seek time |
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
|
**Example:**
|
||||||
```javascript
|
```javascript
|
||||||
{
|
{
|
||||||
currentTime: 100.5;
|
currentTime: 100.5,
|
||||||
seekTime: 100;
|
seekTime: 100
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Both the currentTime & seekTime are reported because the video player may not seek to the exact requested position in order to improve seek performance.
|
> **Note:** On iOS, this callback is not reported when native controls are enabled.
|
||||||
|
|
||||||
Note: on iOS, when controls are enable, this callback is not reported. This is a known limitation.
|
---
|
||||||
|
|
||||||
### `onTimedMetadata`
|
### `onTimedMetadata`
|
||||||
|
|
||||||
<PlatformsList types={['Android', 'iOS', 'visionOS']} />
|
<PlatformsList types={['Android', 'iOS', 'visionOS']} />
|
||||||
|
|
||||||
Callback function that is called when timed metadata becomes available
|
Triggered when timed metadata is available.
|
||||||
|
|
||||||
Payload:
|
|
||||||
|
|
||||||
|
**Payload:**
|
||||||
| Property | Type | Description |
|
| Property | Type | Description |
|
||||||
| -------- | ----- | ------------------------- |
|
|----------|------|--------------------------|
|
||||||
| metadata | array | Array of metadata objects |
|
| metadata | array | Array of metadata objects |
|
||||||
|
|
||||||
Example:
|
**Example:**
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
{
|
{
|
||||||
metadata: [
|
metadata: [
|
||||||
{ value: 'Streaming Encoder', identifier: 'TRSN' },
|
{ value: 'Streaming Encoder', identifier: 'TRSN' },
|
||||||
{ value: 'Internet Stream', identifier: 'TRSO' },
|
{ value: 'Internet Stream', identifier: 'TRSO' },
|
||||||
{value: 'Any Time You Like', identifier: 'TIT2'},
|
{ value: 'Any Time You Like', identifier: 'TIT2' }
|
||||||
];
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### `onTextTrackDataChanged`
|
### `onTextTrackDataChanged`
|
||||||
|
|
||||||
<PlatformsList types={['Android', 'iOS']} />
|
<PlatformsList types={['Android', 'iOS']} />
|
||||||
|
|
||||||
Callback function that is called when new subtitle data is available. It provides the actual subtitle content for the current selected text track, if available (mainly WebVTT).
|
Triggered when new subtitle data becomes available.
|
||||||
|
|
||||||
Payload:
|
|
||||||
|
|
||||||
|
**Payload:**
|
||||||
| Property | Type | Description |
|
| Property | Type | Description |
|
||||||
|----------------|--------|--------------------------------------------------|
|
|----------------|--------|--------------------------------------------------|
|
||||||
| `subtitleTracks` | `string` | The subtitles text content in a compatible format. |
|
| subtitleTracks | string | The subtitle text content in a compatible format |
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
|
**Example:**
|
||||||
```javascript
|
```javascript
|
||||||
{
|
{
|
||||||
subtitleTracks: "This blade has a dark past.",
|
subtitleTracks: "This blade has a dark past."
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
For details on how to control the visibility of subtitles, see the [subtitleStyle](./props.mdx#subtitleStyle) section.
|
---
|
||||||
|
|
||||||
### `onTextTracks`
|
### `onTextTracks`
|
||||||
|
|
||||||
<PlatformsList types={['Android', 'iOS']} />
|
<PlatformsList types={['Android', 'iOS']} />
|
||||||
|
|
||||||
Callback function that is called when text tracks change
|
Triggered when available text (subtitle) tracks change.
|
||||||
|
|
||||||
Payload:
|
|
||||||
|
|
||||||
|
**Payload:**
|
||||||
| Property | Type | Description |
|
| Property | Type | Description |
|
||||||
| -------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|----------|--------|--------------------------------------------------------------------------------------------------------------|
|
||||||
| index | number | Internal track ID |
|
| index | number | Internal track ID |
|
||||||
| title | string | Descriptive name for the track |
|
| title | string | Track name |
|
||||||
| language | string | 2 letter [ISO 639-1 code](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) representing the language |
|
| language | string | 2 letter [ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) language code |
|
||||||
| type | string | Mime type of the track<br/> _ TextTrackType.SRT - SubRip (.srt)<br/> _ TextTrackType.TTML - TTML (.ttml)<br/> \* TextTrackType.VTT - WebVTT (.vtt)<br/>iOS only supports VTT, Android supports all 3 |
|
| type | string | Track MIME type (_VTT_, _SRT_, _TTML_) |
|
||||||
| selected | boolean | true if track is playing |
|
| selected | boolean | `true` if the track is currently playing |
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
|
**Example:**
|
||||||
```javascript
|
```javascript
|
||||||
{
|
{
|
||||||
textTracks: [
|
textTracks: [
|
||||||
{
|
{
|
||||||
index: 0,
|
index: 0,
|
||||||
title: 'Any Time You Like',
|
title: 'English Subtitles',
|
||||||
type: 'srt',
|
type: 'vtt',
|
||||||
selected: true,
|
selected: true
|
||||||
},
|
}
|
||||||
];
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### `onVideoTracks`
|
### `onVideoTracks`
|
||||||
|
|
||||||
<PlatformsList types={['Android']} />
|
<PlatformsList types={['Android']} />
|
||||||
|
|
||||||
Callback function that is called when video tracks change
|
Triggered when video tracks change.
|
||||||
|
|
||||||
Payload:
|
|
||||||
|
|
||||||
|
**Payload:**
|
||||||
| Property | Type | Description |
|
| Property | Type | Description |
|
||||||
| -------- | ------- | --------------------------------------------------------------- |
|
|----------|---------|-----------------------------------|
|
||||||
| index | number | index of the track |
|
| index | number | Track index |
|
||||||
| trackId | string | Internal track ID |
|
| trackId | string | Internal track ID |
|
||||||
| codecs | string | MimeType of codec used for this track |
|
| codecs | string | Codec type |
|
||||||
| width | number | Track width |
|
| width | number | Video width |
|
||||||
| height | number | Track height |
|
| height | number | Video height |
|
||||||
| bitrate | number | Bitrate in bps |
|
| bitrate | number | Track bitrate (bps) |
|
||||||
| selected | boolean | true if track is selected for playing |
|
| selected | boolean | `true` if the track is playing |
|
||||||
| rotation | number | 0, 90, 180 or 270 rotation to apply to the track (android only) |
|
| rotation | number | Rotation angle (0, 90, 180, 270) |
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
|
**Example:**
|
||||||
```javascript
|
```javascript
|
||||||
{
|
{
|
||||||
videoTracks: [
|
videoTracks: [
|
||||||
{
|
{
|
||||||
index: O,
|
index: 0,
|
||||||
trackId: "0",
|
trackId: "1",
|
||||||
codecs: 'video/mp4',
|
codecs: "video/mp4",
|
||||||
width: 1920,
|
width: 1920,
|
||||||
height: 1080,
|
height: 1080,
|
||||||
bitrate: 10000,
|
bitrate: 5000000,
|
||||||
selected: true,
|
selected: true,
|
||||||
rotation: 0,
|
rotation: 0
|
||||||
},
|
}
|
||||||
];
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### `onVolumeChange`
|
### `onVolumeChange`
|
||||||
|
|
||||||
<PlatformsList types={['Android', 'iOS', 'visionOS', 'web']} />
|
<PlatformsList types={['Android', 'iOS', 'visionOS', 'web']} />
|
||||||
|
|
||||||
Callback function that is called when the volume of player changes.
|
Triggered when the player volume changes.
|
||||||
|
|
||||||
> Note: This event applies to the volume of the player, not the volume of the device.
|
> **Note:** This event applies to the player's volume, not the device's system volume.
|
||||||
|
|
||||||
Payload:
|
|
||||||
|
|
||||||
|
**Payload:**
|
||||||
| Property | Type | Description |
|
| Property | Type | Description |
|
||||||
| -------- | ------ | ------------------------------------------ |
|
|----------|--------|---------------------------------|
|
||||||
| volume | number | The volume of the player (between 0 and 1) |
|
| volume | number | Volume level (0 to 1) |
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
|
**Example:**
|
||||||
```javascript
|
```javascript
|
||||||
{
|
{
|
||||||
volume: 0.5;
|
volume: 0.5
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -2,223 +2,262 @@ import PlatformsList from '../../components/PlatformsList/PlatformsList.tsx';
|
|||||||
|
|
||||||
# Methods
|
# Methods
|
||||||
|
|
||||||
This page shows the list of available methods
|
This page shows the list of available methods.
|
||||||
|
|
||||||
|
## Details
|
||||||
|
|
||||||
### `dismissFullscreenPlayer`
|
### `dismissFullscreenPlayer`
|
||||||
|
|
||||||
<PlatformsList types={['Android', 'iOS', 'web']} />
|
<PlatformsList types={['Android', 'iOS', 'web']} />
|
||||||
|
|
||||||
`dismissFullscreenPlayer(): Promise<void>`
|
```tsx
|
||||||
|
dismissFullscreenPlayer(): Promise<void>
|
||||||
|
```
|
||||||
|
|
||||||
Take the player out of fullscreen mode.
|
Exits fullscreen mode.
|
||||||
|
|
||||||
> [!WARNING]
|
> **Deprecated:** Use `setFullScreen(false)` instead.
|
||||||
> deprecated, use setFullScreen method instead
|
|
||||||
|
---
|
||||||
|
|
||||||
### `pause`
|
### `pause`
|
||||||
|
|
||||||
<PlatformsList types={['Android', 'iOS', 'web']} />
|
<PlatformsList types={['Android', 'iOS', 'web']} />
|
||||||
|
|
||||||
`pause(): Promise<void>`
|
```tsx
|
||||||
|
pause(): Promise<void>
|
||||||
|
```
|
||||||
|
|
||||||
Pause the video.
|
Pauses the video.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### `presentFullscreenPlayer`
|
### `presentFullscreenPlayer`
|
||||||
|
|
||||||
<PlatformsList types={['Android', 'iOS', 'web']} />
|
<PlatformsList types={['Android', 'iOS', 'web']} />
|
||||||
|
|
||||||
`presentFullscreenPlayer(): Promise<void>`
|
```tsx
|
||||||
|
presentFullscreenPlayer(): Promise<void>
|
||||||
|
```
|
||||||
|
|
||||||
Put the player in fullscreen mode.
|
Enters fullscreen mode.
|
||||||
|
|
||||||
On iOS, this displays the video in a fullscreen view controller with controls.
|
- On **iOS**, this opens a fullscreen view controller with controls.
|
||||||
|
- On **Android**, this makes the player fullscreen but requires styling to match screen dimensions.
|
||||||
|
|
||||||
On Android, this puts the navigation controls in fullscreen mode. It is not a complete fullscreen implementation, so you will still need to apply a style that makes the width and height match your screen dimensions to get a fullscreen video.
|
> **Deprecated:** Use `setFullScreen(true)` instead.
|
||||||
|
|
||||||
> [!WARNING]
|
---
|
||||||
> deprecated, use setFullScreen method instead
|
|
||||||
|
|
||||||
### `resume`
|
### `resume`
|
||||||
|
|
||||||
<PlatformsList types={['Android', 'iOS', 'web']} />
|
<PlatformsList types={['Android', 'iOS', 'web']} />
|
||||||
|
|
||||||
`resume(): Promise<void>`
|
```tsx
|
||||||
|
resume(): Promise<void>
|
||||||
|
```
|
||||||
|
|
||||||
Resume the video.
|
Resumes video playback.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### `restoreUserInterfaceForPictureInPictureStopCompleted`
|
### `restoreUserInterfaceForPictureInPictureStopCompleted`
|
||||||
|
|
||||||
<PlatformsList types={['iOS']} />
|
<PlatformsList types={['iOS']} />
|
||||||
|
|
||||||
`restoreUserInterfaceForPictureInPictureStopCompleted(restored)`
|
```tsx
|
||||||
|
restoreUserInterfaceForPictureInPictureStopCompleted(restored)
|
||||||
|
```
|
||||||
|
|
||||||
This function corresponds to the completion handler in Apple's [restoreUserInterfaceForPictureInPictureStop](https://developer.apple.com/documentation/avkit/avpictureinpicturecontrollerdelegate/1614703-pictureinpicturecontroller?language=objc). IMPORTANT: This function must be called after `onRestoreUserInterfaceForPictureInPictureStop` is called.
|
Must be called after `onRestoreUserInterfaceForPictureInPictureStop`.
|
||||||
|
Corresponds to Apple's [`restoreUserInterfaceForPictureInPictureStop`](https://developer.apple.com/documentation/avkit/avpictureinpicturecontrollerdelegate/1614703-pictureinpicturecontroller?language=objc).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### `save`
|
### `save`
|
||||||
|
|
||||||
<PlatformsList types={['iOS']} />
|
<PlatformsList types={['iOS']} />
|
||||||
|
|
||||||
`save(): Promise<{ uri: string }>`
|
```tsx
|
||||||
|
save(): Promise<{ uri: string }>
|
||||||
|
```
|
||||||
|
|
||||||
Save video to your Photos with current filter prop. Returns promise.
|
Saves the video to the user's **Photos app** with the current filter.
|
||||||
|
|
||||||
Notes:
|
#### Notes:
|
||||||
|
- Supports **MP4** export only.
|
||||||
|
- Exports to the **cache directory** with a generated UUID filename.
|
||||||
|
- Requires **internet connection** if the video is not already buffered.
|
||||||
|
- Video remains in the **Photos app** until manually deleted.
|
||||||
|
- Works with **cached videos**.
|
||||||
|
|
||||||
- Currently only supports highest quality export
|
#### Future improvements:
|
||||||
- Currently only supports MP4 export
|
- Support for **multiple quality options**.
|
||||||
- Currently only supports exporting to user's cache directory with a generated UUID filename.
|
- Support for **more formats**.
|
||||||
- User will need to remove the saved video through their Photos app
|
- Support for **custom directory and filename**.
|
||||||
- Works with cached videos as well. (Checkout video-caching example)
|
|
||||||
- If the video is has not began buffering (e.g. there is no internet connection) then the save function will throw an error.
|
|
||||||
- If the video is buffering then the save function promise will return after the video has finished buffering and processing.
|
|
||||||
|
|
||||||
Future:
|
---
|
||||||
|
|
||||||
- Will support multiple qualities through options
|
|
||||||
- Will support more formats in the future through options
|
|
||||||
- Will support custom directory and file name through options
|
|
||||||
|
|
||||||
### `enterPictureInPicture`
|
### `enterPictureInPicture`
|
||||||
|
|
||||||
<PlatformsList types={['Android', 'iOS', 'web']} />
|
<PlatformsList types={['Android', 'iOS', 'web']} />
|
||||||
|
|
||||||
`enterPictureInPicture()`
|
```tsx
|
||||||
|
enterPictureInPicture()
|
||||||
|
```
|
||||||
|
|
||||||
To use this feature on Android with Expo, you must set 'enableAndroidPictureInPicture' true within expo plugin config (app.json)
|
Activates Picture-in-Picture (PiP) mode.
|
||||||
|
|
||||||
|
#### Android setup:
|
||||||
|
For **Expo**, enable PiP in `app.json`:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
"plugins": [
|
"plugins": [
|
||||||
[
|
[
|
||||||
"react-native-video",
|
"react-native-video",
|
||||||
{
|
{
|
||||||
"enableAndroidPictureInPicture": true,
|
"enableAndroidPictureInPicture": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
To use this feature on Android with Bare React Native, you must:
|
For **Bare React Native**, update `AndroidManifest.xml`:
|
||||||
|
|
||||||
- [Declare PiP support](https://developer.android.com/develop/ui/views/picture-in-picture#declaring) in your AndroidManifest.xml
|
|
||||||
- setting `android:supportsPictureInPicture` to `true`
|
|
||||||
|
|
||||||
```xml
|
```xml
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
...
|
|
||||||
android:supportsPictureInPicture="true">
|
android:supportsPictureInPicture="true">
|
||||||
|
</activity>
|
||||||
```
|
```
|
||||||
|
|
||||||
NOTE: Foreground picture in picture is not supported on Android due to limitations of react native (Single Activity App). So, If you call `enterPictureInPicture`, application will switch to background on Android.
|
> **Note:**
|
||||||
NOTE: Video ads cannot start when you are using the PIP on iOS (more info available at [Google IMA SDK Docs](https://developers.google.com/interactive-media-ads/docs/sdks/ios/client-side/picture_in_picture?hl=en#starting_ads)). If you are using custom controls, you must hide your PIP button when you receive the `STARTED` event from `onReceiveAdEvent` and show it again when you receive the `ALL_ADS_COMPLETED` event.
|
> - On **Android**, entering PiP moves the app to the **background**.
|
||||||
|
> - On **iOS**, **video ads cannot start** in PiP mode ([Google IMA SDK](https://developers.google.com/interactive-media-ads/docs/sdks/ios/client-side/picture_in_picture?hl=en#starting_ads)).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### `exitPictureInPicture`
|
### `exitPictureInPicture`
|
||||||
|
|
||||||
<PlatformsList types={['Android', 'iOS', 'web']} />
|
<PlatformsList types={['Android', 'iOS', 'web']} />
|
||||||
|
|
||||||
`exitPictureInPicture()`
|
```tsx
|
||||||
|
exitPictureInPicture()
|
||||||
|
```
|
||||||
|
|
||||||
Exits the active picture in picture; if it is not active, the function call is ignored.
|
Exits Picture-in-Picture (PiP) mode.
|
||||||
|
|
||||||
### `restoreUserInterfaceForPictureInPictureStopCompleted`
|
---
|
||||||
|
|
||||||
<PlatformsList types={['iOS']} />
|
|
||||||
|
|
||||||
`restoreUserInterfaceForPictureInPictureStopCompleted(restored)`
|
|
||||||
|
|
||||||
This function corresponds to the completion handler in Apple's [restoreUserInterfaceForPictureInPictureStop](https://developer.apple.com/documentation/avkit/avpictureinpicturecontrollerdelegate/1614703-pictureinpicturecontroller?language=objc). IMPORTANT: This function must be called after `onRestoreUserInterfaceForPictureInPictureStop` is called.
|
|
||||||
|
|
||||||
### `seek`
|
### `seek`
|
||||||
|
|
||||||
<PlatformsList types={['All']} />
|
<PlatformsList types={['All']} />
|
||||||
|
|
||||||
`seek(seconds)`
|
```tsx
|
||||||
|
seek(seconds: number)
|
||||||
|
```
|
||||||
|
|
||||||
Seek to the specified position represented by seconds. seconds is a float value.
|
Seeks to the specified position (**in seconds**).
|
||||||
|
|
||||||
`seek()` can only be called after the `onLoad` event has fired. Once completed, the [onSeek](./events#onseek) event will be called.
|
#### Notes:
|
||||||
|
- **Must be called after** `onLoad`.
|
||||||
|
- Triggers the [`onSeek`](./events#onseek) event.
|
||||||
|
|
||||||
#### Exact seek
|
#### **iOS Exact Seek:**
|
||||||
|
```tsx
|
||||||
|
seek(seconds, tolerance: number)
|
||||||
|
```
|
||||||
|
- Default **tolerance**: ±100ms.
|
||||||
|
- Set `tolerance = 0` for **precise seeking**.
|
||||||
|
|
||||||
<PlatformsList types={['iOS']} />
|
---
|
||||||
|
|
||||||
By default iOS seeks within 100 milliseconds of the target position. If you need more accuracy, you can use the seek with tolerance method:
|
|
||||||
|
|
||||||
`seek(seconds, tolerance)`
|
|
||||||
|
|
||||||
tolerance is the max distance in milliseconds from the seconds position that's allowed. Using a more exact tolerance can cause seeks to take longer. If you want to seek exactly, set tolerance to 0.
|
|
||||||
|
|
||||||
### `setVolume`
|
### `setVolume`
|
||||||
|
|
||||||
<PlatformsList types={['Android', 'iOS', 'web']} />
|
<PlatformsList types={['Android', 'iOS', 'web']} />
|
||||||
|
|
||||||
`setVolume(value): Promise<void>`
|
```tsx
|
||||||
|
setVolume(value: number): Promise<void>
|
||||||
|
```
|
||||||
|
|
||||||
This function will change the volume exactly like [volume](./props#volume) property. default value and range are the same then.
|
Changes the **volume** level. Same behavior as the [`volume`](./props#volume) prop.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### `getCurrentPosition`
|
### `getCurrentPosition`
|
||||||
|
|
||||||
<PlatformsList types={['Android', 'iOS', 'web']} />
|
<PlatformsList types={['Android', 'iOS', 'web']} />
|
||||||
|
|
||||||
`getCurrentPosition(): Promise<number>`
|
```tsx
|
||||||
|
getCurrentPosition(): Promise<number>
|
||||||
|
```
|
||||||
|
|
||||||
This function retrieves and returns the precise current position of the video playback, measured in seconds.
|
Returns the **current playback position** in seconds.
|
||||||
This function will throw an error if player is not initialized.
|
|
||||||
|
|
||||||
|
> **Throws an error** if the player is not initialized.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### `setSource`
|
### `setSource`
|
||||||
|
|
||||||
<PlatformsList types={['Android', 'iOS']} />
|
<PlatformsList types={['Android', 'iOS']} />
|
||||||
|
|
||||||
`setSource(source: ReactVideoSource): Promise<void>`
|
```tsx
|
||||||
|
setSource(source: ReactVideoSource): Promise<void>
|
||||||
|
```
|
||||||
|
|
||||||
This function will change the source exactly like [source](./props#source) property.
|
Updates the media source **dynamically**.
|
||||||
Changing source with this function will overide source provided as props.
|
|
||||||
|
> **Note:** This **overrides** the `source` prop.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### `setFullScreen`
|
### `setFullScreen`
|
||||||
|
|
||||||
<PlatformsList types={['Android', 'iOS', 'web']} />
|
<PlatformsList types={['Android', 'iOS', 'web']} />
|
||||||
|
|
||||||
`setFullScreen(fullscreen): Promise<void>`
|
```tsx
|
||||||
|
setFullScreen(fullscreen: boolean): Promise<void>
|
||||||
|
```
|
||||||
|
|
||||||
If you set it to `true`, the player enters fullscreen mode. If you set it to `false`, the player exits fullscreen mode.
|
Toggles fullscreen mode.
|
||||||
|
|
||||||
On iOS, this displays the video in a fullscreen view controller with controls.
|
- `true` → Enters fullscreen.
|
||||||
|
- `false` → Exits fullscreen.
|
||||||
|
|
||||||
On Android, this puts the navigation controls in fullscreen mode. It is not a complete fullscreen implementation, so you will still need to apply a style that makes the width and height match your screen dimensions to get a fullscreen video.
|
---
|
||||||
|
|
||||||
### `nativeHtmlVideoRef`
|
### `nativeHtmlVideoRef`
|
||||||
|
|
||||||
<PlatformsList types={['web']} />
|
<PlatformsList types={['web']} />
|
||||||
|
|
||||||
A ref to the underlying html video element. This can be used if you need to integrate a 3d party, web only video library (like hls.js, shaka, video.js...).
|
A **reference to the native HTML `<video>` element**.
|
||||||
|
Useful for integrating **third-party** video libraries like **hls.js, shaka, video.js, etc.**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### Example Usage
|
### **Example Usage**
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
const videoRef = useRef<VideoRef>(null);
|
const videoRef = useRef<VideoRef>(null);
|
||||||
|
|
||||||
const someCoolFunctions = async () => {
|
const handleVideoControls = async () => {
|
||||||
if (!videoRef.current) {
|
if (!videoRef.current) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// present or dismiss fullscreen player
|
// Fullscreen controls
|
||||||
videoRef.current.presentFullscreenPlayer();
|
videoRef.current.presentFullscreenPlayer();
|
||||||
videoRef.current.dismissFullscreenPlayer();
|
videoRef.current.dismissFullscreenPlayer();
|
||||||
|
|
||||||
// pause or resume the video
|
// Playback controls
|
||||||
videoRef.current.pause();
|
videoRef.current.pause();
|
||||||
videoRef.current.resume();
|
videoRef.current.resume();
|
||||||
|
|
||||||
// save video to your Photos with current filter prop
|
// Save video
|
||||||
const response = await videoRef.current.save();
|
const response = await videoRef.current.save();
|
||||||
const path = response.uri;
|
console.log('Saved video path:', response.uri);
|
||||||
|
|
||||||
// seek to the specified position represented by seconds
|
// Seek to 200s (or with tolerance on iOS)
|
||||||
videoRef.current.seek(200);
|
videoRef.current.seek(200);
|
||||||
// or on iOS you can seek with tolerance
|
|
||||||
videoRef.current.seek(200, 10);
|
videoRef.current.seek(200, 10);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -230,56 +269,69 @@ return (
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
## Static methods
|
## Static Methods
|
||||||
|
|
||||||
### `getWidevineLevel`
|
### `getWidevineLevel`
|
||||||
|
|
||||||
<PlatformsList types={['Android']} />
|
<PlatformsList types={['Android']} />
|
||||||
|
|
||||||
Indicates whether the widevine level supported by device.
|
```tsx
|
||||||
|
getWidevineLevel(): Promise<number>
|
||||||
|
```
|
||||||
|
|
||||||
Possible values are:
|
Returns the **Widevine DRM level**:
|
||||||
|
|
||||||
- 0 - unable to determine widevine support (typically not supported)
|
- **0** → Unknown / Not supported.
|
||||||
- 1, 2, 3 - Widevine level supported
|
- **1, 2, 3** → Supported Widevine levels.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### `isCodecSupported`
|
### `isCodecSupported`
|
||||||
|
|
||||||
<PlatformsList types={['Android', 'web']} />
|
<PlatformsList types={['Android', 'web']} />
|
||||||
|
|
||||||
Indicates whether the provided codec is supported level supported by device.
|
```tsx
|
||||||
|
isCodecSupported(mimetype: string, width: number, height: number): Promise<'hardware' | 'software' | 'unsupported'>
|
||||||
|
```
|
||||||
|
|
||||||
parameters:
|
Checks if the given **video codec** is supported.
|
||||||
|
|
||||||
- `mimetype`: mime type of codec to query
|
| Result | Meaning |
|
||||||
- `width`, `height`: resolution to query
|
|------------|--------------------------------------|
|
||||||
|
| `hardware` | Hardware decoding supported |
|
||||||
|
| `software` | Only software decoding available |
|
||||||
|
| `unsupported` | Codec **not supported** |
|
||||||
|
|
||||||
Possible results:
|
---
|
||||||
|
|
||||||
- `hardware` - codec is supported by hardware
|
|
||||||
- `software` - codec is supported by software only
|
|
||||||
- `unsupported` - codec is not supported
|
|
||||||
|
|
||||||
### `isHEVCSupported`
|
### `isHEVCSupported`
|
||||||
|
|
||||||
<PlatformsList types={['Android']} />
|
<PlatformsList types={['Android']} />
|
||||||
|
|
||||||
Helper which Indicates whether the provided HEVC/1920\*1080 is supported level supported by device. It uses isCodecSupported internally.
|
```tsx
|
||||||
|
isHEVCSupported(): Promise<boolean>
|
||||||
|
```
|
||||||
|
|
||||||
### Example Usage
|
Checks if **HEVC (H.265)** is supported at **1920×1080 resolution**.
|
||||||
|
|
||||||
|
> Uses `isCodecSupported` internally.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Static Methods Example Usage
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
import { VideoDecoderProperties } from 'react-native-video';
|
import { VideoDecoderProperties } from 'react-native-video';
|
||||||
|
|
||||||
VideoDecoderProperties.getWidevineLevel().then((level) => {
|
VideoDecoderProperties.getWidevineLevel().then((level) => {
|
||||||
...
|
console.log('Widevine Level:', level);
|
||||||
});
|
});
|
||||||
|
|
||||||
VideoDecoderProperties.isCodecSupported('video/hevc', 1920, 1080).then((support) => {
|
VideoDecoderProperties.isCodecSupported('video/hevc', 1920, 1080).then((support) => {
|
||||||
...
|
console.log('HEVC Support:', support);
|
||||||
});
|
});
|
||||||
|
|
||||||
VideoDecoderProperties.isHEVCSupported().then((support) => {
|
VideoDecoderProperties.isHEVCSupported().then((support) => {
|
||||||
...
|
console.log('HEVC 1080p Support:', support);
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,43 +1,42 @@
|
|||||||
# A `<Video>` component for React Native
|
# A `<Video>` Component for React Native
|
||||||
|
|
||||||
## About
|
## About
|
||||||
`react-native-video` is a React Native library that provides a Video component that renders media content such as videos and streams
|
`react-native-video` is a React Native library that provides a Video component to render media content like videos and streams.
|
||||||
|
|
||||||
It allows to stream video files (m3u, mpd, mp4, ...) inside your react native application.
|
It allows you to stream video files (m3u, mpd, mp4, etc.) inside your React Native application.
|
||||||
|
|
||||||
- Exoplayer for android
|
- ExoPlayer for Android
|
||||||
- AVplayer for iOS, tvOS and visionOS
|
- AVPlayer for iOS, tvOS, and visionOS
|
||||||
- Windows UWP for windows
|
- Windows UWP for Windows
|
||||||
- HTML5 for web
|
- HTML5 for Web
|
||||||
- Trick mode support
|
- Trick mode support
|
||||||
- Subtitles (embeded or side loaded)
|
- Subtitles (embedded or side-loaded)
|
||||||
- DRM support
|
- DRM support
|
||||||
- Client side Ads insertion (via google IMA)
|
- Client-side ad insertion (via Google IMA)
|
||||||
- Pip
|
- PiP (Picture-in-Picture)
|
||||||
- Embedded playback controls
|
- Embedded playback controls
|
||||||
- And much more
|
- And more
|
||||||
|
|
||||||
The aim of this package is to have a thin and exhaustive control of player.
|
The goal of this package is to provide lightweight but full control over the player.
|
||||||
|
|
||||||
## V6.0.0 Information
|
## V6.0.0 Information
|
||||||
> ⚠️ **Version 6**: The following documentation refer to features only available through the v6.0.0 releases.
|
> ⚠️ **Version 6**: This documentation covers features available only in v6.0.0 and later.
|
||||||
> As major rework has been done in case of doubt, you can still use [version 5.2.x, see documentation](https://github.com/TheWidlarzGroup/react-native-video/blob/v5.2.0/README.md)
|
> If you're unsure or need an older version, you can still use [version 5.2.x](https://github.com/TheWidlarzGroup/react-native-video/blob/v5.2.0/README.md).
|
||||||
|
|
||||||
Version 6.x requires **react-native >= 0.68.2**
|
Version 6.x requires **react-native >= 0.68.2**
|
||||||
> ⚠️ from **6.0.0-beta.8** requires also **iOS >= 13.0** (default in react-native 0.73)
|
> ⚠️ From **6.0.0-beta.8**, it also requires **iOS >= 13.0** (default in React Native 0.73).
|
||||||
|
|
||||||
For older versions of react-native, [please use version 5.x](https://github.com/TheWidlarzGroup/react-native-video/tree/v5.2.0).
|
For older versions of React Native, [please use version 5.x](https://github.com/TheWidlarzGroup/react-native-video/tree/v5.2.0).
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// Load the module
|
// Load the module
|
||||||
|
|
||||||
import Video, { VideoRef } from 'react-native-video';
|
import Video, { VideoRef } from 'react-native-video';
|
||||||
|
|
||||||
// Within your render function, assuming you have a file called
|
// Inside your render function, assuming you have a file called
|
||||||
// "background.mp4" in your project. You can include multiple videos
|
// "background.mp4" in your project. You can include multiple videos
|
||||||
// on a single screen if you like.
|
// on a single screen if needed.
|
||||||
|
|
||||||
const VideoPlayer = () => {
|
const VideoPlayer = () => {
|
||||||
const videoRef = useRef<VideoRef>(null);
|
const videoRef = useRef<VideoRef>(null);
|
||||||
@@ -51,14 +50,14 @@ const VideoPlayer = () => {
|
|||||||
ref={videoRef}
|
ref={videoRef}
|
||||||
// Callback when remote video is buffering
|
// Callback when remote video is buffering
|
||||||
onBuffer={onBuffer}
|
onBuffer={onBuffer}
|
||||||
// Callback when video cannot be loaded
|
// Callback when the video cannot be loaded
|
||||||
onError={onError}
|
onError={onError}
|
||||||
style={styles.backgroundVideo}
|
style={styles.backgroundVideo}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
// Later on in your styles..
|
// Later in your styles...
|
||||||
var styles = StyleSheet.create({
|
var styles = StyleSheet.create({
|
||||||
backgroundVideo: {
|
backgroundVideo: {
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
@@ -69,3 +68,4 @@ var styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
|
|
||||||
|
|
||||||
# Installation
|
# Installation
|
||||||
|
|
||||||
Using npm:
|
Using npm:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
@@ -13,9 +12,10 @@ or using yarn:
|
|||||||
yarn add react-native-video
|
yarn add react-native-video
|
||||||
```
|
```
|
||||||
|
|
||||||
Then follow the instructions for your platform to link react-native-video into your project
|
Then follow the instructions for your platform to link `react-native-video` into your project.
|
||||||
|
|
||||||
|
# Specific Platform Installation
|
||||||
|
|
||||||
# Specific platform installation
|
|
||||||
<details>
|
<details>
|
||||||
<summary>iOS</summary>
|
<summary>iOS</summary>
|
||||||
|
|
||||||
@@ -24,65 +24,70 @@ Then follow the instructions for your platform to link react-native-video into y
|
|||||||
### Standard Method
|
### Standard Method
|
||||||
Run `pod install` in the `ios` directory of your project.
|
Run `pod install` in the `ios` directory of your project.
|
||||||
|
|
||||||
⚠️ from version `6.0.0` the minimum iOS version required is `13.0`. For more information see [updating section](updating.md)
|
⚠️ From version `6.0.0`, the minimum iOS version required is `13.0`. For more information, see the [updating section](updating.md).
|
||||||
|
|
||||||
### Enable custom feature in podfile file
|
### Enable Custom Features in the Podfile
|
||||||
|
|
||||||
Samples available in sample app see [sample pod file](https://github.com/TheWidlarzGroup/react-native-video/blob/9c669a2d8a53df36773fd82ff0917280d0659bc7/examples/basic/ios/Podfile#L34)
|
Sample configurations are available in the sample app. See the [sample pod file](https://github.com/TheWidlarzGroup/react-native-video/blob/9c669a2d8a53df36773fd82ff0917280d0659bc7/examples/basic/ios/Podfile#L34).
|
||||||
|
|
||||||
#### Video caching
|
#### Video Caching
|
||||||
|
|
||||||
To enable Video caching usage, add following line in your podfile:
|
To enable video caching, add the following line to your Podfile: ([more info here](other/caching.md))
|
||||||
([more info here](other/caching.md))
|
|
||||||
|
|
||||||
```podfile
|
```podfile
|
||||||
# enable Video caching
|
# Enable Video Caching
|
||||||
+ $RNVideoUseVideoCaching=true
|
$RNVideoUseVideoCaching=true
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Google IMA
|
#### Google IMA
|
||||||
|
|
||||||
Google IMA is the google SDK to support Client Side Ads Integration (CSAI), see [google documentation](https://developers.google.com/interactive-media-ads/docs/sdks/ios/client-side) for more information.
|
Google IMA is the SDK for client-side ads integration. See the [Google documentation](https://developers.google.com/interactive-media-ads/docs/sdks/ios/client-side) for more details.
|
||||||
|
|
||||||
|
To enable Google IMA, add the following line to your Podfile:
|
||||||
|
|
||||||
To enable google IMA usage define add following line in your podfile:
|
|
||||||
```podfile
|
```podfile
|
||||||
$RNVideoUseGoogleIMA=true
|
$RNVideoUseGoogleIMA=true
|
||||||
```
|
```
|
||||||
|
|
||||||
**If you are using Expo you can use [expo plugin](other/expo.md) for it**
|
**If you are using Expo, you can use the [Expo plugin](other/expo.md).**
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>Android</summary>
|
<summary>Android</summary>
|
||||||
|
|
||||||
## Android
|
## Android
|
||||||
|
|
||||||
From version >= 6.0.0, your application needs to have kotlin version >= 1.8.0
|
From version `>= 6.0.0`, your application must use Kotlin version `>= 1.8.0`.
|
||||||
|
|
||||||
```:
|
```gradle
|
||||||
buildscript {
|
buildscript {
|
||||||
...
|
...
|
||||||
ext.kotlinVersion = '1.8.0',
|
ext.kotlinVersion = '1.8.0'
|
||||||
ext.compileSdkVersion = 34
|
ext.compileSdkVersion = 34
|
||||||
ext.targetSdkVersion = 34
|
ext.targetSdkVersion = 34
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Enable custom feature in gradle file
|
### Enable Custom Features in the Gradle File
|
||||||
|
|
||||||
**If you are using Expo you can use [expo plugin](other/expo.md) for it**
|
**If you are using Expo, you can use the [Expo plugin](other/expo.md).**
|
||||||
|
|
||||||
You can disable or enable the following features by setting the following variables in your `android/build.gradle` file:
|
You can enable or disable the following features by setting the corresponding variables in your `android/build.gradle` file:
|
||||||
- `useExoplayerIMA` - Enable Google IMA SDK (Ads support)
|
|
||||||
|
- `useExoplayerIMA` - Enable Google IMA SDK (ads support)
|
||||||
- `useExoplayerRtsp` - Enable RTSP support
|
- `useExoplayerRtsp` - Enable RTSP support
|
||||||
- `useExoplayerSmoothStreaming` - Enable SmoothStreaming support
|
- `useExoplayerSmoothStreaming` - Enable SmoothStreaming support
|
||||||
- `useExoplayerDash` - Enable Dash support
|
- `useExoplayerDash` - Enable Dash support
|
||||||
- `useExoplayerHls` - Enable HLS support
|
- `useExoplayerHls` - Enable HLS support
|
||||||
|
|
||||||
Each of these features enabled will increase the size of your APK, so only enable the features you need.
|
Each enabled feature increases the APK size, so only enable what you need.
|
||||||
By default enabled features are: `useExoplayerSmoothStreaming`, `useExoplayerDash`, `useExoplayerHls`
|
|
||||||
|
|
||||||
|
By default, the enabled features are:
|
||||||
|
- `useExoplayerSmoothStreaming`
|
||||||
|
- `useExoplayerDash`
|
||||||
|
- `useExoplayerHls`
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
@@ -100,9 +105,10 @@ buildscript {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
See [sample app](https://github.com/TheWidlarzGroup/react-native-video/blob/9c669a2d8a53df36773fd82ff0917280d0659bc7/examples/basic/android/build.gradle#L14C5-L14C5)
|
See the [sample app](https://github.com/TheWidlarzGroup/react-native-video/blob/9c669a2d8a53df36773fd82ff0917280d0659bc7/examples/basic/android/build.gradle#L14C5-L14C5).
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>Windows</summary>
|
<summary>Windows</summary>
|
||||||
|
|
||||||
@@ -112,81 +118,97 @@ See [sample app](https://github.com/TheWidlarzGroup/react-native-video/blob/9c66
|
|||||||
|
|
||||||
**React Native Windows 0.63 and above**
|
**React Native Windows 0.63 and above**
|
||||||
|
|
||||||
Autolinking should automatically add react-native-video to your app.
|
Autolinking should automatically add `react-native-video` to your app.
|
||||||
|
|
||||||
### Manual Linking
|
### Manual Linking
|
||||||
|
|
||||||
**React Native Windows 0.62**
|
**React Native Windows 0.62**
|
||||||
|
|
||||||
Make the following additions to the given files manually:
|
Make the following manual additions:
|
||||||
|
|
||||||
`windows\myapp.sln`
|
#### `windows\myapp.sln`
|
||||||
|
|
||||||
Add the _ReactNativeVideoCPP_ project to your solution (eg. `windows\myapp.sln`):
|
Add the _ReactNativeVideoCPP_ project to your solution:
|
||||||
|
|
||||||
1. Open your solution in Visual Studio 2019
|
1. Open your solution in Visual Studio 2019.
|
||||||
2. Right-click Solution icon in Solution Explorer > Add > Existing Project...
|
2. Right-click the Solution icon in Solution Explorer > Add > Existing Project...
|
||||||
3. Select `node_modules\react-native-video\windows\ReactNativeVideoCPP\ReactNativeVideoCPP.vcxproj`
|
3. Select `node_modules\react-native-video\windows\ReactNativeVideoCPP\ReactNativeVideoCPP.vcxproj`.
|
||||||
|
|
||||||
`windows\myapp\myapp.vcxproj`
|
#### `windows\myapp\myapp.vcxproj`
|
||||||
|
|
||||||
Add a reference to _ReactNativeVideoCPP_ to your main application project (eg. `windows\myapp\myapp.vcxproj`):
|
Add a reference to _ReactNativeVideoCPP_ to your main application project:
|
||||||
|
|
||||||
1. Open your solution in Visual Studio 2019
|
1. Open your solution in Visual Studio 2019.
|
||||||
2. Right-click main application project > Add > Reference...
|
2. Right-click the main application project > Add > Reference...
|
||||||
3. Check _ReactNativeVideoCPP_ from Solution Projects
|
3. Check _ReactNativeVideoCPP_ from Solution Projects.
|
||||||
|
|
||||||
`pch.h`
|
#### `pch.h`
|
||||||
|
|
||||||
Add `#include "winrt/ReactNativeVideoCPP.h"`.
|
Add:
|
||||||
|
|
||||||
`app.cpp`
|
```cpp
|
||||||
|
#include "winrt/ReactNativeVideoCPP.h"
|
||||||
|
```
|
||||||
|
|
||||||
Add `PackageProviders().Append(winrt::ReactNativeVideoCPP::ReactPackageProvider());` before `InitializeComponent();`.
|
#### `app.cpp`
|
||||||
|
|
||||||
|
Add:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
PackageProviders().Append(winrt::ReactNativeVideoCPP::ReactPackageProvider());
|
||||||
|
```
|
||||||
|
|
||||||
|
before `InitializeComponent();`.
|
||||||
|
|
||||||
**React Native Windows 0.61 and below**
|
**React Native Windows 0.61 and below**
|
||||||
|
|
||||||
Follow the manual linking instructions for React Native Windows 0.62 above, but substitute _ReactNativeVideoCPP61_ for _ReactNativeVideoCPP_.
|
Follow the manual linking steps for React Native Windows 0.62, but use _ReactNativeVideoCPP61_ instead of _ReactNativeVideoCPP_.
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>tvOS</summary>
|
<summary>tvOS</summary>
|
||||||
|
|
||||||
## tvOS
|
## tvOS
|
||||||
|
|
||||||
`react-native link react-native-video` doesn’t work properly with the tvOS target so we need to add the library manually.
|
`react-native link react-native-video` does not work properly with the tvOS target, so the library must be added manually.
|
||||||
|
|
||||||
First select your project in Xcode.
|
### Steps:
|
||||||
|
|
||||||
|
1. Select your project in Xcode.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
After that, select the tvOS target of your application and select « General » tab
|
2. Select the tvOS target of your application and open the "General" tab.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
Scroll to « Linked Frameworks and Libraries » and tap on the + button
|
3. Scroll to "Linked Frameworks and Libraries" and click the `+` button.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
Select RCTVideo-tvOS
|
4. Select `RCTVideo-tvOS`.
|
||||||
|
|
||||||

|

|
||||||
</details>
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>visionOS</summary>
|
<summary>visionOS</summary>
|
||||||
|
|
||||||
## visionOS
|
## visionOS
|
||||||
Run `pod install` in the `visionos` directory of your project
|
|
||||||
|
Run `pod install` in the `visionos` directory of your project.
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>web</summary>
|
<summary>Web</summary>
|
||||||
|
|
||||||
Nothing to do, everything should work out of the box.
|
## Web
|
||||||
|
|
||||||
Note that only basic video support is present, no hls/dash or ads/drm for now.
|
No additional setup is required. Everything should work out of the box.
|
||||||
|
|
||||||
|
However, only basic video support is available. HLS, Dash, ads, and DRM are not currently supported.
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"caching": "Caching",
|
"caching": "Caching",
|
||||||
|
"downloading": "Downloading",
|
||||||
"misc": "Misc",
|
"misc": "Misc",
|
||||||
"debug": "Debugging",
|
"debug": "Debugging",
|
||||||
"new-arch": "New Architecture",
|
"new-arch": "New Architecture",
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
# Caching
|
# Caching
|
||||||
|
|
||||||
Caching is supported on `iOS` platforms with a CocoaPods setup, and on `android` using `SimpleCache`.
|
Caching is supported on `iOS` platforms with a CocoaPods setup and on `Android` using `SimpleCache`.
|
||||||
|
|
||||||
## Android
|
## Android
|
||||||
|
|
||||||
Android uses a LRU `SimpleCache` with a variable cache size that can be specified by bufferConfig - cacheSizeMB. This creates a folder named `RNVCache` in the app's `cache` folder. Do note RNV does not yet offer a native call to flush the cache, it can be flushed by clearing the app's cache.
|
Android uses an LRU `SimpleCache` with a variable cache size, which can be specified by `bufferConfig - cacheSizeMB`. This creates a folder named `RNVCache` inside the app's `cache` directory.
|
||||||
|
|
||||||
In addition, this resolves RNV6's repeated source URI call problem when looping a video on Android.
|
Note that `react-native-video` does not currently offer a native method to flush the cache, but it can be cleared by manually clearing the app's cache.
|
||||||
|
|
||||||
|
Additionally, this resolves the issue in RNV6 where the source URI was repeatedly called when looping a video on Android.
|
||||||
|
|
||||||
## iOS
|
## iOS
|
||||||
|
|
||||||
@@ -14,17 +16,18 @@ In addition, this resolves RNV6's repeated source URI call problem when looping
|
|||||||
|
|
||||||
The cache is backed by [SPTPersistentCache](https://github.com/spotify/SPTPersistentCache) and [DVAssetLoaderDelegate](https://github.com/vdugnist/DVAssetLoaderDelegate).
|
The cache is backed by [SPTPersistentCache](https://github.com/spotify/SPTPersistentCache) and [DVAssetLoaderDelegate](https://github.com/vdugnist/DVAssetLoaderDelegate).
|
||||||
|
|
||||||
### How Does It Work
|
### How It Works
|
||||||
|
|
||||||
The caching is based on the url of the asset.
|
Caching is based on the asset's URL. `SPTPersistentCache` uses an LRU ([Least Recently Used](https://en.wikipedia.org/wiki/Cache_replacement_policies#Least_recently_used_(LRU))) caching policy.
|
||||||
SPTPersistentCache is a LRU ([Least Recently Used](<https://en.wikipedia.org/wiki/Cache_replacement_policies#Least_recently_used_(LRU)>)) cache.
|
|
||||||
|
|
||||||
### Restrictions
|
### Restrictions
|
||||||
|
|
||||||
Currently, caching is only supported for URLs that end in a `.mp4`, `.m4v`, or `.mov` extension. In future versions, URLs that end in a query string (e.g. test.mp4?resolution=480p) will be support once dependencies allow access to the `Content-Type` header. At this time, HLS playlists (.m3u8) and videos that sideload text tracks are not supported and will bypass the cache.
|
Currently, caching is only supported for URLs ending in `.mp4`, `.m4v`, or `.mov`. In future versions, URLs with query strings (e.g., `test.mp4?resolution=480p`) will be supported once dependencies allow access to the `Content-Type` header.
|
||||||
|
|
||||||
You will also receive warnings in the Xcode logs by using the `debug` mode. So if you are not 100% sure if your video is cached, check your Xcode logs!
|
At this time, HLS playlists (`.m3u8`) and videos with sideloaded text tracks are not supported and will bypass the cache.
|
||||||
|
|
||||||
By default files expire after 30 days and the maximum cache size is 100mb.
|
You will see warnings in the Xcode logs when using `debug` mode. If you're unsure whether your video is cached, check your Xcode logs.
|
||||||
|
|
||||||
In a future release the cache might have more configurable options.
|
By default, files expire after 30 days, and the maximum cache size is 100MB.
|
||||||
|
|
||||||
|
Future updates may include more configurable caching options.
|
||||||
|
|||||||
@@ -1,20 +1,38 @@
|
|||||||
# Debugging
|
# Debugging
|
||||||
|
|
||||||
This page describe useful tips for debugging and investigating issue in the package or in your application.
|
This page provides useful tips for debugging and troubleshooting issues in the package or your application.
|
||||||
|
|
||||||
## Using the sample app
|
## Using the Sample App
|
||||||
This repository contains multiple a sample implementation in example folder.
|
|
||||||
It is always preferable to test behavior on a sample app than in a full app implementation.
|
|
||||||
The basic sample allow to test a lot of feature.
|
|
||||||
To use the sample you will need to do steps:
|
|
||||||
- Clone this repository: ``` git clone git@github.com:TheWidlarzGroup/react-native-video.git```
|
|
||||||
- Go to root folder and build it. It will generate a transpiled version of the package in lib folder: ```cd react-native-video && yarn && yarn build```
|
|
||||||
- Go to the sample and install it: ```cd example/basic && yarn install```
|
|
||||||
- Build it ! for android ```yarn android``` for ios ```cd ios && pod install && cd .. && yarn ios```
|
|
||||||
|
|
||||||
|
This repository contains multiple sample implementations in the `example` folder. It is always preferable to test behavior in a sample app rather than in a full application. The basic sample allows testing of many features.
|
||||||
|
|
||||||
## HTTP playback doesn't work or Black Screen on Release build (Android)
|
To use the sample app, follow these steps:
|
||||||
If your video work on Debug mode, but on Release you see only black screen, please, check the link to your video. If you use 'http' protocol there, you will need to add next string to your AndroidManifest.xml file. [Details here](https://developer.android.com/guide/topics/manifest/application-element#usesCleartextTraffic)
|
|
||||||
|
- Clone this repository:
|
||||||
|
```shell
|
||||||
|
git clone git@github.com:TheWidlarzGroup/react-native-video.git
|
||||||
|
```
|
||||||
|
- Navigate to the root folder and build the package. This generates a transpiled version in the `lib` folder:
|
||||||
|
```shell
|
||||||
|
cd react-native-video && yarn && yarn build
|
||||||
|
```
|
||||||
|
- Navigate to the sample app and install dependencies:
|
||||||
|
```shell
|
||||||
|
cd example/basic && yarn install
|
||||||
|
```
|
||||||
|
- Build and run the app:
|
||||||
|
- For Android:
|
||||||
|
```shell
|
||||||
|
yarn android
|
||||||
|
```
|
||||||
|
- For iOS:
|
||||||
|
```shell
|
||||||
|
cd ios && pod install && cd .. && yarn ios
|
||||||
|
```
|
||||||
|
|
||||||
|
## HTTP Playback Doesn't Work or Black Screen on Release Build (Android)
|
||||||
|
|
||||||
|
If your video works in Debug mode but shows only a black screen in Release mode, check the URL of your video. If you are using the `http` protocol, you need to add the following line to your `AndroidManifest.xml` file. [More details here](https://developer.android.com/guide/topics/manifest/application-element#usesCleartextTraffic):
|
||||||
|
|
||||||
```xml
|
```xml
|
||||||
<application
|
<application
|
||||||
@@ -25,56 +43,56 @@ If your video work on Debug mode, but on Release you see only black screen, plea
|
|||||||
|
|
||||||
## Decoder Issue (Android)
|
## Decoder Issue (Android)
|
||||||
|
|
||||||
Devices have a maximum of simultaneous possible playback. It means you have reach this limit. Exoplayer returns: 'Unable to instantiate decoder'
|
Some devices have a maximum number of simultaneous video playbacks. If this limit is reached, ExoPlayer returns an error: `Unable to instantiate decoder`.
|
||||||
|
|
||||||
**known issue**: This issue happen really often in debug mode.
|
**Known issue:** This happens frequently in Debug mode.
|
||||||
|
|
||||||
## You cannot play clean content (all OS)
|
## Unable to Play Clear Content (All OS)
|
||||||
|
|
||||||
Here are the steps to consider before opening a ticket in issue tracker
|
Before opening a ticket, follow these steps:
|
||||||
|
|
||||||
## Check you can access to remote file
|
### Check Remote File Access
|
||||||
|
|
||||||
Ensure you can download to manifest / content file with a browser for example
|
Ensure you can download the manifest/content file using a browser.
|
||||||
|
|
||||||
## Check another player can read the content
|
### Check If Another Player Can Play the Content
|
||||||
|
|
||||||
Usually clear playback can be read with all Video player. Then you should ensure content can be played without any issue with another player ([VideoLan/VLC](https://www.videolan.org/vlc/) is a good reference implementation)
|
Clear playback should work with any video player. Test the content with another player, such as [VLC](https://www.videolan.org/vlc/), to confirm it plays without issues.
|
||||||
|
|
||||||
## You cannot play protected content (all OS)
|
## Unable to Play Protected Content (All OS)
|
||||||
|
|
||||||
## Protected content gives error (token error / access forbidden)
|
### Protected Content Gives an Error (Token Error / Access Forbidden)
|
||||||
|
|
||||||
If content is protected with an access token or any other http header, ensure you can access to you data with a wget call or a rest client app. You need to provide all needed access token / authentication parameters.
|
If the content requires an access token or HTTP headers, ensure you can access the data using `wget` or a REST client. Provide all necessary authentication parameters.
|
||||||
|
|
||||||
## I need to debug network calls but I don't see them in react native debugging tools
|
## Debugging Network Calls Not Visible in React Native Debugging Tools
|
||||||
|
|
||||||
This is a react native limitation. React native tools can only see network calls done in JS.
|
This is a React Native limitation—React Native debugging tools only capture network calls made in JavaScript.
|
||||||
To achieve that, you need to record network trace to ensure communications with server is correct.
|
|
||||||
[Charles proxy](https://www.charlesproxy.com/) or [Fiddler](https://www.telerik.com/fiddler) are a simple and useful tool to sniff all http/https calls.
|
|
||||||
With these tool you should be able to analyze what is going on with network. You will see all access to content and DRM, audio / video chunks, ...
|
|
||||||
|
|
||||||
Then try to compare exchanges with previous tests you made.
|
To debug network calls, use tools like:
|
||||||
|
- [Charles Proxy](https://www.charlesproxy.com/)
|
||||||
|
- [Fiddler](https://www.telerik.com/fiddler)
|
||||||
|
|
||||||
## Debug media3: build from media3 source
|
These tools allow you to sniff all HTTP/HTTPS calls, including access to content, DRM, and audio/video chunks. Compare the request/response patterns with previous tests to diagnose issues.
|
||||||
|
|
||||||
If you need to use a specific exoplayer version or patch default behavior, you may want to build from media3 source code.
|
## Debugging Media3: Build from Media3 Source
|
||||||
|
|
||||||
Building from media3 source is possible. You need to add 2 or 3 things in your app:
|
If you need to use a specific ExoPlayer version or modify default behavior, you may need to build from the Media3 source code.
|
||||||
|
|
||||||
### Configure player path
|
### Configure Player Path
|
||||||
|
|
||||||
You need to add following lines in settings.gradle to configure your media3 source path:
|
Add the following lines to `settings.gradle` to configure your Media3 source path:
|
||||||
|
|
||||||
```gradle
|
```gradle
|
||||||
gradle.ext.androidxMediaModulePrefix = 'media-'
|
gradle.ext.androidxMediaModulePrefix = 'media-'
|
||||||
apply from: file("../../../../media3/core_settings.gradle")
|
apply from: file("../../../../media3/core_settings.gradle")
|
||||||
````
|
```
|
||||||
|
|
||||||
Of course, you should replace with media3 source path. Be carefull, you need to use the same version (or version with compatible api) that the package support.
|
Replace this with the actual Media3 source path. Ensure that you use the same version (or a compatible API version) supported by the package.
|
||||||
|
|
||||||
### Enable building from source
|
### Enable Building from Source
|
||||||
In your build.gradle file, add following setting:
|
|
||||||
|
In your `build.gradle` file, add the following setting:
|
||||||
|
|
||||||
```gradle
|
```gradle
|
||||||
buildscript {
|
buildscript {
|
||||||
@@ -86,6 +104,7 @@ buildscript {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## It's still not working
|
## Still Not Working?
|
||||||
|
|
||||||
|
You can open a ticket or contact us for [premium support](https://www.thewidlarzgroup.com/?utm_source=rnv&utm_medium=docs#Contact).
|
||||||
|
|
||||||
You can try to open a ticket or contact us for [premium support](https://www.thewidlarzgroup.com/?utm_source=rnv&utm_medium=docs&utm_campaign=debugging&utm_id=enterprise#Contact)!
|
|
||||||
|
|||||||
40
docs/pages/other/downloading.md
Normal file
40
docs/pages/other/downloading.md
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
# Offline Video SDK
|
||||||
|
|
||||||
|
## What is the Offline Video SDK?
|
||||||
|
|
||||||
|
The [Offline Video SDK](https://www.thewidlarzgroup.com/offline-video-sdk/?utm_source=rnv&utm_medium=docs&utm_campaign=downloading&utm_id=offline-video-sdk-link) extends `react-native-video` (v6 or v7) with the ability to download and store video content for offline playback. It also supports DRM-protected content. The SDK manages background tasks—such as queuing, pausing, resuming, and tracking progress or errors—without requiring major changes to your existing setup.
|
||||||
|
|
||||||
|
### Key Features
|
||||||
|
|
||||||
|
- **Stream Downloading**
|
||||||
|
The SDK allows you to download streams and store them for offline playback. It also includes an asset manager to manage downloaded files on the device.
|
||||||
|
|
||||||
|
- **Offline DRM**
|
||||||
|
Securely plays DRM-protected content offline while ensuring content protection and rights management.
|
||||||
|
|
||||||
|
### Additional Capabilities
|
||||||
|
|
||||||
|
- **Multiple Audio Tracks & Subtitles**
|
||||||
|
Supports downloading various audio and subtitle tracks, including optional subtitle exclusion or inclusion.
|
||||||
|
|
||||||
|
- **Selective Downloads**
|
||||||
|
Only the selected tracks (resolution, language, etc.) is downloaded by default to optimize storage usage.
|
||||||
|
|
||||||
|
- **DRM License Optimization**
|
||||||
|
If your DRM provider issues persistent tokens, they can be stored and updated only upon expiration, reducing licensing costs.
|
||||||
|
|
||||||
|
- **Pluggable Architecture**
|
||||||
|
Designed for offline capabilities without restricting additional video player features. Future `react-native-video` (v7+) updates will further simplify plugin integrations.
|
||||||
|
|
||||||
|
### Implementation & Support
|
||||||
|
|
||||||
|
- **Integration Options**
|
||||||
|
You can integrate the SDK yourself or get assistance from our team. We also offer commercial collaboration for stalled projects. [Contact us](mailto:hi@thewidlarzgroup.com) for support.
|
||||||
|
|
||||||
|
- **Basic Requirements**
|
||||||
|
1. `react-native-video` version **6** or **7**.
|
||||||
|
2. Actual stream downloads are required for offline playback. A content ID or persistent key alone is not sufficient.
|
||||||
|
|
||||||
|
### Licensing & Inquiries
|
||||||
|
|
||||||
|
For licensing, trials, or further assistance, [contact us](mailto:hi@thewidlarzgroup.com). We’d be happy to discuss your needs and answer any questions.
|
||||||
@@ -1,8 +1,12 @@
|
|||||||
# Expo
|
# Expo
|
||||||
|
|
||||||
## Expo plugin
|
## Expo Plugin
|
||||||
From version `6.3.1`, we have added support for expo plugin. You can configure `react-native-video` properties in `app.json` (or `app.config.json` or `app.config.js`) file.
|
|
||||||
It's useful when you are using `expo` managed workflow (expo prebuild) as it will automatically configure `react-native-video` properties in native part of the expo project.
|
Starting from version `6.3.1`, `react-native-video` supports an Expo plugin. You can configure `react-native-video` properties in the `app.json`, `app.config.json`, or `app.config.js` file.
|
||||||
|
|
||||||
|
This is particularly useful when using the `Expo` managed workflow (`expo prebuild`), as it automatically sets up `react-native-video` properties in the native part of the Expo project.
|
||||||
|
|
||||||
|
### Example Configuration
|
||||||
|
|
||||||
```json
|
```json
|
||||||
// app.json
|
// app.json
|
||||||
@@ -12,7 +16,6 @@ It's useful when you are using `expo` managed workflow (expo prebuild) as it wil
|
|||||||
[
|
[
|
||||||
"react-native-video",
|
"react-native-video",
|
||||||
{
|
{
|
||||||
// ...
|
|
||||||
"enableNotificationControls": true,
|
"enableNotificationControls": true,
|
||||||
"androidExtensions": {
|
"androidExtensions": {
|
||||||
"useExoplayerRtsp": false,
|
"useExoplayerRtsp": false,
|
||||||
@@ -20,7 +23,6 @@ It's useful when you are using `expo` managed workflow (expo prebuild) as it wil
|
|||||||
"useExoplayerHls": false,
|
"useExoplayerHls": false,
|
||||||
"useExoplayerDash": false
|
"useExoplayerDash": false
|
||||||
}
|
}
|
||||||
// ...
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -2,54 +2,60 @@
|
|||||||
|
|
||||||
## iOS App Transport Security
|
## iOS App Transport Security
|
||||||
|
|
||||||
- By default, iOS will only load encrypted (https) urls. If you want to load content from an unencrypted (http) source, you will need to modify your Info.plist file and add the following entry:
|
By default, iOS only allows loading encrypted (`https`) URLs. If you need to load content from an unencrypted (`http`) source, you must modify your `Info.plist` file and add the following entry:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
For more detailed info check this [article](https://cocoacasts.com/how-to-add-app-transport-security-exception-domains)
|
For more details, check this [article](https://cocoacasts.com/how-to-add-app-transport-security-exception-domains).
|
||||||
</details>
|
|
||||||
|
|
||||||
## Audio Mixing
|
## Audio Mixing
|
||||||
|
|
||||||
At some point in the future, react-native-video will include an Audio Manager for configuring how videos mix with other apps playing sounds on the device.
|
In future versions, `react-native-video` will include an Audio Manager for configuring how videos mix with other audio-playing apps.
|
||||||
|
|
||||||
On iOS, if you would like to allow other apps to play music over your video component, make the following change:
|
On iOS, if you want to allow background music from other apps to continue playing over your video component, update your `AppDelegate.m` file:
|
||||||
|
|
||||||
**AppDelegate.m**
|
### **AppDelegate.m**
|
||||||
|
|
||||||
```objective-c
|
```objective-c
|
||||||
#import <AVFoundation/AVFoundation.h> // import
|
#import <AVFoundation/AVFoundation.h> // Import the AVFoundation framework
|
||||||
|
|
||||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
||||||
{
|
{
|
||||||
...
|
...
|
||||||
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:nil]; // allow
|
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:nil]; // Allow background audio
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also use the [ignoreSilentSwitch](#ignoresilentswitch) prop.
|
You can also use the [`ignoreSilentSwitch`](#ignoresilentswitch) prop.
|
||||||
</details>
|
|
||||||
|
|
||||||
## Android Expansion File Usage
|
## Android Expansion File Usage
|
||||||
Expansions files allow you to ship assets that exceed the 100MB apk size limit and don't need to be updated each time you push an app update.
|
|
||||||
|
|
||||||
This only supports mp4 files and they must not be compressed. Example command line for preventing compression:
|
Expansion files allow you to include assets exceeding the 100MB APK size limit without requiring an update every time you push a new version.
|
||||||
|
|
||||||
|
- Only supports `.mp4` files, and they **must not be compressed**.
|
||||||
|
- Example command to prevent compression:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
zip -r -n .mp4 *.mp4 player.video.example.com
|
zip -r -n .mp4 *.mp4 player.video.example.com
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Example Usage in Code:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// Within your render function, assuming you have a file called
|
// Assuming "background.mp4" is included in your expansion file.
|
||||||
// "background.mp4" in your expansion file. Just add your main and (if applicable) patch version
|
<Video
|
||||||
<Video source={{uri: "background", mainVer: 1, patchVer: 0}} // Looks for .mp4 file (background.mp4) in the given expansion version.
|
source={{uri: "background", mainVer: 1, patchVer: 0}} // Looks for "background.mp4" in the specified expansion version.
|
||||||
resizeMode="cover" // Fill the whole screen at aspect ratio.
|
resizeMode="cover" // Fill the whole screen while maintaining aspect ratio.
|
||||||
style={styles.backgroundVideo} />
|
style={styles.backgroundVideo}
|
||||||
|
/>
|
||||||
```
|
```
|
||||||
|
|
||||||
## Load files with the RN Asset System
|
## Load Files with the React Native Asset System
|
||||||
|
|
||||||
The asset system [introduced in RN `0.14`](http://www.reactnative.com/react-native-v0-14-0-released/) allows loading image resources shared across iOS and Android without touching native code. As of RN `0.31` [the same is true](https://github.com/facebook/react-native/commit/91ff6868a554c4930fd5fda6ba8044dbd56c8374) of mp4 video assets for Android. As of [RN `0.33`](https://github.com/facebook/react-native/releases/tag/v0.33.0) iOS is also supported. Requires `react-native-video@0.9.0`.
|
The asset system introduced in RN `0.14` allows loading shared image resources across iOS and Android without modifying native code. As of RN `0.31`, the same applies to `.mp4` video assets on Android. From RN `0.33`, iOS support was added. Requires `react-native-video@0.9.0` or later.
|
||||||
|
|
||||||
|
### Example:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
<Video
|
<Video
|
||||||
@@ -57,6 +63,8 @@ The asset system [introduced in RN `0.14`](http://www.reactnative.com/react-nati
|
|||||||
/>
|
/>
|
||||||
```
|
```
|
||||||
|
|
||||||
## Play in background on iOS
|
## Play in Background on iOS
|
||||||
|
|
||||||
To enable audio to play in background on iOS the audio session needs to be set to `AVAudioSessionCategoryPlayback`. See [Apple documentation][3] for additional details. (NOTE: there is now a ticket to [expose this as a prop]( https://github.com/react-native-community/react-native-video/issues/310) )
|
To allow audio playback in the background on iOS, set the audio session to `AVAudioSessionCategoryPlayback`. See the [Apple documentation](https://developer.apple.com/documentation/avfoundation/avaudiosession) for more details.
|
||||||
|
|
||||||
|
_(Note: There is an open ticket to [expose this as a prop](https://github.com/react-native-community/react-native-video/issues/310).)_
|
||||||
|
|||||||
@@ -1,12 +1,18 @@
|
|||||||
# New Architecture
|
# New Architecture
|
||||||
|
|
||||||
## Fabric
|
## Fabric
|
||||||
Library currently does not support Fabric. We are working on it. In the meantime, you can use Interop Layer.
|
|
||||||
|
The library currently does not support Fabric. We are working on adding support. In the meantime, you can use the Interop Layer.
|
||||||
|
|
||||||
## Interop Layer
|
## Interop Layer
|
||||||
You can use this library on New Architecture by using Interop Layer. <br/> To use Interop Layer you need to have `react-native` >= `0.72.0` & `react-native-video` >= `6.0.0-beta.5`.
|
|
||||||
|
|
||||||
For `react-native` < `0.74` you need to add config in `react-native.config.js` file.
|
You can use this library with the New Architecture by enabling the Interop Layer.
|
||||||
|
|
||||||
|
### Requirements:
|
||||||
|
- `react-native` **>= 0.72.0**
|
||||||
|
- `react-native-video` **>= 6.0.0-beta.5**
|
||||||
|
|
||||||
|
For `react-native` versions **< 0.74**, you need to add the following configuration in the `react-native.config.js` file:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
module.exports = {
|
module.exports = {
|
||||||
@@ -22,4 +28,5 @@ module.exports = {
|
|||||||
```
|
```
|
||||||
|
|
||||||
## Bridgeless Mode
|
## Bridgeless Mode
|
||||||
Library currently does not support Bridgeless Mode. We are working on it.
|
|
||||||
|
The library currently does not support Bridgeless Mode. We are working on adding support.
|
||||||
|
|||||||
@@ -1,115 +1,120 @@
|
|||||||
# Plugin (experimental)
|
# Plugin
|
||||||
|
|
||||||
Since Version 6.4.0, it is possible to create plugins for analytics management and maybe much more.
|
Since version `6.4.0`, it is possible to create plugins for analytics management and potentially more.
|
||||||
A sample plugin is available in the repository in: example/react-native-video-plugin-sample. (important FIXME, put sample link)
|
A sample plugin is available in the repository: [example/react-native-video-plugin-sample](https://github.com/TheWidlarzGroup/react-native-video/tree/master/examples/react-native-video-plugin-sample).
|
||||||
|
|
||||||
## Concept
|
## Commercial Plugins
|
||||||
|
|
||||||
Most of the analytics system which tracks player information (bitrate, errors, ...) can be integrated directly with Exoplayer or AVPlayer handles.
|
We at The Widlarz Group have created a set of plugins for comprehensive offline video support. If you are interested, check out our [Offline Video SDK](https://www.thewidlarzgroup.com/offline-video-sdk/?utm_source=rnv&utm_medium=docs&utm_campaign=plugins&utm_id=text). If you need additional plugins (analytics, processing, etc.), let us know.
|
||||||
|
|
||||||
This plugin system allows none intrusive integration of analytics in the react-native-package. It shall be done in native language (kotlin/swift).
|
> Using or recommending our commercial software helps support the maintenance of this open-source project. Thank you!
|
||||||
|
|
||||||
The idea behind this system is to be able to plug an analytics package to react native video without doing any code change (ideally).
|
## Plugins for Analytics
|
||||||
|
|
||||||
Following documentation will show on how to create a new plugin for react native video
|
Most analytics systems that track player data (e.g., bitrate, errors) can be integrated directly with ExoPlayer or AVPlayer.
|
||||||
|
This plugin system allows for non-intrusive analytics integration with `react-native-video`. It should be implemented in native languages (Kotlin/Swift) to ensure efficiency.
|
||||||
|
|
||||||
## Warning and consideration
|
The goal is to enable easy analytics integration without modifying `react-native-video` itself.
|
||||||
This is an experiental API, it is subject to change. The api with player is very simple but should be flexible enough to implement analytics system. If you need some metadata, you should implement setter in the new package you are creating.
|
|
||||||
|
|
||||||
As api is flexible, it makes possible to missuse the system. It is necessary to consider the player handle as read-only. If you modify player behavior, we cannot garanty the good behavior of react-native-video package.
|
## Warnings & Considerations
|
||||||
|
|
||||||
## General
|
This is an **experimental API** and may change over time. The API is simple yet flexible enough to implement analytics systems.
|
||||||
|
If additional metadata is needed, you should implement a setter in your custom package.
|
||||||
|
|
||||||
First you need to create a new react native package:
|
Since the API is flexible, misuse is possible. The player handle should be treated as **read-only**. Modifying player behavior may cause unexpected issues in `react-native-video`.
|
||||||
````shell
|
|
||||||
|
## General Setup
|
||||||
|
|
||||||
|
First, create a new React Native package:
|
||||||
|
|
||||||
|
```shell
|
||||||
npx create-react-native-library@latest react-native-video-custom-analytics
|
npx create-react-native-library@latest react-native-video-custom-analytics
|
||||||
````
|
```
|
||||||
|
|
||||||
Both android and iOS implementation expose an interface `RNVPlugin`.
|
Both Android and iOS implementations expose an `RNVPlugin` interface.
|
||||||
Your `react-native-video-custom-analytics` shall implement this interface and register itself as a plugin for react native video.
|
Your `react-native-video-custom-analytics` package should implement this interface and register itself as a plugin for `react-native-video`.
|
||||||
|
|
||||||
## Android
|
## Android Implementation
|
||||||
There is no special requierement for gradle file.
|
|
||||||
You need two mandatory action to be able to receive player handle
|
|
||||||
|
|
||||||
### 1/ Create the plugin
|
### 1. Create the Plugin
|
||||||
|
|
||||||
First you should instanciate a class which extends `RNVPlugin`.
|
First, instantiate a class that extends `RNVPlugin`.
|
||||||
|
|
||||||
The proposed integration implement `RNVPlugin` directly inside the Module file (`VideoPluginSampleModule`).
|
The recommended approach is to implement `RNVPlugin` inside the Module file (`VideoPluginSampleModule`).
|
||||||
|
|
||||||
The `RNVPlugin` interface only defines 2 functions, see description here under.
|
The `RNVPlugin` interface defines two functions:
|
||||||
|
|
||||||
```kotlin
|
```kotlin
|
||||||
/**
|
/**
|
||||||
* Function called when a new player is created
|
* Called when a new player instance is created.
|
||||||
* @param id: a random string identifying the player
|
* @param id: A unique identifier for the player instance.
|
||||||
* @param player: the instantiated player reference
|
* @param player: The instantiated player reference.
|
||||||
*/
|
*/
|
||||||
fun onInstanceCreated(id: String, player: Any)
|
fun onInstanceCreated(id: String, player: Any)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function called when a player should be destroyed
|
* Called when a player instance should be destroyed.
|
||||||
* when this callback is called, the plugin shall free all
|
* The plugin should free resources and release all references to the player object.
|
||||||
* resources and release all reference to Player object
|
* @param id: A unique identifier for the player instance.
|
||||||
* @param id: a random string identifying the player
|
* @param player: The player to release.
|
||||||
* @param player: the player to release
|
|
||||||
*/
|
*/
|
||||||
fun onInstanceRemoved(id: String, player: Any)
|
fun onInstanceRemoved(id: String, player: Any)
|
||||||
````
|
```
|
||||||
|
|
||||||
### 2/ register the plugin
|
### 2. Register the Plugin
|
||||||
|
|
||||||
To register this allocated class in the main react native video package you should call following function:
|
To register the plugin within the main `react-native-video` package, call:
|
||||||
|
|
||||||
```kotlin
|
```kotlin
|
||||||
ReactNativeVideoManager.getInstance().registerPlugin(plugin)
|
ReactNativeVideoManager.getInstance().registerPlugin(plugin)
|
||||||
```
|
```
|
||||||
The proposed integration register the instanciated class in `createNativeModules` entry point.
|
|
||||||
|
|
||||||
Your native module can now track Player updates directly from Player reference and report to backend.
|
In the sample implementation, the plugin is registered in the `createNativeModules` entry point.
|
||||||
|
|
||||||
## ios
|
Once registered, your module can track player updates and report analytics data.
|
||||||
|
|
||||||
### 1/ podspec integration
|
## iOS Implementation
|
||||||
|
|
||||||
Your new module shall be able to access to react-native-video package, then we must declare it as a dependency of the new module you are creating.
|
### 1. Podspec Integration
|
||||||
|
|
||||||
|
Your new module must have access to `react-native-video`. Add it as a dependency in your Podspec file:
|
||||||
|
|
||||||
```podfile
|
```podfile
|
||||||
s.dependency "react-native-video"
|
s.dependency "react-native-video"
|
||||||
````
|
```
|
||||||
|
|
||||||
### 2/ Create the plugin
|
### 2. Create the Plugin
|
||||||
|
|
||||||
First you should instanciate a class which extends `RNVPlugin`.
|
Instantiate a class that extends `RNVPlugin`.
|
||||||
|
|
||||||
The proposed integration implement `RNVPlugin` directly inside the entry point of the module file (`VideoPluginSample`).
|
The recommended approach is to implement `RNVPlugin` inside the entry point module file (`VideoPluginSample`).
|
||||||
|
|
||||||
The `RNVPlugin` interface only defines 2 functions, see description here under.
|
The `RNVPlugin` interface defines two functions:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
/**
|
/**
|
||||||
* Function called when a new player is created
|
* Called when a new player instance is created.
|
||||||
* @param player: the instantiated player reference
|
* @param player: The instantiated player reference.
|
||||||
*/
|
*/
|
||||||
func onInstanceCreated(player: Any)
|
func onInstanceCreated(player: Any)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function called when a player should be destroyed
|
* Called when a player instance should be destroyed.
|
||||||
* when this callback is called, the plugin shall free all
|
* The plugin should free resources and release all references to the player object.
|
||||||
* resources and release all reference to Player object
|
* @param player: The player to release.
|
||||||
* @param player: the player to release
|
|
||||||
*/
|
*/
|
||||||
func onInstanceRemoved(player: Any)
|
func onInstanceRemoved(player: Any)
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3/ Register the plugin
|
### 3. Register the Plugin
|
||||||
|
|
||||||
To register this allocated class in the main react native video package you should register it by calling this function:
|
To register the plugin in `react-native-video`, call:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
ReactNativeVideoManager.shared.registerPlugin(plugin: plugin)
|
ReactNativeVideoManager.shared.registerPlugin(plugin: plugin)
|
||||||
```
|
```
|
||||||
|
|
||||||
The proposed integration register the instanciated class in file `VideoPluginSample` in the init function:
|
In the sample implementation, the plugin is registered inside the `VideoPluginSample` file within the `init` function:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
import react_native_video
|
import react_native_video
|
||||||
@@ -122,4 +127,4 @@ override init() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Your native module can now track Player updates directly from Player reference and report to backend.
|
Once registered, your module can track player updates and report analytics data to your backend.
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
# Useful projects
|
# Useful Projects
|
||||||
This page links other open source projects which can be useful for your player implementation. <br>
|
|
||||||
If you have a project which can be useful for other users, feel free to open a PR to add it here.
|
|
||||||
|
|
||||||
## Our (TheWidlarzGroup) libraries
|
This page lists open-source projects that can be helpful for your player implementation. <br>
|
||||||
- [react-native-video-player](https://github.com/TheWidlarzGroup/react-native-video-player): Our video player UI library
|
If you have a project that could benefit other users, feel free to open a PR to add it here.
|
||||||
|
|
||||||
|
## Our (TheWidlarzGroup) Libraries
|
||||||
|
- [react-native-video-player](https://github.com/TheWidlarzGroup/react-native-video-player): Our video player UI library.
|
||||||
|
|
||||||
|
## Community Libraries
|
||||||
|
- [react-native-corner-video](https://github.com/Lg0gs/react-native-corner-video): A floating video player.
|
||||||
|
- [react-native-track-player](https://github.com/doublesymmetry/react-native-track-player): A toolbox for audio playback.
|
||||||
|
- [react-native-video-controls](https://github.com/itsnubix/react-native-video-controls): A video player UI.
|
||||||
|
- [react-native-media-console](https://github.com/criszz77/react-native-media-console): An updated version of react-native-video-controls, rewritten in TypeScript.
|
||||||
|
|
||||||
## Community libraries
|
|
||||||
- [react-native-corner-video](https://github.com/Lg0gs/react-native-corner-video): A floating video player
|
|
||||||
- [react-native-track-player](https://github.com/doublesymmetry/react-native-track-player): A toolbox for audio playback
|
|
||||||
- [react-native-video-controls](https://github.com/itsnubix/react-native-video-controls): Video player UI
|
|
||||||
- [react-native-media-console](https://github.com/criszz77/react-native-media-console): React-native-video-controls updated and rewritten in typescript
|
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
# Updating
|
# Updating
|
||||||
|
|
||||||
### Version 6.0.0
|
## Version 6.0.0
|
||||||
|
|
||||||
#### iOS
|
### iOS
|
||||||
|
|
||||||
##### Min iOS version
|
#### Minimum iOS Version
|
||||||
From version 6.0.0, the minimum iOS version supported is 13.0. Projects that are using `react-native < 0.73` will need to set the minimum iOS version to 13.0 in the Podfile.
|
Starting from version 6.0.0, the minimum supported iOS version is 13.0. Projects using `react-native < 0.73` must set the minimum iOS version to 13.0 in the Podfile.
|
||||||
|
|
||||||
|
You can do this by adding the following code to your Podfile:
|
||||||
|
|
||||||
You can do it by adding the following code to your Podfile:
|
|
||||||
```diff
|
```diff
|
||||||
- platform :ios, min_ios_version_supported
|
- platform :ios, min_ios_version_supported
|
||||||
|
|
||||||
@@ -17,16 +18,16 @@ You can do it by adding the following code to your Podfile:
|
|||||||
+ end
|
+ end
|
||||||
```
|
```
|
||||||
|
|
||||||
##### linking
|
#### Linking
|
||||||
In your project Podfile add support for static dependency linking. This is required to support the new Promises subdependency in the iOS swift conversion.
|
In your project's Podfile, add support for static dependency linking. This is required to support the new Promises subdependency in the iOS Swift conversion.
|
||||||
|
|
||||||
Add `use_frameworks! :linkage => :static` just under `platform :ios` in your ios project Podfile.
|
Add `use_frameworks! :linkage => :static` right below `platform :ios` in your iOS project Podfile.
|
||||||
|
|
||||||
[See the example ios project for reference](https://github.com/TheWidlarzGroup/react-native-video/blob/master/examples/basic/ios/Podfile#L5)
|
[See the example iOS project for reference](https://github.com/TheWidlarzGroup/react-native-video/blob/master/examples/basic/ios/Podfile#L5).
|
||||||
|
|
||||||
##### podspec
|
#### Podspec
|
||||||
|
|
||||||
You can remove following lines from your podfile as they are not necessary anymore
|
You can remove the following lines from your Podfile as they are no longer needed:
|
||||||
|
|
||||||
```diff
|
```diff
|
||||||
- `pod 'react-native-video', :path => '../node_modules/react-native-video/react-native-video.podspec'`
|
- `pod 'react-native-video', :path => '../node_modules/react-native-video/react-native-video.podspec'`
|
||||||
@@ -34,19 +35,20 @@ You can remove following lines from your podfile as they are not necessary anymo
|
|||||||
- `pod 'react-native-video/VideoCaching', :path => '../node_modules/react-native-video/react-native-video.podspec'`
|
- `pod 'react-native-video/VideoCaching', :path => '../node_modules/react-native-video/react-native-video.podspec'`
|
||||||
```
|
```
|
||||||
|
|
||||||
If you were previously using VideoCaching, you should $RNVideoUseVideoCaching flag in your podspec, see: [installation section](https://docs.thewidlarzgroup.com/react-native-video/installation#video-caching)
|
If you were previously using VideoCaching, you should set the `$RNVideoUseVideoCaching` flag in your Podspec. See the [installation section](https://docs.thewidlarzgroup.com/react-native-video/installation#video-caching) for details.
|
||||||
|
|
||||||
#### Android
|
### Android
|
||||||
|
|
||||||
If you are already using Exoplayer on V5, you should remove the patch done from **android/settings.gradle**
|
If you were using ExoPlayer on V5, remove the patch from **android/settings.gradle**:
|
||||||
|
|
||||||
```diff
|
```diff
|
||||||
- include ':react-native-video'
|
- include ':react-native-video'
|
||||||
- project(':react-native-video').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-video/android-exoplayer')
|
- project(':react-native-video').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-video/android-exoplayer')
|
||||||
``````
|
```
|
||||||
|
|
||||||
|
#### Using App Build Settings
|
||||||
|
You need to create a `project.ext` section in the top-level `build.gradle` file (not `app/build.gradle`). Fill in the values from the example below using the ones found in your `app/build.gradle` file.
|
||||||
|
|
||||||
##### Using app build settings
|
|
||||||
You will need to create a `project.ext` section in the top-level build.gradle file (not app/build.gradle). Fill in the values from the example below using the values found in your app/build.gradle file.
|
|
||||||
```groovy
|
```groovy
|
||||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
|
|
||||||
@@ -66,4 +68,5 @@ allprojects {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
If you encounter an error `Could not find com.android.support:support-annotations:27.0.0.` reinstall your Android Support Repository.
|
|
||||||
|
If you encounter the error `Could not find com.android.support:support-annotations:27.0.0.`, reinstall your Android Support Repository.
|
||||||
|
|||||||
@@ -68,7 +68,8 @@ export default {
|
|||||||
footer: {
|
footer: {
|
||||||
text: (
|
text: (
|
||||||
<span>
|
<span>
|
||||||
Built with ❤️ by <strong>React Native Community</strong>
|
Built with ❤️ by <strong>TheWidlarzGroup</strong> &{' '}
|
||||||
|
<strong>React Native Community</strong>
|
||||||
</span>
|
</span>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user