GUACAMOLE-732: Merge retrieve audio stream via Promise for newer versions of getUserMedia().

diff --git a/guacamole-common-js/src/main/webapp/modules/AudioRecorder.js b/guacamole-common-js/src/main/webapp/modules/AudioRecorder.js
index d91bf50..e54dcca 100644
--- a/guacamole-common-js/src/main/webapp/modules/AudioRecorder.js
+++ b/guacamole-common-js/src/main/webapp/modules/AudioRecorder.js
@@ -412,6 +412,53 @@
     };
 
     /**
+     * getUserMedia() callback which handles successful retrieval of an
+     * audio stream (successful start of recording).
+     *
+     * @private
+     * @param {MediaStream} stream
+     *     A MediaStream which provides access to audio data read from the
+     *     user's local audio input device.
+     */
+    var streamReceived = 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;
+
+    };
+
+    /**
+     * getUserMedia() callback which handles audio recording denial. The
+     * underlying Guacamole output stream is closed, and the failure to
+     * record is noted using onerror.
+     *
+     * @private
+     */
+    var streamDenied = function streamDenied() {
+
+        // Simply end stream if audio access is not allowed
+        writer.sendEnd();
+
+        // Notify of closure
+        if (recorder.onerror)
+            recorder.onerror();
+
+    };
+
+    /**
      * 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
@@ -423,34 +470,14 @@
     var beginAudioCapture = function beginAudioCapture() {
 
         // Attempt to retrieve an audio input stream from the browser
-        navigator.mediaDevices.getUserMedia({ 'audio' : true }, function streamReceived(stream) {
+        var promise = navigator.mediaDevices.getUserMedia({
+            'audio' : true
+        }, streamReceived, streamDenied);
 
-            // 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();
-
-        });
+        // Handle stream creation/rejection via Promise for newer versions of
+        // getUserMedia()
+        if (promise && promise.then)
+            promise.then(streamReceived, streamDenied);
 
     };