makeCall method
Future<SipCall?>
makeCall(
- String target, {
- bool withVideo = false,
- VideoEncoder? videoEncoder,
- VideoDecoder? videoDecoder,
Implementation
Future<SipCall?> makeCall(
String target, {
bool withVideo = false,
VideoEncoder? videoEncoder,
VideoDecoder? videoDecoder,
}) async {
final acc = _account;
final tx = _transport;
if (acc == null || tx == null || !tx.isConnected) return null;
if (isWeb) {
_log(
'makeCall: rejected — RTP media (UDP) is not supported on web. '
'Outgoing audio/video calls require a native build.',
);
return null;
}
final targetUri = _normaliseTarget(target, acc.domain);
final callId = _uuid.v4();
final fromTag = _shortTag();
final branch = _branch();
final cseq = _nextCseq();
// Bind a local RTP port and put it in our SDP offer.
final media = MediaSession(
sink: _audioSinkFactory?.call(),
packetTap: _rtpPacketTap,
);
final rtpPort = await media.bindLocalPort();
VideoSession? video;
int? videoPort;
if (withVideo) {
video = VideoSession(encoder: videoEncoder, decoder: videoDecoder);
videoPort = await video.bindLocalPort();
}
final sdpSid = DateTime.now().millisecondsSinceEpoch ~/ 1000;
final body = video == null
? buildG711Offer(
username: acc.username,
localHost: _mediaLocalHost(),
localPort: rtpPort,
rtcpPort: media.localRtcpPort,
sessionId: sdpSid,
sessionVersion: sdpSid,
)
: buildAvOffer(
username: acc.username,
localHost: _mediaLocalHost(),
audioPort: rtpPort,
videoPort: videoPort,
audioRtcpPort: media.localRtcpPort,
sessionId: sdpSid,
sessionVersion: sdpSid,
);
final extra = <String, String>{
'Content-Type': 'application/sdp',
// RFC 4028: advertise session timer support and propose interval.
'Supported': 'timer',
'Session-Expires': '${acc.sessionExpires};refresher=uac',
'Min-SE': '${acc.minSE}',
};
final invite = _buildRequest(
method: 'INVITE',
requestUri: targetUri,
callId: callId,
fromTag: fromTag,
cseq: cseq,
branch: branch,
target: targetUri,
account: acc,
extra: extra,
body: body,
);
final ctx = _CallContext(
call: SipCall(
id: callId,
remoteParty: targetUri,
outgoing: true,
state: CallState.outgoingRinging,
startedAt: DateTime.now(),
),
localTag: fromTag,
cseq: cseq,
lastInvite: invite,
branch: branch,
proposedSE: acc.sessionExpires,
minSE: acc.minSE,
sdpSessionId: sdpSid,
);
ctx.media = media;
ctx.video = video;
_calls[callId] = ctx;
_emitCall(ctx.call);
_send(invite);
return ctx.call;
}