GUACAMOLE-250: Add support for seeking within session recordings. Project: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/commit/4f9469d9 Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/tree/4f9469d9 Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/diff/4f9469d9
Branch: refs/heads/master Commit: 4f9469d901a5f845c5d22827c28369f31c84a8eb Parents: 9d5e111 Author: Michael Jumper <[email protected]> Authored: Sat Apr 15 17:11:32 2017 -0700 Committer: Michael Jumper <[email protected]> Committed: Sat Apr 15 17:12:29 2017 -0700 ---------------------------------------------------------------------- .../src/main/webapp/modules/SessionRecording.js | 73 ++++++++++++++++++++ 1 file changed, 73 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/4f9469d9/guacamole-common-js/src/main/webapp/modules/SessionRecording.js ---------------------------------------------------------------------- diff --git a/guacamole-common-js/src/main/webapp/modules/SessionRecording.js b/guacamole-common-js/src/main/webapp/modules/SessionRecording.js index aa9e335..139597b 100644 --- a/guacamole-common-js/src/main/webapp/modules/SessionRecording.js +++ b/guacamole-common-js/src/main/webapp/modules/SessionRecording.js @@ -220,6 +220,51 @@ Guacamole.SessionRecording = function SessionRecording(tunnel) { }; /** + * Searches through the given region of frames for the frame having a + * relative timestamp closest to the timestamp given. + * + * @private + * @param {Number} minIndex + * The index of the first frame in the region (the frame having the + * smallest timestamp). + * + * @param {Number} maxIndex + * The index of the last frame in the region (the frame having the + * largest timestamp). + * + * @param {Number} timestamp + * The relative timestamp to search for, where zero denotes the first + * frame in the recording. + * + * @returns {Number} + * The index of the frame having a relative timestamp closest to the + * given value. + */ + var findFrame = function findFrame(minIndex, maxIndex, timestamp) { + + // Do not search if the region contains only one element + if (minIndex === maxIndex) + return minIndex; + + // Split search region into two halves + var midIndex = Math.floor((minIndex + maxIndex) / 2); + var midTimestamp = toRelativeTimestamp(frames[midIndex].timestamp); + + // If timestamp is within lesser half, search again within that half + if (timestamp < midTimestamp && midIndex > minIndex) + return findFrame(minIndex, midIndex - 1, timestamp); + + // If timestamp is within greater half, search again within that half + if (timestamp > midTimestamp && midIndex < maxIndex) + return findFrame(midIndex + 1, maxIndex, timestamp); + + // Otherwise, we lucked out and found a frame with exactly the + // desired timestamp + return midIndex; + + }; + + /** * Replays the instructions associated with the given frame, sending those * instructions to the playback client. * @@ -483,6 +528,34 @@ Guacamole.SessionRecording = function SessionRecording(tunnel) { }; /** + * Seeks to the given position within the recording. If the recording is + * currently being played back, playback will continue after the seek is + * performed. If the recording is currently paused, playback will be + * paused after the seek is performed. + * + * @param {Number} position + * The position within the recording to seek to, in milliseconds. + */ + this.seek = function seek(position) { + + // Do not seek if no frames exist + if (frames.length === 0) + return; + + // Pause playback, preserving playback state + var originallyPlaying = recording.isPlaying(); + recording.pause(); + + // Perform seek + seekToFrame(findFrame(0, frames.length - 1, position)); + + // Restore playback state + if (originallyPlaying) + recording.play(); + + }; + + /** * Pauses playback of the recording, if playback is currently in progress. * If playback is not in progress, this function has no effect. Playback is * initially paused when a Guacamole.SessionRecording is created, and must
