257 lines
12 KiB
JavaScript
257 lines
12 KiB
JavaScript
// this code simulates what the actual backend recording feature will do
|
|
(function(context, $) {
|
|
|
|
|
|
"use strict";
|
|
|
|
context.JK = context.JK || {};
|
|
context.JK.FakeJamClientRecordings = function(app, fakeJamClient, p2pMessageFactory) {
|
|
|
|
var logger = context.JK.logger;
|
|
|
|
var startRecordingResultCallbackName = null;
|
|
var stopRecordingResultCallbackName = null;
|
|
var startedRecordingResultCallbackName = null;
|
|
var stoppedRecordingEventCallbackName = null;
|
|
var abortedRecordingEventCallbackName = null;
|
|
|
|
var startingSessionState = null;
|
|
var stoppingSessionState = null;
|
|
|
|
var currentRecordingId = null;
|
|
var currentRecordingCreatorClientId = null;
|
|
var currentRecordingClientIds = null;
|
|
|
|
function timeoutStartRecordingTimer() {
|
|
eval(startRecordingResultCallbackName).call(this, startingSessionState.recordingId, {success:false, reason:'client-no-response', detail:startingSessionState.groupedClientTracks[0]});
|
|
startingSessionState = null;
|
|
}
|
|
|
|
function timeoutStopRecordingTimer() {
|
|
eval(stopRecordingResultCallbackName).call(this, stoppingSessionState.recordingId, {success:false, reason:'client-no-response', detail:stoppingSessionState.groupedClientTracks[0]});
|
|
}
|
|
|
|
function StartRecording(recordingId, clients) {
|
|
startingSessionState = {};
|
|
|
|
// we expect all clients to respond within 1 seconds to mimic the reliable UDP layer
|
|
startingSessionState.aggegratingStartResultsTimer = setTimeout(timeoutStartRecordingTimer, 1000);
|
|
startingSessionState.recordingId = recordingId;
|
|
startingSessionState.groupedClientTracks = copyClientIds(clients, app.clientId); // we will manipulate this new one
|
|
|
|
// store the current recording's data
|
|
currentRecordingId = recordingId;
|
|
currentRecordingCreatorClientId = app.clientId;
|
|
currentRecordingClientIds = copyClientIds(clients, app.clientId);
|
|
|
|
if(startingSessionState.groupedClientTracks.length == 0) {
|
|
// if there are no clients but 'self', then you can declare a successful recording immediately
|
|
finishSuccessfulStart(recordingId);
|
|
}
|
|
else {
|
|
// signal all other connected clients that the recording has started
|
|
for(var i = 0; i < startingSessionState.groupedClientTracks.length; i++) {
|
|
var clientId = startingSessionState.groupedClientTracks[i];
|
|
context.JK.JamServer.sendP2PMessage(clientId, JSON.stringify(p2pMessageFactory.startRecording(recordingId)));
|
|
}
|
|
}
|
|
}
|
|
|
|
function StopRecording(recordingId, clients, result) {
|
|
|
|
if(startingSessionState) {
|
|
// we are currently starting a session.
|
|
// TODO
|
|
}
|
|
|
|
if(!result) {
|
|
result = {success:true}
|
|
}
|
|
|
|
stoppingSessionState = {};
|
|
|
|
// we expect all clients to respond within 1 seconds to mimic the reliable UDP layer
|
|
stoppingSessionState.aggegratingStopResultsTimer = setTimeout(timeoutStopRecordingTimer, 1000);
|
|
stoppingSessionState.recordingId = recordingId;
|
|
stoppingSessionState.groupedClientTracks = copyClientIds(clients, app.clientId);
|
|
|
|
if(stoppingSessionState.groupedClientTracks.length == 0) {
|
|
finishSuccessfulStop(recordingId);
|
|
}
|
|
else {
|
|
// signal all other connected clients that the recording has stopped
|
|
for(var i = 0; i < stoppingSessionState.groupedClientTracks.length; i++) {
|
|
var clientId = stoppingSessionState.groupedClientTracks[i];
|
|
context.JK.JamServer.sendP2PMessage(clientId, JSON.stringify(p2pMessageFactory.stopRecording(recordingId, result.success, result.reason, result.detail)));
|
|
}
|
|
}
|
|
}
|
|
|
|
function AbortRecording(recordingId, errorReason, errorDetail) {
|
|
// todo check recordingId
|
|
context.JK.JamServer.sendP2PMessage(currentRecordingCreatorClientId, JSON.stringify(p2pMessageFactory.abortRecording(recordingId, errorReason, errorDetail)));
|
|
}
|
|
|
|
function onStartRecording(from, payload) {
|
|
logger.debug("received start recording request from " + from, context.SessionStore.isRecording);
|
|
if(context.SessionStore.isRecording) {
|
|
// reject the request to start the recording
|
|
context.JK.JamServer.sendP2PMessage(from, JSON.stringify(p2pMessageFactory.startRecordingAck(payload.recordingId, false, "already-recording", null)));
|
|
}
|
|
else {
|
|
// accept the request, and then tell the frontend we are now recording
|
|
// a better client implementation would verify that the tracks specified match that what we have configured currently
|
|
|
|
// store the current recording's data
|
|
currentRecordingId = payload.recordingId;
|
|
currentRecordingCreatorClientId = from;
|
|
|
|
context.JK.JamServer.sendP2PMessage(from, JSON.stringify(p2pMessageFactory.startRecordingAck(payload.recordingId, true, null, null)));
|
|
eval(startedRecordingResultCallbackName).call(this, payload.recordingId, {success:true}, from);
|
|
}
|
|
}
|
|
|
|
function onStartRecordingAck(from, payload) {
|
|
logger.debug("received start recording ack from " + from);
|
|
|
|
// we should check transactionId; this could be an ACK for a different recording
|
|
if(startingSessionState) {
|
|
|
|
if(payload.success) {
|
|
var index = startingSessionState.groupedClientTracks.indexOf(from);
|
|
startingSessionState.groupedClientTracks.splice(index, 1);
|
|
|
|
if(startingSessionState.groupedClientTracks.length == 0) {
|
|
finishSuccessfulStart(payload.recordingId);
|
|
}
|
|
}
|
|
else {
|
|
// TOOD: a client responded with error; we need to tell all other clients to abandon recording
|
|
logger.warn("received an unsuccessful start_record_ack from: " + from);
|
|
}
|
|
}
|
|
else {
|
|
logger.warn("received a start_record_ack when there is no recording starting from: " + from);
|
|
// TODO: this is an error case; we should signal back to the sender that we gave up
|
|
}
|
|
}
|
|
|
|
function onStopRecording(from, payload) {
|
|
logger.debug("received stop recording request from " + from);
|
|
|
|
// TODO check recordingId, and if currently recording
|
|
// we should return success if we are currently recording, or if we were already asked to stop for this recordingId
|
|
// this means we should keep a list of the last N recordings that we've seen, rather than just keeping the current
|
|
context.JK.JamServer.sendP2PMessage(from, JSON.stringify(p2pMessageFactory.stopRecordingAck(payload.recordingId, true)));
|
|
|
|
if(stopRecordingResultCallbackName) {
|
|
eval(stopRecordingResultCallbackName).call(this, payload.recordingId, {success:payload.success, reason:payload.reason, detail:from});
|
|
}
|
|
}
|
|
|
|
function onStopRecordingAck(from, payload) {
|
|
logger.debug("received stop recording ack from " + from);
|
|
|
|
// we should check transactionId; this could be an ACK for a different recording
|
|
if(stoppingSessionState) {
|
|
|
|
if(payload.success) {
|
|
var index = stoppingSessionState.groupedClientTracks.indexOf(from);
|
|
stoppingSessionState.groupedClientTracks.splice(index, 1);
|
|
|
|
if(stoppingSessionState.groupedClientTracks.length == 0) {
|
|
finishSuccessfulStop(payload.recordingId);
|
|
}
|
|
}
|
|
else {
|
|
// TOOD: a client responded with error; what now?
|
|
logger.error("client responded with error: ", payload);
|
|
}
|
|
}
|
|
else {
|
|
// TODO: this is an error case; we should tell the caller we have no recording at the moment
|
|
}
|
|
}
|
|
|
|
function onAbortRecording(from, payload) {
|
|
logger.debug("received abort recording from " + from);
|
|
|
|
// TODO check if currently recording and if matches payload.recordingId
|
|
|
|
// if creator, tell everyone else to stop
|
|
if(app.clientId == currentRecordingCreatorClientId) {
|
|
// ask the front end to stop the recording because it has the full track listing
|
|
for(var i = 0; i < currentRecordingClientIds.length; i++) {
|
|
var clientId = currentRecordingClientIds[i];
|
|
context.JK.JamServer.sendP2PMessage(clientId, JSON.stringify(p2pMessageFactory.abortRecording(currentRecordingId, payload.reason, from)));
|
|
}
|
|
|
|
}
|
|
else {
|
|
logger.debug("only the creator currently deals with the abort request. abort request sent from:" + from + " with a reason of: " + payload.errorReason);
|
|
}
|
|
|
|
eval(abortedRecordingEventCallbackName).call(this, payload.recordingId, {success:payload.success, reason:payload.reason, detail:from});
|
|
}
|
|
|
|
function RegisterRecordingCallbacks(startRecordingCallbackName,
|
|
stopRecordingCallbackName,
|
|
startedRecordingCallbackName,
|
|
stoppedRecordingCallbackName,
|
|
abortedRecordingCallbackName) {
|
|
startRecordingResultCallbackName = startRecordingCallbackName;
|
|
stopRecordingResultCallbackName = stopRecordingCallbackName;
|
|
startedRecordingResultCallbackName = startedRecordingCallbackName;
|
|
stoppedRecordingEventCallbackName = stoppedRecordingCallbackName;
|
|
abortedRecordingEventCallbackName = abortedRecordingCallbackName;
|
|
}
|
|
|
|
// copies all clientIds, but removes current client ID because we don't want to message that user
|
|
function copyClientIds(clientIds, myClientId) {
|
|
var newClientIds = [];
|
|
for(var i = 0; i < clientIds.length; i++) {
|
|
var clientId = clientIds[i]
|
|
if(clientId != myClientId) {
|
|
newClientIds.push(clientId);
|
|
}
|
|
}
|
|
return newClientIds;
|
|
}
|
|
|
|
function finishSuccessfulStart(recordingId) {
|
|
// all clients have responded.
|
|
clearTimeout(startingSessionState.aggegratingStartResultsTimer);
|
|
startingSessionState = null;
|
|
eval(startRecordingResultCallbackName).call(this, recordingId, {success:true});
|
|
}
|
|
|
|
function finishSuccessfulStop(recordingId, errorReason) {
|
|
// all clients have responded.
|
|
clearTimeout(stoppingSessionState.aggegratingStopResultsTimer);
|
|
stoppingSessionState = null;
|
|
var result = { success: true }
|
|
if(errorReason)
|
|
{
|
|
result.success = false;
|
|
result.reason = errorReason
|
|
result.detail = ""
|
|
}
|
|
eval(stopRecordingResultCallbackName).call(this, recordingId, result);
|
|
}
|
|
|
|
|
|
// register for p2p callbacks
|
|
var callbacks = {};
|
|
callbacks[p2pMessageFactory.Types.START_RECORDING] = onStartRecording;
|
|
callbacks[p2pMessageFactory.Types.START_RECORDING_ACK] = onStartRecordingAck;
|
|
callbacks[p2pMessageFactory.Types.STOP_RECORDING] = onStopRecording;
|
|
callbacks[p2pMessageFactory.Types.STOP_RECORDING_ACK] = onStopRecordingAck;
|
|
callbacks[p2pMessageFactory.Types.ABORT_RECORDING] = onAbortRecording;
|
|
fakeJamClient.RegisterP2PMessageCallbacks(callbacks);
|
|
this.StartRecording = StartRecording;
|
|
this.StopRecording = StopRecording;
|
|
this.AbortRecording = AbortRecording;
|
|
this.RegisterRecordingCallbacks = RegisterRecordingCallbacks;
|
|
}
|
|
|
|
})(window, jQuery); |