makeCall method

Future<SipCall?> makeCall(
  1. String target, {
  2. bool withVideo = false,
  3. VideoEncoder? videoEncoder,
  4. 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;
}