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.