# react-native-omni
A library to have real players on android and web. It uses VLC on android and
videojs v10 on the web (ios not implemented yet, PR welcome)
## Features
- **vlc v4**: to support more codecs than exoplayer, hdr and so on
- **Adaptive streaming**: HLS out of the box, with automatic quality
(rendition) selection or manual override.
- **Multi-track playback**: enumerate and switch video, audio, and subtitle
tracks at runtime.
- **Rich subtitle support**: vtt, srt, ass (via [jassub](https://github.com/ThaUnknown/jassub)) and pgs (via [libpgs](https://github.com/Arcus92/libpgs-js))
- **Picture-in-Picture**: enter PiP automatically or on demand on Android.
- **Chromecast**: cast to a receiver on both web and Android .
- **and basic player stuff**: media sessions, playlists, hook based api...
## Installation
```bash
bun add react-native-omni react-native-nitro-modules
```
### Expo config plugin (Android)
The library ships an Expo config plugin that wires up media notifications and
picture-in-picture. Add it to your `app.json` / `app.config.js`:
```json
{
"expo": {
"plugins": ["react-native-omni"]
}
}
```
The plugin will:
- Register the `OmniPlayerService` media session service and add the
`FOREGROUND_SERVICE` / `FOREGROUND_SERVICE_MEDIA_PLAYBACK` permissions.
- Enable Picture-in-Picture on your `MainActivity` (declares
`supportsPictureInPicture`, adds the required `configChanges`, and hooks the
pip lifecycle callbacks).
- Register omni's Chromecast `OptionsProvider`
If you are not using Expo, replicate those manifest/activity changes manually.
### Web setup
Most features are available out of the box, you need custom steps for advanced
subtitles rendering:
ass rendering
#### Cross-origin isolation
jassub's wasm is multi-threaded and relies on `SharedArrayBuffer`, which
browsers only expose on a **cross-origin-isolated** page. Serve these response
headers on your HTML document:
```
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: credentialless
```
`credentialless` keeps cross-origin video/subtitle/font requests working without
requiring `Cross-Origin-Resource-Policy` headers on every remote asset. Without
isolation, JASSUB initializes but silently never renders.
## Quick start
Wrap your player UI in an `OmniProvider` with a `source`, then render an
`OmniView` and drive it with the hooks.
```tsx
import {
OmniProvider,
OmniView,
usePlayer,
usePlayerState,
useEvent,
} from "react-native-omni";
function Player() {
const player = usePlayer();
const isPlaying = usePlayerState("isPlaying");
const currentTime = usePlayerState("currentTime");
const duration = usePlayerState("duration");
useEvent("end", () => player.playNext());
return (
<>