http://git-wip-us.apache.org/repos/asf/guacamole-website/blob/044692cf/doc/1.0.0/guacamole-common-js/AudioContextFactory.js.html ---------------------------------------------------------------------- diff --git a/doc/1.0.0/guacamole-common-js/AudioContextFactory.js.html b/doc/1.0.0/guacamole-common-js/AudioContextFactory.js.html new file mode 100644 index 0000000..126a7fd --- /dev/null +++ b/doc/1.0.0/guacamole-common-js/AudioContextFactory.js.html @@ -0,0 +1,130 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="utf-8"> + <title>JSDoc: Source: AudioContextFactory.js</title> + + <script src="scripts/prettify/prettify.js"> </script> + <script src="scripts/prettify/lang-css.js"> </script> + <!--[if lt IE 9]> + <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> + <![endif]--> + <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css"> + <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css"> +</head> + +<body> + +<div id="main"> + + <h1 class="page-title">Source: AudioContextFactory.js</h1> + + + + + + + <section> + <article> + <pre class="prettyprint source linenums"><code>/* + * 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 || {}; + +/** + * Maintains a singleton instance of the Web Audio API AudioContext class, + * instantiating the AudioContext only in response to the first call to + * getAudioContext(), and only if no existing AudioContext instance has been + * provided via the singleton property. Subsequent calls to getAudioContext() + * will return the same instance. + * + * @namespace + */ +Guacamole.AudioContextFactory = { + + /** + * A singleton instance of a Web Audio API AudioContext object, or null if + * no instance has yes been created. This property may be manually set if + * you wish to supply your own AudioContext instance, but care must be + * taken to do so as early as possible. Assignments to this property will + * not retroactively affect the value returned by previous calls to + * getAudioContext(). + * + * @type {AudioContext} + */ + 'singleton' : null, + + /** + * Returns a singleton instance of a Web Audio API AudioContext object. + * + * @return {AudioContext} + * A singleton instance of a Web Audio API AudioContext object, or null + * if the Web Audio API is not supported. + */ + 'getAudioContext' : 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 { + + // Create new instance if none yet exists + if (!Guacamole.AudioContextFactory.singleton) + Guacamole.AudioContextFactory.singleton = new AudioContext(); + + // Return singleton instance + return Guacamole.AudioContextFactory.singleton; + + } + catch (e) { + // Do not use Web Audio API if not allowed by browser + } + } + + // Web Audio API not supported + return null; + + } + +}; +</code></pre> + </article> + </section> + + + + +</div> + +<nav> + <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Guacamole.ArrayBufferReader.html">ArrayBufferReader</a></li><li><a href="Guacamole.ArrayBufferWriter.html">ArrayBufferWriter</a></li><li><a href="Guacamole.AudioPlayer.html">AudioPlayer</a></li><li><a href="Guacamole.AudioRecorder.html">AudioRecorder</a></li><li><a href="Guacamole.BlobReader.html">BlobReader</a></li><li><a href="Guacamole.BlobWriter.html">BlobWriter</a></li><li><a href="Guacamole.ChainedTunnel.html">ChainedTunnel</a></li><li><a href="Guacamole.Client.html">Client</a></li><li><a href="Guacamole.DataURIReader.html">DataURIReader</a></li><li><a href="Guacamole.Display.html">Display</a></li><li><a href="Guacamole.Display.VisibleLayer.html">VisibleLayer</a></li><li><a href="Guacamole.HTTPTunnel.html">HTTPTunnel</a></li><li><a href="Guacamole.InputSink.html">InputSink</a></li><li><a href="Guacamole.InputStream.html">InputStream</a></li><li><a href="Guacamole.IntegerPool.html">IntegerPool</a></li><l i><a href="Guacamole.JSONReader.html">JSONReader</a></li><li><a href="Guacamole.Keyboard.html">Keyboard</a></li><li><a href="Guacamole.Keyboard.ModifierState.html">ModifierState</a></li><li><a href="Guacamole.Layer.html">Layer</a></li><li><a href="Guacamole.Layer.Pixel.html">Pixel</a></li><li><a href="Guacamole.Mouse.html">Mouse</a></li><li><a href="Guacamole.Mouse.State.html">State</a></li><li><a href="Guacamole.Mouse.Touchpad.html">Touchpad</a></li><li><a href="Guacamole.Mouse.Touchscreen.html">Touchscreen</a></li><li><a href="Guacamole.Object.html">Object</a></li><li><a href="Guacamole.OnScreenKeyboard.html">OnScreenKeyboard</a></li><li><a href="Guacamole.OnScreenKeyboard.Key.html">Key</a></li><li><a href="Guacamole.OnScreenKeyboard.Layout.html">Layout</a></li><li><a href="Guacamole.OutputStream.html">OutputStream</a></li><li><a href="Guacamole.Parser.html">Parser</a></li><li><a href="Guacamole.RawAudioFormat.html">RawAudioFormat</a></li><li><a href="Guacamole.RawAudioPlayer.html ">RawAudioPlayer</a></li><li><a href="Guacamole.RawAudioRecorder.html">RawAudioRecorder</a></li><li><a href="Guacamole.SessionRecording.html">SessionRecording</a></li><li><a href="Guacamole.StaticHTTPTunnel.html">StaticHTTPTunnel</a></li><li><a href="Guacamole.Status.html">Status</a></li><li><a href="Guacamole.StringReader.html">StringReader</a></li><li><a href="Guacamole.StringWriter.html">StringWriter</a></li><li><a href="Guacamole.Tunnel.html">Tunnel</a></li><li><a href="Guacamole.VideoPlayer.html">VideoPlayer</a></li><li><a href="Guacamole.WebSocketTunnel.html">WebSocketTunnel</a></li></ul><h3>Events</h3><ul><li><a href="Guacamole.ArrayBufferReader.html#event:ondata">ondata</a></li><li><a href="Guacamole.ArrayBufferReader.html#event:onend">onend</a></li><li><a href="Guacamole.ArrayBufferWriter.html#event:onack">onack</a></li><li><a href="Guacamole.AudioRecorder.html#event:onclose">onclose</a></li><li><a href="Guacamole.AudioRecorder.html#event:onerror">onerror</a></li><li><a hre f="Guacamole.BlobReader.html#event:onend">onend</a></li><li><a href="Guacamole.BlobReader.html#event:onprogress">onprogress</a></li><li><a href="Guacamole.BlobWriter.html#event:onack">onack</a></li><li><a href="Guacamole.BlobWriter.html#event:oncomplete">oncomplete</a></li><li><a href="Guacamole.BlobWriter.html#event:onerror">onerror</a></li><li><a href="Guacamole.BlobWriter.html#event:onprogress">onprogress</a></li><li><a href="Guacamole.ChainedTunnel.html#event:onerror">onerror</a></li><li><a href="Guacamole.ChainedTunnel.html#event:oninstruction">oninstruction</a></li><li><a href="Guacamole.ChainedTunnel.html#event:onstatechange">onstatechange</a></li><li><a href="Guacamole.Client.html#event:onaudio">onaudio</a></li><li><a href="Guacamole.Client.html#event:onclipboard">onclipboard</a></li><li><a href="Guacamole.Client.html#event:onerror">onerror</a></li><li><a href="Guacamole.Client.html#event:onfile">onfile</a></li><li><a href="Guacamole.Client.html#event:onfilesystem">onfilesys tem</a></li><li><a href="Guacamole.Client.html#event:onname">onname</a></li><li><a href="Guacamole.Client.html#event:onpipe">onpipe</a></li><li><a href="Guacamole.Client.html#event:onstatechange">onstatechange</a></li><li><a href="Guacamole.Client.html#event:onsync">onsync</a></li><li><a href="Guacamole.Client.html#event:onvideo">onvideo</a></li><li><a href="Guacamole.DataURIReader.html#event:onend">onend</a></li><li><a href="Guacamole.Display.html#event:oncursor">oncursor</a></li><li><a href="Guacamole.Display.html#event:onresize">onresize</a></li><li><a href="Guacamole.HTTPTunnel.html#event:onerror">onerror</a></li><li><a href="Guacamole.HTTPTunnel.html#event:oninstruction">oninstruction</a></li><li><a href="Guacamole.HTTPTunnel.html#event:onstatechange">onstatechange</a></li><li><a href="Guacamole.InputStream.html#event:onblob">onblob</a></li><li><a href="Guacamole.InputStream.html#event:onend">onend</a></li><li><a href="Guacamole.JSONReader.html#event:onend">onend</a></li><li><a href="Guacamole.JSONReader.html#event:onprogress">onprogress</a></li><li><a href="Guacamole.Keyboard.html#event:onkeydown">onkeydown</a></li><li><a href="Guacamole.Keyboard.html#event:onkeyup">onkeyup</a></li><li><a href="Guacamole.Mouse.Touchpad.html#event:onmousedown">onmousedown</a></li><li><a href="Guacamole.Mouse.Touchpad.html#event:onmousemove">onmousemove</a></li><li><a href="Guacamole.Mouse.Touchpad.html#event:onmouseup">onmouseup</a></li><li><a href="Guacamole.Mouse.Touchscreen.html#event:onmousedown">onmousedown</a></li><li><a href="Guacamole.Mouse.Touchscreen.html#event:onmousemove">onmousemove</a></li><li><a href="Guacamole.Mouse.Touchscreen.html#event:onmouseup">onmouseup</a></li><li><a href="Guacamole.Mouse.html#event:onmousedown">onmousedown</a></li><li><a href="Guacamole.Mouse.html#event:onmousemove">onmousemove</a></li><li><a href="Guacamole.Mouse.html#event:onmouseout">onmouseout</a></li><li><a href="Guacamole.Mouse.html#event:onmouseup">onmouseup</a></li><li><a h ref="Guacamole.Object.html#event:onbody">onbody</a></li><li><a href="Guacamole.Object.html#event:onundefine">onundefine</a></li><li><a href="Guacamole.OnScreenKeyboard.html#event:onkeydown">onkeydown</a></li><li><a href="Guacamole.OnScreenKeyboard.html#event:onkeyup">onkeyup</a></li><li><a href="Guacamole.OutputStream.html#event:onack">onack</a></li><li><a href="Guacamole.Parser.html#event:oninstruction">oninstruction</a></li><li><a href="Guacamole.RawAudioRecorder.html#event:onclose">onclose</a></li><li><a href="Guacamole.RawAudioRecorder.html#event:onerror">onerror</a></li><li><a href="Guacamole.SessionRecording._PlaybackTunnel.html#event:onerror">onerror</a></li><li><a href="Guacamole.SessionRecording._PlaybackTunnel.html#event:oninstruction">oninstruction</a></li><li><a href="Guacamole.SessionRecording._PlaybackTunnel.html#event:onstatechange">onstatechange</a></li><li><a href="Guacamole.SessionRecording.html#event:onpause">onpause</a></li><li><a href="Guacamole.SessionRecording .html#event:onplay">onplay</a></li><li><a href="Guacamole.SessionRecording.html#event:onprogress">onprogress</a></li><li><a href="Guacamole.SessionRecording.html#event:onseek">onseek</a></li><li><a href="Guacamole.StaticHTTPTunnel.html#event:onerror">onerror</a></li><li><a href="Guacamole.StaticHTTPTunnel.html#event:oninstruction">oninstruction</a></li><li><a href="Guacamole.StaticHTTPTunnel.html#event:onstatechange">onstatechange</a></li><li><a href="Guacamole.StringReader.html#event:onend">onend</a></li><li><a href="Guacamole.StringReader.html#event:ontext">ontext</a></li><li><a href="Guacamole.StringWriter.html#event:onack">onack</a></li><li><a href="Guacamole.Tunnel.html#event:onerror">onerror</a></li><li><a href="Guacamole.Tunnel.html#event:oninstruction">oninstruction</a></li><li><a href="Guacamole.Tunnel.html#event:onstatechange">onstatechange</a></li><li><a href="Guacamole.WebSocketTunnel.html#event:onerror">onerror</a></li><li><a href="Guacamole.WebSocketTunnel.html#event:o ninstruction">oninstruction</a></li><li><a href="Guacamole.WebSocketTunnel.html#event:onstatechange">onstatechange</a></li></ul><h3>Namespaces</h3><ul><li><a href="Guacamole.html">Guacamole</a></li><li><a href="Guacamole.AudioContextFactory.html">AudioContextFactory</a></li></ul> +</nav> + +<br class="clear"> + +<footer> + Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Fri Dec 21 2018 13:47:10 GMT-0800 (PST) +</footer> + +<script> prettyPrint(); </script> +<script src="scripts/linenumber.js"> </script> +</body> +</html>
http://git-wip-us.apache.org/repos/asf/guacamole-website/blob/044692cf/doc/1.0.0/guacamole-common-js/AudioPlayer.js.html ---------------------------------------------------------------------- diff --git a/doc/1.0.0/guacamole-common-js/AudioPlayer.js.html b/doc/1.0.0/guacamole-common-js/AudioPlayer.js.html new file mode 100644 index 0000000..c9f8ef9 --- /dev/null +++ b/doc/1.0.0/guacamole-common-js/AudioPlayer.js.html @@ -0,0 +1,556 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="utf-8"> + <title>JSDoc: Source: AudioPlayer.js</title> + + <script src="scripts/prettify/prettify.js"> </script> + <script src="scripts/prettify/lang-css.js"> </script> + <!--[if lt IE 9]> + <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> + <![endif]--> + <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css"> + <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css"> +</head> + +<body> + +<div id="main"> + + <h1 class="page-title">Source: AudioPlayer.js</h1> + + + + + + + <section> + <article> + <pre class="prettyprint source linenums"><code>/* + * 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 player which accepts, queues and plays back arbitrary audio + * data. It is up to implementations of this class to provide some means of + * handling a provided Guacamole.InputStream. Data received along the provided + * stream is to be played back immediately. + * + * @constructor + */ +Guacamole.AudioPlayer = function AudioPlayer() { + + /** + * Notifies this Guacamole.AudioPlayer that all audio up to the current + * point in time has been given via the underlying stream, and that any + * difference in time between queued audio data and the current time can be + * considered latency. + */ + this.sync = function sync() { + // Default implementation - do nothing + }; + +}; + +/** + * Determines whether the given mimetype is supported by any built-in + * implementation of Guacamole.AudioPlayer, and thus will be properly handled + * by Guacamole.AudioPlayer.getInstance(). + * + * @param {String} mimetype + * The mimetype to check. + * + * @returns {Boolean} + * true if the given mimetype is supported by any built-in + * Guacamole.AudioPlayer, false otherwise. + */ +Guacamole.AudioPlayer.isSupportedType = function isSupportedType(mimetype) { + + return Guacamole.RawAudioPlayer.isSupportedType(mimetype); + +}; + +/** + * Returns a list of all mimetypes supported by any built-in + * Guacamole.AudioPlayer, 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.AudioPlayer, + * excluding any parameters. + */ +Guacamole.AudioPlayer.getSupportedTypes = function getSupportedTypes() { + + return Guacamole.RawAudioPlayer.getSupportedTypes(); + +}; + +/** + * Returns an instance of Guacamole.AudioPlayer providing support for the given + * audio format. If support for the given audio format is not available, null + * is returned. + * + * @param {Guacamole.InputStream} stream + * The Guacamole.InputStream to read audio data from. + * + * @param {String} mimetype + * The mimetype of the audio data in the provided stream. + * + * @return {Guacamole.AudioPlayer} + * A Guacamole.AudioPlayer instance supporting the given mimetype and + * reading from the given stream, or null if support for the given mimetype + * is absent. + */ +Guacamole.AudioPlayer.getInstance = function getInstance(stream, mimetype) { + + // Use raw audio player if possible + if (Guacamole.RawAudioPlayer.isSupportedType(mimetype)) + return new Guacamole.RawAudioPlayer(stream, mimetype); + + // No support for given mimetype + return null; + +}; + +/** + * Implementation of Guacamole.AudioPlayer providing support for raw PCM format + * audio. This player relies only on the Web Audio API and does not require any + * browser-level support for its audio formats. + * + * @constructor + * @augments Guacamole.AudioPlayer + * @param {Guacamole.InputStream} stream + * The Guacamole.InputStream to read audio data from. + * + * @param {String} mimetype + * The mimetype of the audio data in 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.RawAudioPlayer = function RawAudioPlayer(stream, mimetype) { + + /** + * The format of audio this player will decode. + * + * @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 = Guacamole.AudioContextFactory.getAudioContext(); + + /** + * The earliest possible time that the next packet could play without + * overlapping an already-playing packet, in seconds. Note that while this + * value is in seconds, it is not an integer value and has microsecond + * resolution. + * + * @private + * @type {Number} + */ + var nextPacketTime = context.currentTime; + + /** + * Guacamole.ArrayBufferReader wrapped around the audio input stream + * provided with this Guacamole.RawAudioPlayer was created. + * + * @private + * @type {Guacamole.ArrayBufferReader} + */ + var reader = new Guacamole.ArrayBufferReader(stream); + + /** + * The minimum size of an audio packet split by splitAudioPacket(), in + * seconds. Audio packets smaller than this will not be split, nor will the + * split result of a larger packet ever be smaller in size than this + * minimum. + * + * @private + * @constant + * @type {Number} + */ + var MIN_SPLIT_SIZE = 0.02; + + /** + * The maximum amount of latency to allow between the buffered data stream + * and the playback position, in seconds. Initially, this is set to + * roughly one third of a second. + * + * @private + * @type {Number} + */ + var maxLatency = 0.3; + + /** + * 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 + * received by this audio player. 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 queue of all pending audio packets, as an array of sample arrays. + * Audio packets which are pending playback will be added to this queue for + * further manipulation prior to scheduling via the Web Audio API. Once an + * audio packet leaves this queue and is scheduled via the Web Audio API, + * no further modifications can be made to that packet. + * + * @private + * @type {SampleArray[]} + */ + var packetQueue = []; + + /** + * Given an array of audio packets, returns a single audio packet + * containing the concatenation of those packets. + * + * @private + * @param {SampleArray[]} packets + * The array of audio packets to concatenate. + * + * @returns {SampleArray} + * A single audio packet containing the concatenation of all given + * audio packets. If no packets are provided, this will be undefined. + */ + var joinAudioPackets = function joinAudioPackets(packets) { + + // Do not bother joining if one or fewer packets are in the queue + if (packets.length <= 1) + return packets[0]; + + // Determine total sample length of the entire queue + var totalLength = 0; + packets.forEach(function addPacketLengths(packet) { + totalLength += packet.length; + }); + + // Append each packet within queue + var offset = 0; + var joined = new SampleArray(totalLength); + packets.forEach(function appendPacket(packet) { + joined.set(packet, offset); + offset += packet.length; + }); + + return joined; + + }; + + /** + * Given a single packet of audio data, splits off an arbitrary length of + * audio data from the beginning of that packet, returning the split result + * as an array of two packets. The split location is determined through an + * algorithm intended to minimize the liklihood of audible clicking between + * packets. If no such split location is possible, an array containing only + * the originally-provided audio packet is returned. + * + * @private + * @param {SampleArray} data + * The audio packet to split. + * + * @returns {SampleArray[]} + * An array of audio packets containing the result of splitting the + * provided audio packet. If splitting is possible, this array will + * contain two packets. If splitting is not possible, this array will + * contain only the originally-provided packet. + */ + var splitAudioPacket = function splitAudioPacket(data) { + + var minValue = Number.MAX_VALUE; + var optimalSplitLength = data.length; + + // Calculate number of whole samples in the provided audio packet AND + // in the minimum possible split packet + var samples = Math.floor(data.length / format.channels); + var minSplitSamples = Math.floor(format.rate * MIN_SPLIT_SIZE); + + // Calculate the beginning of the "end" of the audio packet + var start = Math.max( + format.channels * minSplitSamples, + format.channels * (samples - minSplitSamples) + ); + + // For all samples at the end of the given packet, find a point where + // the perceptible volume across all channels is lowest (and thus is + // the optimal point to split) + for (var offset = start; offset < data.length; offset += format.channels) { + + // Calculate the sum of all values across all channels (the result + // will be proportional to the average volume of a sample) + var totalValue = 0; + for (var channel = 0; channel < format.channels; channel++) { + totalValue += Math.abs(data[offset + channel]); + } + + // If this is the smallest average value thus far, set the split + // length such that the first packet ends with the current sample + if (totalValue <= minValue) { + optimalSplitLength = offset + format.channels; + minValue = totalValue; + } + + } + + // If packet is not split, return the supplied packet untouched + if (optimalSplitLength === data.length) + return [data]; + + // Otherwise, split the packet into two new packets according to the + // calculated optimal split length + return [ + new SampleArray(data.buffer.slice(0, optimalSplitLength * format.bytesPerSample)), + new SampleArray(data.buffer.slice(optimalSplitLength * format.bytesPerSample)) + ]; + + }; + + /** + * Pushes the given packet of audio data onto the playback queue. Unlike + * other private functions within Guacamole.RawAudioPlayer, the type of the + * ArrayBuffer packet of audio data here need not be specific to the type + * of audio (as with SampleArray). The ArrayBuffer type provided by a + * Guacamole.ArrayBufferReader, for example, is sufficient. Any necessary + * conversions will be performed automatically internally. + * + * @private + * @param {ArrayBuffer} data + * A raw packet of audio data that should be pushed onto the audio + * playback queue. + */ + var pushAudioPacket = function pushAudioPacket(data) { + packetQueue.push(new SampleArray(data)); + }; + + /** + * Shifts off and returns a packet of audio data from the beginning of the + * playback queue. The length of this audio packet is determined + * dynamically according to the click-reduction algorithm implemented by + * splitAudioPacket(). + * + * @private + * @returns {SampleArray} + * A packet of audio data pulled from the beginning of the playback + * queue. + */ + var shiftAudioPacket = function shiftAudioPacket() { + + // Flatten data in packet queue + var data = joinAudioPackets(packetQueue); + if (!data) + return null; + + // Pull an appropriate amount of data from the front of the queue + packetQueue = splitAudioPacket(data); + data = packetQueue.shift(); + + return data; + + }; + + /** + * Converts the given audio packet into an AudioBuffer, ready for playback + * by the Web Audio API. Unlike the raw audio packets received by this + * audio player, AudioBuffers require floating point samples and are split + * into isolated planes of channel-specific data. + * + * @private + * @param {SampleArray} data + * The raw audio packet that should be converted into a Web Audio API + * AudioBuffer. + * + * @returns {AudioBuffer} + * A new Web Audio API AudioBuffer containing the provided audio data, + * converted to the format used by the Web Audio API. + */ + var toAudioBuffer = function toAudioBuffer(data) { + + // Calculate total number of samples + var samples = data.length / format.channels; + + // Determine exactly when packet CAN play + var packetTime = context.currentTime; + if (nextPacketTime < packetTime) + nextPacketTime = packetTime; + + // Get audio buffer for specified format + var audioBuffer = context.createBuffer(format.channels, samples, format.rate); + + // Convert each channel + for (var channel = 0; channel < format.channels; channel++) { + + var audioData = audioBuffer.getChannelData(channel); + + // Fill audio buffer with data for channel + var offset = channel; + for (var i = 0; i < samples; i++) { + audioData[i] = data[offset] / maxSampleValue; + offset += format.channels; + } + + } + + return audioBuffer; + + }; + + // Defer playback of received audio packets slightly + reader.ondata = function playReceivedAudio(data) { + + // Push received samples onto queue + pushAudioPacket(new SampleArray(data)); + + // Shift off an arbitrary packet of audio data from the queue (this may + // be different in size from the packet just pushed) + var packet = shiftAudioPacket(); + if (!packet) + return; + + // Determine exactly when packet CAN play + var packetTime = context.currentTime; + if (nextPacketTime < packetTime) + nextPacketTime = packetTime; + + // Set up buffer source + var source = context.createBufferSource(); + source.connect(context.destination); + + // Use noteOn() instead of start() if necessary + if (!source.start) + source.start = source.noteOn; + + // Schedule packet + source.buffer = toAudioBuffer(packet); + source.start(nextPacketTime); + + // Update timeline by duration of scheduled packet + nextPacketTime += packet.length / format.channels / format.rate; + + }; + + /** @override */ + this.sync = function sync() { + + // Calculate elapsed time since last sync + var now = context.currentTime; + + // Reschedule future playback time such that playback latency is + // bounded within a reasonable latency threshold + nextPacketTime = Math.min(nextPacketTime, now + maxLatency); + + }; + +}; + +Guacamole.RawAudioPlayer.prototype = new Guacamole.AudioPlayer(); + +/** + * Determines whether the given mimetype is supported by + * Guacamole.RawAudioPlayer. + * + * @param {String} mimetype + * The mimetype to check. + * + * @returns {Boolean} + * true if the given mimetype is supported by Guacamole.RawAudioPlayer, + * false otherwise. + */ +Guacamole.RawAudioPlayer.isSupportedType = function isSupportedType(mimetype) { + + // No supported types if no Web Audio API + if (!Guacamole.AudioContextFactory.getAudioContext()) + return false; + + return Guacamole.RawAudioFormat.parse(mimetype) !== null; + +}; + +/** + * Returns a list of all mimetypes supported by Guacamole.RawAudioPlayer. 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.RawAudioPlayer, excluding + * any parameters. If the necessary JavaScript APIs for playing raw audio + * are absent, this list will be empty. + */ +Guacamole.RawAudioPlayer.getSupportedTypes = function getSupportedTypes() { + + // No supported types if no Web Audio API + if (!Guacamole.AudioContextFactory.getAudioContext()) + return []; + + // We support 8-bit and 16-bit raw PCM + return [ + 'audio/L8', + 'audio/L16' + ]; + +}; +</code></pre> + </article> + </section> + + + + +</div> + +<nav> + <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Guacamole.ArrayBufferReader.html">ArrayBufferReader</a></li><li><a href="Guacamole.ArrayBufferWriter.html">ArrayBufferWriter</a></li><li><a href="Guacamole.AudioPlayer.html">AudioPlayer</a></li><li><a href="Guacamole.AudioRecorder.html">AudioRecorder</a></li><li><a href="Guacamole.BlobReader.html">BlobReader</a></li><li><a href="Guacamole.BlobWriter.html">BlobWriter</a></li><li><a href="Guacamole.ChainedTunnel.html">ChainedTunnel</a></li><li><a href="Guacamole.Client.html">Client</a></li><li><a href="Guacamole.DataURIReader.html">DataURIReader</a></li><li><a href="Guacamole.Display.html">Display</a></li><li><a href="Guacamole.Display.VisibleLayer.html">VisibleLayer</a></li><li><a href="Guacamole.HTTPTunnel.html">HTTPTunnel</a></li><li><a href="Guacamole.InputSink.html">InputSink</a></li><li><a href="Guacamole.InputStream.html">InputStream</a></li><li><a href="Guacamole.IntegerPool.html">IntegerPool</a></li><l i><a href="Guacamole.JSONReader.html">JSONReader</a></li><li><a href="Guacamole.Keyboard.html">Keyboard</a></li><li><a href="Guacamole.Keyboard.ModifierState.html">ModifierState</a></li><li><a href="Guacamole.Layer.html">Layer</a></li><li><a href="Guacamole.Layer.Pixel.html">Pixel</a></li><li><a href="Guacamole.Mouse.html">Mouse</a></li><li><a href="Guacamole.Mouse.State.html">State</a></li><li><a href="Guacamole.Mouse.Touchpad.html">Touchpad</a></li><li><a href="Guacamole.Mouse.Touchscreen.html">Touchscreen</a></li><li><a href="Guacamole.Object.html">Object</a></li><li><a href="Guacamole.OnScreenKeyboard.html">OnScreenKeyboard</a></li><li><a href="Guacamole.OnScreenKeyboard.Key.html">Key</a></li><li><a href="Guacamole.OnScreenKeyboard.Layout.html">Layout</a></li><li><a href="Guacamole.OutputStream.html">OutputStream</a></li><li><a href="Guacamole.Parser.html">Parser</a></li><li><a href="Guacamole.RawAudioFormat.html">RawAudioFormat</a></li><li><a href="Guacamole.RawAudioPlayer.html ">RawAudioPlayer</a></li><li><a href="Guacamole.RawAudioRecorder.html">RawAudioRecorder</a></li><li><a href="Guacamole.SessionRecording.html">SessionRecording</a></li><li><a href="Guacamole.StaticHTTPTunnel.html">StaticHTTPTunnel</a></li><li><a href="Guacamole.Status.html">Status</a></li><li><a href="Guacamole.StringReader.html">StringReader</a></li><li><a href="Guacamole.StringWriter.html">StringWriter</a></li><li><a href="Guacamole.Tunnel.html">Tunnel</a></li><li><a href="Guacamole.VideoPlayer.html">VideoPlayer</a></li><li><a href="Guacamole.WebSocketTunnel.html">WebSocketTunnel</a></li></ul><h3>Events</h3><ul><li><a href="Guacamole.ArrayBufferReader.html#event:ondata">ondata</a></li><li><a href="Guacamole.ArrayBufferReader.html#event:onend">onend</a></li><li><a href="Guacamole.ArrayBufferWriter.html#event:onack">onack</a></li><li><a href="Guacamole.AudioRecorder.html#event:onclose">onclose</a></li><li><a href="Guacamole.AudioRecorder.html#event:onerror">onerror</a></li><li><a hre f="Guacamole.BlobReader.html#event:onend">onend</a></li><li><a href="Guacamole.BlobReader.html#event:onprogress">onprogress</a></li><li><a href="Guacamole.BlobWriter.html#event:onack">onack</a></li><li><a href="Guacamole.BlobWriter.html#event:oncomplete">oncomplete</a></li><li><a href="Guacamole.BlobWriter.html#event:onerror">onerror</a></li><li><a href="Guacamole.BlobWriter.html#event:onprogress">onprogress</a></li><li><a href="Guacamole.ChainedTunnel.html#event:onerror">onerror</a></li><li><a href="Guacamole.ChainedTunnel.html#event:oninstruction">oninstruction</a></li><li><a href="Guacamole.ChainedTunnel.html#event:onstatechange">onstatechange</a></li><li><a href="Guacamole.Client.html#event:onaudio">onaudio</a></li><li><a href="Guacamole.Client.html#event:onclipboard">onclipboard</a></li><li><a href="Guacamole.Client.html#event:onerror">onerror</a></li><li><a href="Guacamole.Client.html#event:onfile">onfile</a></li><li><a href="Guacamole.Client.html#event:onfilesystem">onfilesys tem</a></li><li><a href="Guacamole.Client.html#event:onname">onname</a></li><li><a href="Guacamole.Client.html#event:onpipe">onpipe</a></li><li><a href="Guacamole.Client.html#event:onstatechange">onstatechange</a></li><li><a href="Guacamole.Client.html#event:onsync">onsync</a></li><li><a href="Guacamole.Client.html#event:onvideo">onvideo</a></li><li><a href="Guacamole.DataURIReader.html#event:onend">onend</a></li><li><a href="Guacamole.Display.html#event:oncursor">oncursor</a></li><li><a href="Guacamole.Display.html#event:onresize">onresize</a></li><li><a href="Guacamole.HTTPTunnel.html#event:onerror">onerror</a></li><li><a href="Guacamole.HTTPTunnel.html#event:oninstruction">oninstruction</a></li><li><a href="Guacamole.HTTPTunnel.html#event:onstatechange">onstatechange</a></li><li><a href="Guacamole.InputStream.html#event:onblob">onblob</a></li><li><a href="Guacamole.InputStream.html#event:onend">onend</a></li><li><a href="Guacamole.JSONReader.html#event:onend">onend</a></li><li><a href="Guacamole.JSONReader.html#event:onprogress">onprogress</a></li><li><a href="Guacamole.Keyboard.html#event:onkeydown">onkeydown</a></li><li><a href="Guacamole.Keyboard.html#event:onkeyup">onkeyup</a></li><li><a href="Guacamole.Mouse.Touchpad.html#event:onmousedown">onmousedown</a></li><li><a href="Guacamole.Mouse.Touchpad.html#event:onmousemove">onmousemove</a></li><li><a href="Guacamole.Mouse.Touchpad.html#event:onmouseup">onmouseup</a></li><li><a href="Guacamole.Mouse.Touchscreen.html#event:onmousedown">onmousedown</a></li><li><a href="Guacamole.Mouse.Touchscreen.html#event:onmousemove">onmousemove</a></li><li><a href="Guacamole.Mouse.Touchscreen.html#event:onmouseup">onmouseup</a></li><li><a href="Guacamole.Mouse.html#event:onmousedown">onmousedown</a></li><li><a href="Guacamole.Mouse.html#event:onmousemove">onmousemove</a></li><li><a href="Guacamole.Mouse.html#event:onmouseout">onmouseout</a></li><li><a href="Guacamole.Mouse.html#event:onmouseup">onmouseup</a></li><li><a h ref="Guacamole.Object.html#event:onbody">onbody</a></li><li><a href="Guacamole.Object.html#event:onundefine">onundefine</a></li><li><a href="Guacamole.OnScreenKeyboard.html#event:onkeydown">onkeydown</a></li><li><a href="Guacamole.OnScreenKeyboard.html#event:onkeyup">onkeyup</a></li><li><a href="Guacamole.OutputStream.html#event:onack">onack</a></li><li><a href="Guacamole.Parser.html#event:oninstruction">oninstruction</a></li><li><a href="Guacamole.RawAudioRecorder.html#event:onclose">onclose</a></li><li><a href="Guacamole.RawAudioRecorder.html#event:onerror">onerror</a></li><li><a href="Guacamole.SessionRecording._PlaybackTunnel.html#event:onerror">onerror</a></li><li><a href="Guacamole.SessionRecording._PlaybackTunnel.html#event:oninstruction">oninstruction</a></li><li><a href="Guacamole.SessionRecording._PlaybackTunnel.html#event:onstatechange">onstatechange</a></li><li><a href="Guacamole.SessionRecording.html#event:onpause">onpause</a></li><li><a href="Guacamole.SessionRecording .html#event:onplay">onplay</a></li><li><a href="Guacamole.SessionRecording.html#event:onprogress">onprogress</a></li><li><a href="Guacamole.SessionRecording.html#event:onseek">onseek</a></li><li><a href="Guacamole.StaticHTTPTunnel.html#event:onerror">onerror</a></li><li><a href="Guacamole.StaticHTTPTunnel.html#event:oninstruction">oninstruction</a></li><li><a href="Guacamole.StaticHTTPTunnel.html#event:onstatechange">onstatechange</a></li><li><a href="Guacamole.StringReader.html#event:onend">onend</a></li><li><a href="Guacamole.StringReader.html#event:ontext">ontext</a></li><li><a href="Guacamole.StringWriter.html#event:onack">onack</a></li><li><a href="Guacamole.Tunnel.html#event:onerror">onerror</a></li><li><a href="Guacamole.Tunnel.html#event:oninstruction">oninstruction</a></li><li><a href="Guacamole.Tunnel.html#event:onstatechange">onstatechange</a></li><li><a href="Guacamole.WebSocketTunnel.html#event:onerror">onerror</a></li><li><a href="Guacamole.WebSocketTunnel.html#event:o ninstruction">oninstruction</a></li><li><a href="Guacamole.WebSocketTunnel.html#event:onstatechange">onstatechange</a></li></ul><h3>Namespaces</h3><ul><li><a href="Guacamole.html">Guacamole</a></li><li><a href="Guacamole.AudioContextFactory.html">AudioContextFactory</a></li></ul> +</nav> + +<br class="clear"> + +<footer> + Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Fri Dec 21 2018 13:47:10 GMT-0800 (PST) +</footer> + +<script> prettyPrint(); </script> +<script src="scripts/linenumber.js"> </script> +</body> +</html> http://git-wip-us.apache.org/repos/asf/guacamole-website/blob/044692cf/doc/1.0.0/guacamole-common-js/AudioRecorder.js.html ---------------------------------------------------------------------- diff --git a/doc/1.0.0/guacamole-common-js/AudioRecorder.js.html b/doc/1.0.0/guacamole-common-js/AudioRecorder.js.html new file mode 100644 index 0000000..4a0b73b --- /dev/null +++ b/doc/1.0.0/guacamole-common-js/AudioRecorder.js.html @@ -0,0 +1,622 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="utf-8"> + <title>JSDoc: Source: AudioRecorder.js</title> + + <script src="scripts/prettify/prettify.js"> </script> + <script src="scripts/prettify/lang-css.js"> </script> + <!--[if lt IE 9]> + <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> + <![endif]--> + <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css"> + <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css"> +</head> + +<body> + +<div id="main"> + + <h1 class="page-title">Source: AudioRecorder.js</h1> + + + + + + + <section> + <article> + <pre class="prettyprint source linenums"><code>/* + * 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() { + + /** + * Callback which is invoked when the audio recording process has stopped + * and the underlying Guacamole stream has been closed normally. Audio will + * only resume recording if a new Guacamole.AudioRecorder is started. This + * Guacamole.AudioRecorder instance MAY NOT be reused. + * + * @event + */ + this.onclose = null; + + /** + * Callback which is invoked when the audio recording process cannot + * continue due to an error, if it has started at all. The underlying + * Guacamole stream is automatically closed. Future attempts to record + * audio should not be made, and this Guacamole.AudioRecorder instance + * MAY NOT be reused. + * + * @event + */ + this.onerror = null; + +}; + +/** + * 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) { + + /** + * Reference to this RawAudioRecorder. + * + * @private + * @type {Guacamole.RawAudioRecorder} + */ + var recorder = this; + + /** + * The size of audio buffer to request from the Web Audio API when + * recording or processing audio, in sample-frames. This must be a power of + * two between 256 and 16384 inclusive, as required by + * AudioContext.createScriptProcessor(). + * + * @private + * @constant + * @type {Number} + */ + var BUFFER_SIZE = 2048; + + /** + * The window size to use when applying Lanczos interpolation, commonly + * denoted by the variable "a". + * See: https://en.wikipedia.org/wiki/Lanczos_resampling + * + * @private + * @contant + * @type Number + */ + var LANCZOS_WINDOW_SIZE = 3; + + /** + * 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 = Guacamole.AudioContextFactory.getAudioContext(); + + // Some browsers do not implement navigator.mediaDevices - this + // shims in this functionality to ensure code compatibility. + if (!navigator.mediaDevices) + navigator.mediaDevices = {}; + + // Browsers that either do not implement navigator.mediaDevices + // at all or do not implement it completely need the getUserMedia + // method defined. This shims in this function by detecting + // one of the supported legacy methods. + if (!navigator.mediaDevices.getUserMedia) + navigator.mediaDevices.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 total number of audio samples read from the local audio input device + * over the life of this audio recorder. + * + * @private + * @type {Number} + */ + var readSamples = 0; + + /** + * The total number of audio samples written to the underlying Guacamole + * connection over the life of this audio recorder. + * + * @private + * @type {Number} + */ + var writtenSamples = 0; + + /** + * The audio stream provided by the browser, if allowed. If no stream has + * yet been received, this will be null. + * + * @type MediaStream + */ + var mediaStream = null; + + /** + * The source node providing access to the local audio input device. + * + * @private + * @type {MediaStreamAudioSourceNode} + */ + var source = null; + + /** + * The script processing node which receives audio input from the media + * stream source node as individual audio buffers. + * + * @private + * @type {ScriptProcessorNode} + */ + var processor = null; + + /** + * The normalized sinc function. The normalized sinc function is defined as + * 1 for x=0 and sin(PI * x) / (PI * x) for all other values of x. + * + * See: https://en.wikipedia.org/wiki/Sinc_function + * + * @private + * @param {Number} x + * The point at which the normalized sinc function should be computed. + * + * @returns {Number} + * The value of the normalized sinc function at x. + */ + var sinc = function sinc(x) { + + // The value of sinc(0) is defined as 1 + if (x === 0) + return 1; + + // Otherwise, normlized sinc(x) is sin(PI * x) / (PI * x) + var piX = Math.PI * x; + return Math.sin(piX) / piX; + + }; + + /** + * Calculates the value of the Lanczos kernal at point x for a given window + * size. See: https://en.wikipedia.org/wiki/Lanczos_resampling + * + * @private + * @param {Number} x + * The point at which the value of the Lanczos kernel should be + * computed. + * + * @param {Number} a + * The window size to use for the Lanczos kernel. + * + * @returns {Number} + * The value of the Lanczos kernel at the given point for the given + * window size. + */ + var lanczos = function lanczos(x, a) { + + // Lanczos is sinc(x) * sinc(x / a) for -a < x < a ... + if (-a < x && x < a) + return sinc(x) * sinc(x / a); + + // ... and 0 otherwise + return 0; + + }; + + /** + * Determines the value of the waveform represented by the audio data at + * the given location. If the value cannot be determined exactly as it does + * not correspond to an exact sample within the audio data, the value will + * be derived through interpolating nearby samples. + * + * @private + * @param {Float32Array} audioData + * An array of audio data, as returned by AudioBuffer.getChannelData(). + * + * @param {Number} t + * The relative location within the waveform from which the value + * should be retrieved, represented as a floating point number between + * 0 and 1 inclusive, where 0 represents the earliest point in time and + * 1 represents the latest. + * + * @returns {Number} + * The value of the waveform at the given location. + */ + var interpolateSample = function getValueAt(audioData, t) { + + // Convert [0, 1] range to [0, audioData.length - 1] + var index = (audioData.length - 1) * t; + + // Determine the start and end points for the summation used by the + // Lanczos interpolation algorithm (see: https://en.wikipedia.org/wiki/Lanczos_resampling) + var start = Math.floor(index) - LANCZOS_WINDOW_SIZE + 1; + var end = Math.floor(index) + LANCZOS_WINDOW_SIZE; + + // Calculate the value of the Lanczos interpolation function for the + // required range + var sum = 0; + for (var i = start; i <= end; i++) { + sum += (audioData[i] || 0) * lanczos(index - i, LANCZOS_WINDOW_SIZE); + } + + return sum; + + }; + + /** + * 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) { + + // Track overall amount of data read + var inSamples = audioBuffer.length; + readSamples += inSamples; + + // Calculate the total number of samples that should be written as of + // the audio data just received and adjust the size of the output + // packet accordingly + var expectedWrittenSamples = Math.round(readSamples * format.rate / audioBuffer.sampleRate); + var outSamples = expectedWrittenSamples - writtenSamples; + + // Update number of samples written + writtenSamples += outSamples; + + // Get array for raw PCM storage + var data = new SampleArray(outSamples * format.channels); + + // 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 < outSamples; i++) { + data[offset] = interpolateSample(audioData, i / (outSamples - 1)) * maxSampleValue; + offset += format.channels; + } + + } + + return data; + + }; + + /** + * Requests access to the user's microphone and begins capturing audio. All + * received audio data is resampled as necessary and forwarded to the + * Guacamole stream underlying this Guacamole.RawAudioRecorder. This + * function must be invoked ONLY ONCE per instance of + * Guacamole.RawAudioRecorder. + * + * @private + */ + var beginAudioCapture = function beginAudioCapture() { + + // Attempt to retrieve an audio input stream from the browser + navigator.mediaDevices.getUserMedia({ 'audio' : true }, function streamReceived(stream) { + + // Create processing node which receives appropriately-sized audio buffers + processor = context.createScriptProcessor(BUFFER_SIZE, 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).buffer); + }; + + // Connect processing node to user's audio input source + source = context.createMediaStreamSource(stream); + source.connect(processor); + + // Save stream for later cleanup + mediaStream = stream; + + }, function streamDenied() { + + // Simply end stream if audio access is not allowed + writer.sendEnd(); + + // Notify of closure + if (recorder.onerror) + recorder.onerror(); + + }); + + }; + + /** + * Stops capturing audio, if the capture has started, freeing all associated + * resources. If the capture has not started, this function simply ends the + * underlying Guacamole stream. + * + * @private + */ + var stopAudioCapture = function stopAudioCapture() { + + // Disconnect media source node from script processor + if (source) + source.disconnect(); + + // Disconnect associated script processor node + if (processor) + processor.disconnect(); + + // Stop capture + if (mediaStream) { + var tracks = mediaStream.getTracks(); + for (var i = 0; i < tracks.length; i++) + tracks[i].stop(); + } + + // Remove references to now-unneeded components + processor = null; + source = null; + mediaStream = null; + + // End stream + writer.sendEnd(); + + }; + + // Once audio stream is successfully open, request and begin reading audio + writer.onack = function audioStreamAcknowledged(status) { + + // Begin capture if successful response and not yet started + if (status.code === Guacamole.Status.Code.SUCCESS && !mediaStream) + beginAudioCapture(); + + // Otherwise stop capture and cease handling any further acks + else { + + // Stop capturing audio + stopAudioCapture(); + writer.onack = null; + + // Notify if stream has closed normally + if (status.code === Guacamole.Status.Code.RESOURCE_CLOSED) { + if (recorder.onclose) + recorder.onclose(); + } + + // Otherwise notify of closure due to error + else { + if (recorder.onerror) + recorder.onerror(); + } + + } + + }; + +}; + +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 (!Guacamole.AudioContextFactory.getAudioContext()) + 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 (!Guacamole.AudioContextFactory.getAudioContext()) + return []; + + // We support 8-bit and 16-bit raw PCM + return [ + 'audio/L8', + 'audio/L16' + ]; + +}; +</code></pre> + </article> + </section> + + + + +</div> + +<nav> + <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Guacamole.ArrayBufferReader.html">ArrayBufferReader</a></li><li><a href="Guacamole.ArrayBufferWriter.html">ArrayBufferWriter</a></li><li><a href="Guacamole.AudioPlayer.html">AudioPlayer</a></li><li><a href="Guacamole.AudioRecorder.html">AudioRecorder</a></li><li><a href="Guacamole.BlobReader.html">BlobReader</a></li><li><a href="Guacamole.BlobWriter.html">BlobWriter</a></li><li><a href="Guacamole.ChainedTunnel.html">ChainedTunnel</a></li><li><a href="Guacamole.Client.html">Client</a></li><li><a href="Guacamole.DataURIReader.html">DataURIReader</a></li><li><a href="Guacamole.Display.html">Display</a></li><li><a href="Guacamole.Display.VisibleLayer.html">VisibleLayer</a></li><li><a href="Guacamole.HTTPTunnel.html">HTTPTunnel</a></li><li><a href="Guacamole.InputSink.html">InputSink</a></li><li><a href="Guacamole.InputStream.html">InputStream</a></li><li><a href="Guacamole.IntegerPool.html">IntegerPool</a></li><l i><a href="Guacamole.JSONReader.html">JSONReader</a></li><li><a href="Guacamole.Keyboard.html">Keyboard</a></li><li><a href="Guacamole.Keyboard.ModifierState.html">ModifierState</a></li><li><a href="Guacamole.Layer.html">Layer</a></li><li><a href="Guacamole.Layer.Pixel.html">Pixel</a></li><li><a href="Guacamole.Mouse.html">Mouse</a></li><li><a href="Guacamole.Mouse.State.html">State</a></li><li><a href="Guacamole.Mouse.Touchpad.html">Touchpad</a></li><li><a href="Guacamole.Mouse.Touchscreen.html">Touchscreen</a></li><li><a href="Guacamole.Object.html">Object</a></li><li><a href="Guacamole.OnScreenKeyboard.html">OnScreenKeyboard</a></li><li><a href="Guacamole.OnScreenKeyboard.Key.html">Key</a></li><li><a href="Guacamole.OnScreenKeyboard.Layout.html">Layout</a></li><li><a href="Guacamole.OutputStream.html">OutputStream</a></li><li><a href="Guacamole.Parser.html">Parser</a></li><li><a href="Guacamole.RawAudioFormat.html">RawAudioFormat</a></li><li><a href="Guacamole.RawAudioPlayer.html ">RawAudioPlayer</a></li><li><a href="Guacamole.RawAudioRecorder.html">RawAudioRecorder</a></li><li><a href="Guacamole.SessionRecording.html">SessionRecording</a></li><li><a href="Guacamole.StaticHTTPTunnel.html">StaticHTTPTunnel</a></li><li><a href="Guacamole.Status.html">Status</a></li><li><a href="Guacamole.StringReader.html">StringReader</a></li><li><a href="Guacamole.StringWriter.html">StringWriter</a></li><li><a href="Guacamole.Tunnel.html">Tunnel</a></li><li><a href="Guacamole.VideoPlayer.html">VideoPlayer</a></li><li><a href="Guacamole.WebSocketTunnel.html">WebSocketTunnel</a></li></ul><h3>Events</h3><ul><li><a href="Guacamole.ArrayBufferReader.html#event:ondata">ondata</a></li><li><a href="Guacamole.ArrayBufferReader.html#event:onend">onend</a></li><li><a href="Guacamole.ArrayBufferWriter.html#event:onack">onack</a></li><li><a href="Guacamole.AudioRecorder.html#event:onclose">onclose</a></li><li><a href="Guacamole.AudioRecorder.html#event:onerror">onerror</a></li><li><a hre f="Guacamole.BlobReader.html#event:onend">onend</a></li><li><a href="Guacamole.BlobReader.html#event:onprogress">onprogress</a></li><li><a href="Guacamole.BlobWriter.html#event:onack">onack</a></li><li><a href="Guacamole.BlobWriter.html#event:oncomplete">oncomplete</a></li><li><a href="Guacamole.BlobWriter.html#event:onerror">onerror</a></li><li><a href="Guacamole.BlobWriter.html#event:onprogress">onprogress</a></li><li><a href="Guacamole.ChainedTunnel.html#event:onerror">onerror</a></li><li><a href="Guacamole.ChainedTunnel.html#event:oninstruction">oninstruction</a></li><li><a href="Guacamole.ChainedTunnel.html#event:onstatechange">onstatechange</a></li><li><a href="Guacamole.Client.html#event:onaudio">onaudio</a></li><li><a href="Guacamole.Client.html#event:onclipboard">onclipboard</a></li><li><a href="Guacamole.Client.html#event:onerror">onerror</a></li><li><a href="Guacamole.Client.html#event:onfile">onfile</a></li><li><a href="Guacamole.Client.html#event:onfilesystem">onfilesys tem</a></li><li><a href="Guacamole.Client.html#event:onname">onname</a></li><li><a href="Guacamole.Client.html#event:onpipe">onpipe</a></li><li><a href="Guacamole.Client.html#event:onstatechange">onstatechange</a></li><li><a href="Guacamole.Client.html#event:onsync">onsync</a></li><li><a href="Guacamole.Client.html#event:onvideo">onvideo</a></li><li><a href="Guacamole.DataURIReader.html#event:onend">onend</a></li><li><a href="Guacamole.Display.html#event:oncursor">oncursor</a></li><li><a href="Guacamole.Display.html#event:onresize">onresize</a></li><li><a href="Guacamole.HTTPTunnel.html#event:onerror">onerror</a></li><li><a href="Guacamole.HTTPTunnel.html#event:oninstruction">oninstruction</a></li><li><a href="Guacamole.HTTPTunnel.html#event:onstatechange">onstatechange</a></li><li><a href="Guacamole.InputStream.html#event:onblob">onblob</a></li><li><a href="Guacamole.InputStream.html#event:onend">onend</a></li><li><a href="Guacamole.JSONReader.html#event:onend">onend</a></li><li><a href="Guacamole.JSONReader.html#event:onprogress">onprogress</a></li><li><a href="Guacamole.Keyboard.html#event:onkeydown">onkeydown</a></li><li><a href="Guacamole.Keyboard.html#event:onkeyup">onkeyup</a></li><li><a href="Guacamole.Mouse.Touchpad.html#event:onmousedown">onmousedown</a></li><li><a href="Guacamole.Mouse.Touchpad.html#event:onmousemove">onmousemove</a></li><li><a href="Guacamole.Mouse.Touchpad.html#event:onmouseup">onmouseup</a></li><li><a href="Guacamole.Mouse.Touchscreen.html#event:onmousedown">onmousedown</a></li><li><a href="Guacamole.Mouse.Touchscreen.html#event:onmousemove">onmousemove</a></li><li><a href="Guacamole.Mouse.Touchscreen.html#event:onmouseup">onmouseup</a></li><li><a href="Guacamole.Mouse.html#event:onmousedown">onmousedown</a></li><li><a href="Guacamole.Mouse.html#event:onmousemove">onmousemove</a></li><li><a href="Guacamole.Mouse.html#event:onmouseout">onmouseout</a></li><li><a href="Guacamole.Mouse.html#event:onmouseup">onmouseup</a></li><li><a h ref="Guacamole.Object.html#event:onbody">onbody</a></li><li><a href="Guacamole.Object.html#event:onundefine">onundefine</a></li><li><a href="Guacamole.OnScreenKeyboard.html#event:onkeydown">onkeydown</a></li><li><a href="Guacamole.OnScreenKeyboard.html#event:onkeyup">onkeyup</a></li><li><a href="Guacamole.OutputStream.html#event:onack">onack</a></li><li><a href="Guacamole.Parser.html#event:oninstruction">oninstruction</a></li><li><a href="Guacamole.RawAudioRecorder.html#event:onclose">onclose</a></li><li><a href="Guacamole.RawAudioRecorder.html#event:onerror">onerror</a></li><li><a href="Guacamole.SessionRecording._PlaybackTunnel.html#event:onerror">onerror</a></li><li><a href="Guacamole.SessionRecording._PlaybackTunnel.html#event:oninstruction">oninstruction</a></li><li><a href="Guacamole.SessionRecording._PlaybackTunnel.html#event:onstatechange">onstatechange</a></li><li><a href="Guacamole.SessionRecording.html#event:onpause">onpause</a></li><li><a href="Guacamole.SessionRecording .html#event:onplay">onplay</a></li><li><a href="Guacamole.SessionRecording.html#event:onprogress">onprogress</a></li><li><a href="Guacamole.SessionRecording.html#event:onseek">onseek</a></li><li><a href="Guacamole.StaticHTTPTunnel.html#event:onerror">onerror</a></li><li><a href="Guacamole.StaticHTTPTunnel.html#event:oninstruction">oninstruction</a></li><li><a href="Guacamole.StaticHTTPTunnel.html#event:onstatechange">onstatechange</a></li><li><a href="Guacamole.StringReader.html#event:onend">onend</a></li><li><a href="Guacamole.StringReader.html#event:ontext">ontext</a></li><li><a href="Guacamole.StringWriter.html#event:onack">onack</a></li><li><a href="Guacamole.Tunnel.html#event:onerror">onerror</a></li><li><a href="Guacamole.Tunnel.html#event:oninstruction">oninstruction</a></li><li><a href="Guacamole.Tunnel.html#event:onstatechange">onstatechange</a></li><li><a href="Guacamole.WebSocketTunnel.html#event:onerror">onerror</a></li><li><a href="Guacamole.WebSocketTunnel.html#event:o ninstruction">oninstruction</a></li><li><a href="Guacamole.WebSocketTunnel.html#event:onstatechange">onstatechange</a></li></ul><h3>Namespaces</h3><ul><li><a href="Guacamole.html">Guacamole</a></li><li><a href="Guacamole.AudioContextFactory.html">AudioContextFactory</a></li></ul> +</nav> + +<br class="clear"> + +<footer> + Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Fri Dec 21 2018 13:47:10 GMT-0800 (PST) +</footer> + +<script> prettyPrint(); </script> +<script src="scripts/linenumber.js"> </script> +</body> +</html> http://git-wip-us.apache.org/repos/asf/guacamole-website/blob/044692cf/doc/1.0.0/guacamole-common-js/BlobReader.js.html ---------------------------------------------------------------------- diff --git a/doc/1.0.0/guacamole-common-js/BlobReader.js.html b/doc/1.0.0/guacamole-common-js/BlobReader.js.html new file mode 100644 index 0000000..94592b6 --- /dev/null +++ b/doc/1.0.0/guacamole-common-js/BlobReader.js.html @@ -0,0 +1,178 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="utf-8"> + <title>JSDoc: Source: BlobReader.js</title> + + <script src="scripts/prettify/prettify.js"> </script> + <script src="scripts/prettify/lang-css.js"> </script> + <!--[if lt IE 9]> + <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> + <![endif]--> + <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css"> + <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css"> +</head> + +<body> + +<div id="main"> + + <h1 class="page-title">Source: BlobReader.js</h1> + + + + + + + <section> + <article> + <pre class="prettyprint source linenums"><code>/* + * 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 reader which automatically handles the given input stream, assembling all + * received blobs into a single blob by appending them to each other in order. + * 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. + * @param {String} mimetype The mimetype of the blob being built. + */ +Guacamole.BlobReader = function(stream, mimetype) { + + /** + * Reference to this Guacamole.InputStream. + * @private + */ + var guac_reader = this; + + /** + * The length of this Guacamole.InputStream in bytes. + * @private + */ + var length = 0; + + // Get blob builder + var blob_builder; + if (window.BlobBuilder) blob_builder = new BlobBuilder(); + else if (window.WebKitBlobBuilder) blob_builder = new WebKitBlobBuilder(); + else if (window.MozBlobBuilder) blob_builder = new MozBlobBuilder(); + else + blob_builder = new (function() { + + var blobs = []; + + /** @ignore */ + this.append = function(data) { + blobs.push(new Blob([data], {"type": mimetype})); + }; + + /** @ignore */ + this.getBlob = function() { + return new Blob(blobs, {"type": mimetype}); + }; + + })(); + + // Append received blobs + 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<binary.length; i++) + bufferView[i] = binary.charCodeAt(i); + + blob_builder.append(arrayBuffer); + length += arrayBuffer.byteLength; + + // Call handler, if present + if (guac_reader.onprogress) + guac_reader.onprogress(arrayBuffer.byteLength); + + // Send success response + stream.sendAck("OK", 0x0000); + + }; + + // Simply call onend when end received + stream.onend = function() { + if (guac_reader.onend) + guac_reader.onend(); + }; + + /** + * Returns the current length of this Guacamole.InputStream, in bytes. + * @return {Number} The current length of this Guacamole.InputStream. + */ + this.getLength = function() { + return length; + }; + + /** + * Returns the contents of this Guacamole.BlobReader as a Blob. + * @return {Blob} The contents of this Guacamole.BlobReader. + */ + this.getBlob = function() { + return blob_builder.getBlob(); + }; + + /** + * Fired once for every blob of data received. + * + * @event + * @param {Number} length The number of bytes received. + */ + this.onprogress = null; + + /** + * Fired once this stream is finished and no further data will be written. + * @event + */ + this.onend = null; + +};</code></pre> + </article> + </section> + + + + +</div> + +<nav> + <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Guacamole.ArrayBufferReader.html">ArrayBufferReader</a></li><li><a href="Guacamole.ArrayBufferWriter.html">ArrayBufferWriter</a></li><li><a href="Guacamole.AudioPlayer.html">AudioPlayer</a></li><li><a href="Guacamole.AudioRecorder.html">AudioRecorder</a></li><li><a href="Guacamole.BlobReader.html">BlobReader</a></li><li><a href="Guacamole.BlobWriter.html">BlobWriter</a></li><li><a href="Guacamole.ChainedTunnel.html">ChainedTunnel</a></li><li><a href="Guacamole.Client.html">Client</a></li><li><a href="Guacamole.DataURIReader.html">DataURIReader</a></li><li><a href="Guacamole.Display.html">Display</a></li><li><a href="Guacamole.Display.VisibleLayer.html">VisibleLayer</a></li><li><a href="Guacamole.HTTPTunnel.html">HTTPTunnel</a></li><li><a href="Guacamole.InputSink.html">InputSink</a></li><li><a href="Guacamole.InputStream.html">InputStream</a></li><li><a href="Guacamole.IntegerPool.html">IntegerPool</a></li><l i><a href="Guacamole.JSONReader.html">JSONReader</a></li><li><a href="Guacamole.Keyboard.html">Keyboard</a></li><li><a href="Guacamole.Keyboard.ModifierState.html">ModifierState</a></li><li><a href="Guacamole.Layer.html">Layer</a></li><li><a href="Guacamole.Layer.Pixel.html">Pixel</a></li><li><a href="Guacamole.Mouse.html">Mouse</a></li><li><a href="Guacamole.Mouse.State.html">State</a></li><li><a href="Guacamole.Mouse.Touchpad.html">Touchpad</a></li><li><a href="Guacamole.Mouse.Touchscreen.html">Touchscreen</a></li><li><a href="Guacamole.Object.html">Object</a></li><li><a href="Guacamole.OnScreenKeyboard.html">OnScreenKeyboard</a></li><li><a href="Guacamole.OnScreenKeyboard.Key.html">Key</a></li><li><a href="Guacamole.OnScreenKeyboard.Layout.html">Layout</a></li><li><a href="Guacamole.OutputStream.html">OutputStream</a></li><li><a href="Guacamole.Parser.html">Parser</a></li><li><a href="Guacamole.RawAudioFormat.html">RawAudioFormat</a></li><li><a href="Guacamole.RawAudioPlayer.html ">RawAudioPlayer</a></li><li><a href="Guacamole.RawAudioRecorder.html">RawAudioRecorder</a></li><li><a href="Guacamole.SessionRecording.html">SessionRecording</a></li><li><a href="Guacamole.StaticHTTPTunnel.html">StaticHTTPTunnel</a></li><li><a href="Guacamole.Status.html">Status</a></li><li><a href="Guacamole.StringReader.html">StringReader</a></li><li><a href="Guacamole.StringWriter.html">StringWriter</a></li><li><a href="Guacamole.Tunnel.html">Tunnel</a></li><li><a href="Guacamole.VideoPlayer.html">VideoPlayer</a></li><li><a href="Guacamole.WebSocketTunnel.html">WebSocketTunnel</a></li></ul><h3>Events</h3><ul><li><a href="Guacamole.ArrayBufferReader.html#event:ondata">ondata</a></li><li><a href="Guacamole.ArrayBufferReader.html#event:onend">onend</a></li><li><a href="Guacamole.ArrayBufferWriter.html#event:onack">onack</a></li><li><a href="Guacamole.AudioRecorder.html#event:onclose">onclose</a></li><li><a href="Guacamole.AudioRecorder.html#event:onerror">onerror</a></li><li><a hre f="Guacamole.BlobReader.html#event:onend">onend</a></li><li><a href="Guacamole.BlobReader.html#event:onprogress">onprogress</a></li><li><a href="Guacamole.BlobWriter.html#event:onack">onack</a></li><li><a href="Guacamole.BlobWriter.html#event:oncomplete">oncomplete</a></li><li><a href="Guacamole.BlobWriter.html#event:onerror">onerror</a></li><li><a href="Guacamole.BlobWriter.html#event:onprogress">onprogress</a></li><li><a href="Guacamole.ChainedTunnel.html#event:onerror">onerror</a></li><li><a href="Guacamole.ChainedTunnel.html#event:oninstruction">oninstruction</a></li><li><a href="Guacamole.ChainedTunnel.html#event:onstatechange">onstatechange</a></li><li><a href="Guacamole.Client.html#event:onaudio">onaudio</a></li><li><a href="Guacamole.Client.html#event:onclipboard">onclipboard</a></li><li><a href="Guacamole.Client.html#event:onerror">onerror</a></li><li><a href="Guacamole.Client.html#event:onfile">onfile</a></li><li><a href="Guacamole.Client.html#event:onfilesystem">onfilesys tem</a></li><li><a href="Guacamole.Client.html#event:onname">onname</a></li><li><a href="Guacamole.Client.html#event:onpipe">onpipe</a></li><li><a href="Guacamole.Client.html#event:onstatechange">onstatechange</a></li><li><a href="Guacamole.Client.html#event:onsync">onsync</a></li><li><a href="Guacamole.Client.html#event:onvideo">onvideo</a></li><li><a href="Guacamole.DataURIReader.html#event:onend">onend</a></li><li><a href="Guacamole.Display.html#event:oncursor">oncursor</a></li><li><a href="Guacamole.Display.html#event:onresize">onresize</a></li><li><a href="Guacamole.HTTPTunnel.html#event:onerror">onerror</a></li><li><a href="Guacamole.HTTPTunnel.html#event:oninstruction">oninstruction</a></li><li><a href="Guacamole.HTTPTunnel.html#event:onstatechange">onstatechange</a></li><li><a href="Guacamole.InputStream.html#event:onblob">onblob</a></li><li><a href="Guacamole.InputStream.html#event:onend">onend</a></li><li><a href="Guacamole.JSONReader.html#event:onend">onend</a></li><li><a href="Guacamole.JSONReader.html#event:onprogress">onprogress</a></li><li><a href="Guacamole.Keyboard.html#event:onkeydown">onkeydown</a></li><li><a href="Guacamole.Keyboard.html#event:onkeyup">onkeyup</a></li><li><a href="Guacamole.Mouse.Touchpad.html#event:onmousedown">onmousedown</a></li><li><a href="Guacamole.Mouse.Touchpad.html#event:onmousemove">onmousemove</a></li><li><a href="Guacamole.Mouse.Touchpad.html#event:onmouseup">onmouseup</a></li><li><a href="Guacamole.Mouse.Touchscreen.html#event:onmousedown">onmousedown</a></li><li><a href="Guacamole.Mouse.Touchscreen.html#event:onmousemove">onmousemove</a></li><li><a href="Guacamole.Mouse.Touchscreen.html#event:onmouseup">onmouseup</a></li><li><a href="Guacamole.Mouse.html#event:onmousedown">onmousedown</a></li><li><a href="Guacamole.Mouse.html#event:onmousemove">onmousemove</a></li><li><a href="Guacamole.Mouse.html#event:onmouseout">onmouseout</a></li><li><a href="Guacamole.Mouse.html#event:onmouseup">onmouseup</a></li><li><a h ref="Guacamole.Object.html#event:onbody">onbody</a></li><li><a href="Guacamole.Object.html#event:onundefine">onundefine</a></li><li><a href="Guacamole.OnScreenKeyboard.html#event:onkeydown">onkeydown</a></li><li><a href="Guacamole.OnScreenKeyboard.html#event:onkeyup">onkeyup</a></li><li><a href="Guacamole.OutputStream.html#event:onack">onack</a></li><li><a href="Guacamole.Parser.html#event:oninstruction">oninstruction</a></li><li><a href="Guacamole.RawAudioRecorder.html#event:onclose">onclose</a></li><li><a href="Guacamole.RawAudioRecorder.html#event:onerror">onerror</a></li><li><a href="Guacamole.SessionRecording._PlaybackTunnel.html#event:onerror">onerror</a></li><li><a href="Guacamole.SessionRecording._PlaybackTunnel.html#event:oninstruction">oninstruction</a></li><li><a href="Guacamole.SessionRecording._PlaybackTunnel.html#event:onstatechange">onstatechange</a></li><li><a href="Guacamole.SessionRecording.html#event:onpause">onpause</a></li><li><a href="Guacamole.SessionRecording .html#event:onplay">onplay</a></li><li><a href="Guacamole.SessionRecording.html#event:onprogress">onprogress</a></li><li><a href="Guacamole.SessionRecording.html#event:onseek">onseek</a></li><li><a href="Guacamole.StaticHTTPTunnel.html#event:onerror">onerror</a></li><li><a href="Guacamole.StaticHTTPTunnel.html#event:oninstruction">oninstruction</a></li><li><a href="Guacamole.StaticHTTPTunnel.html#event:onstatechange">onstatechange</a></li><li><a href="Guacamole.StringReader.html#event:onend">onend</a></li><li><a href="Guacamole.StringReader.html#event:ontext">ontext</a></li><li><a href="Guacamole.StringWriter.html#event:onack">onack</a></li><li><a href="Guacamole.Tunnel.html#event:onerror">onerror</a></li><li><a href="Guacamole.Tunnel.html#event:oninstruction">oninstruction</a></li><li><a href="Guacamole.Tunnel.html#event:onstatechange">onstatechange</a></li><li><a href="Guacamole.WebSocketTunnel.html#event:onerror">onerror</a></li><li><a href="Guacamole.WebSocketTunnel.html#event:o ninstruction">oninstruction</a></li><li><a href="Guacamole.WebSocketTunnel.html#event:onstatechange">onstatechange</a></li></ul><h3>Namespaces</h3><ul><li><a href="Guacamole.html">Guacamole</a></li><li><a href="Guacamole.AudioContextFactory.html">AudioContextFactory</a></li></ul> +</nav> + +<br class="clear"> + +<footer> + Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Fri Dec 21 2018 13:47:10 GMT-0800 (PST) +</footer> + +<script> prettyPrint(); </script> +<script src="scripts/linenumber.js"> </script> +</body> +</html>