Просмотр исходного кода

feat: add MediaSource support for Sound

menduz 7 лет назад
Родитель
Сommit
68cfcfcfbb
1 измененных файлов с 41 добавлено и 13 удалено
  1. 41 13
      src/Audio/babylon.sound.ts

+ 41 - 13
src/Audio/babylon.sound.ts

@@ -42,12 +42,12 @@ module BABYLON {
         private _registerFunc: Nullable<(connectedMesh: TransformNode) => void>;
         private _isOutputConnected = false;
         private _htmlAudioElement: HTMLAudioElement;
-        private _urlType: string = "Unknown";
+        private _urlType: 'Unknown' | 'String' | 'Array' | 'ArrayBuffer' | 'MediaStream' = "Unknown";
 
         /**
         * Create a sound and attach it to a scene
         * @param name Name of your sound 
-        * @param urlOrArrayBuffer Url to the sound to load async or ArrayBuffer 
+        * @param urlOrArrayBuffer Url to the sound to load async or ArrayBuffer, it also works with MediaStreams
         * @param readyToPlayCallback Provide a callback function if you'd like to load your code once the sound is ready to be played
         * @param options Objects to provide with the current available options: autoplay, loop, volume, spatialSound, maxDistance, rolloffFactor, refDistance, distanceModel, panningModel, streaming
         */
@@ -98,11 +98,25 @@ module BABYLON {
                         if (typeof (urlOrArrayBuffer) === "string") this._urlType = "String";
                         if (Array.isArray(urlOrArrayBuffer)) this._urlType = "Array";
                         if (urlOrArrayBuffer instanceof ArrayBuffer) this._urlType = "ArrayBuffer";
+                        if (urlOrArrayBuffer instanceof MediaStream) this._urlType = "MediaStream";
 
                         var urls: string[] = [];
                         var codecSupportedFound = false;
 
                         switch (this._urlType) {
+                            case "MediaStream":
+                                this._streaming = true;
+                                this._isReadyToPlay = true;
+                                this._streamingSource = Engine.audioEngine.audioContext.createMediaStreamSource(urlOrArrayBuffer);
+
+                                if (this.autoplay) {
+                                    this.play();
+                                }
+
+                                if (this._readyToPlayCallback) {
+                                    this._readyToPlayCallback();
+                                }
+                                break;
                             case "ArrayBuffer":
                                 if ((<ArrayBuffer>urlOrArrayBuffer).byteLength > 0) {
                                     codecSupportedFound = true;
@@ -131,8 +145,8 @@ module BABYLON {
                                     if (codecSupportedFound) {
                                         // Loading sound using XHR2
                                         if (!this._streaming) {
-                                            this._scene._loadFile(url, (data) => { 
-                                                this._soundLoaded(data as ArrayBuffer); 
+                                            this._scene._loadFile(url, (data) => {
+                                                this._soundLoaded(data as ArrayBuffer);
                                             }, undefined, true, true, (exception) => {
                                                 if (exception) {
                                                     Tools.Error("XHR " + exception.status + " error on: " + url + ".");
@@ -210,7 +224,7 @@ module BABYLON {
         }
 
         public dispose() {
-            if (Engine.audioEngine.canUseWebAudio) { 
+            if (Engine.audioEngine.canUseWebAudio) {
                 if (this.isPlaying) {
                     this.stop();
                 }
@@ -241,6 +255,10 @@ module BABYLON {
                     document.body.removeChild(this._htmlAudioElement);
                 }
 
+                if (this._streamingSource) {
+                    this._streamingSource.disconnect();
+                }
+
                 if (this._connectedMesh && this._registerFunc) {
                     this._connectedMesh.unregisterAfterWorldMatrixUpdate(this._registerFunc);
                     this._connectedMesh = null;
@@ -282,7 +300,7 @@ module BABYLON {
                 this._playbackRate = options.playbackRate || this._playbackRate;
                 this._updateSpatialParameters();
                 if (this.isPlaying) {
-                    if (this._streaming) {
+                    if (this._streaming && this._htmlAudioElement) {
                         this._htmlAudioElement.playbackRate = this._playbackRate;
                     }
                     else {
@@ -449,7 +467,9 @@ module BABYLON {
                         }
                         this._streamingSource.disconnect();
                         this._streamingSource.connect(this._inputAudioNode);
-                        this._htmlAudioElement.play();
+                        if (this._htmlAudioElement) {
+                            this._htmlAudioElement.play();
+                        }
                     }
                     else {
                         this._soundSource = Engine.audioEngine.audioContext.createBufferSource();
@@ -486,10 +506,14 @@ module BABYLON {
         public stop(time?: number) {
             if (this.isPlaying) {
                 if (this._streaming) {
-                    this._htmlAudioElement.pause();
-                    // Test needed for Firefox or it will generate an Invalid State Error
-                    if (this._htmlAudioElement.currentTime > 0) {
-                        this._htmlAudioElement.currentTime = 0;
+                    if (this._htmlAudioElement) {
+                        this._htmlAudioElement.pause();
+                        // Test needed for Firefox or it will generate an Invalid State Error
+                        if (this._htmlAudioElement.currentTime > 0) {
+                            this._htmlAudioElement.currentTime = 0;
+                        }
+                    } else {
+                        this._streamingSource.disconnect();
                     }
                 }
                 else if (Engine.audioEngine.audioContext && this._soundSource) {
@@ -508,7 +532,11 @@ module BABYLON {
             if (this.isPlaying) {
                 this.isPaused = true;
                 if (this._streaming) {
-                    this._htmlAudioElement.pause();
+                    if (this._htmlAudioElement) {
+                        this._htmlAudioElement.pause();
+                    } else {
+                        this._streamingSource.disconnect();
+                    }
                 }
                 else if (Engine.audioEngine.audioContext) {
                     this.stop(0);
@@ -534,7 +562,7 @@ module BABYLON {
         public setPlaybackRate(newPlaybackRate: number) {
             this._playbackRate = newPlaybackRate;
             if (this.isPlaying) {
-                if (this._streaming) {
+                if (this._streaming && this._htmlAudioElement) {
                     this._htmlAudioElement.playbackRate = this._playbackRate;
                 }
                 else if (this._soundSource) {