Website Integration

Because every game exposes Genvid differently, every game requires a customized website. This includes both the skinning aspect (HTML and CSS) as well as the functional side (JavaScript). Developers will also need to run a web server hosting the web application that is running in the browser.

Since there are multiple ways of creating websites, we will only focus on steps that are common to the Genvid SDK. But luckily, these steps are simple.

Backend integration

The web client of Genvid needs to access a single service, called the leaf, which provides a websocket server from which the client will access the game data. To get the connection URL for this service, two web requests must be sent to the Disco service API:

Since those API use a secret code for protection, it is recommended that they should only be called from a trusted website. In the tutorial website, we route them inside the routes/streams.t.ts file to /streams and /channels/join URL respectively.

The disco service is registered with Consul and you can find its URL this way.

Note

Future versions of the API will expose more API for authenticating the user with a third party service and using this authentication for assigning the websocket, which is the main reason why this API is protected. For now, this functionality is disabled and no authentication is done in this version.

Commands integration

The command service gives the possibility to send command directly to the game. This is useful for an admin website. To send commands you can refer to the Command service API:

Frontend integration

The first step in integrating Genvid into your frontend is to simply instantiate a IGenvidClient() object using the createGenvidClient():

let client = genvid.createGenvidClient(streamInfo, websocketURL, websocketToken, video_player_id);

You need to specify 3 parameters.

The first parameter corresponds to an IStreamInfo() structure, typically returned by the backend service from the GET /disco/stream/info call.

The next 2 parameters, websocketURL and websocketToken, are the two values specifying the websocket address and security token, respectively. They are provided by the backend through the POST /disco/stream/join call.

The last parameter, video_player_id, is a string referencing an HTML element that you want to use for the live streaming video player. When the IGenvidClient creates the video player, it will replace this HTML element with the one from the live streaming service.

onVideoPlayerReady callback

When the player is created, the IGenvidClient will call whatever function was specified using IGenvidClient.onVideoPlayerReady(). This is typically used to hook up the overlay.

client.onVideoPlayerReady( function(elem) { console.log('Create the overlay!'); } );

onAuthenticated callback

Should the user need to know when the IGenvidClient successfully connects to the Genvid Services, it should register an IGenvidClient.onAuthenticated() callback:

client.onAuthenticated( function(succeed) { if (succeeded) { console.log('Connected!'); } });

onStreamReceived callback

In order to know when new stream data is received, the IGenvidClient.onStreamReceived() can be used. This callback is useful to decode or analyze the data before it is rendered.

client.onStreamReceived((streams) => { myGameOverlay.onStreamReceived(streams); });

onNotificationsReceived callback

Notifications are used to transfer information as fast as possible and are not related to a timecode. They are describe with the IDataNotifications() interface.

client.onNotificationsReceived((notifications) => { myGameOverlay.onNotificationsReceived(notifications); });

onDraw callback

An important callback to set is the IGenvidClient.onDraw() member, which specifies a routine to call regularly (currently, 30 times per second) in order to draw the overlay:

client.onDraw((frame) => { myGameOverlay.onDraw(frame); });

When that draw callback is invoked, it will receive, as a parameter, an IDataFrame() instance containing the timecode for this video frame as well as a map of streams and annotations.

Streams and annotation behave differently but are describe with the same structure. IDataStreamFrame()

The current streams will contain only the latest frame for each, while the annotations will hold all of the previous ones accumulated so far, and they will not get repeated next time.

Genvid carries data in binary form, in a field called rawdata, which is a JavaScript ArrayBuffer. Developers are responsible for interpreting that data as they please, but Genvid provides a few utility routines which can help decoding.

For example, if the game sends JSON data encoded as UTF-8, the website code will need to decode the rawdata binary field as UTF-8, and then parse that resulting string as JSON, e.g.:

onDraw(frame) {
   let stream = frame.streams["position"]
   let datastr = genvid.UTF8ToString(frame.rawdata);
   stream.user = JSON.parse(datastr);
   console.log(stream.user.myPosition);
}

Because Genvid can sometimes repeat some data (e.g., when a stream has a very low framerate value), it might be suboptimal to decode identical data multiple times. For that reason, the IGenvidClient also have an IGenvidClient.onStreamReceived() which get a pass a IDataStreams() collection upon reception of the data. The data streams contains a collection of streams and their frames and you are free to modify any of them before they get integrate into the Genvid synchronization engine. You can, for example parse them immediately and detect an event to come, or simply remove them.

Note that the function could be modified to decode differently based on the streamId. Developers must simply be consistent with whatever format they used when sending data from the game process (see Game Data Streaming).

Once everything is ready in the game’s website code, you can the officially start the GenvidClient’s streaming:

client.start();

From now on, the IGenvidClient will now automatically call configured callbacks and will handle synchronization between the streaming video and the game data sent in the onDraw.

Overlay

While Genvid doesn’t provide a strict overlay API, it does expose everything necessary in the IGenvidClient for the overlay to work. We also expose WebGL utility routines which we use for all of our samples.

The main entry point to the overlay is the callback set using IGenvidClient.onDraw(). On regular intervals, the specified callback will get invoked, with a frame of data for all of the streams existing in the game.

This callback will receive the latest game data frame for every stream. The developer then has full control of what to do with that data: render some 3D highlight in a WebGL canvas, tweak HTML elements to display current game stats, adjust button visibility to allow new game events from the spectator, etc.

To facilitate WebGL rendering, Genvid provides a IWebGLContext() class which is meant to simplify repetitive tasks in WebGL. You can create it with createWebGlContext() method.

Events

You can send events back to the Genvid Services through the IGenvidClient instance. See IGenvidClient.sendEvent() and IGenvidClient.sendEventObject() for details.