sip.js
Version:
A SIP library for JavaScript
298 lines (297 loc) • 12.6 kB
JavaScript
import { SessionManager } from "../session-manager/session-manager.js";
/**
* A simple SIP user class.
* @remarks
* While this class is completely functional for simple use cases, it is not intended
* to provide an interface which is suitable for most (must less all) applications.
* While this class has many limitations (for example, it only handles a single concurrent session),
* it is, however, intended to serve as a simple example of using the SIP.js API.
* @public
*/
export class SimpleUser {
/**
* Constructs a new instance of the `SimpleUser` class.
* @param server - SIP WebSocket Server URL.
* @param options - Options bucket. See {@link SimpleUserOptions} for details.
*/
constructor(server, options = {}) {
this.session = undefined;
// Delegate
this.delegate = options.delegate;
// Copy options
this.options = Object.assign({}, options);
// Session manager options
const sessionManagerOptions = {
aor: this.options.aor,
delegate: {
onCallAnswered: () => { var _a, _b; return (_b = (_a = this.delegate) === null || _a === void 0 ? void 0 : _a.onCallAnswered) === null || _b === void 0 ? void 0 : _b.call(_a); },
onCallCreated: (session) => {
var _a, _b;
this.session = session;
(_b = (_a = this.delegate) === null || _a === void 0 ? void 0 : _a.onCallCreated) === null || _b === void 0 ? void 0 : _b.call(_a);
},
onCallReceived: () => { var _a, _b; return (_b = (_a = this.delegate) === null || _a === void 0 ? void 0 : _a.onCallReceived) === null || _b === void 0 ? void 0 : _b.call(_a); },
onCallHangup: () => {
var _a, _b;
this.session = undefined;
((_a = this.delegate) === null || _a === void 0 ? void 0 : _a.onCallHangup) && ((_b = this.delegate) === null || _b === void 0 ? void 0 : _b.onCallHangup());
},
onCallHold: (s, held) => { var _a, _b; return (_b = (_a = this.delegate) === null || _a === void 0 ? void 0 : _a.onCallHold) === null || _b === void 0 ? void 0 : _b.call(_a, held); },
onCallDTMFReceived: (s, tone, dur) => { var _a, _b; return (_b = (_a = this.delegate) === null || _a === void 0 ? void 0 : _a.onCallDTMFReceived) === null || _b === void 0 ? void 0 : _b.call(_a, tone, dur); },
onMessageReceived: (message) => { var _a, _b; return (_b = (_a = this.delegate) === null || _a === void 0 ? void 0 : _a.onMessageReceived) === null || _b === void 0 ? void 0 : _b.call(_a, message.request.body); },
onRegistered: () => { var _a, _b; return (_b = (_a = this.delegate) === null || _a === void 0 ? void 0 : _a.onRegistered) === null || _b === void 0 ? void 0 : _b.call(_a); },
onUnregistered: () => { var _a, _b; return (_b = (_a = this.delegate) === null || _a === void 0 ? void 0 : _a.onUnregistered) === null || _b === void 0 ? void 0 : _b.call(_a); },
onServerConnect: () => { var _a, _b; return (_b = (_a = this.delegate) === null || _a === void 0 ? void 0 : _a.onServerConnect) === null || _b === void 0 ? void 0 : _b.call(_a); },
onServerDisconnect: () => { var _a, _b; return (_b = (_a = this.delegate) === null || _a === void 0 ? void 0 : _a.onServerDisconnect) === null || _b === void 0 ? void 0 : _b.call(_a); }
},
maxSimultaneousSessions: 1,
media: this.options.media,
reconnectionAttempts: this.options.reconnectionAttempts,
reconnectionDelay: this.options.reconnectionDelay,
registererOptions: this.options.registererOptions,
sendDTMFUsingSessionDescriptionHandler: this.options.sendDTMFUsingSessionDescriptionHandler,
userAgentOptions: this.options.userAgentOptions
};
this.sessionManager = new SessionManager(server, sessionManagerOptions);
// Use the SIP.js logger
this.logger = this.sessionManager.userAgent.getLogger("sip.SimpleUser");
}
/**
* Instance identifier.
* @internal
*/
get id() {
return (this.options.userAgentOptions && this.options.userAgentOptions.displayName) || "Anonymous";
}
/** The local media stream. Undefined if call not answered. */
get localMediaStream() {
return this.session && this.sessionManager.getLocalMediaStream(this.session);
}
/** The remote media stream. Undefined if call not answered. */
get remoteMediaStream() {
return this.session && this.sessionManager.getRemoteMediaStream(this.session);
}
/**
* The local audio track, if available.
* @deprecated Use localMediaStream and get track from the stream.
*/
get localAudioTrack() {
return this.session && this.sessionManager.getLocalAudioTrack(this.session);
}
/**
* The local video track, if available.
* @deprecated Use localMediaStream and get track from the stream.
*/
get localVideoTrack() {
return this.session && this.sessionManager.getLocalVideoTrack(this.session);
}
/**
* The remote audio track, if available.
* @deprecated Use remoteMediaStream and get track from the stream.
*/
get remoteAudioTrack() {
return this.session && this.sessionManager.getRemoteAudioTrack(this.session);
}
/**
* The remote video track, if available.
* @deprecated Use remoteMediaStream and get track from the stream.
*/
get remoteVideoTrack() {
return this.session && this.sessionManager.getRemoteVideoTrack(this.session);
}
/**
* Connect.
* @remarks
* Start the UserAgent's WebSocket Transport.
*/
connect() {
this.logger.log(`[${this.id}] Connecting UserAgent...`);
return this.sessionManager.connect();
}
/**
* Disconnect.
* @remarks
* Stop the UserAgent's WebSocket Transport.
*/
disconnect() {
this.logger.log(`[${this.id}] Disconnecting UserAgent...`);
return this.sessionManager.disconnect();
}
/**
* Return true if connected.
*/
isConnected() {
return this.sessionManager.isConnected();
}
/**
* Start receiving incoming calls.
* @remarks
* Send a REGISTER request for the UserAgent's AOR.
* Resolves when the REGISTER request is sent, otherwise rejects.
*/
register(registererRegisterOptions) {
this.logger.log(`[${this.id}] Registering UserAgent...`);
return this.sessionManager.register(registererRegisterOptions);
}
/**
* Stop receiving incoming calls.
* @remarks
* Send an un-REGISTER request for the UserAgent's AOR.
* Resolves when the un-REGISTER request is sent, otherwise rejects.
*/
unregister(registererUnregisterOptions) {
this.logger.log(`[${this.id}] Unregistering UserAgent...`);
return this.sessionManager.unregister(registererUnregisterOptions);
}
/**
* Make an outgoing call.
* @remarks
* Send an INVITE request to create a new Session.
* Resolves when the INVITE request is sent, otherwise rejects.
* Use `onCallAnswered` delegate method to determine if Session is established.
* @param destination - The target destination to call. A SIP address to send the INVITE to.
* @param inviterOptions - Optional options for Inviter constructor.
* @param inviterInviteOptions - Optional options for Inviter.invite().
*/
call(destination, inviterOptions, inviterInviteOptions) {
this.logger.log(`[${this.id}] Beginning Session...`);
if (this.session) {
return Promise.reject(new Error("Session already exists."));
}
return this.sessionManager.call(destination, inviterOptions, inviterInviteOptions).then(() => {
return;
});
}
/**
* Hangup a call.
* @remarks
* Send a BYE request, CANCEL request or reject response to end the current Session.
* Resolves when the request/response is sent, otherwise rejects.
* Use `onCallHangup` delegate method to determine if and when call is ended.
*/
hangup() {
this.logger.log(`[${this.id}] Hangup...`);
if (!this.session) {
return Promise.reject(new Error("Session does not exist."));
}
return this.sessionManager.hangup(this.session).then(() => {
this.session = undefined;
});
}
/**
* Answer an incoming call.
* @remarks
* Accept an incoming INVITE request creating a new Session.
* Resolves with the response is sent, otherwise rejects.
* Use `onCallAnswered` delegate method to determine if and when call is established.
* @param invitationAcceptOptions - Optional options for Inviter.accept().
*/
answer(invitationAcceptOptions) {
this.logger.log(`[${this.id}] Accepting Invitation...`);
if (!this.session) {
return Promise.reject(new Error("Session does not exist."));
}
return this.sessionManager.answer(this.session, invitationAcceptOptions);
}
/**
* Decline an incoming call.
* @remarks
* Reject an incoming INVITE request.
* Resolves with the response is sent, otherwise rejects.
* Use `onCallHangup` delegate method to determine if and when call is ended.
*/
decline() {
this.logger.log(`[${this.id}] rejecting Invitation...`);
if (!this.session) {
return Promise.reject(new Error("Session does not exist."));
}
return this.sessionManager.decline(this.session);
}
/**
* Hold call
* @remarks
* Send a re-INVITE with new offer indicating "hold".
* Resolves when the re-INVITE request is sent, otherwise rejects.
* Use `onCallHold` delegate method to determine if request is accepted or rejected.
* See: https://tools.ietf.org/html/rfc6337
*/
hold() {
this.logger.log(`[${this.id}] holding session...`);
if (!this.session) {
return Promise.reject(new Error("Session does not exist."));
}
return this.sessionManager.hold(this.session);
}
/**
* Unhold call.
* @remarks
* Send a re-INVITE with new offer indicating "unhold".
* Resolves when the re-INVITE request is sent, otherwise rejects.
* Use `onCallHold` delegate method to determine if request is accepted or rejected.
* See: https://tools.ietf.org/html/rfc6337
*/
unhold() {
this.logger.log(`[${this.id}] unholding session...`);
if (!this.session) {
return Promise.reject(new Error("Session does not exist."));
}
return this.sessionManager.unhold(this.session);
}
/**
* Hold state.
* @remarks
* True if session is on hold.
*/
isHeld() {
return this.session ? this.sessionManager.isHeld(this.session) : false;
}
/**
* Mute call.
* @remarks
* Disable sender's media tracks.
*/
mute() {
this.logger.log(`[${this.id}] disabling media tracks...`);
return this.session && this.sessionManager.mute(this.session);
}
/**
* Unmute call.
* @remarks
* Enable sender's media tracks.
*/
unmute() {
this.logger.log(`[${this.id}] enabling media tracks...`);
return this.session && this.sessionManager.unmute(this.session);
}
/**
* Mute state.
* @remarks
* True if sender's media track is disabled.
*/
isMuted() {
return this.session ? this.sessionManager.isMuted(this.session) : false;
}
/**
* Send DTMF.
* @remarks
* Send an INFO request with content type application/dtmf-relay.
* @param tone - Tone to send.
*/
sendDTMF(tone) {
this.logger.log(`[${this.id}] sending DTMF...`);
if (!this.session) {
return Promise.reject(new Error("Session does not exist."));
}
return this.sessionManager.sendDTMF(this.session, tone);
}
/**
* Send a message.
* @remarks
* Send a MESSAGE request.
* @param destination - The target destination for the message. A SIP address to send the MESSAGE to.
*/
message(destination, message) {
this.logger.log(`[${this.id}] sending message...`);
return this.sessionManager.message(destination, message);
}
}