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 genvid.IGenvidClient()
object using the
genvid.createGenvidClient()
:
let client = genvid.createGenvidClient(streamInfo, websocketURL, websocketToken, video_player_id);
You need to specify 3 parameters.
The first parameter corresponds to an genvid.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 genvid.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
onAuthenticated()
callback:
client.onAuthenticated( function(succeed) { if (succeeded) { console.log('Connected!'); } });
onStreamsReceived callback¶
In order to know when new stream data is received, the
onStreamsReceived()
can be used. This callback is
useful to decode or analyze the data before it is rendered.
client.onStreamsReceived((streams) => { myGameOverlay.onStreamsReceived(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 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 genvid.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. genvid.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
onStreamsReceived()
which get a pass a
genvid.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
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
genvid.IWebGLContext()
class which is meant to simplify
repetitive tasks in WebGL. You can create it with
genvid.createWebGLContext()
method.
Events¶
You can send events back to the Genvid Services through the
IGenvidClient()
instance. See
sendEvent()
and
sendEventObject()
for details.