diff --git a/package-lock.json b/package-lock.json index 3149b9cd..5126135a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "hifi-spatial-audio", - "version": "0.7.1", + "version": "0.7.2", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index 65a85d6c..d8eb7ad7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hifi-spatial-audio", - "version": "0.7.1", + "version": "0.7.2", "description": "The High Fidelity Audio Client Library allows developers to integrate High Fidelity's spatial audio technology into their projects.", "main": "./dist/index.js", "types": "./dist/index.d.ts", diff --git a/src/classes/HiFiAudioAPIData.ts b/src/classes/HiFiAudioAPIData.ts index 747082e9..3e536632 100644 --- a/src/classes/HiFiAudioAPIData.ts +++ b/src/classes/HiFiAudioAPIData.ts @@ -293,7 +293,7 @@ export function eulerFromQuaternion(quat: OrientationQuat3D, order: OrientationE const ONE_MINUS_EPSILON = 0.9999999; switch (order) { case OrientationEuler3DOrder.PitchYawRoll: { - yaw = Math.asin( r02 ); + yaw = Math.asin( HiFiUtilities.clampNormalized(r02) ); if ( Math.abs( r02 ) < ONE_MINUS_EPSILON ) { pitch = Math.atan2( -r12, r22); roll = Math.atan2( -r01, r00); @@ -302,7 +302,7 @@ export function eulerFromQuaternion(quat: OrientationQuat3D, order: OrientationE } } break; case OrientationEuler3DOrder.YawPitchRoll: { - pitch = Math.asin(-r12); + pitch = Math.asin( HiFiUtilities.clampNormalized(-r12) ); if ( Math.abs( r12 ) < ONE_MINUS_EPSILON ) { yaw = Math.atan2(r02, r22); roll = Math.atan2(r10, r11); @@ -311,7 +311,7 @@ export function eulerFromQuaternion(quat: OrientationQuat3D, order: OrientationE } } break; case OrientationEuler3DOrder.RollPitchYaw: { - pitch = Math.asin(r21); + pitch = Math.asin( HiFiUtilities.clampNormalized(r21) ); if ( Math.abs( r21 ) < ONE_MINUS_EPSILON ) { yaw = Math.atan2(-r20, r22); roll = Math.atan2(-r01, r11); @@ -320,7 +320,7 @@ export function eulerFromQuaternion(quat: OrientationQuat3D, order: OrientationE } } break; case OrientationEuler3DOrder.RollYawPitch: { - yaw = Math.asin( -r20 ); + yaw = Math.asin( HiFiUtilities.clampNormalized(-r20) ); if ( Math.abs( r20 ) < ONE_MINUS_EPSILON ) { pitch = Math.atan2( r21, r22); roll = Math.atan2( r10, r00); @@ -329,7 +329,7 @@ export function eulerFromQuaternion(quat: OrientationQuat3D, order: OrientationE } } break; case OrientationEuler3DOrder.YawRollPitch: { - roll = Math.asin( r10 ); + roll = Math.asin( HiFiUtilities.clampNormalized(r10) ); if ( Math.abs( r10 ) < ONE_MINUS_EPSILON ) { pitch = Math.atan2( -r12, r11); yaw = Math.atan2( -r20, r00); @@ -338,7 +338,7 @@ export function eulerFromQuaternion(quat: OrientationQuat3D, order: OrientationE } } break; case OrientationEuler3DOrder.PitchRollYaw: { - roll = Math.asin( -r01 ); + roll = Math.asin( HiFiUtilities.clampNormalized(-r01) ); if ( Math.abs( r01 ) < ONE_MINUS_EPSILON ) { pitch = Math.atan2( r21, r11); yaw = Math.atan2( r02, r00); diff --git a/src/classes/HiFiMixerSession.ts b/src/classes/HiFiMixerSession.ts index 8f7183d3..fafaed8f 100644 --- a/src/classes/HiFiMixerSession.ts +++ b/src/classes/HiFiMixerSession.ts @@ -536,16 +536,19 @@ export class HiFiMixerSession { /** * Sets the input audio stream to "muted" by _either_: * 1. Calling `stop()` on all of the `MediaStreamTrack`s associated with the user's input audio stream OR - * 2. Setting `track.enabled = false|true` on all of the tracks on the user's input audio stream + * 2. Setting `track.enabled = false|true` on all of the tracks on the user's input audio stream (the default behavior) * * Method 1 will work if and only if: * 1. The developer has set the `tryToStopMicStream` argument to this function to `true` AND * 2. The application code is running in the browser context (not the NodeJS context) AND * 3. The user's browser gives the user the ability to permanently allow a website to access the user's microphone + * and provides the `navigator.permissions` and `navigator.permissions.query` objects/methods. + * (Refer to https://developer.mozilla.org/en-US/docs/Web/API/Permissions - as of March 2021, this + * list does not include Safari on desktop or iOS.) * * Reasons to use Method 1: * - Bluetooth Audio I/O devices will switch modes between mono out and stereo out when the user is muted, - * which yields significantly imrpoved audio output quality and proper audio spatialization. + * which yields significantly improved audio output quality and proper audio spatialization. * - When the user is muted, the browser will report that their microphone is not in use, which can improve * user trust in the application. * @@ -555,6 +558,7 @@ export class HiFiMixerSession { * - If a user is using a Bluetooth Audio I/O device, there is a delay between the moment the user un-mutes * and when a user can hear other users in a Space due to the fact that the Bluetooth audio device must * switch I/O profiles. + * - Not all browsers support the `navigator.permissions` API * @returns `true` if the stream was successfully muted/unmuted, `false` if it was not. */ async setInputAudioMuted(newMutedValue: boolean, tryToStopMicStream: boolean = false): Promise { diff --git a/src/utilities/HiFiUtilities.ts b/src/utilities/HiFiUtilities.ts index 09494448..e3ee80fe 100644 --- a/src/utilities/HiFiUtilities.ts +++ b/src/utilities/HiFiUtilities.ts @@ -198,8 +198,6 @@ export class HiFiUtilities { let requiredFeatures: Array = [ // Navigator mediaDevices "navigator", // Found on source code HiFiMixerSession.ts, RaviStreamController.ts - "navigator.permissions", // Found on source code HiFiMixerSession.ts (ln.544) - "navigator.permissions.query", // Found on source code HiFiMixerSession.ts (ln.544) "navigator.mediaDevices.getUserMedia", // Found on source code HiFiMixerSession.ts (ln.590) "navigator.mediaDevices.getSupportedConstraints", // Found on source code HiFiUtilities (ln. 130, 134, 138) // WebRTC @@ -232,4 +230,9 @@ export class HiFiUtilities { static clampNonan(v: number, min: number, max: number, ifnan: number): number { return (v > max ? max : (v < min ? min : HiFiUtilities.nonan(v, ifnan))); } -} \ No newline at end of file + + static clampNormalized(v: number): number { + // if v is Nan returns Nan + return (v > 1.0 ? 1.0 : (v < -1.0 ? -1.0 : v)); + } +} diff --git a/tests/unit/src/classes/HiFiAudioAPIData.unit.test.ts b/tests/unit/src/classes/HiFiAudioAPIData.unit.test.ts index cd36c3f6..b135b406 100644 --- a/tests/unit/src/classes/HiFiAudioAPIData.unit.test.ts +++ b/tests/unit/src/classes/HiFiAudioAPIData.unit.test.ts @@ -166,6 +166,12 @@ describe('Orientation_EulerToFromQuat', () => { test_eulerFromQuaternion( {Y: 30, P: 85}, OrientationEuler3DOrder.YawRollPitch, {w: 0.7121552207625228, x: 0.6525700295239598, y: 0.19082141628892588, z: -0.1748556124156989}); test_eulerFromQuaternion( {Y: 30, P: 85}, OrientationEuler3DOrder.PitchRollYaw, {w: 0.7121552207625228, x: 0.6525700295239598, y: 0.19082141628892588, z: 0.1748556124156989}); }); + test('verifies eulerToOrientation Pitch around 90 in YPR mode', () => { + const DEG_TO_RAD = Math.PI / 180.0; + test_eulerFromQuaternion( {Y: 0, P: 89}, OrientationEuler3DOrder.YawPitchRoll, {w: Math.cos(89 * DEG_TO_RAD * 0.5), x: Math.sin(89 * DEG_TO_RAD * 0.5), y: 0, z: 0}); + test_eulerFromQuaternion( {Y: 0, P: 90}, OrientationEuler3DOrder.YawPitchRoll, {w: Math.cos(90 * DEG_TO_RAD * 0.5), x: Math.sin(90 * DEG_TO_RAD * 0.5), y: 0, z: 0}); + test_eulerFromQuaternion( {Y: 0, P: 91}, OrientationEuler3DOrder.YawPitchRoll, {w: Math.cos(91 * DEG_TO_RAD * 0.5), x: Math.sin(91 * DEG_TO_RAD * 0.5), y: 0, z: 0}); + }); test('verifies eulerToOrientation Yaw:30, Pitch:85, Roll: 85', () => { // 6 different quaternions, each 4 components has 2 possible values test_eulerFromQuaternion( {Y: 30, P: 85, R: 85}, OrientationEuler3DOrder.PitchYawRoll, {w: 0.40692516506453336, x: 0.6100421736976789, y:-0.30018161612201427, z: 0.6100421736976789});