@aurally/speech-control
Version:
A class to handle microphone permissions, start and observe speech input
146 lines • 6.23 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
var rxjs_1 = require("rxjs");
var operators_1 = require("rxjs/operators");
var notification_1 = require("./components/notification");
var SpeechControlErrors;
(function (SpeechControlErrors) {
SpeechControlErrors["NoSpeechRecognition"] = "no-speech-recognition";
SpeechControlErrors["Disabled"] = "disabled";
})(SpeechControlErrors = exports.SpeechControlErrors || (exports.SpeechControlErrors = {}));
var SpeechControl = /** @class */ (function () {
function SpeechControl(options) {
this._stopped = false;
this._notificationShown = false;
this.recLanguage = options && options.recLanguage;
this.notification = {};
}
SpeechControl.prototype._record = function (subscriber) {
var SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
this._recognition = new SpeechRecognition();
if (this._recognition) {
// this._recognition.continuous = true
if (this.recLanguage) {
this._recognition.lang = this.recLanguage;
}
this._recognition.onresult = subscriber.next.bind(subscriber);
this._recognition.onend = subscriber.complete.bind(subscriber);
this._recognition.onerror = subscriber.error.bind(subscriber);
this._recognition.start();
}
};
SpeechControl.prototype._disableRec = function () {
window.sessionStorage.setItem('ARLY_DISABLE_REC', 'true');
this.stop();
};
SpeechControl.prototype.askForPermission = function () {
return rxjs_1.from(navigator.mediaDevices.getUserMedia({ audio: true }).then(function (stream) {
// stop it immediately, its just used to trigger the permission
stream.getTracks().forEach(function (track) {
track.stop();
});
}));
};
SpeechControl.prototype.whenPermissionGranted = function () {
if (!navigator.permissions) {
console.warn('SPEECH CONTROL: PERMISSIONS API IS NOT AVAILABLE, USING getUserMedia HERE');
return this.askForPermission();
}
var handleState = function (subscriber, status) {
if (status.state == 'granted') {
subscriber.next();
subscriber.complete();
}
else if (status.state == 'prompt') {
status.addEventListener('change', function (_a) {
var target = _a.target;
handleState(subscriber, target);
});
}
else {
subscriber.error();
}
};
return new rxjs_1.Observable(function (subscriber) {
;
navigator.permissions
.query({ name: 'microphone' })
.then(function (status) { return handleState(subscriber, status); });
});
};
SpeechControl.prototype.isEnabled = function () {
// check if not disabled and speech _recognition available
return (!window.sessionStorage.getItem('ARLY_DISABLE_REC') &&
(window.hasOwnProperty('SpeechRecognition') ||
window.hasOwnProperty('webkitSpeechRecognition')));
};
SpeechControl.prototype.setNotification = function (notification) {
this.notification = notification;
};
SpeechControl.prototype.on = function (term) {
var _this = this;
if (!this._observable) {
this._observable = this.start().pipe(operators_1.finalize(function () { return (_this._observable = undefined); }));
}
return this._observable.pipe(operators_1.filter(function (event) {
var item = event.results
.item(event.results.length - 1)[0]
.transcript.trim()
.toLowerCase()
.replace(/\s/g, ', ');
return item.includes(term);
}));
};
SpeechControl.prototype.start = function (notificationOptions) {
var _this = this;
this._stopped = false;
return new rxjs_1.Observable(function (subscriber) {
if (_this.isEnabled()) {
_this._record(subscriber);
_this.whenPermissionGranted().subscribe(function () {
if (!_this._notificationShown) {
var notification = notification_1.append(notificationOptions || _this.notification);
notification.then(function (nr) {
return nr.disable.then(function () {
_this._disableRec();
subscriber.error(SpeechControlErrors.Disabled);
});
});
setTimeout(notification_1.remove, 3000);
_this._notificationShown = true;
}
});
}
else {
subscriber.error(SpeechControlErrors.NoSpeechRecognition);
}
}).pipe(operators_1.debounceTime(500), operators_1.repeatWhen(function (complete) {
return complete.pipe(operators_1.mergeMap(function () {
// repeat because continouse does not work on all mobile devices
if (_this._stopped) {
return rxjs_1.empty();
}
return rxjs_1.timer(500);
}));
}), operators_1.retryWhen(function (error) {
return error.pipe(operators_1.mergeMap(function (error) {
console.log(error);
// retry if noting said
if (error && error.error === 'no-speech') {
return rxjs_1.timer(500);
}
return rxjs_1.throwError(error);
}));
}));
};
SpeechControl.prototype.stop = function () {
notification_1.remove();
this._stopped = true;
if (this._recognition) {
this._recognition.stop();
}
};
return SpeechControl;
}());
exports.SpeechControl = SpeechControl;
//# sourceMappingURL=speech-control.js.map