You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@guacamole.apache.org by jm...@apache.org on 2016/03/30 22:20:35 UTC
[1/5] incubator-guacamole-client git commit: GUAC-1511: Refactor
private Guacamole.RawAudioPlayer._Format to public Guacamole.RawAudioFormat.
Repository: incubator-guacamole-client
Updated Branches:
refs/heads/master 0d39a04a1 -> 065548fcd
GUAC-1511: Refactor private Guacamole.RawAudioPlayer._Format to public Guacamole.RawAudioFormat.
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/b9de1d74
Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/tree/b9de1d74
Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/diff/b9de1d74
Branch: refs/heads/master
Commit: b9de1d74c1db0be6443dabbd8d8f9537866170db
Parents: 0d39a04
Author: Michael Jumper <mj...@apache.org>
Authored: Wed Mar 30 09:17:30 2016 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed Mar 30 09:17:30 2016 -0700
----------------------------------------------------------------------
.../src/main/webapp/modules/AudioPlayer.js | 133 +----------------
.../src/main/webapp/modules/RawAudioFormat.js | 146 +++++++++++++++++++
2 files changed, 149 insertions(+), 130 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/b9de1d74/guacamole-common-js/src/main/webapp/modules/AudioPlayer.js
----------------------------------------------------------------------
diff --git a/guacamole-common-js/src/main/webapp/modules/AudioPlayer.js b/guacamole-common-js/src/main/webapp/modules/AudioPlayer.js
index 3f745d9..881ef94 100644
--- a/guacamole-common-js/src/main/webapp/modules/AudioPlayer.js
+++ b/guacamole-common-js/src/main/webapp/modules/AudioPlayer.js
@@ -126,9 +126,9 @@ Guacamole.RawAudioPlayer = function RawAudioPlayer(stream, mimetype) {
* The format of audio this player will decode.
*
* @private
- * @type {Guacamole.RawAudioPlayer._Format}
+ * @type {Guacamole.RawAudioFormat}
*/
- var format = Guacamole.RawAudioPlayer._Format.parse(mimetype);
+ var format = Guacamole.RawAudioFormat.parse(mimetype);
/**
* An instance of a Web Audio API AudioContext object, or null if the
@@ -475,133 +475,6 @@ Guacamole.RawAudioPlayer = function RawAudioPlayer(stream, mimetype) {
Guacamole.RawAudioPlayer.prototype = new Guacamole.AudioPlayer();
/**
- * A description of the format of raw PCM audio received by a
- * Guacamole.RawAudioPlayer. This object describes the number of bytes per
- * sample, the number of channels, and the overall sample rate.
- *
- * @private
- * @constructor
- * @param {Guacamole.RawAudioPlayer._Format|Object} template
- * The object whose properties should be copied into the corresponding
- * properties of the new Guacamole.RawAudioPlayer._Format.
- */
-Guacamole.RawAudioPlayer._Format = function _Format(template) {
-
- /**
- * The number of bytes in each sample of audio data. This value is
- * independent of the number of channels.
- *
- * @type {Number}
- */
- this.bytesPerSample = template.bytesPerSample;
-
- /**
- * The number of audio channels (ie: 1 for mono, 2 for stereo).
- *
- * @type {Number}
- */
- this.channels = template.channels;
-
- /**
- * The number of samples per second, per channel.
- *
- * @type {Number}
- */
- this.rate = template.rate;
-
-};
-
-/**
- * Parses the given mimetype, returning a new Guacamole.RawAudioPlayer._Format
- * which describes the type of raw audio data represented by that mimetype. If
- * the mimetype is not supported by Guacamole.RawAudioPlayer, null is returned.
- *
- * @private
- * @param {String} mimetype
- * The audio mimetype to parse.
- *
- * @returns {Guacamole.RawAudioPlayer._Format}
- * A new Guacamole.RawAudioPlayer._Format which describes the type of raw
- * audio data represented by the given mimetype, or null if the given
- * mimetype is not supported.
- */
-Guacamole.RawAudioPlayer._Format.parse = function parseFormat(mimetype) {
-
- var bytesPerSample;
-
- // Rate is absolutely required - if null is still present later, the
- // mimetype must not be supported
- var rate = null;
-
- // Default for both "audio/L8" and "audio/L16" is one channel
- var channels = 1;
-
- // "audio/L8" has one byte per sample
- if (mimetype.substring(0, 9) === 'audio/L8;') {
- mimetype = mimetype.substring(9);
- bytesPerSample = 1;
- }
-
- // "audio/L16" has two bytes per sample
- else if (mimetype.substring(0, 10) === 'audio/L16;') {
- mimetype = mimetype.substring(10);
- bytesPerSample = 2;
- }
-
- // All other types are unsupported
- else
- return null;
-
- // Parse all parameters
- var parameters = mimetype.split(',');
- for (var i = 0; i < parameters.length; i++) {
-
- var parameter = parameters[i];
-
- // All parameters must have an equals sign separating name from value
- var equals = parameter.indexOf('=');
- if (equals === -1)
- return null;
-
- // Parse name and value from parameter string
- var name = parameter.substring(0, equals);
- var value = parameter.substring(equals+1);
-
- // Handle each supported parameter
- switch (name) {
-
- // Number of audio channels
- case 'channels':
- channels = parseInt(value);
- break;
-
- // Sample rate
- case 'rate':
- rate = parseInt(value);
- break;
-
- // All other parameters are unsupported
- default:
- return null;
-
- }
-
- };
-
- // The rate parameter is required
- if (rate === null)
- return null;
-
- // Return parsed format details
- return new Guacamole.RawAudioPlayer._Format({
- bytesPerSample : bytesPerSample,
- channels : channels,
- rate : rate
- });
-
-};
-
-/**
* Determines whether the given mimetype is supported by
* Guacamole.RawAudioPlayer.
*
@@ -618,7 +491,7 @@ Guacamole.RawAudioPlayer.isSupportedType = function isSupportedType(mimetype) {
if (!window.AudioContext && !window.webkitAudioContext)
return false;
- return Guacamole.RawAudioPlayer._Format.parse(mimetype) !== null;
+ return Guacamole.RawAudioFormat.parse(mimetype) !== null;
};
http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/b9de1d74/guacamole-common-js/src/main/webapp/modules/RawAudioFormat.js
----------------------------------------------------------------------
diff --git a/guacamole-common-js/src/main/webapp/modules/RawAudioFormat.js b/guacamole-common-js/src/main/webapp/modules/RawAudioFormat.js
new file mode 100644
index 0000000..0fe8ac1
--- /dev/null
+++ b/guacamole-common-js/src/main/webapp/modules/RawAudioFormat.js
@@ -0,0 +1,146 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+var Guacamole = Guacamole || {};
+
+/**
+ * A description of the format of raw PCM audio, such as that used by
+ * Guacamole.RawAudioPlayer and Guacamole.RawAudioRecorder. This object
+ * describes the number of bytes per sample, the number of channels, and the
+ * overall sample rate.
+ *
+ * @constructor
+ * @param {Guacamole.RawAudioFormat|Object} template
+ * The object whose properties should be copied into the corresponding
+ * properties of the new Guacamole.RawAudioFormat.
+ */
+Guacamole.RawAudioFormat = function RawAudioFormat(template) {
+
+ /**
+ * The number of bytes in each sample of audio data. This value is
+ * independent of the number of channels.
+ *
+ * @type {Number}
+ */
+ this.bytesPerSample = template.bytesPerSample;
+
+ /**
+ * The number of audio channels (ie: 1 for mono, 2 for stereo).
+ *
+ * @type {Number}
+ */
+ this.channels = template.channels;
+
+ /**
+ * The number of samples per second, per channel.
+ *
+ * @type {Number}
+ */
+ this.rate = template.rate;
+
+};
+
+/**
+ * Parses the given mimetype, returning a new Guacamole.RawAudioFormat
+ * which describes the type of raw audio data represented by that mimetype. If
+ * the mimetype is not a supported raw audio data mimetype, null is returned.
+ *
+ * @param {String} mimetype
+ * The audio mimetype to parse.
+ *
+ * @returns {Guacamole.RawAudioFormat}
+ * A new Guacamole.RawAudioFormat which describes the type of raw
+ * audio data represented by the given mimetype, or null if the given
+ * mimetype is not supported.
+ */
+Guacamole.RawAudioFormat.parse = function parseFormat(mimetype) {
+
+ var bytesPerSample;
+
+ // Rate is absolutely required - if null is still present later, the
+ // mimetype must not be supported
+ var rate = null;
+
+ // Default for both "audio/L8" and "audio/L16" is one channel
+ var channels = 1;
+
+ // "audio/L8" has one byte per sample
+ if (mimetype.substring(0, 9) === 'audio/L8;') {
+ mimetype = mimetype.substring(9);
+ bytesPerSample = 1;
+ }
+
+ // "audio/L16" has two bytes per sample
+ else if (mimetype.substring(0, 10) === 'audio/L16;') {
+ mimetype = mimetype.substring(10);
+ bytesPerSample = 2;
+ }
+
+ // All other types are unsupported
+ else
+ return null;
+
+ // Parse all parameters
+ var parameters = mimetype.split(',');
+ for (var i = 0; i < parameters.length; i++) {
+
+ var parameter = parameters[i];
+
+ // All parameters must have an equals sign separating name from value
+ var equals = parameter.indexOf('=');
+ if (equals === -1)
+ return null;
+
+ // Parse name and value from parameter string
+ var name = parameter.substring(0, equals);
+ var value = parameter.substring(equals+1);
+
+ // Handle each supported parameter
+ switch (name) {
+
+ // Number of audio channels
+ case 'channels':
+ channels = parseInt(value);
+ break;
+
+ // Sample rate
+ case 'rate':
+ rate = parseInt(value);
+ break;
+
+ // All other parameters are unsupported
+ default:
+ return null;
+
+ }
+
+ };
+
+ // The rate parameter is required
+ if (rate === null)
+ return null;
+
+ // Return parsed format details
+ return new Guacamole.RawAudioFormat({
+ bytesPerSample : bytesPerSample,
+ channels : channels,
+ rate : rate
+ });
+
+};
[4/5] incubator-guacamole-client git commit: GUAC-1511: Automatically
open audio stream upon connect.
Posted by jm...@apache.org.
GUAC-1511: Automatically open audio stream upon connect.
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/900c8f2a
Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/tree/900c8f2a
Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/diff/900c8f2a
Branch: refs/heads/master
Commit: 900c8f2a276e42f6aefc3463e551e1ce25c8af42
Parents: 076995d
Author: Michael Jumper <mj...@apache.org>
Authored: Wed Mar 30 10:00:58 2016 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed Mar 30 11:22:54 2016 -0700
----------------------------------------------------------------------
.../main/webapp/app/client/types/ManagedClient.js | 15 +++++++++++++++
1 file changed, 15 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/900c8f2a/guacamole/src/main/webapp/app/client/types/ManagedClient.js
----------------------------------------------------------------------
diff --git a/guacamole/src/main/webapp/app/client/types/ManagedClient.js b/guacamole/src/main/webapp/app/client/types/ManagedClient.js
index fab359f..64418e0 100644
--- a/guacamole/src/main/webapp/app/client/types/ManagedClient.js
+++ b/guacamole/src/main/webapp/app/client/types/ManagedClient.js
@@ -150,6 +150,15 @@ angular.module('client').factory('ManagedClient', ['$rootScope', '$injector',
};
/**
+ * The mimetype of audio data to be sent along the Guacamole connection if
+ * audio input is supported.
+ *
+ * @constant
+ * @type String
+ */
+ ManagedClient.AUDIO_INPUT_MIMETYPE = 'audio/L16;rate=44100,channels=2';
+
+ /**
* Returns a promise which resolves with the string of connection
* parameters to be passed to the Guacamole client during connection. This
* string generally contains the desired connection ID, display resolution,
@@ -352,6 +361,12 @@ angular.module('client').factory('ManagedClient', ['$rootScope', '$injector',
case 3:
ManagedClientState.setConnectionState(managedClient.clientState,
ManagedClientState.ConnectionState.CONNECTED);
+
+ // Begin streaming audio input if possible
+ var stream = client.createAudioStream(ManagedClient.AUDIO_INPUT_MIMETYPE);
+ if (!Guacamole.AudioRecorder.getInstance(stream, ManagedClient.AUDIO_INPUT_MIMETYPE))
+ stream.sendEnd();
+
break;
// Update history when disconnecting
[2/5] incubator-guacamole-client git commit: GUAC-1511: Clean up
output stream creation. Add generic createOutputStream(). Add
createAudioStream().
Posted by jm...@apache.org.
GUAC-1511: Clean up output stream creation. Add generic createOutputStream(). Add createAudioStream().
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/4e489fef
Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/tree/4e489fef
Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/diff/4e489fef
Branch: refs/heads/master
Commit: 4e489fefad0dc42ab193f363ac896377ca198688
Parents: b9de1d7
Author: Michael Jumper <mj...@apache.org>
Authored: Wed Mar 30 09:41:48 2016 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed Mar 30 09:41:48 2016 -0700
----------------------------------------------------------------------
.../src/main/webapp/modules/Client.js | 153 ++++++++++---------
1 file changed, 81 insertions(+), 72 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/4e489fef/guacamole-common-js/src/main/webapp/modules/Client.js
----------------------------------------------------------------------
diff --git a/guacamole-common-js/src/main/webapp/modules/Client.js b/guacamole-common-js/src/main/webapp/modules/Client.js
index cc23e43..8903f21 100644
--- a/guacamole-common-js/src/main/webapp/modules/Client.js
+++ b/guacamole-common-js/src/main/webapp/modules/Client.js
@@ -233,89 +233,98 @@ Guacamole.Client = function(tunnel) {
};
/**
- * Opens a new file for writing, having the given index, mimetype and
- * filename.
- *
- * @param {String} mimetype The mimetype of the file being sent.
- * @param {String} filename The filename of the file being sent.
- * @return {Guacamole.OutputStream} The created file stream.
+ * Allocates an available stream index and creates a new
+ * Guacamole.OutputStream using that index, associating the resulting
+ * stream with this Guacamole.Client. Note that this stream will not yet
+ * exist as far as the other end of the Guacamole connection is concerned.
+ * Streams exist within the Guacamole protocol only when referenced by an
+ * instruction which creates the stream, such as a "clipboard", "file", or
+ * "pipe" instruction.
+ *
+ * @returns {Guacamole.OutputStream}
+ * A new Guacamole.OutputStream with a newly-allocated index and
+ * associated with this Guacamole.Client.
*/
- this.createFileStream = function(mimetype, filename) {
+ this.createOutputStream = function createOutputStream() {
// Allocate index
var index = stream_indices.next();
- // Create new stream
- tunnel.sendMessage("file", index, mimetype, filename);
+ // Return new stream
var stream = output_streams[index] = new Guacamole.OutputStream(guac_client, index);
+ return stream;
- // Override sendEnd() of stream to automatically free index
- var old_end = stream.sendEnd;
- stream.sendEnd = function() {
- old_end();
- stream_indices.free(index);
- delete output_streams[index];
- };
+ };
- // Return new, overridden stream
+ /**
+ * Opens a new audio stream for writing, where audio data having the give
+ * mimetype will be sent along the returned stream. The instruction
+ * necessary to create this stream will automatically be sent.
+ *
+ * @param {String} mimetype
+ * The mimetype of the audio data that will be sent along the returned
+ * stream.
+ *
+ * @return {Guacamole.OutputStream}
+ * The created audio stream.
+ */
+ this.createAudioStream = function(mimetype) {
+
+ // Allocate and associate stream with audio metadata
+ var stream = guac_client.createOutputStream();
+ tunnel.sendMessage("audio", stream.index, mimetype);
return stream;
};
/**
- * Opens a new pipe for writing, having the given name and mimetype.
- *
- * @param {String} mimetype The mimetype of the data being sent.
- * @param {String} name The name of the pipe.
+ * Opens a new file for writing, having the given index, mimetype and
+ * filename. The instruction necessary to create this stream will
+ * automatically be sent.
+ *
+ * @param {String} mimetype The mimetype of the file being sent.
+ * @param {String} filename The filename of the file being sent.
* @return {Guacamole.OutputStream} The created file stream.
*/
- this.createPipeStream = function(mimetype, name) {
+ this.createFileStream = function(mimetype, filename) {
- // Allocate index
- var index = stream_indices.next();
+ // Allocate and associate stream with file metadata
+ var stream = guac_client.createOutputStream();
+ tunnel.sendMessage("file", stream.index, mimetype, filename);
+ return stream;
- // Create new stream
- tunnel.sendMessage("pipe", index, mimetype, name);
- var stream = output_streams[index] = new Guacamole.OutputStream(guac_client, index);
+ };
- // Override sendEnd() of stream to automatically free index
- var old_end = stream.sendEnd;
- stream.sendEnd = function() {
- old_end();
- stream_indices.free(index);
- delete output_streams[index];
- };
+ /**
+ * Opens a new pipe for writing, having the given name and mimetype. The
+ * instruction necessary to create this stream will automatically be sent.
+ *
+ * @param {String} mimetype The mimetype of the data being sent.
+ * @param {String} name The name of the pipe.
+ * @return {Guacamole.OutputStream} The created file stream.
+ */
+ this.createPipeStream = function(mimetype, name) {
- // Return new, overridden stream
+ // Allocate and associate stream with pipe metadata
+ var stream = guac_client.createOutputStream();
+ tunnel.sendMessage("pipe", stream.index, mimetype, name);
return stream;
};
/**
- * Opens a new clipboard object for writing, having the given mimetype.
- *
+ * Opens a new clipboard object for writing, having the given mimetype. The
+ * instruction necessary to create this stream will automatically be sent.
+ *
* @param {String} mimetype The mimetype of the data being sent.
* @param {String} name The name of the pipe.
* @return {Guacamole.OutputStream} The created file stream.
*/
this.createClipboardStream = function(mimetype) {
- // Allocate index
- var index = stream_indices.next();
-
- // Create new stream
- tunnel.sendMessage("clipboard", index, mimetype);
- var stream = output_streams[index] = new Guacamole.OutputStream(guac_client, index);
-
- // Override sendEnd() of stream to automatically free index
- var old_end = stream.sendEnd;
- stream.sendEnd = function() {
- old_end();
- stream_indices.free(index);
- delete output_streams[index];
- };
-
- // Return new, overridden stream
+ // Allocate and associate stream with clipboard metadata
+ var stream = guac_client.createOutputStream();
+ tunnel.sendMessage("clipboard", stream.index, mimetype);
return stream;
};
@@ -323,7 +332,8 @@ Guacamole.Client = function(tunnel) {
/**
* Creates a new output stream associated with the given object and having
* the given mimetype and name. The legality of a mimetype and name is
- * dictated by the object itself.
+ * dictated by the object itself. The instruction necessary to create this
+ * stream will automatically be sent.
*
* @param {Number} index
* The index of the object for which the output stream is being
@@ -341,22 +351,9 @@ Guacamole.Client = function(tunnel) {
*/
this.createObjectOutputStream = function createObjectOutputStream(index, mimetype, name) {
- // Allocate index
- var streamIndex = stream_indices.next();
-
- // Create new stream
- tunnel.sendMessage("put", index, streamIndex, mimetype, name);
- var stream = output_streams[streamIndex] = new Guacamole.OutputStream(guac_client, streamIndex);
-
- // Override sendEnd() of stream to automatically free index
- var oldEnd = stream.sendEnd;
- stream.sendEnd = function freeStreamIndex() {
- oldEnd();
- stream_indices.free(streamIndex);
- delete output_streams[streamIndex];
- };
-
- // Return new, overridden stream
+ // Allocate and ssociate stream with object metadata
+ var stream = guac_client.createOutputStream();
+ tunnel.sendMessage("put", index, stream.index, mimetype, name);
return stream;
};
@@ -415,9 +412,13 @@ Guacamole.Client = function(tunnel) {
};
/**
- * Marks a currently-open stream as complete.
+ * Marks a currently-open stream as complete. The other end of the
+ * Guacamole connection will be notified via an "end" instruction that the
+ * stream is closed, and the index will be made available for reuse in
+ * future streams.
*
- * @param {Number} index The index of the stream to end.
+ * @param {Number} index
+ * The index of the stream to end.
*/
this.endStream = function(index) {
@@ -425,7 +426,15 @@ Guacamole.Client = function(tunnel) {
if (!isConnected())
return;
+ // Explicitly close stream by sending "end" instruction
tunnel.sendMessage("end", index);
+
+ // Free associated index and stream if they exist
+ if (output_streams[index]) {
+ stream_indices.free(index);
+ delete output_streams[index];
+ }
+
};
/**
[5/5] incubator-guacamole-client git commit: GUAC-1511: Merge front
end audio support changes.
Posted by jm...@apache.org.
GUAC-1511: Merge front end audio support changes.
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/065548fc
Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/tree/065548fc
Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/diff/065548fc
Branch: refs/heads/master
Commit: 065548fcdd885a8f15cbb936f49a60cf9f08b414
Parents: 0d39a04 900c8f2
Author: James Muehlner <ja...@guac-dev.org>
Authored: Wed Mar 30 13:19:35 2016 -0700
Committer: James Muehlner <ja...@guac-dev.org>
Committed: Wed Mar 30 13:19:35 2016 -0700
----------------------------------------------------------------------
.../src/main/webapp/modules/AudioPlayer.js | 133 +-------
.../src/main/webapp/modules/AudioRecorder.js | 324 +++++++++++++++++++
.../src/main/webapp/modules/Client.js | 153 ++++-----
.../src/main/webapp/modules/RawAudioFormat.js | 146 +++++++++
.../webapp/app/client/types/ManagedClient.js | 15 +
5 files changed, 569 insertions(+), 202 deletions(-)
----------------------------------------------------------------------
[3/5] incubator-guacamole-client git commit: GUAC-1511: Implement
Guacamole.AudioRecorder and Guacamole.RawAudioRecorder.
Posted by jm...@apache.org.
GUAC-1511: Implement Guacamole.AudioRecorder and Guacamole.RawAudioRecorder.
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/076995d9
Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/tree/076995d9
Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/diff/076995d9
Branch: refs/heads/master
Commit: 076995d99498453487a91a8f4ba8bba23f600dbd
Parents: 4e489fe
Author: Michael Jumper <mj...@apache.org>
Authored: Wed Mar 30 09:55:30 2016 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed Mar 30 09:55:30 2016 -0700
----------------------------------------------------------------------
.../src/main/webapp/modules/AudioRecorder.js | 324 +++++++++++++++++++
1 file changed, 324 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/076995d9/guacamole-common-js/src/main/webapp/modules/AudioRecorder.js
----------------------------------------------------------------------
diff --git a/guacamole-common-js/src/main/webapp/modules/AudioRecorder.js b/guacamole-common-js/src/main/webapp/modules/AudioRecorder.js
new file mode 100644
index 0000000..34185ad
--- /dev/null
+++ b/guacamole-common-js/src/main/webapp/modules/AudioRecorder.js
@@ -0,0 +1,324 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+var Guacamole = Guacamole || {};
+
+/**
+ * Abstract audio recorder which streams arbitrary audio data to an underlying
+ * Guacamole.OutputStream. It is up to implementations of this class to provide
+ * some means of handling this Guacamole.OutputStream. Data produced by the
+ * recorder is to be sent along the provided stream immediately.
+ *
+ * @constructor
+ */
+Guacamole.AudioRecorder = function AudioRecorder() {
+
+ // AudioRecorder currently provides no functions
+
+};
+
+/**
+ * Determines whether the given mimetype is supported by any built-in
+ * implementation of Guacamole.AudioRecorder, and thus will be properly handled
+ * by Guacamole.AudioRecorder.getInstance().
+ *
+ * @param {String} mimetype
+ * The mimetype to check.
+ *
+ * @returns {Boolean}
+ * true if the given mimetype is supported by any built-in
+ * Guacamole.AudioRecorder, false otherwise.
+ */
+Guacamole.AudioRecorder.isSupportedType = function isSupportedType(mimetype) {
+
+ return Guacamole.RawAudioRecorder.isSupportedType(mimetype);
+
+};
+
+/**
+ * Returns a list of all mimetypes supported by any built-in
+ * Guacamole.AudioRecorder, in rough order of priority. Beware that only the
+ * core mimetypes themselves will be listed. Any mimetype parameters, even
+ * required ones, will not be included in the list. For example, "audio/L8" is
+ * a supported raw audio mimetype that is supported, but it is invalid without
+ * additional parameters. Something like "audio/L8;rate=44100" would be valid,
+ * however (see https://tools.ietf.org/html/rfc4856).
+ *
+ * @returns {String[]}
+ * A list of all mimetypes supported by any built-in
+ * Guacamole.AudioRecorder, excluding any parameters.
+ */
+Guacamole.AudioRecorder.getSupportedTypes = function getSupportedTypes() {
+
+ return Guacamole.RawAudioRecorder.getSupportedTypes();
+
+};
+
+/**
+ * Returns an instance of Guacamole.AudioRecorder providing support for the
+ * given audio format. If support for the given audio format is not available,
+ * null is returned.
+ *
+ * @param {Guacamole.OutputStream} stream
+ * The Guacamole.OutputStream to send audio data through.
+ *
+ * @param {String} mimetype
+ * The mimetype of the audio data to be sent along the provided stream.
+ *
+ * @return {Guacamole.AudioRecorder}
+ * A Guacamole.AudioRecorder instance supporting the given mimetype and
+ * writing to the given stream, or null if support for the given mimetype
+ * is absent.
+ */
+Guacamole.AudioRecorder.getInstance = function getInstance(stream, mimetype) {
+
+ // Use raw audio recorder if possible
+ if (Guacamole.RawAudioRecorder.isSupportedType(mimetype))
+ return new Guacamole.RawAudioRecorder(stream, mimetype);
+
+ // No support for given mimetype
+ return null;
+
+};
+
+/**
+ * Implementation of Guacamole.AudioRecorder providing support for raw PCM
+ * format audio. This recorder relies only on the Web Audio API and does not
+ * require any browser-level support for its audio formats.
+ *
+ * @constructor
+ * @augments Guacamole.AudioRecorder
+ * @param {Guacamole.OutputStream} stream
+ * The Guacamole.OutputStream to write audio data to.
+ *
+ * @param {String} mimetype
+ * The mimetype of the audio data to send along the provided stream, which
+ * must be a "audio/L8" or "audio/L16" mimetype with necessary parameters,
+ * such as: "audio/L16;rate=44100,channels=2".
+ */
+Guacamole.RawAudioRecorder = function RawAudioRecorder(stream, mimetype) {
+
+ /**
+ * The format of audio this recorder will encode.
+ *
+ * @private
+ * @type {Guacamole.RawAudioFormat}
+ */
+ var format = Guacamole.RawAudioFormat.parse(mimetype);
+
+ /**
+ * An instance of a Web Audio API AudioContext object, or null if the
+ * Web Audio API is not supported.
+ *
+ * @private
+ * @type {AudioContext}
+ */
+ var context = (function getAudioContext() {
+
+ // Fallback to Webkit-specific AudioContext implementation
+ var AudioContext = window.AudioContext || window.webkitAudioContext;
+
+ // Get new AudioContext instance if Web Audio API is supported
+ if (AudioContext) {
+ try {
+ return new AudioContext();
+ }
+ catch (e) {
+ // Do not use Web Audio API if not allowed by browser
+ }
+ }
+
+ // Web Audio API not supported
+ return null;
+
+ })();
+
+ /**
+ * A function which directly invokes the browser's implementation of
+ * navigator.getUserMedia() with all provided parameters.
+ *
+ * @type Function
+ */
+ var getUserMedia = (navigator.getUserMedia
+ || navigator.webkitGetUserMedia
+ || navigator.mozGetUserMedia
+ || navigator.msGetUserMedia).bind(navigator);
+
+ /**
+ * Guacamole.ArrayBufferWriter wrapped around the audio output stream
+ * provided when this Guacamole.RawAudioRecorder was created.
+ *
+ * @private
+ * @type {Guacamole.ArrayBufferWriter}
+ */
+ var writer = new Guacamole.ArrayBufferWriter(stream);
+
+ /**
+ * The type of typed array that will be used to represent each audio packet
+ * internally. This will be either Int8Array or Int16Array, depending on
+ * whether the raw audio format is 8-bit or 16-bit.
+ *
+ * @private
+ * @constructor
+ */
+ var SampleArray = (format.bytesPerSample === 1) ? window.Int8Array : window.Int16Array;
+
+ /**
+ * The maximum absolute value of any sample within a raw audio packet sent
+ * by this audio recorder. This depends only on the size of each sample,
+ * and will be 128 for 8-bit audio and 32768 for 16-bit audio.
+ *
+ * @private
+ * @type {Number}
+ */
+ var maxSampleValue = (format.bytesPerSample === 1) ? 128 : 32768;
+
+ /**
+ * The size of audio buffer to request from the Web Audio API when
+ * recording audio. This must be a power of two between 256 and 16384
+ * inclusive, as required by AudioContext.createScriptProcessor().
+ *
+ * @private
+ * @type {Number}
+ */
+ var bufferSize = format.bytesPerSample * 4096;
+
+ /**
+ * Converts the given AudioBuffer into an audio packet, ready for streaming
+ * along the underlying output stream. Unlike the raw audio packets used by
+ * this audio recorder, AudioBuffers require floating point samples and are
+ * split into isolated planes of channel-specific data.
+ *
+ * @private
+ * @param {AudioBuffer} audioBuffer
+ * The Web Audio API AudioBuffer that should be converted to a raw
+ * audio packet.
+ *
+ * @returns {SampleArray}
+ * A new raw audio packet containing the audio data from the provided
+ * AudioBuffer.
+ */
+ var toSampleArray = function toSampleArray(audioBuffer) {
+
+ // Get array for raw PCM storage
+ var data = new SampleArray(audioBuffer.length);
+
+ // Convert each channel
+ for (var channel = 0; channel < format.channels; channel++) {
+
+ var audioData = audioBuffer.getChannelData(channel);
+
+ // Fill array with data from audio buffer channel
+ var offset = channel;
+ for (var i = 0; i < audioData.length; i++) {
+ data[offset] = audioData[i] * maxSampleValue;
+ offset += format.channels;
+ }
+
+ }
+
+ return data;
+
+ };
+
+ // Once audio stream is successfully open, request and begin reading audio
+ writer.onack = function audioStreamAcknowledged(status) {
+
+ // Abort stream if rejected
+ if (status.code !== Guacamole.Status.Code.SUCCESS) {
+ writer.sendEnd();
+ return;
+ }
+
+ // Attempt to retrieve an audio input stream from the browser
+ getUserMedia({ 'audio' : true }, function streamReceived(mediaStream) {
+
+ // Create processing node which receives appropriately-sized audio buffers
+ var processor = context.createScriptProcessor(bufferSize, format.channels, format.channels);
+ processor.connect(context.destination);
+
+ // Send blobs when audio buffers are received
+ processor.onaudioprocess = function processAudio(e) {
+ writer.sendData(toSampleArray(e.inputBuffer));
+ };
+
+ // Connect processing node to user's audio input source
+ var source = context.createMediaStreamSource(mediaStream);
+ source.connect(processor);
+
+ }, function streamDenied() {
+
+ // Simply end stream if audio access is not allowed
+ writer.sendEnd();
+
+ });
+
+ };
+
+};
+
+Guacamole.RawAudioRecorder.prototype = new Guacamole.AudioRecorder();
+
+/**
+ * Determines whether the given mimetype is supported by
+ * Guacamole.RawAudioRecorder.
+ *
+ * @param {String} mimetype
+ * The mimetype to check.
+ *
+ * @returns {Boolean}
+ * true if the given mimetype is supported by Guacamole.RawAudioRecorder,
+ * false otherwise.
+ */
+Guacamole.RawAudioRecorder.isSupportedType = function isSupportedType(mimetype) {
+
+ // No supported types if no Web Audio API
+ if (!window.AudioContext && !window.webkitAudioContext)
+ return false;
+
+ return Guacamole.RawAudioFormat.parse(mimetype) !== null;
+
+};
+
+/**
+ * Returns a list of all mimetypes supported by Guacamole.RawAudioRecorder. Only
+ * the core mimetypes themselves will be listed. Any mimetype parameters, even
+ * required ones, will not be included in the list. For example, "audio/L8" is
+ * a raw audio mimetype that may be supported, but it is invalid without
+ * additional parameters. Something like "audio/L8;rate=44100" would be valid,
+ * however (see https://tools.ietf.org/html/rfc4856).
+ *
+ * @returns {String[]}
+ * A list of all mimetypes supported by Guacamole.RawAudioRecorder,
+ * excluding any parameters. If the necessary JavaScript APIs for recording
+ * raw audio are absent, this list will be empty.
+ */
+Guacamole.RawAudioRecorder.getSupportedTypes = function getSupportedTypes() {
+
+ // No supported types if no Web Audio API
+ if (!window.AudioContext && !window.webkitAudioContext)
+ return [];
+
+ // We support 8-bit and 16-bit raw PCM
+ return [
+ 'audio/L8',
+ 'audio/L16'
+ ];
+
+};