/**
* This class describes the information and current status of a call.
*/
export default class Call {
constructor({
id, callId, accountId,
localContact, localUri, remoteContact, remoteUri,
state, stateText, held, muted, speaker,
connectDuration, totalDuration,
remoteOfferer, remoteAudioCount, remoteVideoCount, audioCount, videoCount,
lastStatusCode, lastReason, media, provisionalMedia
}) {
let remoteNumber = null;
let remoteName = null;
if (remoteUri) {
let match = remoteUri.match(/"([^"]+)" <sip:([^@]+)@/);
if (match) {
remoteName = match[1];
remoteNumber = match[2];
} else {
match = remoteUri.match(/sip:([^@]+)@/);
if (match) {
remoteNumber = match[1];
}
}
}
this._id = id;
this._callId = callId;
this._accountId = accountId;
this._localContact = localContact;
this._localUri = localUri;
this._remoteContact = remoteContact;
this._remoteUri = remoteUri;
this._state = state;
this._stateText = stateText;
this._held = held;
this._muted = muted;
this._speaker = speaker;
this._connectDuration = connectDuration;
this._totalDuration = totalDuration;
this._remoteOfferer = remoteOfferer;
this._remoteAudioCount = remoteAudioCount;
this._remoteVideoCount = remoteVideoCount;
this._remoteNumber = remoteNumber;
this._remoteName = remoteName;
this._audioCount = audioCount;
this._videoCount = videoCount;
this._lastStatusCode = lastStatusCode;
this._lastReason = lastReason;
this._media = media;
this._provisionalMedia = provisionalMedia;
this._constructionTime = Math.round(new Date().getTime() / 1000);
}
/**
* Call identification.
* @returns {int}
*/
getId() {
return this._id;
}
/**
* The account ID where this call belongs.
* @returns {int}
*/
getAccountId() {
return this._accountId;
}
/**
* Dialog Call-ID string.
*
* @returns {String}
*/
getCallId() {
return this._callId;
}
/**
* Up-to-date call duration in seconds.
* Use local time to calculate actual call duration.
*
* @public
* @returns {int}
*/
getTotalDuration() {
let time = Math.round(new Date().getTime() / 1000);
let offset = time - this._constructionTime;
return this._totalDuration + offset;
};
/**
* Up-to-date call connected duration (zero when call is not established)
*
* @returns {int}
*/
getConnectDuration() {
if (this._connectDuration < 0 || this._state == "PJSIP_INV_STATE_DISCONNECTED") {
return this._connectDuration;
}
let time = Math.round(new Date().getTime() / 1000);
let offset = time - this._constructionTime;
return this._connectDuration + offset;
}
/**
* Call duration in "MM:SS" format.
*
* @public
* @returns {string}
*/
getFormattedTotalDuration() {
return this._formatTime(this.getTotalDuration());
};
/**
* Call duration in "MM:SS" format.
*
* @public
* @returns {string}
*/
getFormattedConnectDuration() {
return this._formatTime(this.getConnectDuration());
};
/**
* Local Contact.
* TODO: Provide example
* @returns {String}
*/
getLocalContact() {
return this._localContact;
}
/**
* Local URI.
* TODO: Provide example
* @returns {String}
*/
getLocalUri() {
return this._localUri;
}
/**
* Remote contact.
* TODO: Provide example
* @returns {String}
*/
getRemoteContact() {
return this._remoteContact;
}
/**
* Remote URI.
* TODO: Provide example
* @returns {String}
*/
getRemoteUri() {
return this._remoteUri;
}
/**
* Callee name. Could be null if no name specified in URI.
* @returns {String}
*/
getRemoteName() {
return this._remoteName;
}
/**
* Callee number
* @returns {String}
*/
getRemoteNumber() {
return this._remoteNumber;
}
/**
* @returns {String}
*/
getRemoteFormattedNumber() {
if (this._remoteName && this._remoteNumber) {
return `${this._remoteName} <${this._remoteNumber}>`;
} else if (this._remoteNumber) {
return this._remoteNumber;
} else {
return this._remoteUri
}
}
/**
* Invite session state.
*
* PJSIP_INV_STATE_NULL Before INVITE is sent or received
* PJSIP_INV_STATE_CALLING After INVITE is sent
* PJSIP_INV_STATE_INCOMING After INVITE is received.
* PJSIP_INV_STATE_EARLY After response with To tag.
* PJSIP_INV_STATE_CONNECTING After 2xx is sent/received.
* PJSIP_INV_STATE_CONFIRMED After ACK is sent/received.
* PJSIP_INV_STATE_DISCONNECTED Session is terminated.
*
* @returns {String}
*/
getState() {
return this._state;
}
/**
* Text describing the state.
*
* @returns {String}
*/
getStateText() {
return this._stateText;
}
isHeld() {
return this._held;
}
isMuted() {
return this._muted;
}
isSpeaker() {
return this._speaker;
}
isTerminated() {
return this._state === 'PJSIP_INV_STATE_DISCONNECTED';
}
/**
* Flag if remote was SDP offerer
* @returns {boolean}
*/
getRemoteOfferer() {
// TODO Verify whether boolean value
return this._remoteOfferer;
}
/**
* Number of audio streams offered by remote.
* @returns {int}
*/
getRemoteAudioCount() {
return this._remoteAudioCount;
}
/**
* Number of video streams offered by remote.
* @returns {int}
*/
getRemoteVideoCount() {
return this._remoteVideoCount;
}
/**
* Number of simultaneous active audio streams for this call. If zero - audio is disabled in this call.
* @returns {int}
*/
getAudioCount() {
return this._audioCount;
}
/**
* Number of simultaneous active video streams for this call. If zero - video is disabled in this call.
* @returns {*}
*/
getVideoCount() {
return this._videoCount;
}
/**
* Last status code heard, which can be used as cause code.
* Possible values:
* - PJSIP_SC_TRYING / 100
* - PJSIP_SC_RINGING / 180
* - PJSIP_SC_CALL_BEING_FORWARDED / 181
* - PJSIP_SC_QUEUED / 182
* - PJSIP_SC_PROGRESS / 183
* - PJSIP_SC_OK / 200
* - PJSIP_SC_ACCEPTED / 202
* - PJSIP_SC_MULTIPLE_CHOICES / 300
* - PJSIP_SC_MOVED_PERMANENTLY / 301
* - PJSIP_SC_MOVED_TEMPORARILY / 302
* - PJSIP_SC_USE_PROXY / 305
* - PJSIP_SC_ALTERNATIVE_SERVICE / 380
* - PJSIP_SC_BAD_REQUEST / 400
* - PJSIP_SC_UNAUTHORIZED / 401
* - PJSIP_SC_PAYMENT_REQUIRED / 402
* - PJSIP_SC_FORBIDDEN / 403
* - PJSIP_SC_NOT_FOUND / 404
* - PJSIP_SC_METHOD_NOT_ALLOWED / 405
* - PJSIP_SC_NOT_ACCEPTABLE / 406
* - PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED / 407
* - PJSIP_SC_REQUEST_TIMEOUT / 408
* - PJSIP_SC_GONE / 410
* - PJSIP_SC_REQUEST_ENTITY_TOO_LARGE / 413
* - PJSIP_SC_REQUEST_URI_TOO_LONG / 414
* - PJSIP_SC_UNSUPPORTED_MEDIA_TYPE / 415
* - PJSIP_SC_UNSUPPORTED_URI_SCHEME / 416
* - PJSIP_SC_BAD_EXTENSION / 420
* - PJSIP_SC_EXTENSION_REQUIRED / 421
* - PJSIP_SC_SESSION_TIMER_TOO_SMALL / 422
* - PJSIP_SC_INTERVAL_TOO_BRIEF / 423
* - PJSIP_SC_TEMPORARILY_UNAVAILABLE / 480
* - PJSIP_SC_CALL_TSX_DOES_NOT_EXIST / 481
* - PJSIP_SC_LOOP_DETECTED / 482
* - PJSIP_SC_TOO_MANY_HOPS / 483
* - PJSIP_SC_ADDRESS_INCOMPLETE / 484
* - PJSIP_AC_AMBIGUOUS / 485
* - PJSIP_SC_BUSY_HERE / 486
* - PJSIP_SC_REQUEST_TERMINATED / 487
* - PJSIP_SC_NOT_ACCEPTABLE_HERE / 488
* - PJSIP_SC_BAD_EVENT / 489
* - PJSIP_SC_REQUEST_UPDATED / 490
* - PJSIP_SC_REQUEST_PENDING / 491
* - PJSIP_SC_UNDECIPHERABLE / 493
* - PJSIP_SC_INTERNAL_SERVER_ERROR / 500
* - PJSIP_SC_NOT_IMPLEMENTED / 501
* - PJSIP_SC_BAD_GATEWAY / 502
* - PJSIP_SC_SERVICE_UNAVAILABLE / 503
* - PJSIP_SC_SERVER_TIMEOUT / 504
* - PJSIP_SC_VERSION_NOT_SUPPORTED / 505
* - PJSIP_SC_MESSAGE_TOO_LARGE / 513
* - PJSIP_SC_PRECONDITION_FAILURE / 580
* - PJSIP_SC_BUSY_EVERYWHERE / 600
* - PJSIP_SC_DECLINE / 603
* - PJSIP_SC_DOES_NOT_EXIST_ANYWHERE / 604
* - PJSIP_SC_NOT_ACCEPTABLE_ANYWHERE / 606
* - PJSIP_SC_TSX_TIMEOUT / PJSIP_SC_REQUEST_TIMEOUT
* - PJSIP_SC_TSX_TRANSPORT_ERROR / PJSIP_SC_SERVICE_UNAVAILABLE
*
* @returns {string}
*/
getLastStatusCode() {
return this._lastStatusCode;
}
/**
* The reason phrase describing the last status.
*
* @returns {string}
*/
getLastReason() {
return this._lastReason;
}
getMedia() {
return this._media;
}
getProvisionalMedia() {
return this._provisionalMedia;
}
/**
* Format seconds to "MM:SS" format.
*
* @public
* @returns {string}
*/
_formatTime(seconds) {
if (isNaN(seconds) || seconds < 0) {
return "00:00";
}
var hours = parseInt( seconds / 3600 ) % 24;
var minutes = parseInt( seconds / 60 ) % 60;
var result = "";
seconds = seconds % 60;
if (hours > 0) {
result += (hours < 10 ? "0" + hours : hours) + ":";
}
result += (minutes < 10 ? "0" + minutes : minutes) + ":" + (seconds < 10 ? "0" + seconds : seconds);
return result;
};
}