Skip to main content

Stream Recording JS

The streamrecorder package provides an easy to use interface to connect to an agent session, start and stop recordings, as well as to switch streams during an active recording.

Additionally it provides an interface to connect a supervisor that can watch an agents stream.

info

The client application requires to have an auth token, received from the streamrecorder service /auth_v2/ endpoints and a unique client identifier. Read more in the authentication documentation.

note

Version 3 adds the ability to stream, record, and monitor multiple sources at once.
Although built for multi-stream setups, it remains fully compatible with single-stream use cases and supports from one up to three streams.

Setup

Add the local package and in the project e.g. as streamrecorder-package and locally configure the package in packages.json file.

{
"name": "streamrecorder-ui",
"dependencies": {
"eyeson-streamrec": "./streamrecorder-package"
},
}

Usage

An agent requires to have a proper client identifer and an authentication token in order to connect to the eyeson service.

import eyeson from 'eyeson-streamrec';

const clientId; // A client identifier.
const clientAuthToken; // Client auth token gathered by the streamrec service.
const firstStream; // A media stream
const secondStream; // A media stream
const thirdStream; // A media stream
const webhookUrl; // A target URL for webhooks.

console.info(eyeson.version); // current version of library
console.info(eyeson.maxStreamCount); // maximum supported streams

// Optional maximum bitrate per stream in kbps - min: 150, max: 4000, null for auto
eyeson.setOptionMaxBitrate(250);

async function() {
try {
eyeson.addEventListener(event => {
const { type } = event;
console.debug('[Agent] Event received:', type);
if (type === 'connected') {
setConnected(true);
}
if (type === 'disconnected') {
setRecording(false);
setConnected(false);
console.info(event.termination_cause);
}
if (type === 'recording_state') {
// Whenever recording state changes
// states are STARTED, STOPPED, FAILED
console.info(event.recording_id, event.stream_id, event.state);
}
if (type === 'stream_ended') {
// Info about local stream has stopped
console.info(event.id, event.stream);
}
if (type === 'statistics_ready') {
// onUpdate is called every 5 seconds
event.statistics.onUpdate(stats => {
// contains quality limitation durations in seconds for
// "cpu", "bandwidth", "other" and "none"
// stats.qualityLimitationDurations
// stats.total.qualityLimitationDurations
});
}
});

const streams = {
'first': firstStream,
'second': secondStream,
};
const recordings = {
'first': {
'uploadUrl': firstUploadUrl,
'webhookUrl': firstWebhookUrl,
},
'second': {
'uploadUrl': secondUploadUrl,
'webhookUrl': secondWebhookUrl,
},
'third': {
'uploadUrl': thirdUploadUrl,
'webhookUrl': thirdWebhookUrl,
},
};
// Connect the client to a session.
const sessionId = await eyeson.connect(clientId, clientAuthToken, streams,
webhookUrl);

// Add new streams (NOT during recording)
await eyeson.addStream({ 'third': thirdStream });

// Start a recording for the connected session.
const recordingIds = await eyeson.startRecording(recordings);
// recordingIds:
// {
// "first": { recording_id: "0ecdf0e3...", state: "STARTED" },
// "second": { recording_id: "14399bf0...", state: "STARTED" },
// "third": { recording_id: "1f46bbf7...", state: "STARTED" }
// }

// Switch to another media stream.
await eyeson.switchStream({
'first': newFirstStream // Stream id must already exist
});

// Remove stream by its Id (recording will be stopped and uploaded)
await eyeson.removeStream('third');

// Ensure Recording is started and has not yet been stopped before stopping
// the recording or switching the stream.
await eyeson.stopRecording();
// Disconnect the client session.
await eyeson.disconnect();
} catch(err) {
console.error(err);
}
}()

The termination_cause property is one of the following codes:

  • CONN_ERROR ... generic connection error
  • CONN_TIMEOUT ... connection timeout, client network problems
  • TERM_BY_CLIENT ... terminated by client
  • AGENT_SESSION_TERM ... the monitored agent session was stopped
  • PEERCONN_FAILED ... the peer-connection failed
  • SDP_ERROR ... the SDP could not be processed
  • SERVICE_SHUTDOWN ... streamrec service is shutting down
  • NO_ACTIVE_AGENT ... no active agent exists for the specifiec client-id
  • TWO_TIMER ... agent or supervisor already has an active session
  • MAX_SUPERVISORS_PER_AGENT ... limit of monitoring sessions reached
  • NO_PACKET_RECEIVED ... connection timeout due to missing media packets

Supervisor

A supervisor requires to have a proper client identifier and an authentication token in order to connect to the eyeson service. Ensure the supervisor is allowed to monitor the agent when fetching the authentication token at the /auth_v2/ endpoint.

import { Supervisor as eyeson } from 'eyeson-streamrec';

async function() {
try {
eyeson.addEventListener(event => {
const { type } = event;
console.debug('[Supervisor] Event received:', type)
if (type === 'disconnected') {
setConnected(false);
console.info(event.termination_cause);
}
if (type === 'add_stream') {
showStream(event.id, event.stream);
}
if (type === 'remove_stream') {
removeStream(event.id);
}
});

await eyeson.connect(supervisorId, authToken, agentId, webhookUrl);
setConnected(true);
setTimeout(eyeson.disconnect, 30 * 1000); // just an example
} catch(err) {
console.error(err);
}
}()