///
import { EventEmitter } from 'events';
import { WarningName } from './constants';
import { DiagnosticError } from './errors';
import { AudioRecorder } from './recorder/audio';
import { SubsetRequired, TimeMeasurement } from './types';
export declare interface AudioInputTest {
/**
* This event is emitted with a test report when the test ends.
* @param event [[AudioInputTest.Events.End]]
* @param report Summary of the test.
* @private
*/
emit(event: AudioInputTest.Events.End, report: AudioInputTest.Report): boolean;
/**
* This event is emitted with a [[DiagnosticError]] when the test encounters
* an error, fatal or not.
* @param event [[AudioInputTest.Events.Error]]
* @param error The [[DiagnosticError]] that was encountered.
* @private
*/
emit(event: AudioInputTest.Events.Error, error: DiagnosticError): boolean;
/**
* This event is emitted with a volume level every
* [[AudioInputTest.Options.volumeEventIntervalMs]] after the test starts succesfully.
* @param event [[AudioInputTest.Events.Volume]]
* @param value The current volume of the audio source.
* @private
*/
emit(event: AudioInputTest.Events.Volume, value: number): boolean;
/**
* This event is emitted when the test encounters a non-fatal warning during
* its run-time.
* @param event [[AudioInputTest.Events.Warning]]
* @param warning The warning that the test encountered.
* @private
*/
emit(event: AudioInputTest.Events.Warning, warning: WarningName): boolean;
/**
* This event is emitted when the test clears a previously encountered
* non-fatal warning during its run-time.
* @param event [[AudioInputTest.Events.WarningCleared]]
* @param warning The warning that the test encountered that should be cleared.
* @private
*/
emit(event: AudioInputTest.Events.WarningCleared, warning: WarningName): boolean;
/**
* Raised upon completion of the test.
* @param event [[AudioInputTest.Events.End]]
* @param listener A callback that expects the following parameters:
* An [[AudioInputTest.Report]] that summarizes the test.
* @returns This [[AudioInputTest]] instance.
* @event
*/
on(event: AudioInputTest.Events.End, listener: (report: AudioInputTest.Report) => any): this;
/**
* Raised by the test when encountering an error with a parameter of type
* [[DiagnosticError]].
* @param event [[AudioInputTest.Events.Error]]
* @param listener A callback that expects the following parameters:
* A [[DiagnosticError]] that the test encountered.
* @returns This [[AudioInputTest]] instance.
* @event
*/
on(event: AudioInputTest.Events.Error, listener: (error: DiagnosticError) => any): this;
/**
* Raised by the test every [[Options.volumeEventIntervalMs]] amount of
* milliseconds with a parameter of type `number` that represents the
* current volume of the audio stream.
* @param event [[AudioInputTest.Events.Volume]]
* @param listener A callback that expects the following parameters:
* A `number` that represents the audio source's current volume.
* @returns This [[AudioInputTest]] instance.
* @event
*/
on(event: AudioInputTest.Events.Volume, listener: (value: number) => any): this;
/**
* Raised by the test when the test encounters a non-fatal warning during
* its run-time.
* @param event [[AudioInputTest.Events.Warning]]
* @param listener A callback that expects the following parameters:
* A [[WarningName]].
* @returns This [[AudioInputTest]] instance.
* @event
*/
on(event: AudioInputTest.Events.Warning, listener: (warningName: WarningName) => any): this;
/**
* Raised by the test when the test clears a previously encountered non-fatal
* warning during its run-time.
* @param event [[AudioInputTest.Events.WarningCleared]]
* @param listener A callback that expects the following parameters:
* A [[WarningName]] name.
* @returns This [[AudioInputTest]] instance.
* @event
*/
on(event: AudioInputTest.Events.WarningCleared, listener: (warningName: WarningName) => any): this;
}
/**
* [[AudioInputTest]] class that parses options and starts an audio input device
* test.
*
* Please see [[testAudioInputDevice]] for details and recommended practices.
*/
export declare class AudioInputTest extends EventEmitter {
/**
* Name of the test.
*/
static readonly testName: string;
/**
* Default options for the [[AudioInputTest]].
*/
private static defaultOptions;
/**
* Active warnings to keep track of.
*/
readonly activeWarnings: Set;
/**
* An `AudioContext` to use for generating volume levels.
*/
private _audioContext;
/**
* An AudioRecorder object used to capture audio input during the test
*/
private _audioRecorder;
/**
* A function that will be assigned in `_startTest` that when run will clean
* up the audio nodes created in the same function.
*/
private _cleanupAudio;
/**
* The default media devices when starting the test.
*/
private _defaultDevices;
/**
* A timestamp that is set when the test ends.
*/
private _endTime;
/**
* An array of any errors that occur during the run time of the test.
*/
private readonly _errors;
/**
* A `MediaStream` that is created from the input device.
*/
private _mediaStream;
/**
* Options that are passed to and set in the constructor for use during the
* test.
*/
private _options;
/**
* A timestamp that is set when the test starts after a successful call to getUserMedia.
*/
private _startTime;
/**
* Volume levels generated from the audio source during the run time of the
* test.
*/
private readonly _volumeStats;
/**
* The timeout that causes the volume event to loop; created by `setTimeout`.
*/
private _volumeTimeout;
/**
* Initializes the `startTime` and `options`.
* @param options Optional settings to pass to the test.
*/
constructor(options?: AudioInputTest.Options);
/**
* Stop the currently running [[AudioInputTest]].
*/
stop(): void;
/**
* Clean up any instantiated objects (i.e. `AudioContext`, `MediaStreams`,
* etc.).
* Called by `.stop`.
*/
private _cleanup;
/**
* Helper function that should be called when an error occurs, recoverable
* or not.
* @param error
*/
private _onError;
/**
* Called every `AudioInputTest._options.volumeEventIntervalMs` amount of
* milliseconds, emits the volume passed to it as a `Events.Volume` event.
* @param value the volume
*/
private _onVolume;
/**
* Warning event handler.
* @param warning
*/
private _onWarning;
/**
* Entry point into the audio input device test. Uses the `MediaStream` that the
* object was set up with, and performs a fourier transform on the audio data
* using an `AnalyserNode`. The output of the fourier transform are the
* relative amplitudes of the frequencies of the audio data. The average of
* this data can then be used as an estimate as the average volume of the
* entire volume source.
*
* @event Events.Volume
*/
private _startTest;
}
export declare namespace AudioInputTest {
/**
* Possible events that an [[AudioInputTest]] might emit. See [[AudioInputTest.on]].
*/
enum Events {
End = "end",
Error = "error",
Volume = "volume",
Warning = "warning",
WarningCleared = "warning-cleared"
}
/**
* Represents the report generated from an [[AudioInputTest]].
*/
interface Report {
/**
* The device ID used to get a MediaStream from using [getUserMedia](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia).
*/
deviceId: MediaTrackConstraintSet['deviceId'];
/**
* Any errors that occurred during the test.
*/
errors: DiagnosticError[];
/**
* If [[AudioInputTest.Options.enableRecording]] is set to true,
* `recordingUrl` will be available in the report which can be used to playback captured audio from the microphone.
* Your application should revoke this URL if it is no longer needed.
*
* Example:
*
* ```ts
* const audioInputTest: AudioInputTest = testAudioInputDevice({ enableRecording: true });
* audioInputTest.on(AudioInputTest.Events.End, (report: AudioInputTest.Report) => {
* const audioEl = new Audio();
* audioEl.src = report.recordingUrl;
* audioEl.play();
*
* // Revoke the url if no longer needed
* URL.revokeObjectURL(report.recordingUrl);
* });
* ```
*/
recordingUrl?: string;
/**
* The name of the test.
*/
testName: typeof AudioInputTest.testName;
/**
* Time measurements of test run time.
*/
testTiming?: TimeMeasurement;
/**
* The volume levels emitted by the test during its run-time.
*/
values: number[];
}
/**
* Options passed to [[AudioInputTest]] constructor.
*/
interface Options {
/**
* AudioContext mock to be used during the test.
* @private
*/
audioContextFactory?: typeof window.AudioContext;
/**
* AudioRecorder mock to be used during the test.
* @private
*/
audioRecorderFactory?: typeof AudioRecorder;
/**
* Whether or not to log debug statements to the console.
* @private
*/
debug?: boolean;
/**
* The device ID to try to get a MediaStream from using [getUserMedia](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia).
*/
deviceId?: MediaTrackConstraintSet['deviceId'];
/**
* Duration of time to run the test in ms.
* @default Infinity
*/
duration?: number;
/**
* Whether the test should record the audio input or not.
* If set to true, [[AudioInputTest.Report.recordingUrl]] will be available for audio playback.
* Your application should revoke this URL if it is no longer needed.
*
* Example:
*
* ```ts
* const audioInputTest: AudioInputTest = testAudioInputDevice({ enableRecording: true });
* audioInputTest.on(AudioInputTest.Events.End, (report: AudioInputTest.Report) => {
* const audioEl = new Audio();
* audioEl.src = report.recordingUrl;
* audioEl.play();
*
* // Revoke the url if no longer needed
* URL.revokeObjectURL(report.recordingUrl);
* });
* ```
* @default false
*/
enableRecording?: boolean;
/**
* Used to mock the call to `enumerateDevices`.
* @private
*/
enumerateDevices?: typeof navigator.mediaDevices.enumerateDevices;
/**
* Used to mock calls to `getUserMedia`.
* @private
*/
getUserMedia?: typeof window.navigator.mediaDevices.getUserMedia;
/**
* The interval between emissions of volume events in milliseconds.
* @default 100
*/
volumeEventIntervalMs?: number;
}
/**
* Option typing after initialization, so we can have type guarantees.
* @private
*/
type InternalOptions = SubsetRequired;
}
/**
* [[AudioInputTest]] tests audio input capabilities. It serves to help diagnose
* potential audio device issues that would prevent audio from being recognized
* in a WebRTC call.
*
* ---
*
* The [[AudioInputTest]] class is an `EventEmitter` (please see [[AudioInputTest.on]] for
* events and their details) and helps to diagnose issues by capturing user
* audio and emitting the volume levels detected in that media.
* ```ts
* import { AudioInputTest, testAudioInputDevice } from '@twilio/rtc-diagnostics';
* const options: AudioInputTest.Options = { ... };
* // `options` may be left `undefined` to use default option values
* const audioInputTest: AudioInputTest = testAudioInputDevice(options);
* ```
* Applications can use the volume events emitted by the test to update their UI
* to show to the user whether or not their media was captured successfully.
* ```ts
* audioInputTest.on(AudioInputTest.Events.Volume, (volume: number) => {
* ui.updateVolume(volume); // Update your UI with the volume value here.
* });
* ```
* The test can be normally stopped two ways: allowing the test to time out and
* stopping the test manually.
*
* To end the test manually, the application can ask the end-user to confirm
* that the volume levels it emits are what the end-user expects. If so, the
* application can call the [[AudioInputTest.stop]] method with `true`. Otherwise,
* if the audio values are not expected, the application can call
* [[AudioInputTest.stop]] with `false`.
* ```ts
* // The UI should indicate that if the volume values are what the user
* // expects, they can click this button to pass and stop the test...
* const volumeCorrectButton = ...;
* volumeCorrectButton.addEventListener('click', () => {
* audioInputTest.stop(true);
* });
*
* // ...otherwise, if the volume levels are not what they expect, they can
* // click this.
* const volumeIncorrectButton = ...;
* volumeIncorrectButton.addEventListener('click', () => {
* audioInputTest.stop(false);
* });
* ```
* Calling [[AudioInputTest.stop]] will immediately end the test.
*
* ---
*
* The [[AudioInputTest]] object will always emit a [[AudioInputTest.Report]] with the
* [[AudioInputTest.Events.End]] event, regardless of the occurrence of errors during
* the runtime of the test.
*
* Fatal errors will immediately end the test and emit a report such that the
* value of [[AudioInputTest.Report.errors]] will contain the fatal error.
*
* Non-fatal errors will not end the test, but will be included in the value of
* [[AudioInputTest.Report.errors]] upon completion of the test.
*
* ---
*
* Note: In Firefox, `deviceId` will be ignored, and instead the user will get a
* browser pop-up where they can select the device they want to use. This is
* unavoidable as it is Firefox's implementation of `getUserMedia()`.
*
* In most browsers, such as Chrome and Safari, when `getUserMedia()` is called,
* a prompt will ask the user for broad microphone-access permissions. Then, the
* parameters passed to `getUserMedia()` will determine the device that is
* captured.
*
* Firefox differs in that the prompt will ask for a specific input device.
* Regardless of the parameters passed to `getUserMedia()`, the device
* selected in that prompt will be captured. If the user opts to have the
* browser "Remember this selection" within the prompt, the device that was
* selected will be captured by every future `getUserMedia()` call as well.
* This selection will persist even through changes in the system OS, i.e. when
* default devices are changed. In order to change the device, the user has to
* revoke the webpage's microphone-access permissions for the prompt to show
* again.
*
* Please see this link for more information on microphone access in Firefox:
* https://support.mozilla.org/en-US/kb/how-manage-your-camera-and-microphone-permissions
*
* ---
*
* The function [[testAudioInputDevice]] serves as a factory function that accepts
* [[AudioInputTest.Options]] as its only parameter and will instantiate an
* [[AudioInputTest]] object with those options.
* ```ts
* import { AudioInputTest, testAudioInputDevice } from '@twilio/rtc-diagnostics';
* const options: AudioInputTest.Options = { ... };
* const audioInputTest: AudioInputTest = testAudioInputDevice(options);
* ```
*
* @param options Options to pass to the [[AudioInputTest]] constructor.
*/
export declare function testAudioInputDevice(options?: AudioInputTest.Options): AudioInputTest;