diff --git a/package-lock.json b/package-lock.json index 73533345..d4d74243 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "hifi-spatial-audio", - "version": "2.0.0", + "version": "2.1.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 408293cc..390020eb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hifi-spatial-audio", - "version": "2.0.0", + "version": "2.1.0", "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 b9a60781..d387b0b0 100644 --- a/src/classes/HiFiAudioAPIData.ts +++ b/src/classes/HiFiAudioAPIData.ts @@ -44,6 +44,17 @@ export class HiFiAudioAPIData { * A volume level below this value is considered background noise and will be smoothly gated off. * The floating point value is specified in dBFS (decibels relative to full scale) with values between -96 dB (indicating no gating) * and 0 dB (effectively muting the input from this user). It is in the same decibel units as the VolumeDecibels component of UserDataSubscription. + * Setting this value to `NaN` will cause the volume threshold from the space to be used instead. + * + * **COMPATIBILITY WARNING:** Currently, setting `volumeThreshold` to `null` will also reset its value to the space default volume threshold. + * In the future, the value of `volumeThreshold` will only be reset if it is set to `NaN`. + * A `volumeThreshold` set to `null` will in the future will be treated as if `volumeThreshold` is not supplied. + * If your spatial audio client application is currently resetting `volumeThreshold` by setting it to `null`, please change + * it to set `volumeThreshold` to `NaN` instead, in order for it to continue working with future versions of + * High Fidelity's Spatial Audio API. + * + * If you don't supply a `volumeThreshold` when constructing instantiations of this class, the previous value of `volumeThreshold` will + * be used. If `volumeThreshold` has never been supplied, the volume threshold of the space will be used instead. */ volumeThreshold: number; /** @@ -61,23 +72,29 @@ export class HiFiAudioAPIData { * This value affects how far a user's sound will travel in 3D space, without affecting the user's loudness. * By default, there is a global attenuation value (set for a given space) that applies to all users in a space. This default space * attenuation is usually 0.5, which represents a reasonable approximation of a real-world fall-off in sound over distance. - * Lower numbers represent less attenuation (i.e. sound travels farther); higher numbers represent more attenuation (i.e. sound drops - * off more quickly). * * When setting this value for an individual user, the following holds: - * - Positive numbers should be between 0 and 1, and they represent a logarithmic attenuation. This range is recommended, as it is + * - A value of `NaN` causes the user to inherit the global attenuation for a space, or, if zones are defined for the space, + * the attenuation settings at the user's position. **COMPATIBILITY WARNING:** Currently, setting `userAttenuation` to 0 will + * also reset its value to the space/zone default attenuation. + * In the future, the value of `userAttenuation` will only be reset if it is set to `NaN`. + * A `userAttenuation` set to 0 will in the future be treated as a "broadcast mode", making + * the user audible throughout the entire space. + * If your spatial audio client application is currently resetting `userAttenuation` by setting it to 0, please change + * it to set `userAttenuation` to `NaN` instead, in order for it to continue working with future versions of + * High Fidelity's Spatial Audio API. + * - Positive numbers between 0 and 1 (excluding 0) represent logarithmic attenuation. This range is recommended, as it is * more natural sounding. Smaller numbers represent less attenuation, so a number such as 0.2 can be used to make a particular - * user's audio travel farther than other users', for instance in "amplified" concert type settings. Similarly, an extremely - * small non-zero number (e.g. 0.00001) can be used to effectively turn off attenuation for a given user within a reasonably - * sized space, resulting in a "broadcast mode" where the user can be heard throughout most of the space regardless of their location - * relative to other users. (Note: The actual value "0" is used internally to represent the default; for setting minimal attenuation, - * small non-zero numbers should be used instead. See also "userRolloff" below.) + * user's audio travel farther than other users', for instance in "amplified" concert type settings. A number such as 0.02 will + * make the user's audio travel even farther. + * - A value of near 0, such as 0.001, will greatly reduce attenuation for a given user, resulting effectively in a "broadcast mode" where the user can be + * heard throughout the entire space regardless of their location relative to other users. * - Negative attenuation numbers are used to represent linear attenuation, and are a somewhat artificial, non-real-world concept. However, * this setting can be used as a blunt tool to easily test attenuation, and tune it aggressively in extreme circumstances. When using linear * attenuation, the setting is the distance in meters at which the audio becomes totally inaudible. * - * If you don't supply an `userAttenuation` when constructing instantiations of this class, `userAttenuation` will be `null` and the - * default will be used. + * If you don't supply a `userAttenuation` when constructing instantiations of this class, the previous value of `userAttenuation` will + * be used. If `userAttenuation` has never been supplied, the attenuation of the space will be used instead. * * ✔ The client sends `userAttenuation` data to the server when `_transmitHiFiAudioAPIDataToServer()` is called. * @@ -93,7 +110,19 @@ export class HiFiAudioAPIData { * extremely high values (e.g. 99999) should be used in combination with "broadcast mode"-style userAttenuation settings to cause the * broadcasted voice to sound crisp and "up close" even at very large distances. * - * If you don't supply an `userRolloff` when constructing instantiations of this class, `userRolloff` will be `null`. + * A `userRolloff` of `NaN` will cause the user to inherit the global frequency rolloff for the space, or, if zones are defined + * for the space, the frequency rolloff settings at the user's position. + * + * **COMPATIBILITY WARNING:** Currently, setting `userRolloff` to 0 will also reset its value to the space/zone default rolloff + * In the future, the value of `userRolloff` will only be reset if it is set to `NaN` + * A `userRolloff` set to 0 will in the future be treated as a valid frequency rolloff value, + * which will cause the user's sound to become muffled over a short distance. + * If your spatial audio client application is currently resetting `userRolloff` by setting it to 0, please change + * it to set `userRolloff` to `NaN` instead, in order for it to continue working with future versions of + * High Fidelity's Spatial Audio API. + * + * If you don't supply a `userRolloff` when constructing instantiations of this class, the previous value of `userRolloff` will + * be used. If `userRolloff` has never been supplied, the frequency rolloff of the space will be used instead. * * ✔ The client sends `userRolloff` data to the server when `_transmitHiFiAudioAPIDataToServer()` is called. * diff --git a/src/classes/HiFiCommunicator.ts b/src/classes/HiFiCommunicator.ts index 9bdc3a2f..e5dd686c 100644 --- a/src/classes/HiFiCommunicator.ts +++ b/src/classes/HiFiCommunicator.ts @@ -979,15 +979,42 @@ export class HiFiCommunicator { * @param __namedParameters * @param position - The new position of the user. * @param orientation - The new orientation of the user (in Quaternion form) - * @param volumeThreshold - The new volumeThreshold of the user. Setting this to null will use the space default volume threshold. + * @param volumeThreshold - The new volumeThreshold of the user. Setting this to `NaN` will reset its value to the space default volume threshold. + * + * **COMPATIBILITY WARNING:** Currently, setting `volumeThreshold` to `null` will also reset its value to the space default volume threshold. + * In the future, the value of `volumeThreshold` will only be reset if it is set to `NaN`. + * A `volumeThreshold` set to `null` will in the future will be treated as if `volumeThreshold` is not supplied. + * If your spatial audio client application is currently resetting `volumeThreshold` by setting it to `null`, please change + * it to set `volumeThreshold` to `NaN` instead, in order for it to continue working with future versions of + * High Fidelity's Spatial Audio API. * @param hiFiGain - This value affects how loud User A will sound to User B at a given distance in 3D space. * This value also affects the distance at which User A can be heard in 3D space. * Higher values for User A means that User A will sound louder to other users around User A, and it also means that User A will be audible from a greater distance. * The new hiFiGain of the user. + * * @param userAttenuation - This value affects how far a user's voice will travel in 3D space. - * The new attenuation value for the user. + * Setting this to `NaN` will use the space default attenuation, or, if zones are defined for the space, + * the attenuation settings at the user's position. + * + * **COMPATIBILITY WARNING:** Currently, setting `userAttenuation` to 0 will also reset its value to the space/zone default attenuation. + * In the future, the value of `userAttenuation` will only be reset if it is set to `NaN`. + * A `userAttenuation` set to 0 will in the future be treated as a "broadcast mode", making + * the user audible throughout the entire space. + * If your spatial audio client application is currently resetting `userAttenuation` by setting it to 0, please change + * it to set `userAttenuation` to `NaN` instead, in order for it to continue working with future versions of + * High Fidelity's Spatial Audio API. + * * @param userRolloff - This value affects the frequency rolloff for a given user. - * The new rolloff value for the user. + * Setting this to `NaN` or 0 will use the space default rolloff, or, if zones are defined for the space, + * the frequency rolloff settings at the user's position. + * + * **COMPATIBILITY WARNING:** Currently, setting `userRolloff` to 0 will also reset its value to the space/zone default rolloff + * In the future, the value of `userRolloff` will only be reset if it is set to `NaN` + * A `userRolloff` set to 0 will in the future be treated as a valid frequency rolloff value, + * which will cause the user's sound to become muffled over a short distance. + * If your spatial audio client application is currently resetting `userRolloff` by setting it to 0, please change + * it to set `userRolloff` to `NaN` instead, in order for it to continue working with future versions of + * High Fidelity's Spatial Audio API. */ private _updateUserData({ position, orientation, volumeThreshold, hiFiGain, userAttenuation, userRolloff }: { position?: Point3D, orientation?: Quaternion, volumeThreshold?: number, hiFiGain?: number, userAttenuation?: number, userRolloff?: number } = {}): void { if (position) { @@ -1011,17 +1038,17 @@ export class HiFiCommunicator { this._currentHiFiAudioAPIData.orientation.z = orientation.z ?? this._currentHiFiAudioAPIData.orientation.z; } - if (typeof (volumeThreshold) === "number" || + if (typeof (volumeThreshold) === "number" || // May be NaN volumeThreshold === null) { this._currentHiFiAudioAPIData.volumeThreshold = volumeThreshold; } if (typeof (hiFiGain) === "number") { this._currentHiFiAudioAPIData.hiFiGain = Math.max(0, hiFiGain); } - if (typeof (userAttenuation) === "number") { + if (typeof (userAttenuation) === "number") { // May be NaN this._currentHiFiAudioAPIData.userAttenuation = userAttenuation; } - if (typeof (userRolloff) === "number") { + if (typeof (userRolloff) === "number") { // May be NaN this._currentHiFiAudioAPIData.userRolloff = Math.max(0, userRolloff); } } @@ -1067,7 +1094,7 @@ export class HiFiCommunicator { this._lastTransmittedHiFiAudioAPIData.orientation.z = dataJustTransmitted.orientation.z ?? this._lastTransmittedHiFiAudioAPIData.orientation.z; } - if (typeof (dataJustTransmitted.volumeThreshold) === "number" || + if (typeof (dataJustTransmitted.volumeThreshold) === "number" || // May be NaN dataJustTransmitted.volumeThreshold === null) { this._lastTransmittedHiFiAudioAPIData["volumeThreshold"] = dataJustTransmitted.volumeThreshold; } @@ -1075,10 +1102,10 @@ export class HiFiCommunicator { if (typeof (dataJustTransmitted.hiFiGain) === "number") { this._lastTransmittedHiFiAudioAPIData["hiFiGain"] = dataJustTransmitted.hiFiGain; } - if (typeof (dataJustTransmitted.userAttenuation) === "number") { + if (typeof (dataJustTransmitted.userAttenuation) === "number") { // May be NaN this._lastTransmittedHiFiAudioAPIData["userAttenuation"] = dataJustTransmitted.userAttenuation; } - if (typeof (dataJustTransmitted.userRolloff) === "number") { + if (typeof (dataJustTransmitted.userRolloff) === "number") { // May be NaN this._lastTransmittedHiFiAudioAPIData["userRolloff"] = dataJustTransmitted.userRolloff; } if (typeof (dataJustTransmitted._otherUserGainQueue) === "object") { @@ -1172,6 +1199,7 @@ export class HiFiCommunicator { /** * A simple function that calls {@link _updateUserData}, followed by {@link _transmitHiFiAudioAPIDataToServer}. + * See {@link HiFiAudioAPIData} for what data can be sent to the High Fidelity Audio API Server. * Developers can call this function as often as they want. This function will update the internal data store of the user's * position, orientation, etc. No matter how often developers call this function, the internal data store transmission is rate-limited * and will only be sent to the server once every `transmitRateLimitTimeoutMS` milliseconds. When the internal data store is transmitted, diff --git a/src/classes/HiFiMixerSession.ts b/src/classes/HiFiMixerSession.ts index 21cd3469..0fd48f72 100644 --- a/src/classes/HiFiMixerSession.ts +++ b/src/classes/HiFiMixerSession.ts @@ -1,6 +1,9 @@ /** - * Code in this module is used internally by the [[HiFiCommunicator]] object to manage the connection between client and server. - * Developers do not need to and should not consider this module when writing their applications. + * Code in this module is used by [[HiFiCommunicator]] object to manage the connection between client and server. + * This module is also home to some types used to manage client volume state, for example + * {@link OnMuteChangedCallback}. + * The class HiFiMixerSession is an internal class. Developers do not need to and should not consider it + * when writing their applications. * @packageDocumentation */ @@ -32,17 +35,33 @@ const PERSONAL_VOLUME_ADJUST_TIMEOUT_MS = 5000; type ConnectionStateChangeHandler = (state: HiFiConnectionStates, result: HiFiConnectionAttemptResult) => void; +/** @internal */ interface AudionetSetOtherUserGainsForThisConnectionResponse { success: boolean, reason?: string } +/** + * The result of calling {@link HiFiCommunicator.setOtherUserGainsForThisConnection}, which adjusts the + * gain of one or more users for the communicator's current connection only. + */ export interface SetOtherUserGainsForThisConnectionResponse { + /** + * `true` if the gains of other users were adjusted, `false` otherwise + */ success: boolean, + /** + * if {@link success} is `false`, then a message explaining why the gains of other users could not be adjusted + */ error?: string, + /** @internal */ audionetSetOtherUserGainsForThisConnectionResponse?: AudionetSetOtherUserGainsForThisConnectionResponse } +/** + * The result of calling {@link HiFiCommunicator.setOtherUserGainForThisConnection}, which adjusts the + * gain of another user for the communicator's current connection only. + */ export type SetOtherUserGainForThisConnectionResponse = SetOtherUserGainsForThisConnectionResponse; /** @@ -114,6 +133,7 @@ export type OnMuteChangedCallback = (muteChangedEvent: MuteChangedEvent) => void /** * Instantiations of this class contain data about a connection between a client and a mixer. * Client library users shouldn't have to care at all about the variables and methods contained in this class. + * @internal */ export class HiFiMixerSession { /** @@ -1207,7 +1227,7 @@ export class HiFiMixerSession { } } - if (typeof (currentHifiAudioAPIData.volumeThreshold) === "number" || + if (typeof (currentHifiAudioAPIData.volumeThreshold) === "number" || // May be NaN currentHifiAudioAPIData.volumeThreshold === null) { dataForMixer["T"] = currentHifiAudioAPIData.volumeThreshold; } @@ -1216,11 +1236,11 @@ export class HiFiMixerSession { dataForMixer["g"] = Math.max(0, currentHifiAudioAPIData.hiFiGain); } - if (typeof (currentHifiAudioAPIData.userAttenuation) === "number") { + if (typeof (currentHifiAudioAPIData.userAttenuation) === "number") { // May be NaN dataForMixer["a"] = currentHifiAudioAPIData.userAttenuation; } - if (typeof (currentHifiAudioAPIData.userRolloff) === "number") { + if (typeof (currentHifiAudioAPIData.userRolloff) === "number") { // May be NaN dataForMixer["r"] = Math.max(0, currentHifiAudioAPIData.userRolloff); } @@ -1272,6 +1292,7 @@ export class HiFiMixerSession { let commandController = this._raviSession.getCommandController(); if (commandController) { + // Stringified NaN values get converted to null, which the mixer interprets as unset let stringifiedDataForMixer = JSON.stringify(dataForMixer); commandController.sendInput(stringifiedDataForMixer); return { diff --git a/src/index.ts b/src/index.ts index 9b80e0ce..4472d7c2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -21,6 +21,7 @@ export { apiVersion }; // Scroll down to check out those shorter synonyms. export { HiFiAudioAPIData, ReceivedHiFiAudioAPIData, Point3D, Quaternion } from "./classes/HiFiAudioAPIData"; export { HiFiCommunicator, HiFiConnectionStates, HiFiUserDataStreamingScopes } from "./classes/HiFiCommunicator"; +export { SetOtherUserGainForThisConnectionResponse, SetOtherUserGainsForThisConnectionResponse, MuteReason, MuteChangedEvent, OnMuteChangedCallback } from "./classes/HiFiMixerSession"; export { WebRTCSessionParams } from "./libravi/RaviSession"; export { AvailableUserDataSubscriptionComponents, UserDataSubscription } from "./classes/HiFiUserDataSubscription"; export { HiFiLogLevel, HiFiLogger } from "./utilities/HiFiLogger"; diff --git a/src/utilities/HiFiMath.ts b/src/utilities/HiFiMath.ts index b4863b68..5e5b1e66 100644 --- a/src/utilities/HiFiMath.ts +++ b/src/utilities/HiFiMath.ts @@ -132,7 +132,7 @@ export class Quaternion { axis.x = this.x / imaginaryLength; axis.y = this.y / imaginaryLength; axis.z = this.z / imaginaryLength; - let wholeLength = Math.sqrt(imaginaryLength + this.w * this.w); + let wholeLength = Math.sqrt(imaginaryLength2 + this.w * this.w); let angle = 2.0 * Math.acos(this.w / wholeLength); if (angle < 0.0) { // we choose the axis that corresponds to positive angle diff --git a/tsconfig.json b/tsconfig.json index 1992e486..2316b2c9 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -17,12 +17,13 @@ "src/classes/HiFiAudioAPIData.ts", "src/classes/HiFiAxisConfiguration.ts", "src/classes/HiFiCommunicator.ts", + "src/classes/HiFiMixerSession.ts", "src/classes/HiFiUserDataSubscription.ts", "src/controls/HiFiControls.ts", "src/constants/HiFiConstants.ts", "src/libravi/RaviSession.ts", "src/utilities/HiFiLogger.ts", - "src/utilities/HiFiUtilities.ts", + "src/utilities/HiFiUtilities.ts" ], "out": "docs", "readme": "./tsdocIndexPage.md", @@ -33,4 +34,4 @@ "excludeInternal": true, "exclude": ["dist"] } -} \ No newline at end of file +}