sip.js
Version:
A SIP library for JavaScript
109 lines (108 loc) • 5.31 kB
JavaScript
import { C } from "../messages/methods/constants.js";
import { InviteClientTransaction } from "../transactions/invite-client-transaction.js";
import { UserAgentClient } from "./user-agent-client.js";
/**
* Re-INVITE UAC.
* @remarks
* 14 Modifying an Existing Session
* https://tools.ietf.org/html/rfc3261#section-14
* 14.1 UAC Behavior
* https://tools.ietf.org/html/rfc3261#section-14.1
* @public
*/
export class ReInviteUserAgentClient extends UserAgentClient {
constructor(dialog, delegate, options) {
const message = dialog.createOutgoingRequestMessage(C.INVITE, options);
super(InviteClientTransaction, dialog.userAgentCore, message, delegate);
this.delegate = delegate;
dialog.signalingStateTransition(message);
// FIXME: TODO: next line obviously needs to be improved...
dialog.reinviteUserAgentClient = this; // let the dialog know re-invite request sent
this.dialog = dialog;
}
receiveResponse(message) {
if (!this.authenticationGuard(message, this.dialog)) {
return;
}
const statusCode = message.statusCode ? message.statusCode.toString() : "";
if (!statusCode) {
throw new Error("Response status code undefined.");
}
switch (true) {
case /^100$/.test(statusCode):
if (this.delegate && this.delegate.onTrying) {
this.delegate.onTrying({ message });
}
break;
case /^1[0-9]{2}$/.test(statusCode):
if (this.delegate && this.delegate.onProgress) {
this.delegate.onProgress({
message,
session: this.dialog,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
prack: (options) => {
throw new Error("Unimplemented.");
}
});
}
break;
case /^2[0-9]{2}$/.test(statusCode):
// Update dialog signaling state with offer/answer in body
this.dialog.signalingStateTransition(message);
if (this.delegate && this.delegate.onAccept) {
this.delegate.onAccept({
message,
session: this.dialog,
ack: (options) => {
const outgoingAckRequest = this.dialog.ack(options);
return outgoingAckRequest;
}
});
}
break;
case /^3[0-9]{2}$/.test(statusCode):
this.dialog.signalingStateRollback();
this.dialog.reinviteUserAgentClient = undefined; // ACK was handled by transaction
if (this.delegate && this.delegate.onRedirect) {
this.delegate.onRedirect({ message });
}
break;
case /^[4-6][0-9]{2}$/.test(statusCode):
this.dialog.signalingStateRollback();
this.dialog.reinviteUserAgentClient = undefined; // ACK was handled by transaction
if (this.delegate && this.delegate.onReject) {
this.delegate.onReject({ message });
}
else {
// If a UA receives a non-2xx final response to a re-INVITE, the session
// parameters MUST remain unchanged, as if no re-INVITE had been issued.
// Note that, as stated in Section 12.2.1.2, if the non-2xx final
// response is a 481 (Call/Transaction Does Not Exist), or a 408
// (Request Timeout), or no response at all is received for the re-
// INVITE (that is, a timeout is returned by the INVITE client
// transaction), the UAC will terminate the dialog.
//
// If a UAC receives a 491 response to a re-INVITE, it SHOULD start a
// timer with a value T chosen as follows:
//
// 1. If the UAC is the owner of the Call-ID of the dialog ID
// (meaning it generated the value), T has a randomly chosen value
// between 2.1 and 4 seconds in units of 10 ms.
//
// 2. If the UAC is not the owner of the Call-ID of the dialog ID, T
// has a randomly chosen value of between 0 and 2 seconds in units
// of 10 ms.
//
// When the timer fires, the UAC SHOULD attempt the re-INVITE once more,
// if it still desires for that session modification to take place. For
// example, if the call was already hung up with a BYE, the re-INVITE
// would not take place.
// https://tools.ietf.org/html/rfc3261#section-14.1
// FIXME: TODO: The above.
}
break;
default:
throw new Error(`Invalid status code ${statusCode}`);
}
}
}