diff --git a/src/extensions/scratch3_speech/index.js b/src/extensions/scratch3_speech/index.js index df7379993..e4ce73b24 100644 --- a/src/extensions/scratch3_speech/index.js +++ b/src/extensions/scratch3_speech/index.js @@ -155,18 +155,18 @@ class Scratch3SpeechBlocks { this._audioPromise = null; /** - * Audio buffer for sound to indicate that listending has started. - * @type {bufferSourceNode} + * Player for sound to indicate that listending has started. + * @type {SoundPlayer} * @private */ - this._startSoundBuffer = null; + this._startSoundPlayer = null; /** - * Audio buffer for sound to indicate that listending has ended. - * @type {bufferSourceNode} + * Player for for sound to indicate that listending has ended. + * @type {SoundPlayer} * @private */ - this._endSoundBuffer = null; + this._endSoundPlayer = null; /** @@ -198,13 +198,13 @@ class Scratch3SpeechBlocks { */ _loadUISounds () { const startSoundBuffer = assetData['speech-rec-start.mp3']; - this._decodeSound(startSoundBuffer).then(buffer => { - this._startSoundBuffer = buffer; + this._decodeSound(startSoundBuffer).then(player => { + this._startSoundPlayer = player; }); const endSoundBuffer = assetData['speech-rec-end.mp3']; - this._decodeSound(endSoundBuffer).then(buffer => { - this._endSoundBuffer = buffer; + this._decodeSound(endSoundBuffer).then(player => { + this._endSoundPlayer = player; }); } @@ -215,43 +215,39 @@ class Scratch3SpeechBlocks { * @private */ _decodeSound (soundBuffer) { - const context = this.runtime.audioEngine && this.runtime.audioEngine.audioContext; + const engine = this.runtime.audioEngine; - if (!context) { - return Promise.reject(new Error('No Audio Context Detected')); + if (!engine) { + return Promise.reject(new Error('No Audio Engine Detected')); } // Check for newer promise-based API - if (context.decodeAudioData.length === 1) { - return context.decodeAudioData(soundBuffer); - } else { // eslint-disable-line no-else-return - // Fall back to callback API - return new Promise((resolve, reject) => - context.decodeAudioData(soundBuffer, - buffer => resolve(buffer), - error => reject(error) - ) - ); - } + return engine.decodeSoundPlayer({data: {buffer: soundBuffer}}); } /** * Play the given sound. - * @param {ArrayBuffer} buffer The audio buffer to play. + * @param {SoundPlayer} player The audio buffer to play. * @returns {Promise} A promise that resoloves when the sound is done playing. * @private */ - _playSound (buffer) { + _playSound (player) { if (this.runtime.audioEngine === null) return; - const context = this.runtime.audioEngine.audioContext; - const bufferSource = context.createBufferSource(); - bufferSource.buffer = buffer; - bufferSource.connect(this.runtime.audioEngine.input); - bufferSource.start(); + if (player.isPlaying) { + // Take the internal player state and create a new player with it. + // `.play` does this internally but then instructs the sound to + // stop. + player.take(); + } + + const engine = this.runtime.audioEngine; + const chain = engine.createEffectChain(); + player.connect(chain); + player.play(); return new Promise(resolve => { - bufferSource.onended = () => { + player.once('stop', () => { resolve(); - }; + }); }); } @@ -727,7 +723,7 @@ class Scratch3SpeechBlocks { // to be some lag between when the sound starts and when the socket message // callback is received. Perhaps we should play the sound after the socket is setup. // TODO: Question - Should we only play the sound if listening isn't already in progress? - return this._playSound(this._startSoundBuffer).then(() => { + return this._playSound(this._startSoundPlayer).then(() => { this._phraseList = this._scanBlocksForPhraseList(); this._utteranceForEdgeTrigger = ''; const speechPromise = new Promise(resolve => { @@ -737,7 +733,7 @@ class Scratch3SpeechBlocks { this._startListening(); } }); - return speechPromise.then(() => this._playSound(this._endSoundBuffer)); + return speechPromise.then(() => this._playSound(this._endSoundPlayer)); }); }