onReceiveCallCallback method

void onReceiveCallCallback(
  1. dynamic callRequest,
  2. OnReceiveVideoCallListener listener
)

Implementation

void onReceiveCallCallback(dynamic callRequest, OnReceiveVideoCallListener listener) async {
  assert(!_functionCalled, "Please, create another instance of this class, this one is already in use");
  assert(!_callServiceExpired, "Please, create another instance of this class and use it right away, because of getWebRTCParams");

  _callServiceExpired = _functionCalled = true;
  resultCompleterForAcceptingCall = Completer();
  remoteUserId = callRequest["remoteUserId"];

  _listenToCallToClose();

  Future<AcceptingCallResult> acceptCall({required MediaStream localStream, Map<String,dynamic> additionalData = const {}}) {
    this.localStream = localStream;
    this.additionalData = additionalData;

    if (_sdpHasAlreadyBeenSet) {
      throw ("sdpHasAlreadyBeenSet is true");
    }
    _sdpHasAlreadyBeenSet = true;

    _setup(
        impl: () async {
          final iceCandidateSubscription = AsklessClient.instance.readStream(
              route: "askless-internal/call/ice-candidate-list",
              params: { "remoteUserId": remoteUserId }
          ).listen((event) {
            bool added = false;
            for (final iceCandidate in List.from(event["iceCandidateList"])) {
              added = true;
              rtcPeerConnection!.addCandidate(
                  RTCIceCandidate(
                      iceCandidate["candidate"],
                      iceCandidate["id"],
                      iceCandidate["label"]
                  )
              );
              logger("---------------------------");
              logger(json.encode({
                'candidate':  iceCandidate["candidate"],
                'sdpMid': iceCandidate["id"],
                'sdpMlineIndex': iceCandidate["label"]
              }));
              logger("---------------------------");
            }
            logger(added ? ">> 3 - ${List.from(event["iceCandidateList"]).length} ICE candidates added!" : "NO ICE candidates added");
          }, cancelOnError: true, onError: (err) {
            final errorMessage = "\"askless-internal/call/ice-candidate-list\" failed: \"${err.toString()}\"";
            logger(errorMessage, level: Level.error);
            doDisposeCallback(error: errorMessage);
          });
          addToOnDisposeList(() => iceCandidateSubscription.cancel());

          assert(callRequest["sdp"]["type"] == "offer");

          logger(">> setRemoteDescription from offer");
          await rtcPeerConnection!.setRemoteDescription(
              RTCSessionDescription(
                  callRequest["sdp"]["sdp"],
                  callRequest["sdp"]["type"]
              )
          );
          final sdpAnswer = await rtcPeerConnection!.createAnswer({'offerToReceiveVideo': 1, 'offerToReceiveAudio': 1});
          await rtcPeerConnection!.setLocalDescription(sdpAnswer);

          AsklessClient.instance.create(
              route: "askless-internal/call/response",
              body: {
                "callAccepted": true,
                "remoteUserId": remoteUserId,
                "sdp": sdpAnswer.toMap(),
                "additionalData": additionalData ?? {},
              }
          ).then((result) {
            if (!result.success){
              final errorMessage = "\"askless-internal/call/response\" failed: \"${result.error!.code}: ${result.error!.description}\"";
              logger(errorMessage, level: Level.error);
              doDisposeCallback(error: errorMessage);
            }
          });
        }
    );
    return resultCompleterForAcceptingCall!.future;
  }

  AcceptingCallResult? acceptedCallAnswer;
  bool callAnswered = false;
  listener(
      receivingCall = ReceivingCall(
          doDispose: doDisposeCallback,
          disposeList: disposeList,
          isCallAnswered: () => callAnswered,
          acceptCall: ({required MediaStream localStream, Map<String,dynamic>? additionalData}) async {  /* accepting call */
            if (callAnswered) {
              if (acceptedCallAnswer != null) {
                logger("Call already answered", level: Level.warning);
                return acceptedCallAnswer!;
              }
              throw "Call already answered";
            }
            logger("> Accepting call.. (1)", level: Level.debug);
            callAnswered = true;
            return (acceptedCallAnswer = await acceptCall(localStream: localStream, additionalData: additionalData ?? {},));
          },
          rejectCall: ({Map<String,dynamic>? additionalData}) { /* rejecting call */
            if (callAnswered) {
              logger("Call already answered", level: Level.warning);
              return;
            }
            callAnswered = true;
            logger("> Rejecting call.. (1)", level: Level.debug);
            AsklessClient.instance.create(
                route: "askless-internal/call/response",
                body: {
                  "remoteUserId": remoteUserId,
                  "callAccepted": false,
                  "additionalData": additionalData ?? {},
                }
            );
          },
          remoteUserId: remoteUserId,
          additionalData: Map.from(callRequest["additionalData"] ?? {},)
      )
  );
}