onReceiveCallCallback method
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"] ?? {},)
)
);
}