@twilio/voice-sdk
Version:
Twilio's JavaScript Voice SDK
696 lines (695 loc) • 22 kB
TypeScript
/// <reference types="node" />
/**
* @packageDocumentation
* @module Voice
* @preferred
* @publicapi
*/
import { EventEmitter } from 'events';
import { LogLevelDesc } from 'loglevel';
import AudioHelper from './audiohelper';
import Call from './call';
import { PreflightTest } from './preflight/preflight';
/**
* @private
*/
export declare type IPStream = any;
/**
* @private
*/
export declare type IPublisher = any;
/**
* @private
*/
export declare type ISound = any;
/**
* Options that may be passed to the {@link Device} constructor for internal testing.
* @private
*/
export interface IExtendedDeviceOptions extends Device.Options {
/**
* Custom {@link AudioHelper} constructor
*/
AudioHelper?: typeof AudioHelper;
/**
* The max amount of time in milliseconds to allow stream (re)-connect
* backoffs.
*/
backoffMaxMs?: number;
/**
* Custom {@link Call} constructor
*/
Call?: typeof Call;
/**
* Hostname of the signaling gateway to connect to.
*/
chunderw?: string | string[];
/**
* Hostname of the event gateway to connect to.
*/
eventgw?: string;
/**
* File input stream to use instead of reading from mic
*/
fileInputStream?: MediaStream;
/**
* Ignore browser support, disabling the exception that is thrown when neither WebRTC nor
* ORTC are supported.
*/
ignoreBrowserSupport?: boolean;
/**
* MediaStream constructor.
*/
MediaStream?: typeof MediaStream;
/**
* Whether this is a preflight call or not
*/
preflight?: boolean;
/**
* Custom PStream constructor
*/
PStream?: IPStream;
/**
* Custom Publisher constructor
*/
Publisher?: IPublisher;
/**
* Whether or not to publish events to insights using {@link Device._publisher}.
*/
publishEvents?: boolean;
/**
* MediaStreamConstraints to pass to getUserMedia when making or accepting a Call.
*/
rtcConstraints?: Call.AcceptOptions['rtcConstraints'];
/**
* Custom Sound constructor
*/
Sound?: ISound;
/**
* Voice event SID generator.
*/
voiceEventSidGenerator?: () => string;
}
/**
* A sound definition used to initialize a Sound file.
* @private
*/
export interface ISoundDefinition {
/**
* Name of the sound file.
*/
filename: string;
/**
* The amount of time this sound file should play before being stopped automatically.
*/
maxDuration?: number;
/**
* Whether or not this sound should loop after playthrough finishes.
*/
shouldLoop?: boolean;
}
/**
* Twilio Device. Allows registration for incoming calls, and placing outgoing calls.
* @publicapi
*/
declare class Device extends EventEmitter {
/**
* The AudioContext to be used by {@link Device} instances.
* @private
*/
static get audioContext(): AudioContext | undefined;
/**
* Which sound file extension is supported.
* @private
*/
static get extension(): 'mp3' | 'ogg';
/**
* Whether or not this SDK is supported by the current browser.
*/
static get isSupported(): boolean;
/**
* Package name of the SDK.
*/
static get packageName(): string;
/**
* Run some tests to identify issues, if any, prohibiting successful calling.
* @param token - A Twilio JWT token string
* @param options
*/
static runPreflight(token: string, options?: PreflightTest.Options): PreflightTest;
/**
* String representation of {@link Device} class.
* @private
*/
static toString(): string;
/**
* Current SDK version.
*/
static get version(): string;
/**
* An AudioContext to share between {@link Device}s.
*/
private static _audioContext?;
private static _defaultSounds;
/**
* A DialtonePlayer to play mock DTMF sounds through.
*/
private static _dialtonePlayer?;
/**
* Whether or not the browser uses unified-plan SDP by default.
*/
private static _isUnifiedPlanDefault;
/**
* Initializes the AudioContext instance shared across the Voice SDK,
* or returns the existing instance if one has already been initialized.
*/
private static _getOrCreateAudioContext;
/**
* The currently active {@link Call}, if there is one.
*/
private _activeCall;
/**
* The AudioHelper instance associated with this {@link Device}.
*/
private _audio;
/**
* {@link Device._confirmClose} bound to the specific {@link Device} instance.
*/
private _boundConfirmClose;
/**
* {@link Device.destroy} bound to the specific {@link Device} instance.
*/
private _boundDestroy;
/**
* An audio input MediaStream to pass to new {@link Call} instances.
*/
private _callInputStream;
/**
* An array of {@link Call}s. Though only one can be active, multiple may exist when there
* are multiple incoming, unanswered {@link Call}s.
*/
private _calls;
/**
* An array of {@link Device} IDs to be used to play sounds through, to be passed to
* new {@link Call} instances.
*/
private _callSinkIds;
/**
* The list of chunder URIs that will be passed to PStream
*/
private _chunderURIs;
/**
* Default options used by {@link Device}.
*/
private readonly _defaultOptions;
/**
* The name of the edge the {@link Device} is connected to.
*/
private _edge;
/**
* The name of the home region the {@link Device} is connected to.
*/
private _home;
/**
* The identity associated with this Device.
*/
private _identity;
/**
* Whether SDK is run as a browser extension
*/
private _isBrowserExtension;
/**
* An instance of Logger to use.
*/
private _log;
/**
* Network related information
* See https://developer.mozilla.org/en-US/docs/Web/API/Network_Information_API
*/
private _networkInformation;
/**
* The options passed to {@link Device} constructor or {@link Device.updateOptions}.
*/
private _options;
/**
* The preferred URI to (re)-connect signaling to.
*/
private _preferredURI;
/**
* An Insights Event Publisher.
*/
private _publisher;
/**
* The region the {@link Device} is connected to.
*/
private _region;
/**
* A timeout ID for a setTimeout schedule to re-register the {@link Device}.
*/
private _regTimer;
/**
* Boolean representing whether or not the {@link Device} was registered when
* receiving a signaling `offline`. Determines if the {@link Device} attempts
* a `re-register` once signaling is re-established when receiving a
* `connected` event from the stream.
*/
private _shouldReRegister;
/**
* A Map of Sounds to play.
*/
private _soundcache;
/**
* The current status of the {@link Device}.
*/
private _state;
/**
* A map from {@link Device.State} to {@link Device.EventName}.
*/
private readonly _stateEventMapping;
/**
* The Signaling stream.
*/
private _stream;
/**
* A promise that will resolve when the Signaling stream is ready.
*/
private _streamConnectedPromise;
/**
* The JWT string currently being used to authenticate this {@link Device}.
*/
private _token;
/**
* A timeout to track when the current AccessToken will expire.
*/
private _tokenWillExpireTimeout;
/**
* Construct a {@link Device} instance. The {@link Device} can be registered
* to make and listen for calls using {@link Device.register}.
* @constructor
* @param options
*/
constructor(token: string, options?: Device.Options);
/**
* Return the {@link AudioHelper} used by this {@link Device}.
*/
get audio(): AudioHelper | null;
/**
* Make an outgoing Call.
* @param options
*/
connect(options?: Device.ConnectOptions): Promise<Call>;
/**
* Return the calls that this {@link Device} is maintaining.
*/
get calls(): Call[];
/**
* Destroy the {@link Device}, freeing references to be garbage collected.
*/
destroy(): void;
/**
* Disconnect all {@link Call}s.
*/
disconnectAll(): void;
/**
* Returns the {@link Edge} value the {@link Device} is currently connected
* to. The value will be `null` when the {@link Device} is offline.
*/
get edge(): string | null;
/**
* Returns the home value the {@link Device} is currently connected
* to. The value will be `null` when the {@link Device} is offline.
*/
get home(): string | null;
/**
* Returns the identity associated with the {@link Device} for incoming calls. Only
* populated when registered.
*/
get identity(): string | null;
/**
* Whether the Device is currently on an active Call.
*/
get isBusy(): boolean;
/**
* Register the `Device` to the Twilio backend, allowing it to receive calls.
*/
register(): Promise<void>;
/**
* Get the state of this {@link Device} instance
*/
get state(): Device.State;
/**
* Get the token used by this {@link Device}.
*/
get token(): string | null;
/**
* String representation of {@link Device} instance.
* @private
*/
toString(): string;
/**
* Unregister the `Device` to the Twilio backend, disallowing it to receive
* calls.
*/
unregister(): Promise<void>;
/**
* Set the options used within the {@link Device}.
* @param options
*/
updateOptions(options?: Device.Options): void;
/**
* Update the token used by this {@link Device} to connect to Twilio.
* It is recommended to call this API after [[Device.tokenWillExpireEvent]] is emitted,
* and before or after a call to prevent a potential ~1s audio loss during the update process.
* @param token
*/
updateToken(token: string): void;
/**
* Called on window's beforeunload event if closeProtection is enabled,
* preventing users from accidentally navigating away from an active call.
* @param event
*/
private _confirmClose;
/**
* Create the default Insights payload
* @param call
*/
private _createDefaultPayload;
/**
* Destroy the AudioHelper.
*/
private _destroyAudioHelper;
/**
* Destroy the publisher.
*/
private _destroyPublisher;
/**
* Destroy the connection to the signaling server.
*/
private _destroyStream;
/**
* Find a {@link Call} by its CallSid.
* @param callSid
*/
private _findCall;
/**
* Create a new {@link Call}.
* @param twimlParams - A flat object containing key:value pairs to be sent to the TwiML app.
* @param options - Options to be used to instantiate the {@link Call}.
*/
private _makeCall;
/**
* Stop the incoming sound if no {@link Call}s remain.
*/
private _maybeStopIncomingSound;
/**
* Called when a 'close' event is received from the signaling stream.
*/
private _onSignalingClose;
/**
* Called when a 'connected' event is received from the signaling stream.
*/
private _onSignalingConnected;
/**
* Called when an 'error' event is received from the signaling stream.
*/
private _onSignalingError;
/**
* Called when an 'invite' event is received from the signaling stream.
*/
private _onSignalingInvite;
/**
* Called when an 'offline' event is received from the signaling stream.
*/
private _onSignalingOffline;
/**
* Called when a 'ready' event is received from the signaling stream.
*/
private _onSignalingReady;
/**
* Publish a NetworkInformation#change event to Insights if there's an active {@link Call}.
*/
private _publishNetworkChange;
/**
* Remove a {@link Call} from device.calls by reference
* @param call
*/
private _removeCall;
/**
* Register with the signaling server.
*/
private _sendPresence;
/**
* Helper function that sets and emits the state of the device.
* @param state The new state of the device.
*/
private _setState;
/**
* Set up an audio helper for usage by this {@link Device}.
*/
private _setupAudioHelper;
/**
* Create and set a publisher for the {@link Device} to use.
*/
private _setupPublisher;
/**
* Set up the connection to the signaling server. Tears down an existing
* stream if called while a stream exists.
*/
private _setupStream;
/**
* Start playing the incoming ringtone, and subsequently emit the incoming event.
* @param call
* @param play - The function to be used to play the sound. Must return a Promise.
*/
private _showIncomingCall;
/**
* Set a timeout to send another register message to the signaling server.
*/
private _startRegistrationTimer;
/**
* Stop sending registration messages to the signaling server.
*/
private _stopRegistrationTimer;
/**
* Throw an error if the {@link Device} is destroyed.
*/
private _throwIfDestroyed;
/**
* Update the input stream being used for calls so that any current call and all future calls
* will use the new input stream.
* @param inputStream
*/
private _updateInputStream;
/**
* Update the device IDs of output devices being used to play the incoming ringtone through.
* @param sinkIds - An array of device IDs
*/
private _updateRingtoneSinkIds;
/**
* Update the device IDs of output devices being used to play sounds through.
* @param type - Whether to update ringtone or speaker sounds
* @param sinkIds - An array of device IDs
*/
private _updateSinkIds;
/**
* Update the device IDs of output devices being used to play the non-ringtone sounds
* and Call audio through.
* @param sinkIds - An array of device IDs
*/
private _updateSpeakerSinkIds;
}
declare namespace Device {
/**
* All valid {@link Device} event names.
*/
enum EventName {
Error = "error",
Incoming = "incoming",
Destroyed = "destroyed",
Unregistered = "unregistered",
Registering = "registering",
Registered = "registered",
TokenWillExpire = "tokenWillExpire"
}
/**
* All possible {@link Device} states.
*/
enum State {
Destroyed = "destroyed",
Unregistered = "unregistered",
Registering = "registering",
Registered = "registered"
}
/**
* Names of all sounds handled by the {@link Device}.
*/
enum SoundName {
Incoming = "incoming",
Outgoing = "outgoing",
Disconnect = "disconnect",
Dtmf0 = "dtmf0",
Dtmf1 = "dtmf1",
Dtmf2 = "dtmf2",
Dtmf3 = "dtmf3",
Dtmf4 = "dtmf4",
Dtmf5 = "dtmf5",
Dtmf6 = "dtmf6",
Dtmf7 = "dtmf7",
Dtmf8 = "dtmf8",
Dtmf9 = "dtmf9",
DtmfS = "dtmfs",
DtmfH = "dtmfh"
}
/**
* Names of all togglable sounds.
*/
type ToggleableSound = Device.SoundName.Incoming | Device.SoundName.Outgoing | Device.SoundName.Disconnect;
/**
* Options to be passed to {@link Device.connect}.
*/
interface ConnectOptions extends Call.AcceptOptions {
/**
* A flat object containing key:value pairs to be sent to the TwiML app.
*/
params?: Record<string, string>;
}
/**
* Options that may be passed to the {@link Device} constructor, or Device.setup via public API
*/
interface Options {
/**
* Whether the Device should raise the {@link incomingEvent} event when a new call invite is
* received while already on an active call. Default behavior is false.
*/
allowIncomingWhileBusy?: boolean;
/**
* A name for the application that is instantiating the {@link Device}. This is used to improve logging
* in Insights by associating Insights data with a specific application, particularly in the case where
* one account may be connected to by multiple applications.
*/
appName?: string;
/**
* A version for the application that is instantiating the {@link Device}. This is used to improve logging
* in Insights by associating Insights data with a specific version of the given application. This can help
* track down when application-level bugs were introduced.
*/
appVersion?: string;
/**
* Whether to enable close protection, to prevent users from accidentally
* navigating away from the page during a call. If string, the value will
* be used as a custom message.
*/
closeProtection?: boolean | string;
/**
* An ordered array of codec names, from most to least preferred.
*/
codecPreferences?: Call.Codec[];
/**
* Whether AudioContext sounds should be disabled. Useful for trouble shooting sound issues
* that may be caused by AudioContext-specific sounds. If set to true, will fall back to
* HTMLAudioElement sounds.
*/
disableAudioContextSounds?: boolean;
/**
* Whether to use googDscp in RTC constraints.
*/
dscp?: boolean;
/**
* The edge value corresponds to the geographic location that the client
* will use to connect to Twilio infrastructure. The default value is
* "roaming" which automatically selects an edge based on the latency of the
* client relative to available edges.
*/
edge?: string[] | string;
/**
* Overrides the native MediaDevices.enumerateDevices API.
*/
enumerateDevices?: any;
/**
* Experimental feature.
* Whether to use ICE Aggressive nomination.
*/
forceAggressiveIceNomination?: boolean;
/**
* Overrides the native MediaDevices.getUserMedia API.
*/
getUserMedia?: any;
/**
* Log level.
*/
logLevel?: LogLevelDesc;
/**
* The maximum average audio bitrate to use, in bits per second (bps) based on
* [RFC-7587 7.1](https://tools.ietf.org/html/rfc7587#section-7.1). By default, the setting
* is not used. If you specify 0, then the setting is not used. Any positive integer is allowed,
* but values outside the range 6000 to 510000 are ignored and treated as 0. The recommended
* bitrate for speech is between 8000 and 40000 bps as noted in
* [RFC-7587 3.1.1](https://tools.ietf.org/html/rfc7587#section-3.1.1).
*/
maxAverageBitrate?: number;
/**
* The maximum duration to attempt to reconnect to a preferred URI.
* This is used by signaling reconnection in that during the existence of
* any call, edge-fallback is disabled until this length of time has
* elapsed.
*
* Using a value of 30000 as an example: while a call exists, the Device
* will attempt to reconnect to the edge that the call was established on
* for approximately 30 seconds. After the next failure to connect, the
* Device will use edge-fallback.
*
* This feature is opt-in, and will not work until a number greater than 0
* is explicitly specified within the Device options.
*/
maxCallSignalingTimeoutMs?: number;
/**
* Overrides the native RTCPeerConnection class.
*
* By default, the SDK will use the `unified-plan` SDP format if the browser supports it.
* Unexpected behavior may happen if the `RTCPeerConnection` parameter uses an SDP format
* that is different than what the SDK uses.
*
* For example, if the browser supports `unified-plan` and the `RTCPeerConnection`
* parameter uses `plan-b` by default, the SDK will use `unified-plan`
* which will cause conflicts with the usage of the `RTCPeerConnection`.
*
* In order to avoid this issue, you need to explicitly set the SDP format that you want
* the SDK to use with the `RTCPeerConnection` via [[Device.ConnectOptions.rtcConfiguration]] for outgoing calls.
* Or [[Call.AcceptOptions.rtcConfiguration]] for incoming calls.
*
* See the example below. Assuming the `RTCPeerConnection` you provided uses `plan-b` by default, the following
* code sets the SDP format to `unified-plan` instead.
*
* ```ts
* // Outgoing calls
* const call = await device.connect({
* rtcConfiguration: {
* sdpSemantics: 'unified-plan'
* }
* // Other options
* });
*
* // Incoming calls
* device.on('incoming', call => {
* call.accept({
* rtcConfiguration: {
* sdpSemantics: 'unified-plan'
* }
* // Other options
* });
* });
* ```
*/
RTCPeerConnection?: any;
/**
* A mapping of custom sound URLs by sound name.
*/
sounds?: Partial<Record<Device.SoundName, string>>;
/**
* Number of milliseconds fewer than the token's TTL to emit the tokenWillExpire event.
* Default is 10000 (10 seconds).
*/
tokenRefreshMs?: number;
}
}
export default Device;