Bugzilla – Attachment 663 Details for
Bug 4822
Web Access should support sound/audio
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch for client-side
esd.patch (text/plain), 11.05 KB, created by
Samuel Mannehed
on 2015-12-23 11:25:17 CET
(
hide
)
Description:
Patch for client-side
Filename:
MIME Type:
Creator:
Samuel Mannehed
Created:
2015-12-23 11:25:17 CET
Size:
11.05 KB
patch
obsolete
>Index: noVNC/include/esd.js >=================================================================== >--- noVNC/include/esd.js (revision 0) >+++ noVNC/include/esd.js (working copy) >@@ -0,0 +1,349 @@ >+/* >+ * EsounD Server >+ * Copyright 2013 Samuel Mannehed for Cendio AB >+ */ >+ >+function ESD(defaults) { >+"use strict"; >+ >+var that = {}, // Public API methods >+ conf = {}, // Configuration attributes >+ >+ // Pre-declare private functions used before definitions (jslint) >+ handle_message, connect_audio, disconnect_audio, buffer_audio, >+ parse_stream, parse_format, parse_rate, >+ >+ // >+ // Private ESD namespace variables >+ // >+ esd_host = '', >+ esd_port = 4910, >+ esd_path = '', >+ >+ ws = null, // Websock object >+ >+ ws_loop_timeout = 1000, // time until we loop the ws connection >+ ws_loop_timer = null, // timer for looping the ws connection >+ >+ authenticated = false, // true when the esd connection is authenticated >+ little_endian = false, >+ sixteen_bits = false, >+ stream = false, // true while streaming data >+ play = false, // true while playing sound >+ nrOfChannels = 1, >+ rate = 0, // Sample rate of audio >+ name = "", // name of esd stream >+ >+ context = null, // audio context >+ node = null, // audio processing node >+ buff = new Array(); // buffer for audio data >+ >+// Configuration attributes >+Util.conf_defaults(conf, that, defaults, [ >+ ['encrypt', 'rw', 'bool', false, 'Use TLS/SSL/wss encryption'] >+ ]); >+ >+// >+// Setup routines >+// >+ >+// Create the public API interface and initialize values that stay >+// constant across connect/disconnect >+function constructor() { >+ >+ ws = new Websock(); >+ ws.on('message', handle_message); >+ ws.on('open', function() { >+ console.log("ESD: WebSocket on-open event"); >+ }); >+ ws.on('close', function(e) { >+ var msg = ""; >+ if (e.code) { >+ msg = " (code: " + e.code; >+ if (e.reason) >+ msg += ", reason: " + e.reason; >+ msg += ")"; >+ } >+ console.log("ESD: WebSocket on-close event, msg: " + msg); >+ >+ // Loop >+ ws_loop_timer = setTimeout(function() { >+ connect(); >+ }, ws_loop_timeout); >+ }); >+ ws.on('error', function(e) { >+ console.log("ESD: WebSocket on-error event, data: " + e.data); >+ if (ws_loop_timer) { >+ console.log("ESD: Clearing websocket loop timer"); >+ clearTimeout(ws_loop_timer); >+ ws_loop_timer = null; >+ } >+ }); >+ >+ ws.init(); >+ >+ /* Check web-socket-js if no builtin WebSocket support */ >+ if (Websock_native) { >+ console.log("ESD: Using native WebSockets"); >+ } else { >+ console.log("ESD: Using web-socket-js bridge. Flash version: " + >+ Util.Flash.version); >+ } >+ >+ try { >+ if (window.AudioContext) >+ context = new AudioContext(); >+ else >+ context = new webkitAudioContext(); >+ } catch(e) { >+ console.log("ESD: Web Audio API is not supported in this browser: " + e); >+ } >+ >+ return that; // Return the public API interface >+} >+ >+// On iOS devices the sound needs to start from an user initiated event >+window.addEventListener('touchstart', function() { >+ >+ if (context.createScriptProcessor) >+ node = context.createScriptProcessor(4096, 0, 1); >+ else >+ node = context.createJavaScriptNode(4096, 0, 1); >+ >+ var source = context.createBufferSource(); >+ var buffer = context.createBuffer(1, 1024, context.sampleRate) >+ var data = buffer.getChannelData(0); >+ for (var i = 0; i < data.length; i++) >+ data[i] = 0; >+ source.buffer = buffer; >+ source.loop = true; >+ source.connect(node); >+ node.connect(context.destination); >+ >+ source.start(0); >+ >+}, false); >+ >+function connect() { >+ var uri; >+ >+ if (typeof UsingSocketIO !== "undefined") { >+ uri = "http://" + esd_host + ":" + esd_port + "/" + esd_path; >+ } else { >+ if (conf.encrypt) >+ uri = "wss://"; >+ else >+ uri = "ws://"; >+ uri += esd_host + ":" + esd_port + "/" + esd_path; >+ } >+ console.log("ESD: connecting to " + uri); >+ ws.open(uri, ['binary','base64','audio']); >+} >+ >+function disconnect() { >+ ws.close(); >+} >+ >+// >+// Utility routines >+// >+ >+handle_message = function() { >+ if (ws.rQlen() === 0) { return; } >+ >+ if (stream && play) { >+ buffer_audio(); >+ return; >+ } >+ >+ var opcode, esdkey, endian; >+ >+ // If we are not authenticated yet >+ if (!authenticated) { >+ if (ws.rQwait("init", 20, 0)) { return; } >+ >+ esdkey = ws.rQshiftBytes(16); >+ endian = ws.rQshiftStr(4); >+ little_endian = (endian == 'NDNE'); >+ if (little_endian) >+ ws.send([1,0,0,0]); >+ else >+ ws.send([0,0,0,1]); >+ authenticated = true; >+ >+ console.log("ESD: authenticated"); >+ >+ } else { >+ opcode = ws.rQshiftBytes(4); >+ >+ switch (opcode[0]) { >+ case 1: //lock >+ case 2: //unlock >+ case 3: //stream-play >+ if (ws.rQwait("stream-play", 136, 4)) { return; } >+ >+ // Parse the header >+ parse_format(ws.rQshiftBytes(4)); >+ parse_rate(ws.rQshiftBytes(4)); >+ name = ws.rQshiftStr(128); >+ >+ console.log("ESD: --- Audio header --- "); >+ console.log((sixteen_bits ? "16bit " : "") + >+ ((nrOfChannels == 1) ? "mono " : "stereo ") + >+ (stream ? "stream " : "") + >+ (play ? "play" : "")); >+ console.log(rate + " Hz"); >+ console.log(name); >+ >+ connect_audio(); >+ case 5: //stream-mon >+ case 6: //sample-cache >+ case 7: //sample-free >+ case 8: //sample-play >+ case 9: //sample-loop >+ case 10: //sample-stop >+ case 11: //sample-kill >+ case 12: //standby >+ case 13: //resume >+ case 14: //sample-getid >+ case 15: //stream-filter >+ case 16: //server-info >+ case 17: //server-all-info >+ case 18: //subscribe >+ case 19: //unsubjcribe >+ case 20: //stream-pan >+ case 21: //sample-pan >+ case 22: //standby-mode >+ case 23: //latency >+ } >+ } >+}; >+ >+connect_audio = function() { >+ // Reset the node >+ if (node != null) >+ node.disconnect(); >+ >+ if (context.createScriptProcessor) >+ node = context.createScriptProcessor(4096, 0, nrOfChannels); >+ else >+ node = context.createJavaScriptNode(4096, 0, nrOfChannels); >+ node.onaudioprocess = parse_stream; >+ node.connect(context.destination); >+}; >+ >+disconnect_audio = function() { >+ >+ node.onaudioprocess = null; >+ node.disconnect(); >+ >+ authenticated = false; >+ little_endian = false; >+ sixteen_bits = false; >+ stream = false; >+ play = false; >+ nrOfChannels = 1; >+ rate = 0; >+ name = ""; >+ >+ buff = new Array(); >+ >+ console.log("ESD: Closed audio connection"); >+}; >+ >+buffer_audio = function() { >+ var ws_data = ws.rQshiftBytes(ws.rQlen()); >+ var l = buff.length; >+ buff = buff.concat(ws_data); >+ console.log("buffered " + (buff.length - l)); >+}; >+ >+parse_stream = function(e) { >+ var audio, n, channels, chan_positions, i16; >+ >+ if (buff.length > 0) { >+ // Take buffered data >+ audio = buff.splice(0, e.outputBuffer.length*4); >+ console.log("playing " + audio.length) >+ >+ n = e.outputBuffer.numberOfChannels; >+ channels = new Array(n); >+ chan_positions = new Array(n); >+ for (var c = 0; c < n; c++) { >+ channels[c] = e.outputBuffer.getChannelData(c); >+ channels[c].sampleRate = rate; >+ chan_positions[c] = 0; >+ } >+ >+ for (var i = 0; i < audio.length; i += 2) { >+ >+ // handle endian and convert to 16bit >+ if (little_endian) >+ i16 = audio[i] + (audio[i+1] << 8); >+ else >+ i16 = (audio[i+1] << 8) + audio[i]; >+ >+ // handle signed >+ if (i16 > 32767) >+ i16 -= 65536; >+ >+ // put audio on the channels >+ for (var c = 0; c < n; c++) { >+ if ((i/2) % n == c) { >+ (channels[c])[chan_positions[c]] = i16 / 32767; >+ chan_positions[c]++; >+ } >+ } >+ } >+ } else { >+ disconnect_audio(); >+ } >+}; >+ >+parse_format = function(ws_data) { >+ var format = "", length = ws_data.length; >+ if (little_endian) { >+ for (var i = length - 1; i >= 0; i--) >+ format += ws_data[i].toString(16); >+ } else { >+ for (var i = 0; i < length; i++) >+ format += ws_data[i].toString(16); >+ } >+ sixteen_bits = format.charAt(format.length - 1) == 1; >+ nrOfChannels = format.charAt(format.length - 2); >+ stream = format.charAt(format.length - 3) == 0; >+ play = format.charAt(format.length - 4) == 1; >+}; >+ >+parse_rate = function(ws_data) { >+ var length = ws_data.length; >+ if (little_endian) { >+ for (var i = length - 1; i >= 0; i--) >+ rate += ws_data[i] * Math.pow(2, 8 * i); >+ } else { >+ for (var i = 0; i < length; i++) >+ rate += ws_data[i] * Math.pow(2, 8 * i); >+ } >+}; >+ >+// >+// Public API interface functions >+// >+ >+that.connect = function(host, port, path) { >+ esd_host = host; >+ esd_port = port; >+ esd_path = (path !== undefined) ? path : ""; >+ >+ if ((!esd_host) || (!esd_port)) >+ return fail("Must set host and port"); >+ connect(); >+}; >+ >+that.disconnect = function() { >+ disconnect(); >+}; >+ >+return constructor(); // Return the public API interface >+ >+} // End of ESD() >Index: noVNC/include/ui.js >=================================================================== >--- noVNC/include/ui.js (revision 28068) >+++ noVNC/include/ui.js (working copy) >@@ -27,7 +27,7 @@ > > Util.load_scripts(["webutil.js", "base64.js", "websock.js", "des.js", > "input.js", "display.js", "jsunzip.js", "rfb.js", >- "keysym.js"]); >+ "keysym.js", "esd.js"]); > > var UI = { > >@@ -113,6 +113,7 @@ > 'onClipboard': UI.clipReceive, > 'onFBUComplete': UI.FBUComplete, > 'onDesktopName': UI.updateDocumentTitle}); >+ UI.esd = ESD({'encrypt': (window.location.protocol === "https:")}); > > autoconnect = WebUtil.getQueryVar('autoconnect', false); > if (autoconnect === 'true' || autoconnect == '1') { >@@ -663,6 +664,7 @@ > UI.rfb.set_repeaterID(UI.getSetting('repeaterID')); > > UI.rfb.connect(host, port, password, path); >+ UI.esd.connect(host, port, path); > > //Close dialog. > setTimeout(UI.setBarPosition, 100); >@@ -672,6 +674,7 @@ > disconnect: function() { > UI.closeSettingsMenu(); > UI.rfb.disconnect(); >+ UI.esd.disconnect(); > > $D('noVNC_logo').style.display = "block"; > UI.connSettingsOpen = false;
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 4822
: 663