/// <summary> /// Calls to disconnect the user from the server. /// </summary> public async Task DisconnectFromServer() { if (_signaller.IsConnected()) { await _signaller.SignOut(); } }
/// <summary> /// Handler for Signaller's OnMessageFromPeer event. /// </summary> /// <param name="peerId">ID of the peer.</param> /// <param name="message">Message from the peer.</param> private void Signaller_OnMessageFromPeer(int peerId, string message) { Task.Run(async() => { Debug.Assert(_peerId == peerId || _peerId == -1); Debug.Assert(message.Length > 0); if (_peerId != peerId && _peerId != -1) { Debug.WriteLine("[Error] Conductor: Received a message from unknown peer while already in a conversation with a different peer."); return; } JsonObject jMessage; if (!JsonObject.TryParse(message, out jMessage)) { Debug.WriteLine("[Error] Conductor: Received unknown message." + message); return; } string type = jMessage.ContainsKey(kSessionDescriptionTypeName) ? jMessage.GetNamedString(kSessionDescriptionTypeName) : null; #if ORTCLIB bool created = false; #endif if (_peerConnection == null) { if (!IsNullOrEmpty(type)) { // Create the peer connection only when call is // about to get initiated. Otherwise ignore the // messages from peers which could be a result // of old (but not yet fully closed) connections. if (type == "offer" || type == "answer" || type == "json") { Debug.Assert(_peerId == -1); _peerId = peerId; IEnumerable <Peer> enumerablePeer = Peers.Where(x => x.Id == peerId); Peer = enumerablePeer.First(); #if ORTCLIB created = true; _signalingMode = Helper.SignalingModeForClientName(Peer.Name); #endif _connectToPeerCancelationTokenSource = new CancellationTokenSource(); _connectToPeerTask = CreatePeerConnection(_connectToPeerCancelationTokenSource.Token); bool connectResult = await _connectToPeerTask; _connectToPeerTask = null; _connectToPeerCancelationTokenSource.Dispose(); if (!connectResult) { Debug.WriteLine("[Error] Conductor: Failed to initialize our PeerConnection instance"); await Signaller.SignOut(); return; } else if (_peerId != peerId) { Debug.WriteLine("[Error] Conductor: Received a message from unknown peer while already in a conversation with a different peer."); return; } } } else { Debug.WriteLine("[Warn] Conductor: Received an untyped message after closing peer connection."); return; } } if (_peerConnection != null && !IsNullOrEmpty(type)) { if (type == "offer-loopback") { // Loopback not supported Debug.Assert(false); } string sdp = null; #if ORTCLIB if (jMessage.ContainsKey(kSessionDescriptionJsonName)) { var containerObject = new JsonObject { { kSessionDescriptionJsonName, jMessage.GetNamedObject(kSessionDescriptionJsonName) } }; sdp = containerObject.Stringify(); } else if (jMessage.ContainsKey(kSessionDescriptionSdpName)) { sdp = jMessage.GetNamedString(kSessionDescriptionSdpName); } #else sdp = jMessage.ContainsKey(kSessionDescriptionSdpName) ? jMessage.GetNamedString(kSessionDescriptionSdpName) : null; #endif if (IsNullOrEmpty(sdp)) { Debug.WriteLine("[Error] Conductor: Can't parse received session description message."); return; } #if ORTCLIB RTCSessionDescriptionSignalingType messageType = RTCSessionDescriptionSignalingType.SdpOffer; switch (type) { case "json": messageType = RTCSessionDescriptionSignalingType.Json; break; case "offer": messageType = RTCSessionDescriptionSignalingType.SdpOffer; break; case "answer": messageType = RTCSessionDescriptionSignalingType.SdpAnswer; break; case "pranswer": messageType = RTCSessionDescriptionSignalingType.SdpPranswer; break; default: Debug.Assert(false, type); break; } #else RTCSdpType messageType = RTCSdpType.Offer; switch (type) { case "offer": messageType = RTCSdpType.Offer; break; case "answer": messageType = RTCSdpType.Answer; break; case "pranswer": messageType = RTCSdpType.Pranswer; break; default: Debug.Assert(false, type); break; } #endif Debug.WriteLine("Conductor: Received session description: " + message); await _peerConnection.SetRemoteDescription(new RTCSessionDescription(messageType, sdp)); #if ORTCLIB if ((messageType == RTCSessionDescriptionSignalingType.SdpOffer) || ((created) && (messageType == RTCSessionDescriptionSignalingType.Json))) #else if (messageType == RTCSdpType.Offer) #endif { var answer = await _peerConnection.CreateAnswer(); await _peerConnection.SetLocalDescription(answer); // Send answer SendSdp(answer); #if ORTCLIB OrtcStatsManager.Instance.StartCallWatch(SessionId, false); #endif } } else { RTCIceCandidate candidate = null; #if ORTCLIB if (RTCPeerConnectionSignalingMode.Json != _signalingMode) #endif { var sdpMid = jMessage.ContainsKey(kCandidateSdpMidName) ? jMessage.GetNamedString(kCandidateSdpMidName) : null; var sdpMlineIndex = jMessage.ContainsKey(kCandidateSdpMlineIndexName) ? jMessage.GetNamedNumber(kCandidateSdpMlineIndexName) : -1; var sdp = jMessage.ContainsKey(kCandidateSdpName) ? jMessage.GetNamedString(kCandidateSdpName) : null; //TODO: Check is this proper condition ((String.IsNullOrEmpty(sdpMid) && (sdpMlineIndex == -1)) || String.IsNullOrEmpty(sdp)) if (IsNullOrEmpty(sdpMid) || sdpMlineIndex == -1 || IsNullOrEmpty(sdp)) { Debug.WriteLine("[Error] Conductor: Can't parse received message.\n" + message); return; } #if ORTCLIB candidate = IsNullOrEmpty(sdpMid) ? RTCIceCandidate.FromSdpStringWithMLineIndex(sdp, (ushort)sdpMlineIndex) : RTCIceCandidate.FromSdpStringWithMid(sdp, sdpMid); #else candidate = new RTCIceCandidate(sdp, sdpMid, (ushort)sdpMlineIndex); #endif } #if ORTCLIB else { candidate = RTCIceCandidate.FromJsonString(message); } _peerConnection?.AddIceCandidate(candidate); #else await _peerConnection.AddIceCandidate(candidate); #endif Debug.WriteLine("Conductor: Received candidate : " + message); } }).Wait(); }