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). You also need to run a web server hosting the web application for the browser.
Since there are multiple ways of creating websites, this section only covers steps common to the Genvid SDK.
Backend integration¶
The Genvid web client 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:
The APIs use a secret code for security, so they should only be called from a
trusted website. In the tutorial website, we route them inside the
routes/streams.t.ts
file to the /streams
and /channels/join
URLs,
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 enables sending commands directly to the game, which is useful for an admin website. See Command service API: for more information.
Frontend integration¶
The first step in integrating Genvid into your frontend is to instantiate a
genvid.IGenvidClient()
object using the
genvid.createGenvidClient()
:
let client = genvid.createGenvidClient(streamInfo, websocketURL, websocketToken, video_player_id);
The first parameter, streamInfo
, corresponds to an
genvid.IStreamInfo()
structure, typically returned by the backend
service from the GET /disco/stream/info
call.
The next two 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 you create the player, IGenvidClient()
calls the
function specified with genvid.IGenvidClient.onVideoPlayerReady()
.
This is typically used to hook up the overlay.
client.onVideoPlayerReady( function(elem) { console.log('Create the overlay!'); } );
onAuthenticated callback¶
The onAuthenticated()
callback tells the user
when the IGenvidClient()
successfully connects to the Genvid
Services:
client.onAuthenticated( function(succeed) { if (succeeded) { console.log('Connected!'); } });
onStreamsReceived callback¶
The onStreamsReceived()
callback tells you when
you recieve new stream data. It’s useful for decoding or analyzing the data
before it’s rendered.
client.onStreamsReceived((streams) => { myGameOverlay.onStreamsReceived(streams); });
onNotificationsReceived callback¶
Notifications transfer information as fast as possible and are not related to a
timecode. They are described with the IDataNotifications()
interface.
client.onNotificationsReceived((notifications) => { myGameOverlay.onNotificationsReceived(notifications); });
onDraw callback¶
The onDraw()
callback specifies a routine to call
regularly (generally 30 times per second) to draw the overlay:
client.onDraw((frame) => { myGameOverlay.onDraw(frame); });
When you invoke the onDraw()
callback, it
receives an genvid.IDataFrame()
instance as a parameter containing the
timecode for this video frame, the data coming from the different streams, and
information about the video composition. The frame data is organized in the
following ways:
- If you have several sources of data, you can obtain it inside the sessions property, which exposes streams and annotations data for each session.
- If you only have one stream, you can also access to the streams and annotations in the root of the IDataFrame instance.
Composition data (an array of genvid.ISourceCompositionData()
) is
information about what transformations were applied to the different video
streams. Some of the ways you can use it include knowing what pixel of the video
overlay matches which video source or to performing a clipping operation to
prevent an overlay related to one video source overlaying another video.
Streams and annotation behave differently but are both described with the
structure genvid.IDataStreamFrame()
.
The current streams contain only the latest frame for each while the annotations hold all of the previous frames accumulated so far and they will not get repeated next time.
Genvid carries data in binary form using the field rawdata
, which is a
JavaScript ArrayBuffer()
. You can interpret the data in any way, 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
needs to decode the rawdata
binary field as UTF-8, and then parse that
resulting string as JSON.
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 sometimes repeats data (for example, when a stream has a low
framerate value), we include a mechanism for avoiding decoding identical data
multiple times. The IGenvidClient()
includes an
onStreamsReceived()
which passes a
genvid.IDataStreams()
collection upon reception of the data. The data
streams contain a collection of video streams and their frames which you can
modify before they get integrated into the Genvid synchronization engine. For
example, parsing a collection to detect an upcoming event or removing the
collection entirely.
You could also modify the function to decode differently based on the streamId
, as long as you’re consistent with the format used when sending data from the game process (see Game-Data Streaming).
Once everything is ready in the game’s website code, you can start the GenvidClient streaming:
client.start();
The IGenvidClient()
automatically uses configured callbacks
and handles 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
onDraw()
. On regular intervals, the specified
callback is invoked, with a frame of data for all streams existing in the game.
This callback receives the latest game-data frame for every stream. You have full control of what to do with that data: render some 3D highlights 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
genvid.IWebGLContext()
class which simplifies repetitive tasks in
WebGL. You can create it with the genvid.createWebGLContext()
method.
Events¶
You can send events back to the Genvid Services through the
IGenvidClient()
instance. See
sendEvent()
and
sendEventObject()
for more information.