mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 13:17:41 +00:00
GUACAMOLE-462: Merge correct recording playback artifacts during seek().
This commit is contained in:
@@ -228,11 +228,14 @@ Guacamole.Client = function(tunnel) {
|
|||||||
currentState = state.currentState;
|
currentState = state.currentState;
|
||||||
currentTimestamp = state.currentTimestamp;
|
currentTimestamp = state.currentTimestamp;
|
||||||
|
|
||||||
|
// Cancel any pending display operations/frames
|
||||||
|
display.cancel();
|
||||||
|
|
||||||
// Dispose of all layers
|
// Dispose of all layers
|
||||||
for (key in layers) {
|
for (key in layers) {
|
||||||
index = parseInt(key);
|
index = parseInt(key);
|
||||||
if (index > 0)
|
if (index > 0)
|
||||||
display.dispose(layers[key]);
|
layers[key].dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
layers = {};
|
layers = {};
|
||||||
|
@@ -201,6 +201,22 @@ Guacamole.Display = function() {
|
|||||||
*/
|
*/
|
||||||
function Frame(callback, tasks) {
|
function Frame(callback, tasks) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels rendering of this frame and all associated tasks. The
|
||||||
|
* callback provided at construction time, if any, is not invoked.
|
||||||
|
*/
|
||||||
|
this.cancel = function cancel() {
|
||||||
|
|
||||||
|
callback = null;
|
||||||
|
|
||||||
|
tasks.forEach(function cancelTask(task) {
|
||||||
|
task.cancel();
|
||||||
|
});
|
||||||
|
|
||||||
|
tasks = [];
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether this frame is ready to be rendered. This function
|
* Returns whether this frame is ready to be rendered. This function
|
||||||
* returns true if and only if ALL underlying tasks are unblocked.
|
* returns true if and only if ALL underlying tasks are unblocked.
|
||||||
@@ -271,6 +287,16 @@ Guacamole.Display = function() {
|
|||||||
*/
|
*/
|
||||||
this.blocked = blocked;
|
this.blocked = blocked;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels this task such that it will not run. The task handler
|
||||||
|
* provided at construction time, if any, is not invoked. Calling
|
||||||
|
* execute() after calling this function has no effect.
|
||||||
|
*/
|
||||||
|
this.cancel = function cancel() {
|
||||||
|
task.blocked = false;
|
||||||
|
taskHandler = null;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unblocks this Task, allowing it to run.
|
* Unblocks this Task, allowing it to run.
|
||||||
*/
|
*/
|
||||||
@@ -417,6 +443,27 @@ Guacamole.Display = function() {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels rendering of all pending frames and associated rendering
|
||||||
|
* operations. The callbacks provided to outstanding past calls to flush(),
|
||||||
|
* if any, are not invoked.
|
||||||
|
*/
|
||||||
|
this.cancel = function cancel() {
|
||||||
|
|
||||||
|
frames.forEach(function cancelFrame(frame) {
|
||||||
|
frame.cancel();
|
||||||
|
});
|
||||||
|
|
||||||
|
frames = [];
|
||||||
|
|
||||||
|
tasks.forEach(function cancelTask(task) {
|
||||||
|
task.cancel();
|
||||||
|
});
|
||||||
|
|
||||||
|
tasks = [];
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the hotspot and image of the mouse cursor displayed within the
|
* Sets the hotspot and image of the mouse cursor displayed within the
|
||||||
* Guacamole display.
|
* Guacamole display.
|
||||||
|
@@ -577,11 +577,12 @@ Guacamole.SessionRecording = function SessionRecording(source) {
|
|||||||
* @param {function} callback
|
* @param {function} callback
|
||||||
* The callback to invoke once the seek operation has completed.
|
* The callback to invoke once the seek operation has completed.
|
||||||
*
|
*
|
||||||
* @param {number} [delay=0]
|
* @param {number} [nextRealTimestamp]
|
||||||
* The number of milliseconds that the seek operation should be
|
* The timestamp of the point in time that the given frame should be
|
||||||
* scheduled to take.
|
* displayed, as would be returned by new Date().getTime(). If omitted,
|
||||||
|
* the frame will be displayed as soon as possible.
|
||||||
*/
|
*/
|
||||||
var seekToFrame = function seekToFrame(index, callback, delay) {
|
var seekToFrame = function seekToFrame(index, callback, nextRealTimestamp) {
|
||||||
|
|
||||||
// Abort any in-progress seek
|
// Abort any in-progress seek
|
||||||
abortSeek();
|
abortSeek();
|
||||||
@@ -591,29 +592,7 @@ Guacamole.SessionRecording = function SessionRecording(source) {
|
|||||||
aborted : false
|
aborted : false
|
||||||
};
|
};
|
||||||
|
|
||||||
var startIndex;
|
var startIndex = index;
|
||||||
|
|
||||||
// Back up until startIndex represents current state
|
|
||||||
for (startIndex = index; startIndex >= 0; startIndex--) {
|
|
||||||
|
|
||||||
var frame = frames[startIndex];
|
|
||||||
|
|
||||||
// If we've reached the current frame, startIndex represents
|
|
||||||
// current state by definition
|
|
||||||
if (startIndex === currentFrame)
|
|
||||||
break;
|
|
||||||
|
|
||||||
// If frame has associated absolute state, make that frame the
|
|
||||||
// current state
|
|
||||||
if (frame.clientState) {
|
|
||||||
frame.clientState.text().then(function textReady(text) {
|
|
||||||
playbackClient.importState(JSON.parse(text));
|
|
||||||
currentFrame = index;
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Replay any applicable incremental frames
|
// Replay any applicable incremental frames
|
||||||
var continueReplay = function continueReplay() {
|
var continueReplay = function continueReplay() {
|
||||||
@@ -629,7 +608,7 @@ Guacamole.SessionRecording = function SessionRecording(source) {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// If frames remain, replay the next frame
|
// If frames remain, replay the next frame
|
||||||
if (!thisSeek.aborted && currentFrame < index)
|
if (currentFrame < index)
|
||||||
replayFrame(currentFrame + 1, continueReplay);
|
replayFrame(currentFrame + 1, continueReplay);
|
||||||
|
|
||||||
// Otherwise, the seek operation is completed
|
// Otherwise, the seek operation is completed
|
||||||
@@ -640,11 +619,39 @@ Guacamole.SessionRecording = function SessionRecording(source) {
|
|||||||
|
|
||||||
// Continue replay after requested delay has elapsed, or
|
// Continue replay after requested delay has elapsed, or
|
||||||
// immediately if no delay was requested
|
// immediately if no delay was requested
|
||||||
if (delay)
|
var continueAfterRequiredDelay = function continueAfterRequiredDelay() {
|
||||||
window.setTimeout(continueReplay, delay);
|
var delay = nextRealTimestamp ? Math.max(nextRealTimestamp - new Date().getTime(), 0) : 0;
|
||||||
else
|
if (delay)
|
||||||
continueReplay();
|
window.setTimeout(continueReplay, delay);
|
||||||
|
else
|
||||||
|
continueReplay();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Back up until startIndex represents current state
|
||||||
|
for (; startIndex >= 0; startIndex--) {
|
||||||
|
|
||||||
|
var frame = frames[startIndex];
|
||||||
|
|
||||||
|
// If we've reached the current frame, startIndex represents
|
||||||
|
// current state by definition
|
||||||
|
if (startIndex === currentFrame)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// If frame has associated absolute state, make that frame the
|
||||||
|
// current state
|
||||||
|
if (frame.clientState) {
|
||||||
|
frame.clientState.text().then(function textReady(text) {
|
||||||
|
playbackClient.importState(JSON.parse(text));
|
||||||
|
currentFrame = startIndex;
|
||||||
|
continueAfterRequiredDelay();
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
continueAfterRequiredDelay();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -679,14 +686,10 @@ Guacamole.SessionRecording = function SessionRecording(source) {
|
|||||||
// frame begins
|
// frame begins
|
||||||
var nextRealTimestamp = next.timestamp - startVideoTimestamp + startRealTimestamp;
|
var nextRealTimestamp = next.timestamp - startVideoTimestamp + startRealTimestamp;
|
||||||
|
|
||||||
// Calculate the relative delay between the current time and
|
|
||||||
// the next frame start
|
|
||||||
var delay = Math.max(nextRealTimestamp - new Date().getTime(), 0);
|
|
||||||
|
|
||||||
// Advance to next frame after enough time has elapsed
|
// Advance to next frame after enough time has elapsed
|
||||||
seekToFrame(currentFrame + 1, function frameDelayElapsed() {
|
seekToFrame(currentFrame + 1, function frameDelayElapsed() {
|
||||||
continuePlayback();
|
continuePlayback();
|
||||||
}, delay);
|
}, nextRealTimestamp);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user