Skip to content

Commit 18a5f31

Browse files
committed
Fixed bug with not closing microphone with continuous: false, added keepMic option
1 parent c940ff6 commit 18a5f31

File tree

4 files changed

+100
-21
lines changed

4 files changed

+100
-21
lines changed

README.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,10 @@ Requires[window.fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_AP
5353

5454
### `.recognizeMicrophone({token})` -> `RecognizeStream`
5555

56-
Options: No direct options, all provided options are passed to MicrophoneStream and RecognizeStream, and WritableElementStream if `options.outputElement` is set
56+
Options:
57+
* `keepMic`: if true, preserves the MicrophoneStream for subsequent calls, preventing additional permissions requests in Firefox
58+
* Other options passed to MediaElementAudioStream and RecognizeStream
59+
* Other options passed to WritableElementStream if `options.outputElement` is set
5760

5861
Requires the `getUserMedia` API, so limited browser compatibility (see http://caniuse.com/#search=getusermedia)
5962
Also note that Chrome requires https (with a few exceptions for localhost and such) - see https://www.chromium.org/Home/chromium-security/prefer-secure-origins-for-powerful-new-features
@@ -155,6 +158,10 @@ Accepts input from `RecognizeStream()` and friends, writes text to supplied `out
155158

156159
## Changelog
157160

161+
### v0.13
162+
* Fixed bug where `continuous: false` didn't close the microphone at end of recognition
163+
* Added `keepMic` option to `recognizeMicrophone()` to prevent multiple permission popups in firefox
164+
158165
### v0.12
159166
* Added `autoPlay` option to `synthesize()`
160167
* Added proper parameter filtering to `synthesize()`
@@ -206,3 +213,5 @@ Accepts input from `RecognizeStream()` and friends, writes text to supplied `out
206213
* look for bug where single-word final results may omit word confidence (possibly due to FormatStream?)
207214
* fix bug where TimingStream shows words slightly before they're spoken
208215
* automatically turn on objectMode when required by other options (timing, confidence, etc.
216+
* support jquery objects for element and targetElement
217+
* add a way to keep the mic stream so the user isn't repeatedly prompted in firefox

dist/watson-speech.js

Lines changed: 50 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

speech-to-text/recognize-microphone.js

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ var FormatStream = require('./format-stream.js');
2323
var assign = require('object.assign/polyfill')();
2424
var WritableElementStream = require('./writable-element-stream');
2525

26+
var preservedMicStream;
27+
2628
/**
2729
* @module watson-speech/speech-to-text/recognize-microphone
2830
*/
@@ -34,6 +36,7 @@ var WritableElementStream = require('./writable-element-stream');
3436
* @param {Object} options - Also passed to {MediaElementAudioStream} and to {RecognizeStream}
3537
* @param {String} options.token - Auth Token - see https://github.com/watson-developer-cloud/node-sdk#authorization
3638
* @param {Boolean} [options.format=true] - pipe the text through a {FormatStream} which performs light formatting
39+
* @param {Boolean} [options.keepMicrophone=false] - keeps an internal reference to the microphone stream to reuse in subsequent calls (prevents multiple permissions dialogs in firefox)
3740
* @param {String|DOMElement} [options.outputElement] pipe the text to a WriteableElementStream targeting the specified element. Also defaults objectMode to true to enable interim results.
3841
*
3942
* @returns {RecognizeStream}
@@ -56,17 +59,46 @@ module.exports = function recognizeMicrophone(options) {
5659

5760
var recognizeStream = new RecognizeStream(rsOpts);
5861

59-
60-
getUserMedia({video: false, audio: true}).then(function(mic) {
61-
var micStream = new MicrophoneStream(mic, {
62-
objectMode: true,
63-
bufferSize: options.bufferSize
62+
var keepMic = options.keepMicrophone;
63+
var getMicStream;
64+
if (keepMic && preservedMicStream) {
65+
getMicStream = Promise.resolve(preservedMicStream);
66+
} else {
67+
getMicStream = getUserMedia({video: false, audio: true}).then(function (mic) {
68+
var micStream = new MicrophoneStream(mic, {
69+
objectMode: true,
70+
bufferSize: options.bufferSize
71+
});
72+
if (keepMic) {
73+
preservedMicStream = micStream;
74+
}
75+
return Promise.resolve(micStream);
6476
});
77+
}
78+
79+
getMicStream.then(function(micStream) {
80+
var l16Stream = new L16({writableObjectMode: true});
81+
6582
micStream
66-
.pipe(new L16({writableObjectMode: true}))
83+
.pipe(l16Stream)
6784
.pipe(recognizeStream);
6885

69-
recognizeStream.on('stop', micStream.stop.bind(micStream));
86+
function end() {
87+
micStream.unpipe(l16Stream);
88+
l16Stream.end();
89+
}
90+
// trigger on both stop and end events:
91+
// stop will not fire when a stream ends due to a timeout or having continuous: false
92+
// but when stop does fire, we want to honor it immediately
93+
// end will always fire, but it may take a few moments after stop
94+
if (keepMic) {
95+
recognizeStream.on('end', end);
96+
recognizeStream.on('stop', end);
97+
} else {
98+
recognizeStream.on('end', micStream.stop.bind(micStream));
99+
recognizeStream.on('stop', micStream.stop.bind(micStream));
100+
}
101+
70102
}).catch(recognizeStream.emit.bind(recognizeStream, 'error'));
71103

72104

speech-to-text/recognize-stream.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,7 @@ RecognizeStream.prototype.finish = function finish() {
391391
this.finished = true;
392392
var self = this;
393393
var closingMessage = {action: 'stop'};
394-
if (self.socket) {
394+
if (self.socket && self.socket.readyState !== self.socket.CLOSED && self.socket.readyState !== self.socket.CLOSING) {
395395
self.sendJSON(closingMessage);
396396
} else {
397397
this.once('connect', function () {

0 commit comments

Comments
 (0)