public IEnumerator MediaStreamTrackThrowExceptionAfterPeerDisposed()
        {
            RTCConfiguration config = default;

            config.iceServers = new[] { new RTCIceServer {
                                            urls = new[] { "stun:stun.l.google.com:19302" }
                                        } };
            var peer1 = new RTCPeerConnection(ref config);
            var peer2 = new RTCPeerConnection(ref config);

            peer1.OnIceCandidate = candidate => { peer2.AddIceCandidate(candidate); };
            peer2.OnIceCandidate = candidate => { peer1.AddIceCandidate(candidate); };

            AudioStreamTrack track = new AudioStreamTrack();

            peer1.AddTrack(track);

            MediaStreamTrack track1 = null;

            peer2.OnTrack = e => { track1 = e.Track; };

            yield return(SignalingOffer(peer1, peer2));

            Assert.That(track1, Is.Not.Null);
            peer2.Dispose();
            Assert.That(() => track1.Id, Throws.TypeOf <InvalidOperationException>());
            track.Dispose();
            track1.Dispose();
        }
예제 #2
0
        public IEnumerator MediaStreamTrackThrowExceptionAfterPeerDisposed()
        {
            RTCConfiguration config = default;

            config.iceServers = new[] { new RTCIceServer {
                                            urls = new[] { "stun:stun.l.google.com:19302" }
                                        } };
            var peer1 = new RTCPeerConnection(ref config);
            var peer2 = new RTCPeerConnection(ref config);

            peer1.OnIceCandidate = candidate => { peer2.AddIceCandidate(candidate); };
            peer2.OnIceCandidate = candidate => { peer1.AddIceCandidate(candidate); };

            var obj    = new GameObject("audio");
            var source = obj.AddComponent <AudioSource>();

            source.clip = AudioClip.Create("test", 480, 2, 48000, false);
            AudioStreamTrack track = new AudioStreamTrack(source);

            peer1.AddTrack(track);

            MediaStreamTrack track1 = null;

            peer2.OnTrack = e => { track1 = e.Track; };

            yield return(SignalingOffer(peer1, peer2));

            Assert.That(track1, Is.Not.Null);
            peer2.Dispose();
            Assert.That(() => track1.Id, Throws.TypeOf <ObjectDisposedException>());
            track.Dispose();
            track1.Dispose();
            Object.DestroyImmediate(source.clip);
            Object.DestroyImmediate(obj);
        }
예제 #3
0
    private void Call()
    {
        Debug.Log("Starting calls");

        pcLocal                 = new RTCPeerConnection(ref configuration);
        pcRemote                = new RTCPeerConnection(ref configuration);
        pcRemote.OnTrack        = e => receiveVideoStream.AddTrack(e.Track);
        pcLocal.OnIceCandidate  = candidate => pcRemote.AddIceCandidate(candidate);
        pcRemote.OnIceCandidate = candidate => pcLocal.AddIceCandidate(candidate);
        Debug.Log("pc1: created local and remote peer connection object");

        foreach (var track in sourceVideoStream.GetTracks())
        {
            pcLocal.AddTrack(track, sourceVideoStream);
        }

        Debug.Log("Adding local stream to pcLocal");

        callButton.interactable         = false;
        createOfferButton.interactable  = true;
        createAnswerButton.interactable = true;
        setOfferButton.interactable     = true;
        setAnswerButton.interactable    = true;
        hangUpButton.interactable       = true;
    }
        public IEnumerator TransceiverReturnsSender()
        {
            RTCConfiguration config = default;

            config.iceServers = new[] { new RTCIceServer {
                                            urls = new[] { "stun:stun.l.google.com:19302" }
                                        } };
            var peer1 = new RTCPeerConnection(ref config);
            var peer2 = new RTCPeerConnection(ref config);

            peer1.OnIceCandidate = candidate => { peer2.AddIceCandidate(candidate); };
            peer2.OnIceCandidate = candidate => { peer1.AddIceCandidate(candidate); };

            AudioStreamTrack track1 = new AudioStreamTrack();

            peer1.AddTrack(track1);

            yield return(SignalingOffer(peer1, peer2));

            Assert.That(peer2.GetTransceivers().Count(), Is.EqualTo(1));
            RTCRtpSender sender1 = peer2.GetTransceivers().First().Sender;

            Assert.That(sender1, Is.Not.Null);

            AudioStreamTrack track2  = new AudioStreamTrack();
            RTCRtpSender     sender2 = peer2.AddTrack(track2);

            Assert.That(sender2, Is.Not.Null);
            Assert.That(sender1, Is.EqualTo(sender2));

            track1.Dispose();
            track2.Dispose();
            peer1.Dispose();
            peer2.Dispose();
        }
예제 #5
0
    /// <summary>
    /// Process JSON messages received from the remote peer. The only messages will be the SDP answer and
    /// ICE candidates.
    /// </summary>
    private void OnMessage(string jsonStr, RTCPeerConnection pc)
    {
        var msgType = JsonRTC.TryGetType(jsonStr);

        Debug.WriteLine($"JSON message type {msgType}.");

        switch (msgType)
        {
        case JsonRTC.JsonMessageType.IceCandidate:
            if (JsonRTC.TryParseIceCandidate(jsonStr, out var iceCandidateInit))
            {
                Debug.WriteLine($"Got remote ICE candidate, {iceCandidateInit.candidate}.");
                _pc.AddIceCandidate(ref iceCandidateInit);
            }
            break;

        case JsonRTC.JsonMessageType.SdpDescription:
            if (JsonRTC.TryParseDescription(jsonStr, out var desc))
            {
                Debug.WriteLine($"Got remote SDP, type {desc.type}.");
                Debug.WriteLine(desc.sdp);
                var  setRemoteOp = _pc.SetRemoteDescription(ref desc);
                bool isDone      = setRemoteOp.MoveNext();
                Debug.WriteLine($"Set remote description is done {isDone}, error {setRemoteOp.IsError}, signalling state {pc.SignalingState}.");
            }
            break;

        default:
            Debug.WriteLine($"node-dss could not parse JSON message. {jsonStr}");
            break;
        }
    }
예제 #6
0
    private void OnWSMessage(object sender, MessageEventArgs args)
    {
        var message = JsonUtility.FromJson <SignalingMessage>(args.Data);
        var data    = message.data;

        switch (message.type)
        {
        case "message":
            Debug.Log($"Receive a message from Node: {data.message}");
            break;

        case "offer":
            Debug.Log("Receive an offer from Node");
            var offerDesc = new RTCSessionDescription {
                type = RTCSdpType.Offer,
                sdp  = data.sdp
            };
            onOfferCallBack = state => { StartCoroutine(OnOffer(offerDesc)); };
            mainThreadSyncCtx.Post(onOfferCallBack, null);
            break;

        case "candidate":
            var candidateInfo = new RTCIceCandidateInit {
                candidate     = data.candidate,
                sdpMid        = data.sdpMid,
                sdpMLineIndex = data.sdpMLineIndex
            };
            pc.AddIceCandidate(new RTCIceCandidate(candidateInfo));
            break;

        default:
            Debug.Log($"Receive unknown message type: {message.type}");
            break;
        }
    }
    private void Call()
    {
        Debug.Log("Starting calls");

        pc1Local                 = new RTCPeerConnection(ref configuration);
        pc1Remote                = new RTCPeerConnection(ref configuration);
        pc1Remote.OnTrack        = e => receiveVideoStream1.AddTrack(e.Track);
        pc1Local.OnIceCandidate  = candidate => pc1Remote.AddIceCandidate(ref candidate);
        pc1Remote.OnIceCandidate = candidate => pc1Local.AddIceCandidate(ref candidate);
        Debug.Log("pc1: created local and remote peer connection object");

        pc2Local                 = new RTCPeerConnection(ref configuration);
        pc2Remote                = new RTCPeerConnection(ref configuration);
        pc2Remote.OnTrack        = e => receiveVideoStream2.AddTrack(e.Track);
        pc2Local.OnIceCandidate  = candidate => pc2Remote.AddIceCandidate(ref candidate);
        pc2Remote.OnIceCandidate = candidate => pc2Local.AddIceCandidate(ref candidate);
        Debug.Log("pc2: created local and remote peer connection object");

        foreach (var track in sourceVideoStream.GetTracks())
        {
            pc1Local.AddTrack(track, sourceVideoStream);
            pc2Local.AddTrack(track, sourceVideoStream);
        }

        Debug.Log("Adding local stream to pc1Local/pc2Local");

        StartCoroutine(NegotiationPeer(pc1Local, pc1Remote));
        StartCoroutine(NegotiationPeer(pc2Local, pc2Remote));

        callButton.interactable   = false;
        hangUpButton.interactable = true;
    }
예제 #8
0
    private void onIceCandidate(string clientId, string candidate, string sdpMid, int sdpMLineIndex)
    {
        var cand = new RTCIceCandidate {
            candidate = candidate, sdpMid = sdpMid, sdpMLineIndex = sdpMLineIndex
        };

        pc.AddIceCandidate(ref cand);
    }
        public IEnumerator RemoteOnRemoveTrack()
        {
            RTCConfiguration config = default;

            config.iceServers = new[] { new RTCIceServer {
                                            urls = new[] { "stun:stun.l.google.com:19302" }
                                        } };
            var peer1 = new RTCPeerConnection(ref config);
            var peer2 = new RTCPeerConnection(ref config);

            peer1.OnIceCandidate = candidate => { peer2.AddIceCandidate(candidate); };
            peer2.OnIceCandidate = candidate => { peer1.AddIceCandidate(candidate); };

            var         stream        = new MediaStream();
            MediaStream receiveStream = null;
            var         track         = new AudioStreamTrack();

            stream.AddTrack(track);
            RTCRtpSender sender = peer1.AddTrack(track, stream);

            bool isInvokeNegotiationNeeded1 = false;

            peer1.OnNegotiationNeeded = () => isInvokeNegotiationNeeded1 = true;

            bool isInvokeOnRemoveTrack = false;

            peer2.OnTrack = e =>
            {
                Assert.That(e.Streams, Has.Count.EqualTo(1));
                receiveStream = e.Streams.First();
                receiveStream.OnRemoveTrack = ev => isInvokeOnRemoveTrack = true;
            };

            yield return(SignalingOffer(peer1, peer2));

            peer1.RemoveTrack(sender);

            var op9 = new WaitUntilWithTimeout(() => isInvokeNegotiationNeeded1, 5000);

            yield return(op9);

            Assert.That(op9.IsCompleted, Is.True);

            yield return(SignalingOffer(peer1, peer2));

            var op10 = new WaitUntilWithTimeout(() => isInvokeOnRemoveTrack, 5000);

            yield return(op10);

            Assert.That(op10.IsCompleted, Is.True);

            stream.Dispose();
            receiveStream.Dispose();
            track.Dispose();
            peer1.Dispose();
            peer2.Dispose();
        }
예제 #10
0
        private static IEnumerator SignalingPeers(RTCPeerConnection offerPc, RTCPeerConnection answerPc)
        {
            offerPc.OnIceCandidate = candidate => answerPc.AddIceCandidate(ref candidate);
            answerPc.OnIceCandidate = candidate => offerPc.AddIceCandidate(ref candidate);

            var offerOption = new RTCOfferOptions {offerToReceiveVideo = true};
            var answerOption = new RTCAnswerOptions {iceRestart = false};

            var pc1CreateOffer = offerPc.CreateOffer(ref offerOption);
            yield return pc1CreateOffer;
            Assert.False(pc1CreateOffer.IsError);
            var offerDesc = pc1CreateOffer.Desc;

            var pc1SetLocalDescription = offerPc.SetLocalDescription(ref offerDesc);
            yield return pc1SetLocalDescription;
            Assert.False(pc1SetLocalDescription.IsError);

            var pc2SetRemoteDescription = answerPc.SetRemoteDescription(ref offerDesc);
            yield return pc2SetRemoteDescription;
            Assert.False(pc2SetRemoteDescription.IsError);

            var pc2CreateAnswer = answerPc.CreateAnswer(ref answerOption);
            yield return pc2CreateAnswer;
            Assert.False(pc2CreateAnswer.IsError);
            var answerDesc = pc2CreateAnswer.Desc;

            var pc2SetLocalDescription = answerPc.SetLocalDescription(ref answerDesc);
            yield return pc2SetLocalDescription;
            Assert.False(pc2SetLocalDescription.IsError);

            var pc1SetRemoteDescription = offerPc.SetRemoteDescription(ref answerDesc);
            yield return pc1SetRemoteDescription;
            Assert.False(pc1SetRemoteDescription.IsError);

            var waitConnectOfferPc = new WaitUntilWithTimeout(() =>
                offerPc.IceConnectionState == RTCIceConnectionState.Connected ||
                offerPc.IceConnectionState == RTCIceConnectionState.Completed, 5000);
            yield return waitConnectOfferPc;
            Assert.True(waitConnectOfferPc.IsCompleted);

            var waitConnectAnswerPc = new WaitUntilWithTimeout(() =>
                answerPc.IceConnectionState == RTCIceConnectionState.Connected ||
                answerPc.IceConnectionState == RTCIceConnectionState.Completed, 5000);
            yield return waitConnectAnswerPc;
            Assert.True(waitConnectAnswerPc.IsCompleted);

            var checkSenders = new WaitUntilWithTimeout(() => offerPc.GetSenders().Any(), 5000);
            yield return checkSenders;
            Assert.True(checkSenders.IsCompleted);

            var checkReceivers = new WaitUntilWithTimeout(() => answerPc.GetReceivers().Any(), 5000);
            yield return checkReceivers;
            Assert.True(checkReceivers.IsCompleted);
        }
    private void Signaling_OnIceCandidate(AntMediaSignalingMessage msg)
    {
        var candidate = new RTCIceCandidate(new RTCIceCandidateInit
        {
            candidate     = msg.candidate,
            sdpMLineIndex = msg.label,
            sdpMid        = msg.id
        });

        peer.AddIceCandidate(candidate);
    }
예제 #12
0
 private void OnIceCandidate(RTCIceCandidate​ e)
 {
     if (!string.IsNullOrEmpty(e.candidate))
     {
         mPeer.AddIceCandidate(ref e);
         DebugUtility.Log(LoggerTags.Online, "{0} ICE candidate:\n {1}", host, e.candidate);
     }
     else
     {
         DebugUtility.Log(LoggerTags.Online, "{0} ICE empty candidate:\n", host);
     }
 }
예제 #13
0
        private void Signaling_OnIceCandidate(AntMediaSignalingMessage msg)
        {
            OnLogEvent.Invoke("Signaling OnIceCandidate", "");
            OnLogEvent.Invoke("AddIceCandidate", "");
            var candidate = new RTCIceCandidate(new RTCIceCandidateInit
            {
                candidate     = msg.candidate,
                sdpMLineIndex = msg.label,
                sdpMid        = msg.id
            });

            peer.AddIceCandidate(candidate);
        }
예제 #14
0
    public void OnMessage(Message message)
    {
        if (message.candidate != null)
        {
            if (!pc.AddIceCandidate(message.candidate) && !ignoreOffer)
            {
                Debug.LogError($"{this} this candidate can't accept current signaling state {pc.SignalingState}.");
            }

            return;
        }

        parent.StartCoroutine(OfferAnswerProcess(message.description));
    }
예제 #15
0
        public IEnumerator RestartIceInvokeOnNegotiationNeeded()
        {
            RTCConfiguration config = default;

            config.iceServers = new[] { new RTCIceServer {
                                            urls = new[] { "stun:stun.l.google.com:19302" }
                                        } };
            var peer1 = new RTCPeerConnection(ref config);
            var peer2 = new RTCPeerConnection(ref config);

            peer1.OnIceCandidate = candidate => { peer2.AddIceCandidate(candidate); };
            peer2.OnIceCandidate = candidate => { peer1.AddIceCandidate(candidate); };

            var obj    = new GameObject("audio");
            var source = obj.AddComponent <AudioSource>();

            source.clip = AudioClip.Create("test", 480, 2, 48000, false);
            AudioStreamTrack track = new AudioStreamTrack(source);

            peer1.AddTrack(track);

            yield return(SignalingOffer(peer1, peer2));

            bool isInvokeOnNegotiationNeeded1 = false;
            bool isInvokeOnNegotiationNeeded2 = false;

            peer1.OnNegotiationNeeded = () => isInvokeOnNegotiationNeeded1 = true;
            peer2.OnNegotiationNeeded = () => isInvokeOnNegotiationNeeded2 = true;

            peer1.RestartIce();
            var op9 = new WaitUntilWithTimeout(() => isInvokeOnNegotiationNeeded1, 5000);

            yield return(op9);

            Assert.That(op9.IsCompleted, Is.True);

            peer2.RestartIce();
            var op10 = new WaitUntilWithTimeout(() => isInvokeOnNegotiationNeeded2, 5000);

            yield return(op10);

            Assert.That(op10.IsCompleted, Is.True);

            track.Dispose();
            peer1.Close();
            peer2.Close();
            Object.DestroyImmediate(source.clip);
            Object.DestroyImmediate(obj);
        }
예제 #16
0
 void RecieveIceCandidate()
 {
     _signalingNCMB.FetchObject((obj) =>
     {
         var json      = NCMB_RTC.GetJson_SDPData(obj, _IsOffer);
         var data      = JsonConverter.FromJson <RTCSendData>(json);
         var remoteICE = new List <RTCIceCandidate>();
         foreach (var target in data.candidateJson)
         {
             remoteICE.Add(JsonConverter.FromJson <RTCIceCandidate>(target));
         }
         remoteICE.ForEach(x => localConnection.AddIceCandidate(ref x));
         Debug.Log($"recieveJson {gameObject.name}");
     });
 }
예제 #17
0
        public IEnumerator TransceiverReturnsSender()
        {
            RTCConfiguration config = default;

            config.iceServers = new[] { new RTCIceServer {
                                            urls = new[] { "stun:stun.l.google.com:19302" }
                                        } };
            var peer1 = new RTCPeerConnection(ref config);
            var peer2 = new RTCPeerConnection(ref config);

            peer1.OnIceCandidate = candidate => { peer2.AddIceCandidate(candidate); };
            peer2.OnIceCandidate = candidate => { peer1.AddIceCandidate(candidate); };

            var obj1    = new GameObject("audio1");
            var source1 = obj1.AddComponent <AudioSource>();

            source1.clip = AudioClip.Create("test1", 480, 2, 48000, false);
            AudioStreamTrack track1 = new AudioStreamTrack(source1);

            peer1.AddTrack(track1);

            yield return(SignalingOffer(peer1, peer2));

            Assert.That(peer2.GetTransceivers().Count(), Is.EqualTo(1));
            RTCRtpSender sender1 = peer2.GetTransceivers().First().Sender;

            Assert.That(sender1, Is.Not.Null);

            var obj2    = new GameObject("audio2");
            var source2 = obj2.AddComponent <AudioSource>();

            source2.clip = AudioClip.Create("test2", 480, 2, 48000, false);
            AudioStreamTrack track2  = new AudioStreamTrack(source2);
            RTCRtpSender     sender2 = peer2.AddTrack(track2);

            Assert.That(sender2, Is.Not.Null);
            Assert.That(sender1, Is.EqualTo(sender2));

            track1.Dispose();
            track2.Dispose();
            peer1.Dispose();
            peer2.Dispose();
            Object.DestroyImmediate(source1.clip);
            Object.DestroyImmediate(source2.clip);
            Object.DestroyImmediate(obj1);
            Object.DestroyImmediate(obj2);
        }
예제 #18
0
        public IEnumerator RestartIceInvokeOnNegotiationNeeded()
        {
            RTCConfiguration config = default;

            config.iceServers = new[] { new RTCIceServer {
                                            urls = new[] { "stun:stun.l.google.com:19302" }
                                        } };
            var peer1 = new RTCPeerConnection(ref config);
            var peer2 = new RTCPeerConnection(ref config);

            peer1.OnIceCandidate = candidate => { peer2.AddIceCandidate(candidate); };
            peer2.OnIceCandidate = candidate => { peer1.AddIceCandidate(candidate); };

            AudioStreamTrack track = new AudioStreamTrack();

            peer1.AddTrack(track);

            yield return(SignalingOffer(peer1, peer2));

            bool isInvokeOnNegotiationNeeded1 = false;
            bool isInvokeOnNegotiationNeeded2 = false;

            peer1.OnNegotiationNeeded = () => isInvokeOnNegotiationNeeded1 = true;
            peer2.OnNegotiationNeeded = () => isInvokeOnNegotiationNeeded2 = true;

            peer1.RestartIce();
            var op9 = new WaitUntilWithTimeout(() => isInvokeOnNegotiationNeeded1, 5000);

            yield return(op9);

            Assert.That(op9.IsCompleted, Is.True);

            peer2.RestartIce();
            var op10 = new WaitUntilWithTimeout(() => isInvokeOnNegotiationNeeded2, 5000);

            yield return(op10);

            Assert.That(op10.IsCompleted, Is.True);

            track.Dispose();
            peer1.Close();
            peer2.Close();
        }
예제 #19
0
    private void onTextData(WebSocket client, string data)
    {
        var msg = JsonUtility.FromJson <SignalingMessage>(data);

        if (msg.type == "candidate")
        {
            log.Print("on ice candidate");
            RTCIceCandidate candidate;
            candidate.candidate     = msg.candidate;
            candidate.sdpMid        = msg.sdpMid;
            candidate.sdpMLineIndex = msg.sdpMLineIndex;
            log.Print("AddIceCandidate");
            pc.AddIceCandidate(ref candidate);
        }
        else if (msg.type == "answer")
        {
            log.Print("on answer");
            StartCoroutine(proccessAnswer(msg.sdp));
        }
    }
예제 #20
0
    private void HandleWebsocketMessage(byte[] data)
    {
        SignalingMessage message = JsonUtility.FromJson <SignalingMessage>(Encoding.UTF8.GetString(data));

        Debug.LogFormat("Receivied message with type {0}", message.type);

        if (localConnection == null)
        {
            CreatePeerConnection();
        }

        if (!string.IsNullOrEmpty(message.sdp))
        {
            StartCoroutine(SetDescription(message.ToDesc(), Side.Remote));
        }

        if (!string.IsNullOrEmpty(message.candidate))
        {
            localConnection.AddIceCandidate(message.ToCand());
        }
    }
예제 #21
0
    private void Call()
    {
        Debug.Log("Starting calls");

        pcLocal                 = new RTCPeerConnection(ref configuration);
        pcRemote                = new RTCPeerConnection(ref configuration);
        pcRemote.OnTrack        = e => receiveVideoStream.AddTrack(e.Track);
        pcLocal.OnIceCandidate  = candidate => pcRemote.AddIceCandidate(candidate);
        pcRemote.OnIceCandidate = candidate => pcLocal.AddIceCandidate(candidate);
        Debug.Log("pc1: created local and remote peer connection object");

        var senders = new List <RTCRtpSender>();

        foreach (var track in sourceVideoStream.GetTracks())
        {
            senders.Add(pcLocal.AddTrack(track, sourceVideoStream));
        }

        if (WebRTCSettings.UseVideoCodec != null)
        {
            var codecs = new[] { WebRTCSettings.UseVideoCodec };
            foreach (var transceiver in pcLocal.GetTransceivers())
            {
                if (senders.Contains(transceiver.Sender))
                {
                    transceiver.SetCodecPreferences(codecs);
                }
            }
        }

        Debug.Log("Adding local stream to pcLocal");

        callButton.interactable         = false;
        createOfferButton.interactable  = true;
        createAnswerButton.interactable = true;
        setOfferButton.interactable     = true;
        setAnswerButton.interactable    = true;
        hangUpButton.interactable       = true;
    }
예제 #22
0
    private void HandleCandidate(string room, JsonMessageData data)
    {
        Debug.Log("HandleCandidate");
        if (room != roomName)
        {
            Debug.LogError("Wrong room name " + room);
            return;
        }
        if (data.candidate == null || data.candidate.Length == 0)
        {
            Debug.LogError("Empty candidate");
            return;
        }

        var candidate = new RTCIceCandidate
        {
            candidate     = data.candidate,
            sdpMid        = data.id,
            sdpMLineIndex = (int)data.label
        };

        peerConnection.AddIceCandidate(ref candidate);
    }
예제 #23
0
        public IEnumerator Signaling()
        {
            offerPc.OnIceCandidate  = candidate => answerPc.AddIceCandidate(candidate);
            answerPc.OnIceCandidate = candidate => offerPc.AddIceCandidate(candidate);

            var pc1CreateOffer = offerPc.CreateOffer();

            yield return(pc1CreateOffer);

            Assert.That(pc1CreateOffer.IsError, Is.False, () => $"Failed {nameof(pc1CreateOffer)}, error:{pc1CreateOffer.Error.message}");
            var offerDesc = pc1CreateOffer.Desc;

            var pc1SetLocalDescription = offerPc.SetLocalDescription(ref offerDesc);

            yield return(pc1SetLocalDescription);

            Assert.That(pc1SetLocalDescription.IsError, Is.False, () => $"Failed {nameof(pc1SetLocalDescription)}, error:{pc1SetLocalDescription.Error.message}");

            var pc2SetRemoteDescription = answerPc.SetRemoteDescription(ref offerDesc);

            yield return(pc2SetRemoteDescription);

            Assert.That(pc2SetRemoteDescription.IsError, Is.False, () => $"Failed {nameof(pc2SetRemoteDescription)}, error:{pc2SetRemoteDescription.Error.message}");

            var pc2CreateAnswer = answerPc.CreateAnswer();

            yield return(pc2CreateAnswer);

            Assert.That(pc2CreateAnswer.IsError, Is.False, () => $"Failed {nameof(pc2CreateAnswer)}, error:{pc2CreateAnswer.Error.message}");
            var answerDesc = pc2CreateAnswer.Desc;

            var pc2SetLocalDescription = answerPc.SetLocalDescription(ref answerDesc);

            yield return(pc2SetLocalDescription);

            Assert.That(pc2SetLocalDescription.IsError, Is.False, () => $"Failed {nameof(pc2SetLocalDescription)}, error:{pc2SetLocalDescription.Error.message}");

            var pc1SetRemoteDescription = offerPc.SetRemoteDescription(ref answerDesc);

            yield return(pc1SetRemoteDescription);

            Assert.That(pc1SetRemoteDescription.IsError, Is.False, () => $"Failed {nameof(pc1SetRemoteDescription)}, error:{pc1SetRemoteDescription.Error.message}");

            var waitConnectOfferPc = new WaitUntilWithTimeout(() =>
                                                              offerPc.IceConnectionState == RTCIceConnectionState.Connected ||
                                                              offerPc.IceConnectionState == RTCIceConnectionState.Completed, 5000);

            yield return(waitConnectOfferPc);

            Assert.That(waitConnectOfferPc.IsCompleted, Is.True);

            var waitConnectAnswerPc = new WaitUntilWithTimeout(() =>
                                                               answerPc.IceConnectionState == RTCIceConnectionState.Connected ||
                                                               answerPc.IceConnectionState == RTCIceConnectionState.Completed, 5000);

            yield return(waitConnectAnswerPc);

            Assert.That(waitConnectAnswerPc.IsCompleted, Is.True);

            var checkSenders = new WaitUntilWithTimeout(() => offerPc.GetSenders().Any(), 5000);

            yield return(checkSenders);

            Assert.That(checkSenders.IsCompleted, Is.True);

            var checkReceivers = new WaitUntilWithTimeout(() => answerPc.GetReceivers().Any(), 5000);

            yield return(checkReceivers);

            Assert.That(checkReceivers.IsCompleted, Is.True);
        }
        private void Call()
        {
            Debug.Log("Starting calls");

            pc1Local          = new RTCPeerConnection(ref configuration);
            pc1Remote         = new RTCPeerConnection(ref configuration);
            pc1Remote.OnTrack = e =>
            {
                if (e.Track is VideoStreamTrack videoTrack)
                {
                    videoTrack.OnVideoReceived += tex =>
                    {
                        receiveImage1.texture = tex;
                    };
                }

                if (e.Track is AudioStreamTrack audioTrack)
                {
                    receiveAudio1.SetTrack(audioTrack);
                    receiveAudio1.loop = true;
                    receiveAudio1.Play();
                }
            };
            pc1Local.OnIceCandidate  = candidate => pc1Remote.AddIceCandidate(candidate);
            pc1Remote.OnIceCandidate = candidate => pc1Local.AddIceCandidate(candidate);
            Debug.Log("pc1: created local and remote peer connection object");

            pc2Local          = new RTCPeerConnection(ref configuration);
            pc2Remote         = new RTCPeerConnection(ref configuration);
            pc2Remote.OnTrack = e =>
            {
                if (e.Track is VideoStreamTrack videoTrack)
                {
                    videoTrack.OnVideoReceived += tex =>
                    {
                        receiveImage2.texture = tex;
                    };
                }

                if (e.Track is AudioStreamTrack audioTrack)
                {
                    receiveAudio2.SetTrack(audioTrack);
                    receiveAudio2.loop = true;
                    receiveAudio2.Play();
                }
            };
            pc2Local.OnIceCandidate  = candidate => pc2Remote.AddIceCandidate(candidate);
            pc2Remote.OnIceCandidate = candidate => pc2Local.AddIceCandidate(candidate);
            Debug.Log("pc2: created local and remote peer connection object");

            var pc1VideoSenders = new List <RTCRtpSender>();
            var pc2VideoSenders = new List <RTCRtpSender>();

            foreach (var track in sourceStream.GetTracks())
            {
                var pc1Sender = pc1Local.AddTrack(track, sourceStream);
                var pc2Sender = pc2Local.AddTrack(track, sourceStream);

                if (track.Kind == TrackKind.Video)
                {
                    pc1VideoSenders.Add(pc1Sender);
                    pc2VideoSenders.Add(pc2Sender);
                }
            }

            if (WebRTCSettings.UseVideoCodec != null)
            {
                var codecs = new[] { WebRTCSettings.UseVideoCodec };
                foreach (var transceiver in pc1Local.GetTransceivers())
                {
                    if (pc1VideoSenders.Contains(transceiver.Sender))
                    {
                        transceiver.SetCodecPreferences(codecs);
                    }
                }

                foreach (var transceiver in pc2Local.GetTransceivers())
                {
                    if (pc2VideoSenders.Contains(transceiver.Sender))
                    {
                        transceiver.SetCodecPreferences(codecs);
                    }
                }
            }

            Debug.Log("Adding local stream to pc1Local/pc2Local");

            StartCoroutine(NegotiationPeer(pc1Local, pc1Remote));
            StartCoroutine(NegotiationPeer(pc2Local, pc2Remote));

            callButton.interactable   = false;
            hangUpButton.interactable = true;
        }
예제 #25
0
        public IEnumerator IceConnectionStateChange()
        {
            RTCConfiguration config = default;

            config.iceServers = new[] { new RTCIceServer {
                                            urls = new[] { "stun:stun.l.google.com:19302" }
                                        } };
            var peer1 = new RTCPeerConnection(ref config);
            var peer2 = new RTCPeerConnection(ref config);

            peer1.OnIceCandidate = candidate => { peer2.AddIceCandidate(ref candidate); };
            peer2.OnIceCandidate = candidate => { peer1.AddIceCandidate(ref candidate); };

            MediaStream stream = Audio.CaptureStream();

            peer1.AddTrack(stream.GetTracks().First());

            RTCOfferOptions  options1 = default;
            RTCAnswerOptions options2 = default;
            var op1 = peer1.CreateOffer(ref options1);

            yield return(op1);

            var desc = op1.Desc;
            var op2  = peer1.SetLocalDescription(ref desc);

            yield return(op2);

            var op3 = peer2.SetRemoteDescription(ref desc);

            yield return(op3);

            var op4 = peer2.CreateAnswer(ref options2);

            yield return(op4);

            desc = op4.Desc;
            var op5 = peer2.SetLocalDescription(ref desc);

            yield return(op5);

            var op6 = peer1.SetRemoteDescription(ref desc);

            yield return(op6);

            var op7 = new WaitUntilWithTimeout(
                () => peer1.IceConnectionState == RTCIceConnectionState.Connected ||
                peer1.IceConnectionState == RTCIceConnectionState.Completed, 5000);

            yield return(op7);

            Assert.True(op7.IsCompleted);
            var op8 = new WaitUntilWithTimeout(
                () => peer2.IceConnectionState == RTCIceConnectionState.Connected ||
                peer2.IceConnectionState == RTCIceConnectionState.Completed, 5000);

            yield return(op8);

            Assert.True(op8.IsCompleted);

            stream.Dispose();
            peer1.Close();
            peer2.Close();
        }
예제 #26
0
        public void MessageFromPeerTaskRun(int peerId, string content)
        {
            PeerId = peerId;

            Task.Run(async() =>
            {
                Debug.Assert(_peerId == PeerId || _peerId == -1);
                Debug.Assert(content.Length > 0);

                if (_peerId != PeerId && _peerId != -1)
                {
                    Debug.WriteLine("Received a message from unknown peer " +
                                    "while already in a conversation with a different peer.");

                    return;
                }

                if (!JsonObject.TryParse(content, out JsonObject jMessage))
                {
                    Debug.WriteLine($"Received unknown message: {content}");
                    return;
                }

                string type = jMessage.ContainsKey(NegotiationAtributes.Type)
                       ? jMessage.GetNamedString(NegotiationAtributes.Type)
                       : null;

                if (PeerConnection == null)
                {
                    if (!string.IsNullOrEmpty(type))
                    {
                        // Create the peer connection only when call is
                        // about to get initiated. Otherwise ignore the
                        // message from peers which could be result
                        // of old (but not yet fully closed) connections.
                        if (type == "offer" || type == "answer" || type == "json")
                        {
                            Debug.Assert(_peerId == -1);
                            _peerId = PeerId;

                            if (!CreatePeerConnection())
                            {
                                Debug.WriteLine("Failed to initialize our PeerConnection instance");

                                OnSignedOut.Invoke(this, null);
                                return;
                            }
                            else if (_peerId != PeerId)
                            {
                                Debug.WriteLine("Received a message from unknown peer while already " +
                                                "in a conversation with a different peer.");

                                return;
                            }
                        }
                    }
                    else
                    {
                        Debug.WriteLine("[Warn] Received an untyped message after closing peer connection.");
                        return;
                    }
                }

                if (PeerConnection != null && !string.IsNullOrEmpty(type))
                {
                    if (type == "offer-loopback")
                    {
                        // Loopback not supported
                        Debug.Assert(false);
                    }

                    string sdp = null;

                    sdp = jMessage.ContainsKey(NegotiationAtributes.Sdp)
                          ? jMessage.GetNamedString(NegotiationAtributes.Sdp)
                          : null;

                    if (string.IsNullOrEmpty(sdp))
                    {
                        Debug.WriteLine("[Error] Can't parse received session description message.");
                        return;
                    }

                    Debug.WriteLine($"Received session description:\n{content}");

                    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;
                    }

                    var sdpInit     = new RTCSessionDescriptionInit();
                    sdpInit.Sdp     = sdp;
                    sdpInit.Type    = messageType;
                    var description = new RTCSessionDescription(sdpInit);

                    await PeerConnection.SetRemoteDescription(description);

                    if (messageType == RTCSdpType.Offer)
                    {
                        var answerOptions             = new RTCAnswerOptions();
                        IRTCSessionDescription answer = await PeerConnection.CreateAnswer(answerOptions);
                        await PeerConnection.SetLocalDescription(answer);
                        string jsonString = SdpToJsonString(answer);
                        // Send answer
                        OnSendMessageToRemotePeer.Invoke(this, jsonString);
                    }
                }
                else
                {
                    RTCIceCandidate candidate = null;

                    string sdpMid = jMessage.ContainsKey(NegotiationAtributes.SdpMid)
                           ? jMessage.GetNamedString(NegotiationAtributes.SdpMid)
                           : null;

                    double sdpMLineIndex = jMessage.ContainsKey(NegotiationAtributes.SdpMLineIndex)
                           ? jMessage.GetNamedNumber(NegotiationAtributes.SdpMLineIndex)
                           : -1;

                    string sdpCandidate = jMessage.ContainsKey(NegotiationAtributes.Candidate)
                           ? jMessage.GetNamedString(NegotiationAtributes.Candidate)
                           : null;

                    if (string.IsNullOrEmpty(sdpMid) || sdpMLineIndex == -1 || string.IsNullOrEmpty(sdpCandidate))
                    {
                        Debug.WriteLine($"[Error] Can't parse received message.\n{content}");
                        return;
                    }

                    var candidateInit           = new RTCIceCandidateInit();
                    candidateInit.Candidate     = sdpCandidate;
                    candidateInit.SdpMid        = sdpMid;
                    candidateInit.SdpMLineIndex = (ushort)sdpMLineIndex;
                    candidate = new RTCIceCandidate(candidateInit);

                    await PeerConnection.AddIceCandidate(candidate);

                    Debug.WriteLine($"Receiving ice candidate:\n{content}");
                }
            }).Wait();
        }
예제 #27
0
    public IEnumerator DataChannel_EventsAreSentToOther()
    {
        RTCConfiguration config = default;

        config.iceServers = new RTCIceServer[]
        {
            new RTCIceServer
            {
                urls = new string[] { "stun:stun.l.google.com:19302" }
            }
        };
        var            peer1 = new RTCPeerConnection(ref config);
        var            peer2 = new RTCPeerConnection(ref config);
        RTCDataChannel channel1 = null, channel2 = null;

        peer1.OnIceCandidate = new DelegateOnIceCandidate(candidate => { peer2.AddIceCandidate(ref candidate); });
        peer2.OnIceCandidate = new DelegateOnIceCandidate(candidate => { peer1.AddIceCandidate(ref candidate); });
        peer2.OnDataChannel  = new DelegateOnDataChannel(channel => { channel2 = channel; });

        var conf = new RTCDataChannelInit(true);

        channel1 = peer1.CreateDataChannel("data", ref conf);

        RTCOfferOptions  options1 = default;
        RTCAnswerOptions options2 = default;
        var op1 = peer1.CreateOffer(ref options1);

        yield return(op1);

        var op2 = peer1.SetLocalDescription(ref op1.desc);

        yield return(op2);

        var op3 = peer2.SetRemoteDescription(ref op1.desc);

        yield return(op3);

        var op4 = peer2.CreateAnswer(ref options2);

        yield return(op4);

        var op5 = peer2.SetLocalDescription(ref op4.desc);

        yield return(op5);

        var op6 = peer1.SetRemoteDescription(ref op4.desc);

        yield return(op6);

        yield return(new WaitUntil(() => peer1.IceConnectionState == RTCIceConnectionState.Connected || peer1.IceConnectionState == RTCIceConnectionState.Completed));

        yield return(new WaitUntil(() => peer2.IceConnectionState == RTCIceConnectionState.Connected || peer2.IceConnectionState == RTCIceConnectionState.Completed));

        yield return(new WaitUntil(() => channel2 != null));

        Assert.AreEqual(channel1.Label, channel2.Label);
        Assert.AreEqual(channel1.Id, channel2.Id);

        string message1 = "hello";
        string message2 = null;

        channel2.OnMessage = new DelegateOnMessage(bytes => { message2 = System.Text.Encoding.UTF8.GetString(bytes); });
        channel1.Send(message1);
        yield return(new WaitUntil(() => !string.IsNullOrEmpty(message2)));

        Assert.AreEqual(message1, message2);

        byte[] message3 = { 1, 2, 3 };
        byte[] message4 = null;
        channel2.OnMessage = new DelegateOnMessage(bytes => { message4 = bytes; });
        channel1.Send(message3);
        yield return(new WaitUntil(() => message4 != null));

        Assert.AreEqual(message3, message4);

        peer1.Close();
        peer2.Close();
    }
예제 #28
0
        public IEnumerator PeerConnectionStateChange()
        {
            RTCConfiguration config = default;

            config.iceServers = new[] { new RTCIceServer {
                                            urls = new[] { "stun:stun.l.google.com:19302" }
                                        } };
            var peer1 = new RTCPeerConnection(ref config);
            var peer2 = new RTCPeerConnection(ref config);

            RTCPeerConnectionState state1    = default;
            RTCPeerConnectionState state2    = default;
            RTCIceConnectionState  iceState1 = default;
            RTCIceConnectionState  iceState2 = default;

            peer1.OnIceCandidate          = candidate => { peer2.AddIceCandidate(candidate); };
            peer2.OnIceCandidate          = candidate => { peer1.AddIceCandidate(candidate); };
            peer1.OnConnectionStateChange = state => { state1 = state; };
            peer2.OnConnectionStateChange = state => { state2 = state; };
            peer1.OnIceConnectionChange   = state => { iceState1 = state; };
            peer2.OnIceConnectionChange   = state => { iceState2 = state; };

            Assert.That(state1, Is.EqualTo(RTCPeerConnectionState.New));
            Assert.That(state2, Is.EqualTo(RTCPeerConnectionState.New));

            var obj    = new GameObject("audio");
            var source = obj.AddComponent <AudioSource>();

            source.clip = AudioClip.Create("test", 480, 2, 48000, false);
            AudioStreamTrack track1 = new AudioStreamTrack(source);

            peer1.AddTrack(track1);

            var op1 = peer1.CreateOffer();

            yield return(op1);

            var desc = op1.Desc;
            var op2  = peer1.SetLocalDescription(ref desc);

            yield return(op2);

            var op3 = peer2.SetRemoteDescription(ref desc);

            yield return(op3);

            var op4 = peer2.CreateAnswer();

            yield return(op4);

            desc = op4.Desc;
            var op5 = peer2.SetLocalDescription(ref desc);

            yield return(op5);

            var op6 = peer1.SetRemoteDescription(ref desc);

            yield return(op6);

            var op7 = new WaitUntilWithTimeout(() =>
                                               state1 == RTCPeerConnectionState.Connected &&
                                               state2 == RTCPeerConnectionState.Connected, 5000);

            yield return(op7);

            Assert.That(op7.IsCompleted, Is.True);

            var op8 = new WaitUntilWithTimeout(() =>
                                               (iceState1 == RTCIceConnectionState.Connected || iceState1 == RTCIceConnectionState.Completed) &&
                                               (iceState2 == RTCIceConnectionState.Connected || iceState2 == RTCIceConnectionState.Completed)
                                               , 5000);

            yield return(op8);

            Assert.That(op8.IsCompleted, Is.True);

            peer1.Close();

            var op9 = new WaitUntilWithTimeout(() =>
                                               state1 == RTCPeerConnectionState.Closed &&
                                               iceState2 == RTCIceConnectionState.Disconnected, 5000);

            yield return(op9);

            Assert.That(op9.IsCompleted, Is.True);

            track1.Dispose();
            peer2.Close();
            Object.DestroyImmediate(source.clip);
            Object.DestroyImmediate(obj);
        }
예제 #29
0
        /// <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();
        }
예제 #30
0
        public IEnumerator EventsAreSentToOther()
        {
            RTCConfiguration config = default;

            config.iceServers = new[] { new RTCIceServer {
                                            urls = new[] { "stun:stun.l.google.com:19302" }
                                        } };
            var            peer1    = new RTCPeerConnection(ref config);
            var            peer2    = new RTCPeerConnection(ref config);
            RTCDataChannel channel2 = null;

            peer1.OnIceCandidate = candidate => { peer2.AddIceCandidate(candidate); };
            peer2.OnIceCandidate = candidate => { peer1.AddIceCandidate(candidate); };
            peer2.OnDataChannel  = channel => { channel2 = channel; };

            var  channel1       = peer1.CreateDataChannel("data");
            bool channel1Opened = false;
            bool channel1Closed = false;

            channel1.OnOpen  = () => { channel1Opened = true; };
            channel1.OnClose = () => { channel1Closed = true; };

            RTCOfferOptions  options1 = default;
            RTCAnswerOptions options2 = default;
            var op1 = peer1.CreateOffer(ref options1);

            yield return(op1);

            var desc = op1.Desc;
            var op2  = peer1.SetLocalDescription(ref desc);

            yield return(op2);

            var op3 = peer2.SetRemoteDescription(ref desc);

            yield return(op3);

            var op4 = peer2.CreateAnswer(ref options2);

            yield return(op4);

            desc = op4.Desc;
            var op5 = peer2.SetLocalDescription(ref desc);

            yield return(op5);

            var op6 = peer1.SetRemoteDescription(ref desc);

            yield return(op6);

            var op7 = new WaitUntilWithTimeout(
                () => peer1.IceConnectionState == RTCIceConnectionState.Connected ||
                peer1.IceConnectionState == RTCIceConnectionState.Completed, 5000);

            yield return(op7);

            Assert.True(op7.IsCompleted);
            var op8 = new WaitUntilWithTimeout(
                () => peer2.IceConnectionState == RTCIceConnectionState.Connected ||
                peer2.IceConnectionState == RTCIceConnectionState.Completed, 5000);

            yield return(op8);

            Assert.True(op8.IsCompleted);
            var op9 = new WaitUntilWithTimeout(() => channel2 != null, 5000);

            yield return(op9);

            Assert.True(op9.IsCompleted);

            Assert.True(channel1Opened);
            Assert.AreEqual(channel1.Label, channel2.Label);
            Assert.AreEqual(channel1.Id, channel2.Id);

            const string message1 = "hello";
            string       message2 = null;

            channel2.OnMessage = bytes => { message2 = System.Text.Encoding.UTF8.GetString(bytes); };
            channel1.Send(message1);
            var op10 = new WaitUntilWithTimeout(() => !string.IsNullOrEmpty(message2), 5000);

            yield return(op10);

            Assert.True(op10.IsCompleted);
            Assert.AreEqual(message1, message2);

            byte[] message3 = { 1, 2, 3 };
            byte[] message4 = null;
            channel2.OnMessage = bytes => { message4 = bytes; };
            channel1.Send(message3);
            var op11 = new WaitUntilWithTimeout(() => message4 != null, 5000);

            yield return(op11);

            Assert.True(op11.IsCompleted);
            Assert.AreEqual(message3, message4);

            channel1.Close();
            var op12 = new WaitUntilWithTimeout(() => channel1Closed, 5000);

            yield return(op12);

            Assert.True(op12.IsCompleted);

            channel2.Close();
            peer1.Close();
            peer2.Close();
        }