onCallInvite method

Future<void> onCallInvite(
  1. String roomId,
  2. String senderId,
  3. Map<String, dynamic> content
)

Implementation

Future<void> onCallInvite(
    String roomId, String senderId, Map<String, dynamic> content) async {
  if (senderId == client.userID) {
    // Ignore messages to yourself.
    return;
  }

  Logs().v(
      '[VOIP] onCallInvite $senderId => ${client.userID}, \ncontent => ${content.toString()}');

  final String callId = content['call_id'];
  final String partyId = content['party_id'];
  final int lifetime = content['lifetime'];
  final String? confId = content['conf_id'];
  final String? deviceId = content['device_id'];
  final call = calls[callId];

  Logs().d(
      '[glare] got new call ${content.tryGet('call_id')} and currently room id is mapped to ${incomingCallRoomId.tryGet(roomId)}');

  if (call != null && call.state == CallState.kEnded) {
    // Session already exist.
    Logs().v('[VOIP] onCallInvite: Session [$callId] already exist.');
    return;
  }

  if (content['invitee'] != null && content['invitee'] != client.userID) {
    return; // This invite was meant for another user in the room
  }

  if (content['capabilities'] != null) {
    final capabilities = CallCapabilities.fromJson(content['capabilities']);
    Logs().v(
        '[VOIP] CallCapabilities: dtmf => ${capabilities.dtmf}, transferee => ${capabilities.transferee}');
  }

  var callType = CallType.kVoice;
  SDPStreamMetadata? sdpStreamMetadata;
  if (content[sdpStreamMetadataKey] != null) {
    sdpStreamMetadata =
        SDPStreamMetadata.fromJson(content[sdpStreamMetadataKey]);
    sdpStreamMetadata.sdpStreamMetadatas
        .forEach((streamId, SDPStreamPurpose purpose) {
      Logs().v(
          '[VOIP] [$streamId] => purpose: ${purpose.purpose}, audioMuted: ${purpose.audio_muted}, videoMuted:  ${purpose.video_muted}');

      if (!purpose.video_muted) {
        callType = CallType.kVideo;
      }
    });
  } else {
    callType = getCallType(content['offer']['sdp']);
  }

  final room = client.getRoomById(roomId);

  final opts = CallOptions()
    ..voip = this
    ..callId = callId
    ..groupCallId = confId
    ..dir = CallDirection.kIncoming
    ..type = callType
    ..room = room!
    ..localPartyId = localPartyId!
    ..iceServers = await getIceSevers();

  final newCall = createNewCall(opts);
  newCall.remotePartyId = partyId;
  newCall.remoteUser = await room.requestUser(senderId);
  newCall.opponentDeviceId = deviceId;
  newCall.opponentSessionId = content['sender_session_id'];
  if (!delegate.canHandleNewCall &&
      (confId == null || confId != currentGroupCID)) {
    Logs().v(
        '[VOIP] onCallInvite: Unable to handle new calls, maybe user is busy.');
    await newCall.reject(reason: CallErrorCode.UserBusy, shouldEmit: false);
    await delegate.handleMissedCall(newCall);
    return;
  }

  final offer = RTCSessionDescription(
    content['offer']['sdp'],
    content['offer']['type'],
  );

  /// play ringtone. We decided to play the ringtone before adding the call to
  /// the incoming call stream because getUserMedia from initWithInvite fails
  /// on firefox unless the tab is in focus. We should atleast be able to notify
  /// the user about an incoming call
  ///
  /// Autoplay on firefox still needs interaction, without which all notifications
  /// could be blocked.
  if (confId == null) {
    await delegate.playRingtone();
  }

  await newCall.initWithInvite(
      callType, offer, sdpStreamMetadata, lifetime, confId != null);

  currentCID = callId;

  // Popup CallingPage for incoming call.
  if (confId == null && !newCall.callHasEnded) {
    await delegate.handleNewCall(newCall);
  }

  onIncomingCall.add(newCall);
}