diff --git a/accessible/src/jsat/AccessFu.jsm b/accessible/src/jsat/AccessFu.jsm index c0cf612968c5..0197518973f5 100644 --- a/accessible/src/jsat/AccessFu.jsm +++ b/accessible/src/jsat/AccessFu.jsm @@ -506,23 +506,52 @@ var Output = { webspeechEnabled: false, + deferredOutputs: [], + init: function init() { let window = Utils.win; this.webspeechEnabled = !!window.speechSynthesis; + let settingsToGet = 2; + let settingsCallback = (aName, aSetting) => { + if (--settingsToGet > 0) { + return; + } + + this.inited = true; + + for (let actions of this.deferredOutputs) { + this.output(actions); + } + }; + + this._volumeSetting = new SettingCache( + 'accessibility.screenreader-volume', settingsCallback, + { defaultValue: 1, callbackNow: true, callbackOnce: true }); + this._rateSetting = new SettingCache( + 'accessibility.screenreader-rate', settingsCallback, + { defaultValue: 0, callbackNow: true, callbackOnce: true }); + for (let earcon of this.EARCONS) { let earconName = /(^.*)\..*$/.exec(earcon)[1]; this.earconBuffers[earconName] = new WeakMap(); this.earconBuffers[earconName].set( window, new window.Audio('chrome://global/content/accessibility/' + earcon)); } + }, - this.inited = true; + uninit: function uninit() { + if (this.inited) { + delete this._volumeSetting; + delete this._rateSetting; + } + this.inited = false; }, output: function output(aActions) { if (!this.inited) { - this.init(); + this.deferredOutputs.push(aActions); + return; } for (let action of aActions) { @@ -535,12 +564,18 @@ var Output = { } if (action.method === 'speak' && this.webspeechEnabled) { - window.speechSynthesis.speak( - new window.SpeechSynthesisUtterance(action.data)); + let utterance = new window.SpeechSynthesisUtterance(action.data); + let requestedRate = this._rateSetting.value; + utterance.volume = this._volumeSetting.value; + utterance.rate = requestedRate >= 0 ? + requestedRate + 1 : 1 / (Math.abs(requestedRate) + 1); + window.speechSynthesis.speak(utterance); } else if (action.method === 'playEarcon') { let audioBufferWeakMap = this.earconBuffers[action.data]; if (audioBufferWeakMap) { - audioBufferWeakMap.get(window).cloneNode(false).play(); + let node = audioBufferWeakMap.get(window).cloneNode(false); + node.volume = this._volumeSetting.value; + node.play(); } } } @@ -549,6 +584,7 @@ var Output = { start: function start() { Cu.import('resource://gre/modules/Geometry.jsm'); + this.speechHelper.init(); }, stop: function stop() { @@ -561,6 +597,8 @@ var Output = { Utils.win.document.documentElement.removeChild(this.announceBox.get()); delete this.announceBox; } + + this.speechHelper.uninit(); }, Speech: function Speech(aDetails, aBrowser) {