diff --git a/guacamole-common-js/src/main/webapp/modules/ArrayBufferReader.js b/guacamole-common-js/src/main/webapp/modules/ArrayBufferReader.js new file mode 100644 index 000000000..1e4bf9fb9 --- /dev/null +++ b/guacamole-common-js/src/main/webapp/modules/ArrayBufferReader.js @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2013 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +var Guacamole = Guacamole || {}; + +/** + * A reader which automatically handles the given input stream, returning + * strictly received packets as array buffers. Note that this object will + * overwrite any installed event handlers on the given Guacamole.InputStream. + * + * @constructor + * @param {Guacamole.InputStream} stream The stream that data will be read + * from. + */ +Guacamole.ArrayBufferReader = function(stream) { + + /** + * Reference to this Guacamole.InputStream. + * @private + */ + var guac_reader = this; + + // Receive blobs as array buffers + stream.onblob = function(data) { + + // Convert to ArrayBuffer + var binary = window.atob(data); + var arrayBuffer = new ArrayBuffer(binary.length); + var bufferView = new Uint8Array(arrayBuffer); + + for (var i=0; i= 0x0100) { - - // Signal error - if (stream.onerror) - stream.onerror(reason, code); - stream_indices.free(stream_index); delete output_streams[stream_index]; } - // Signal error if handler defined - else if (stream.onack) - stream.onack(reason, code); - } }, @@ -621,14 +599,18 @@ Guacamole.Client = function(tunnel) { // Create stream var stream = streams[stream_index] = - new Guacamole.InputStream(mimetype); + new Guacamole.InputStream(guac_client, stream_index); - stream.onclose = function() { - channel.play(mimetype, duration, stream.getBlob()); + // Assemble entire stream as a blob + var blob_reader = new Guacamole.BlobReader(stream, mimetype); + + // Play blob as audio + blob_reader.onend = function() { + channel.play(mimetype, duration, blob_reader.getBlob()); }; // Send success response - tunnel.sendMessage("ack", stream_index, "OK", 0x0000); + guac_client.sendAck(stream_index, "OK", 0x0000); }, @@ -640,10 +622,10 @@ Guacamole.Client = function(tunnel) { var stream = streams[stream_index]; // Write data - stream.receive(data); + stream.onblob(data); // Send success response - tunnel.sendMessage("ack", stream_index, "OK", 0x0000); + guac_client.sendAck(stream_index, "OK", 0x0000); }, @@ -833,8 +815,9 @@ Guacamole.Client = function(tunnel) { var stream_index = parseInt(parameters[0]); var stream = streams[stream_index]; - // Close stream - stream.close(); + // Signal end of stream + if (stream.onend) + stream.onend(); }, @@ -846,23 +829,13 @@ Guacamole.Client = function(tunnel) { // Create stream if (guac_client.onfile) { - - // Attempt to create stream - var stream = guac_client.onfile(mimetype, filename); - if (stream) { - streams[stream_index] = stream; - tunnel.sendMessage("ack", stream_index, "OK", 0x0000); - } - - // Notify if creation failed - else - tunnel.sendMessage("ack", stream_index, "Unable to receive file", 0x0201); - + var stream = streams[stream_index] = new Guacamole.InputStream(guac_client, stream_index); + guac_client.onfile(stream, mimetype, filename); } // Otherwise, unsupported else - tunnel.sendMessage("ack", stream_index, "File transfer unsupported", 0x0100); + guac_client.sendAck(stream_index, "File transfer unsupported", 0x0100); }, @@ -947,23 +920,13 @@ Guacamole.Client = function(tunnel) { // Create stream if (guac_client.onpipe) { - - // Attempt to create stream - var stream = guac_client.onpipe(mimetype, name); - if (stream) { - streams[stream_index] = stream; - tunnel.sendMessage("ack", stream_index, "OK", 0x0000); - } - - // Notify if creation failed - else - tunnel.sendMessage("ack", stream_index, "Unable to create pipe", 0x0201); - + var stream = streams[stream_index] = new Guacamole.InputStream(guac_client, stream_index); + guac_client.onpipe(stream, mimetype, name); } // Otherwise, unsupported else - tunnel.sendMessage("ack", stream_index, "Named pipes unsupported", 0x0100); + guac_client.sendAck(stream_index, "Named pipes unsupported", 0x0100); }, @@ -1227,10 +1190,13 @@ Guacamole.Client = function(tunnel) { // Create stream var stream = streams[stream_index] = - new Guacamole.InputStream(mimetype); + new Guacamole.InputStream(guac_client, stream_index); - // Play video once closed - stream.onclose = function() { + // Assemble entire stream as a blob + var blob_reader = new Guacamole.BlobReader(stream, mimetype); + + // Play video once finished + blob_reader.onend = function() { // Read data from blob from stream var reader = new FileReader(); @@ -1247,7 +1213,7 @@ Guacamole.Client = function(tunnel) { layer.play(mimetype, duration, "data:" + mimetype + ";base64," + window.btoa(binary)); }; - reader.readAsArrayBuffer(stream.getBlob()); + reader.readAsArrayBuffer(blob_reader.getBlob()); }; diff --git a/guacamole-common-js/src/main/webapp/modules/InputStream.js b/guacamole-common-js/src/main/webapp/modules/InputStream.js index 3097aea80..d1d51de93 100644 --- a/guacamole-common-js/src/main/webapp/modules/InputStream.js +++ b/guacamole-common-js/src/main/webapp/modules/InputStream.js @@ -27,266 +27,47 @@ var Guacamole = Guacamole || {}; * transfer of files or other binary data. * * @constructor - * @param {String} mimetype The mimetype of the data this stream will receive. + * @param {Guacamole.Client} client The client owning this stream. + * @param {Number} index The index of this stream. */ -Guacamole.InputStream = function(mimetype) { +Guacamole.InputStream = function(client, index) { /** - * The mimetype of the data contained within this blob. + * Reference to this stream. + * @private */ - this.mimetype = mimetype; + var guac_stream = this; /** - * Receives the given base64-encoded data. + * The index of this stream. + * @type Number + */ + this.index = index; + + /** + * Called when a blob of data is received. * + * @event * @param {String} data The received base64 data. */ - this.receive = function(data) {}; + this.onblob = null; /** - * Closes this Guacamole.InputStream such that no further data will be - * written. - */ - this.close = function() {}; - -}; - -/** - * An input stream which receives all data packets as individual ArrayBuffer - * objects. - * - * @constructor - * @param {String} mimetype The mimetype of the data this stream will receive. - */ -Guacamole.ArrayBufferInputStream = function(mimetype) { - - /** - * Reference to this Guacamole.InputStream. - * @private - */ - var guac_stream = this; - - /* - * This is an input stream. - */ - Guacamole.InputStream.apply(this, [mimetype]); - - // Receive implementation - this.receive = function(data) { - - // Convert to ArrayBuffer - var binary = window.atob(data); - var arrayBuffer = new ArrayBuffer(binary.length); - var bufferView = new Uint8Array(arrayBuffer); - - for (var i=0; i