Skip to content

Commit d97796d

Browse files
authored
Add WebAudio listener fallback implementation (#16797)
Firefox does not implement the audio context listener `forwardX/Y/Z`, `positionX/Y/Z` and `upX/Y/Z` properties, so the deprecated `setPosition` and `setOrientation` methods must be used. This change detects when the newer properties are not available and falls back to the deprecated methods if needed.
1 parent 13cbef6 commit d97796d

File tree

1 file changed

+96
-39
lines changed

1 file changed

+96
-39
lines changed

packages/dev/core/src/AudioV2/webAudio/subProperties/spatialWebAudioListener.ts

Lines changed: 96 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,36 @@ import type { _WebAudioEngine } from "../webAudioEngine";
55

66
const TmpMatrix = Matrix.Zero();
77
const TmpQuaternion = new Quaternion();
8-
const TmpVector = Vector3.Zero();
8+
const TmpVector1 = Vector3.Zero();
9+
const TmpVector2 = Vector3.Zero();
910

1011
/** @internal */
1112
export function _CreateSpatialAudioListener(engine: _WebAudioEngine, autoUpdate: boolean, minUpdateTime: number): _SpatialAudioListener {
12-
return new _SpatialWebAudioListener(engine, autoUpdate, minUpdateTime);
13+
const listener = engine._audioContext.listener;
14+
if (
15+
listener.forwardX &&
16+
listener.forwardY &&
17+
listener.forwardZ &&
18+
listener.positionX &&
19+
listener.positionY &&
20+
listener.positionZ &&
21+
listener.upX &&
22+
listener.upY &&
23+
listener.upZ
24+
) {
25+
return new _SpatialWebAudioListener(engine, autoUpdate, minUpdateTime);
26+
} else {
27+
return new _SpatialWebAudioListenerFallback(engine, autoUpdate, minUpdateTime);
28+
}
1329
}
1430

15-
/**
16-
* This sub property is not backed by a sub node and all properties are set directly on the audio context listener.
17-
*
18-
* @internal
19-
*/
20-
class _SpatialWebAudioListener extends _SpatialAudioListener {
21-
private _audioContext: AudioContext;
22-
private _lastPosition: Vector3 = Vector3.Zero();
23-
private _lastRotation: Vector3 = Vector3.Zero();
24-
private _lastRotationQuaternion: Quaternion = new Quaternion();
25-
private _updaterComponent: _SpatialWebAudioUpdaterComponent;
31+
abstract class _AbstractSpatialWebAudioListener extends _SpatialAudioListener {
32+
protected readonly _listener: AudioListener;
33+
34+
protected _lastPosition: Vector3 = Vector3.Zero();
35+
protected _lastRotation: Vector3 = Vector3.Zero();
36+
protected _lastRotationQuaternion: Quaternion = new Quaternion();
37+
protected _updaterComponent: _SpatialWebAudioUpdaterComponent;
2638

2739
/** @internal */
2840
public readonly engine: _WebAudioEngine;
@@ -38,12 +50,20 @@ class _SpatialWebAudioListener extends _SpatialAudioListener {
3850
public constructor(engine: _WebAudioEngine, autoUpdate: boolean, minUpdateTime: number) {
3951
super();
4052

53+
this._listener = engine._audioContext.listener;
4154
this.engine = engine;
4255

43-
this._audioContext = engine._audioContext;
4456
this._updaterComponent = new _SpatialWebAudioUpdaterComponent(this, autoUpdate, minUpdateTime);
4557
}
4658

59+
/** @internal */
60+
public override dispose(): void {
61+
super.dispose();
62+
63+
this._updaterComponent.dispose();
64+
this._updaterComponent = null!;
65+
}
66+
4767
/** @internal */
4868
public get minUpdateTime(): number {
4969
return this._updaterComponent.minUpdateTime;
@@ -54,14 +74,6 @@ class _SpatialWebAudioListener extends _SpatialAudioListener {
5474
this._updaterComponent.minUpdateTime = value;
5575
}
5676

57-
/** @internal */
58-
public override dispose(): void {
59-
super.dispose();
60-
61-
this._updaterComponent.dispose();
62-
this._updaterComponent = null!;
63-
}
64-
6577
/** @internal */
6678
public update(): void {
6779
if (this.isAttached) {
@@ -72,22 +84,16 @@ class _SpatialWebAudioListener extends _SpatialAudioListener {
7284
}
7385
}
7486

75-
/** @internal */
7687
public _updatePosition(): void {
7788
if (this._lastPosition.equalsWithEpsilon(this.position)) {
7889
return;
7990
}
8091

81-
const listener = this._audioContext.listener;
82-
83-
this.engine._setAudioParam(listener.positionX, this.position.x);
84-
this.engine._setAudioParam(listener.positionY, this.position.y);
85-
this.engine._setAudioParam(listener.positionZ, this.position.z);
92+
this._setWebAudioPosition(this.position);
8693

8794
this._lastPosition.copyFrom(this.position);
8895
}
8996

90-
/** @internal */
9197
public _updateRotation(): void {
9298
if (!this._lastRotationQuaternion.equalsWithEpsilon(this.rotationQuaternion)) {
9399
TmpQuaternion.copyFrom(this.rotationQuaternion);
@@ -100,17 +106,68 @@ class _SpatialWebAudioListener extends _SpatialAudioListener {
100106
}
101107

102108
Matrix.FromQuaternionToRef(TmpQuaternion, TmpMatrix);
103-
const listener = this._audioContext.listener;
104109

105110
// NB: The WebAudio API is right-handed.
106-
Vector3.TransformNormalToRef(Vector3.RightHandedForwardReadOnly, TmpMatrix, TmpVector);
107-
this.engine._setAudioParam(listener.forwardX, TmpVector.x);
108-
this.engine._setAudioParam(listener.forwardY, TmpVector.y);
109-
this.engine._setAudioParam(listener.forwardZ, TmpVector.z);
110-
111-
Vector3.TransformNormalToRef(Vector3.Up(), TmpMatrix, TmpVector);
112-
this.engine._setAudioParam(listener.upX, TmpVector.x);
113-
this.engine._setAudioParam(listener.upY, TmpVector.y);
114-
this.engine._setAudioParam(listener.upZ, TmpVector.z);
111+
Vector3.TransformNormalToRef(Vector3.RightHandedForwardReadOnly, TmpMatrix, TmpVector1);
112+
Vector3.TransformNormalToRef(Vector3.Up(), TmpMatrix, TmpVector2);
113+
114+
this._setWebAudioOrientation(TmpVector1, TmpVector2);
115+
}
116+
117+
protected abstract _setWebAudioPosition(position: Vector3): void;
118+
protected abstract _setWebAudioOrientation(forward: Vector3, up: Vector3): void;
119+
}
120+
121+
/**
122+
* Full-featured spatial audio listener for the Web Audio API.
123+
*
124+
* Used in browsers that support the `forwardX/Y/Z`, `positionX/Y/Z`, and `upX/Y/Z` properties on the AudioContext listener.
125+
*
126+
* NB: Firefox falls back to using this implementation.
127+
*
128+
* @see _SpatialWebAudioListenerFallback for the implementation used if only `setPosition` and `setOrientation` are available.
129+
*
130+
* NB: This sub property is not backed by a sub node and all properties are set directly on the audio context listener.
131+
*
132+
* @internal
133+
*/
134+
class _SpatialWebAudioListener extends _AbstractSpatialWebAudioListener {
135+
protected override _setWebAudioPosition(position: Vector3): void {
136+
this.engine._setAudioParam(this._listener.positionX, position.x);
137+
this.engine._setAudioParam(this._listener.positionY, position.y);
138+
this.engine._setAudioParam(this._listener.positionZ, position.z);
139+
}
140+
141+
protected override _setWebAudioOrientation(forward: Vector3, up: Vector3): void {
142+
this.engine._setAudioParam(this._listener.forwardX, forward.x);
143+
this.engine._setAudioParam(this._listener.forwardY, forward.y);
144+
this.engine._setAudioParam(this._listener.forwardZ, forward.z);
145+
146+
this.engine._setAudioParam(this._listener.upX, up.x);
147+
this.engine._setAudioParam(this._listener.upY, up.y);
148+
this.engine._setAudioParam(this._listener.upZ, up.z);
149+
}
150+
}
151+
152+
/**
153+
* Fallback spatial audio listener for the Web Audio API.
154+
*
155+
* Used in browsers that do not support the `forwardX/Y/Z`, `positionX/Y/Z`, and `upX/Y/Z` properties on the
156+
* AudioContext listener.
157+
*
158+
* @see _SpatialWebAudioListener for the implementation used if the `forwardX/Y/Z`, `positionX/Y/Z`, and `upX/Y/Z`
159+
* properties are available.
160+
*
161+
* NB: This sub property is not backed by a sub node and all properties are set directly on the audio context listener.
162+
*
163+
* @internal
164+
*/
165+
class _SpatialWebAudioListenerFallback extends _AbstractSpatialWebAudioListener {
166+
protected override _setWebAudioPosition(position: Vector3): void {
167+
this._listener.setPosition(this.position.x, this.position.y, this.position.z);
168+
}
169+
170+
protected override _setWebAudioOrientation(forward: Vector3, up: Vector3): void {
171+
this._listener.setOrientation(forward.x, forward.y, forward.z, up.x, up.y, up.z);
115172
}
116173
}

0 commit comments

Comments
 (0)