OV Web RTC Library v6.7.0#

This package provides functionality for managing Omniverse Kit applications streaming from GFN, on a local machine, or from a container instance with a provided URL.

Versioned documentation: The complete API documentation is bundled with the published package. To read the docs that match the version you have installed, open node_modules/@nvidia/ov-web-rtc/docs/index.html in a browser after installing.

Usage#

The AppStreamer class is the main entry point into this library. You can use it to connect to, pause, unpause, and terminate a streaming Omniverse Kit application session. You can also use it to send and receive custom messages to and from the streaming Kit application. The Kit application can stream from GFN, NVCF, OVC, or an ad hoc development environment.

Scoping NPM#

The correct scope must be defined in your .npmrc file before installing.

@nvidia:registry=https://edge.urm.nvidia.com/artifactory/api/npm/omniverse-client-npm/

Installation#

npm install @nvidia/ov-web-rtc

Importing#

import { AppStreamer } from '@nvidia/ov-web-rtc'

GFN#

If connecting to an application running on GFN, you must import GFN separately. The recommended method to import GFN into a project is by sourcing the CDN in the project index.html file, as shown below:

<!DOCTYPE html>
<html lang="en">
    <body>
        <script src="https://sdk.nvidia.com/gfn/client-sdk/1.x/gfn-client-sdk.js"></script>
    </body>
</html>

Creating an AppStreamer#

Construct an AppStreamer instance and drive the session through its lifecycle methods — connect, start, stop, terminate — plus sendMessage for custom messages:

const stream = new AppStreamer();

Each instance owns its own underlying stream. The examples below use this stream instance.

The static form (AppStreamer.connect(...), AppStreamer.terminate(), and so on) is deprecated but still works for backward compatibility: it forwards to a single shared instance — race-prone when more than one stream is active — and each call logs a one-time deprecation warning. It will be removed in a future major release. Construct an instance with new AppStreamer() instead.

Examples#

Connecting#

The following code examples illustrate how to manage streaming connections directly to a container, as well as infrastructure environments such as GFN and NVCF.

Set up the Configuration#

Direct Configuration#

Configuration for a Kit application running in a directly accessible container, either local or remote:

// This example server is localhost, but can be a valid remote IP as well.

const streamParams: DirectConfig = {
    streamSource : StreamType.DIRECT,
    logLevel     : LogLevel.WARN,
    streamConfig : {
        server        : '<some ip address>',
        width         : 1920,
        height        : 1028,
        fps           : 60,
        onStart       : (message: StreamEvent) => {console.info('Stream started')},
        onStop        : (message: StreamEvent) => {console.info('Stream stopped')},
        onStreamStats : (message: StreamEvent) => {console.info('Stream stats')}
    }
};
Configure NVCF#

Configuration for a Kit application running on NVCF:

// This example server is localhost, but can be a valid remote IP as well.

const streamParams: NVCFConfig = {
    streamSource : StreamType.NVCF,
    logLevel     : LogLevel.WARN,
    streamConfig : {
        signalingPort   : <some port number>
        signalingServer : '<some URL>',
        signalingPath   : '<some path>'
        signalingQuery  : ''<some query>'
        width           : 1920,
        height          : 1028,
        fps             : 60,
        onStart         : (message: StreamEvent) => {console.info('Stream started')},
        onStop          : (message: StreamEvent) => {console.info('Stream stopped')},
        onStreamStats   : (message: StatsEvent) => {console.info('Stream stats')}
    }
};
Configure GFN#

Configuration for a Kit app running on GFN:

const streamParams: GFNConfig = {
    streamSource : StreamType.GFN,
    logLevel     : LogLevel.WARN,
    streamConfig : {
        // GFN will be resolved by the script source discussed above.
        GFN             : GFN,
        catalogClientId : <your value>,
        clientId        : <your value>,
        cmsId           : <your value>,
        onStart         : (message: StreamEvent) => {console.info('Stream started')},
        onStop          : (message: StreamEvent) => {console.info('Stream stopped')},
        onStreamStats   : (message: StreamEvent) => {console.info('Stream stats')}
    }
};

Connect & Disconnect#

Connect using Config params#

The library supports connections to Kit applications streaming from multiple infrastructure options. The options are of type StreamType. They allow you to change which infrastructure to connect to with only minor edits to the configuration. Below are examples of configurations for each streaming type.

Using the streamParams config:

stream.connect(streamParams)
    .then((result: StreamEvent) => {
       // The connection request was successful. The onStart
       // callback will fire when the stream is ready.
       console.info(result);
    })
    .catch((error: StreamEvent) => {
       // The connection request has failed.
       console.error(error);
    });
Disconnect#

Call terminate() on the same instance you connected with:

stream.terminate()
    .then((result: StreamEvent) => {
          // Request has been made successfully. The onStop
          // callback will fire when termination is complete.
          console.info(result));
    })
    .catch((error: StreamEvent) => {
          // The terminate request has failed.
          console.error(error));
    });

Callbacks#

All of the callbacks are optional, but there are a few that are very helpful.

onStreamStatusChange()#

Use onStreamStatusChange for lifecycle updates. The callback receives the new StreamStatus; use stream.streamStatus when you only need the current value. onUpdate reports operation events and does not cover every status transition.

onStreamStatusChange: (status: StreamStatus) => {
    console.log('Stream status:', StreamStatus[status]);
}

During connection retries, the reported status remains STARTING until the stream connects or all retry attempts fail.

onStart()#

Define your onStart callback in streamParams to determine the success of the connection request.

onStart(message: StreamEvent) : void {
    if ( message.status === EventStatus.SUCCESS ) {
        // The stream is connected and ready.
        console.info('onStart:', message));
    }
    else if ( message.status === EventStatus.WARNING ) {
        // There may be an issue with the stream connection.
        console.warn('onStart:', message));
    }
    else if ( message.status === EventStatus.ERROR ) {
        // The connection has failed.
        console.info('onStart:', message));
    }
}

onStop()#

Define your onStop callback message to determine unexpected and successful stream disconnections.

onStop(message: StreamEvent) : void {
    if ( message.action === EventAction.TERMINATE &&
          message.status === EventStatus.ERROR ) {
          // The connected stream has been disconnected unexpectedly.
          console.error('onStop:', message));
    }
    else if ( message.action === EventAction.TERMINATE &&
                message.status === EventStatus.SUCCESS ) {
          // A request to disconnect the stream was successful -
          // the stream has been disconnected.
          console.info('onStop:', message));
    }
}

onStreamStats()#

The onStreamStats callback, if passed, will be called at regular intervals to provide information and performance metrics about the connected stream.

onStreamStats(message: StatsEvent) : void {
    console.info('Stream stats:', message.stats);
}

Cursor Support#

When connected to a Kit app that uses cursor changes to communicate tool state — for example, a crosshair for a selection tool or an I-beam over text inputs — the SDK automatically reflects the Kit cursor on the stream viewport element. No configuration is needed.

Standard Cursors#

The SDK maps the six standard Kit cursor shapes to CSS values and applies them to the <video> element. No onCursor callback is required.

Kit Name

CSS Value

Arrow

default

IBeam

text

Hand

pointer

Crosshair

crosshair

HorizontalResize

ew-resize

VerticalResize

ns-resize

Custom Cursors#

If your Kit app registers custom cursor shapes through omni.kit.window.cursor, wire the onCursor callback in DirectConfig. It receives a CursorChange object in which at least one field is always defined:

  • Standard cursor: { cursor: CursorType, kitCursorName?: string } — the SDK has already applied cursor to the viewport, so the callback is a notification and may override it.

  • Custom cursor: { kitCursorName: string }cursor is absent because there is no CSS mapping, so the SDK applied nothing and the caller must handle it.

import { AppStreamer, StreamType, type CursorChange } from '@nvidia/ov-web-rtc';

const video = document.getElementById('remote-video') as HTMLVideoElement;

const stream = new AppStreamer();
await stream.connect({
    streamSource: StreamType.DIRECT,
    streamConfig: {
        signalingServer: '...',
        onCursor: ({ cursor, kitCursorName }: CursorChange) => {
            if (cursor === undefined) {
                // Custom cursor - the SDK applied nothing, so handle it here.
                video.style.cursor = `url(/images/${kitCursorName}.png), auto`;
                return;
            }
            // Standard cursor - the SDK already applied it, and you may override it here.
        },
    },
});

The SDK always applies standard cursors automatically, whether or not onCursor is wired. Wire it only when you have custom cursors to handle.

Kit version requirements: cursor support requires omni.kit.livestream.webrtc v10.7.0, omni.kit.livestream.app v10.3.0, and omni.kit.renderer.imgui v2.2.0. On older Kit builds the feature is inactive and the viewport cursor stays at its default.