Docs menu
Web SDK
On this page
@rerinku/player is the web part of the Rerinku View SDK: plain TypeScript with no dependency on any front-end framework, open source under Apache-2.0.
OnboardClient: a client for Rerinku View’s open API. It handles devices, streams, thumbnails, runtime status and WebRTC signaling.RerinkuPlayer: plays a device’s live video (WebRTC) or recordings (HLS) on a<video>you provide, and reconnects automatically after a disconnect. It has no UI of its own. Its status comes as DOM events, and you use it the same way as anHTMLMediaElement.@rerinku/player/engine: the low-level engines, for cases where you manage signaling and lifecycle yourself.
Installation
npm install @rerinku/player
The ES modules and type definitions are about 10 KB (gzip). hls.js is loaded on demand, only when a recording plays. Pages without a bundler can load the IIFE build directly. It adds a global object, Rerinku:
<script src="https://unpkg.com/@rerinku/player/dist/rerinku-player.iife.js"></script>
Quick start
import { OnboardClient, RerinkuPlayer } from "@rerinku/player";
// 1. Connect to a Rerinku View. A view token is read-only, so it can go in a public web page.
const client = new OnboardClient({
baseUrl: "https://n1234.nodes.rerinku.com",
token: "<view token>",
});
// 2. Create a player on a <video>. It sets the element to muted autoplay.
const video = document.querySelector("video")!;
const player = new RerinkuPlayer(video, { client });
player.addEventListener("statuschange", (e) => console.log(e.detail.state));
// 3. Pick a device and start playing. load() resolves on the first frame; after a disconnect, the player reconnects by itself.
const devices = await client.listDevices();
await player.load({ kind: "live", device: devices[0] });
// When you no longer need it
player.destroy();
Without a bundler, the code is exactly the same, except that the classes come from the global object:
<video muted playsinline autoplay></video>
<script src="https://unpkg.com/@rerinku/player/dist/rerinku-player.iife.js"></script>
<script>
const { OnboardClient, RerinkuPlayer } = Rerinku;
const client = new OnboardClient({ baseUrl: "https://n1234.nodes.rerinku.com", token: "<view token>" });
const player = new RerinkuPlayer(document.querySelector("video"), { client });
client.listDevices().then((devices) => player.load({ kind: "live", device: devices[0] }));
</script>
examples/quickstart/ in the SDK repository has a complete web page version (index.html, with camera switching and a status display; just open it) and a TypeScript version (main.ts).
Authentication
Web pages on any website can call Rerinku View across origins, but requests from other websites must carry a token:
- Public web pages (a demo on an official website, a store display screen, your own website): generate a read-only view token under Settings → Developer in Rerinku View and pass it as
token. Don’t calllogin(). A view token can only list devices (with sensitive fields removed), fetch thumbnails, read runtime status and pull live video. - Server-side programs and native apps: call
client.login(password)to bind, just like the mobile app. No password is needed when Rerinku View has no access password. - Web pages on other websites can get a full token through
login()only when Rerinku View has an access password set.
The token is kept only in memory; whether to persist it is up to you. Pass it in with token when you construct the client, and listen for the tokenchange event. It fires on login, on logout, and when the server determines that the token has been revoked.
const client = new OnboardClient({ baseUrl: "http://192.168.1.10:8080", token: saved });
client.addEventListener("tokenchange", (e) => save(e.detail)); // e.detail is null after revocation
if (!client.token) {
await client.login("", { name: "Store dashboard", installId: "dash-0001" }); // pass the access password if one is set
}
Logging in again with the same installId only replaces the token; it doesn’t add another authorization. Every token is listed under Settings → Developer → Authorized apps, where you can revoke it at any time.
OnboardClient
new OnboardClient({ baseUrl, token, fetch })
| Option | Description |
|---|---|
baseUrl |
Rerinku View’s address, such as https://n1234.nodes.rerinku.com. An empty string means the same origin as the page |
token |
A token from an earlier login, or a view token |
fetch |
A custom fetch (for tests and server-side rendering) |
Every method returns a Promise, and every method accepts { signal } (an AbortSignal) as its last argument for cancellation. Failed requests throw OnboardAPIError (with status and code, such as invalid_token). Failed signaling throws SignalingError.
| Method | Description |
|---|---|
getInfo() |
The server’s ID, name and API version; needs no token |
login(password, { name, installId, appVersion }) |
Exchanges the access password for a token |
logout() |
Revokes the current token |
listDevices() |
The device list, OnboardDevice[] |
listStreams(deviceId) |
The device’s streams (main stream, sub-stream, channels) |
getThumbnail(deviceId) |
The thumbnail JPEG as a Blob. <img> can’t carry a token, so display it with URL.createObjectURL |
getRuntime(deviceId) |
The device’s current runtime status (tempC, cpuPct and so on). The platform reuses the result for the same device within 2 seconds, so don’t poll faster than that |
getIceServers() |
STUN/TURN for live video. The credentials expire, so don’t cache them for long |
sendOffer(deviceId, sdp, { streamId }) |
WebRTC signaling: submits an offer and returns the answer |
Properties: baseUrl, token (assignable). Event: tokenchange (detail is the new token or null).
RerinkuPlayer
new RerinkuPlayer(video, { client, manageVideo })
| Option | Description |
|---|---|
client |
An OnboardClient, or any object that implements sendOffer and getIceServers. Required for live video |
manageVideo |
Default true: sets the element to muted, inline and autoplay (browsers only allow muted autoplay). Pass false to leave the element completely alone |
| Member | Description |
|---|---|
load(source) |
Plays { kind: "live", device, streamId? } or { kind: "hls", url }. Pass null to stop |
unload() |
Stops playback and releases the connection |
retry() |
Reconnects right away: while waiting for an offline device, or after a retryable error |
destroy() |
Releases all resources |
status |
The current status, a PlayerStatus |
source |
The source passed to the most recent load() |
load() resolves when the first frame appears on screen. It rejects with a PlayerError when the player stops on an error, and with a DOMException named AbortError when it’s interrupted by a new load(), unload() or destroy(). While a live source is waiting for an offline device, the Promise stays pending; follow statuschange during that time.
| Event | detail |
|---|---|
statuschange |
The new PlayerStatus |
stats |
Live connection statistics, LiveConnectionStats (about every 2 seconds); null when it ends |
error |
PlayerError (code, detail, retryable) |
streamId picks one of the device’s streams, such as a lower-resolution sub-stream. Without it, the device’s default stream plays. Before every reconnection, the player fetches TURN credentials again.
Playback status
state |
Meaning |
|---|---|
idle |
No source |
connecting |
Setting up the connection; code says what it’s waiting for |
playing |
Video is on screen |
offline |
Reconnecting automatically. reason is device (the server confirmed the device is offline) or network. There are also retryInMs and attempt |
error |
Needs handling. retryable says whether retry() can recover |
message is an English fallback text. To localize, choose your own text by code:
code |
Meaning |
|---|---|
connecting, waiting_frame, waiting_keyframe |
Setting up the connection, waiting for video |
stalled |
The stream stopped after video had played; the picture stays on the last frame |
relay_switch |
The direct connection is poor; switching to the cloud relay |
no_signaling |
No client was provided |
signaling_rejected |
The server rejected this session; detail is the server’s error code |
codec_unsupported |
The browser doesn’t support this codec; detail is the codec name |
h265_unsupported |
The browser has no WebRTC H.265 decoding (Safari has it; Chrome needs hardware decoding) |
hls_failed, hls_media_failed, hls_unsupported, hls_player_load_failed |
Recording playback failed |
Browsers and limitations
- Live video needs a modern browser with WebRTC support. H.264 plays in every browser. H.265 depends on the browser’s WebRTC decoding; the SDK checks before connecting and reports
h265_unsupportedright away when it isn’t supported, instead of pulling a stream for nothing. - Video is muted and autoplays by default. If you need sound, unmute it after a user action.
- Recording (HLS) URLs must come from your own backend, which also handles authentication: HLS requests in the browser can’t carry an
Authorizationheader.
Low-level engines
@rerinku/player/engine exports createWebRTCEngine(video, source, callbacks, options) and createHLSEngine(video, source, callbacks). One engine handles one session. Signaling is injected through options.offer, and status comes back through callbacks. RerinkuPlayer is built on them; you only need them if you manage signaling and lifecycle yourself.