terminate method
Terminate the call.
Implementation
void terminate([Map<String, dynamic>? options]) {
logger.debug('terminate()');
options = options ?? <String, dynamic>{};
Object cause = options['cause'] ?? dart_sip_c.CausesType.BYE;
List<dynamic> extraHeaders = options['extraHeaders'] != null
? utils.cloneArray(options['extraHeaders'])
: <dynamic>[];
Object? body = options['body'];
String? cancel_reason;
int? status_code = options['status_code'] as int?;
String? reason_phrase = options['reason_phrase'] as String?;
// Check Session Status.
if (_status == C.statusTerminated) {
throw exceptions.InvalidStateError(_status);
}
switch (_status) {
// - UAC -
case C.statusNull:
case C.statusInviteSent:
case C.status1xxReceived:
logger.debug('canceling session');
if (status_code != null && (status_code < 200 || status_code >= 700)) {
throw exceptions.TypeError('Invalid status_code: $status_code');
} else if (status_code != null) {
reason_phrase =
reason_phrase ?? dart_sip_c.REASON_PHRASE[status_code];
cancel_reason = 'SIP ;cause=$status_code ;text="$reason_phrase"';
}
// Check Session Status.
if (_status == C.statusNull || _status == C.statusInviteSent) {
_is_canceled = true;
_cancel_reason = cancel_reason;
} else if (_status == C.status1xxReceived) {
_request.cancel(cancel_reason ?? '');
}
_status = C.statusCanceled;
cancel_reason = cancel_reason ?? 'Canceled by local';
status_code = status_code ?? 100;
_failed('local', null, null, null, status_code,
dart_sip_c.CausesType.CANCELED, cancel_reason);
break;
// - UAS -
case C.statusWaitingForAnswer:
case C.statusAnswered:
logger.debug('rejecting session');
status_code = status_code ?? 480;
if (status_code < 300 || status_code >= 700) {
throw exceptions.InvalidStateError(
'Invalid status_code: $status_code');
}
_request.reply(status_code, reason_phrase, extraHeaders, body);
_failed('local', null, null, null, status_code,
dart_sip_c.CausesType.REJECTED, reason_phrase);
break;
case C.statusWaitingForAck:
case C.statusConfirmed:
logger.debug('terminating session');
reason_phrase = options['reason_phrase'] as String? ??
dart_sip_c.REASON_PHRASE[status_code ?? 0];
if (status_code != null && (status_code < 200 || status_code >= 700)) {
throw exceptions.InvalidStateError(
'Invalid status_code: $status_code');
} else if (status_code != null) {
extraHeaders
.add('Reason: SIP ;case=$status_code; text="$reason_phrase"');
}
/* RFC 3261 section 15 (Terminating a session):
*
* "...the callee's UA MUST NOT send a BYE on a confirmed dialog
* until it has received an ACK for its 2xx response or until the server
* transaction times out."
*/
if (_status == C.statusWaitingForAck &&
_direction == 'incoming' &&
_request.server_transaction.state != TransactionState.TERMINATED) {
/// Save the dialog for later restoration.
Dialog dialog = _dialog!;
// Send the BYE as soon as the ACK is received...
receiveRequest = (IncomingMessage request) {
if (request.method == SipMethod.ACK) {
sendRequest(SipMethod.BYE, <String, dynamic>{
'extraHeaders': extraHeaders,
'body': body
});
dialog.terminate();
}
};
// .., or when the INVITE transaction times out
_request.server_transaction.on(EventStateChanged(),
(EventStateChanged state) {
if (_request.server_transaction.state ==
TransactionState.TERMINATED) {
sendRequest(SipMethod.BYE, <String, dynamic>{
'extraHeaders': extraHeaders,
'body': body
});
dialog.terminate();
}
});
_ended(
'local',
null,
ErrorCause(
cause: cause as String?,
status_code: status_code,
reason_phrase: reason_phrase));
// Restore the dialog into 'this' in order to be able to send the in-dialog BYE :-).
_dialog = dialog;
// Restore the dialog into 'ua' so the ACK can reach 'this' session.
_ua!.newDialog(dialog);
} else {
sendRequest(SipMethod.BYE,
<String, dynamic>{'extraHeaders': extraHeaders, 'body': body});
reason_phrase = reason_phrase ?? 'Terminated by local';
status_code = status_code ?? 200;
_ended(
'local',
null,
ErrorCause(
cause: cause as String?,
status_code: status_code,
reason_phrase: reason_phrase));
}
}
}