示例#1
0
        public async Task <string> HandleUpdatedRemoteOffer(string sdp)
        {
            Logger.Debug("PeerChannel", "HandleUpdatedRemoteOffer");

            var sdpInit = new RTCSessionDescriptionInit()
            {
                Type = RTCSdpType.Offer,
                Sdp  = sdp,
            };

            Logger.Debug("PeerChannel", "SetRemoteOffer - SetRemoteDescription");

            await Conn.SetRemoteDescription(new RTCSessionDescription(sdpInit));

            var opts = new RTCAnswerOptions();

            Logger.Debug("PeerChannel", "SetRemoteOffer - CreateAnswer");

            var answer = await Conn.CreateAnswer(opts);

            Logger.Debug("PeerChannel", answer.Sdp);

            await Conn.SetLocalDescription(answer);

            Logger.Debug("PeerChannel", "local description set");

            return(answer.Sdp);
        }
示例#2
0
        IEnumerator SendAnswerCoroutine(string connectionId, RTCPeerConnection pc)
        {
            RTCAnswerOptions options = default;
            var op = pc.CreateAnswer(ref options);

            yield return(op);

            if (op.IsError)
            {
                Debug.LogError($"Network Error: {op.Error.message}");
                yield break;
            }

            var desc        = op.Desc;
            var opLocalDesc = pc.SetLocalDescription(ref desc);

            yield return(opLocalDesc);

            if (opLocalDesc.IsError)
            {
                Debug.LogError($"Network Error: {opLocalDesc.Error.message}");
                yield break;
            }
            _signaling.SendAnswer(connectionId, desc);
        }
示例#3
0
        public IEnumerator UnitySetUp()
        {
            WebRTC.WebRTC.Initialize();

            RTCConfiguration config     = default;
            RTCIceCandidate  candidate_ = null;

            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 => { candidate_ = candidate; };

            MediaStream stream = WebRTC.Audio.CaptureStream();

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

            RTCOfferOptions offerOptions = new RTCOfferOptions();
            var             op1          = peer1.CreateOffer(ref offerOptions);

            yield return(op1);

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

            yield return(op2);

            var op3 = peer2.SetRemoteDescription(ref m_DescOffer);

            yield return(op3);

            RTCAnswerOptions answerOptions = new RTCAnswerOptions();
            var op4 = peer2.CreateAnswer(ref answerOptions);

            yield return(op4);

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

            yield return(op5);

            var op6 = peer1.SetRemoteDescription(ref m_DescAnswer);

            yield return(op6);

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

            m_candidate = candidate_;

            stream.Dispose();
            peer1.Close();
            peer2.Close();

            m_Context  = SynchronizationContext.Current;
            signaling1 = CreateSignaling(m_SignalingType, m_Context);
            signaling2 = CreateSignaling(m_SignalingType, m_Context);
        }
        IEnumerator Answer(string connectionId)
        {
            RTCAnswerOptions options = default;
            var pc = pcs[connectionId];
            var op = pc.CreateAnswer(ref options);

            yield return(op);

            if (op.isError)
            {
                Debug.LogError($"Network Error: {op.error}");
                yield break;
            }
            var opLocalDesc = pc.SetLocalDescription(ref op.desc);

            yield return(opLocalDesc);

            if (opLocalDesc.isError)
            {
                Debug.LogError($"Network Error: {opLocalDesc.error}");
                yield break;
            }
            var op3 = signaling.PostAnswer(this.sessionId, connectionId, op.desc.sdp);

            yield return(op3);

            if (op3.webRequest.isNetworkError)
            {
                Debug.LogError($"Network Error: {op3.webRequest.error}");
                yield break;
            }
        }
示例#5
0
        public Task <RTCSessionDescriptionInit> CreateAnswer(RTCAnswerOptions options)
        {
            var tcs = new TaskCompletionSource <RTCSessionDescriptionInit>();

            ((Webrtc.PeerConnection)NativeObject).CreateAnswer(
                new SdpObserverProxy(tcs),
                new Webrtc.MediaConstraints() /*NativeDefaultMediaConstraints*/);
            return(tcs.Task);
        }
示例#6
0
        public IEnumerator CurrentDirection()
        {
            var config     = GetConfiguration();
            var peer1      = new RTCPeerConnection(ref config);
            var peer2      = new RTCPeerConnection(ref config);
            var audioTrack = new AudioStreamTrack("audio");

            var transceiver1 = peer1.AddTransceiver(TrackKind.Audio);

            transceiver1.Direction = RTCRtpTransceiverDirection.RecvOnly;
            Assert.IsNull(transceiver1.CurrentDirection);

            RTCOfferOptions options1 = new RTCOfferOptions {
                offerToReceiveAudio = true
            };
            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 transceiver2 = peer2.GetTransceivers().First(x => x.Receiver.Track.Kind == TrackKind.Audio);

            Assert.True(transceiver2.Sender.ReplaceTrack(audioTrack));
            transceiver2.Direction = RTCRtpTransceiverDirection.SendOnly;

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

            Assert.AreEqual(transceiver1.CurrentDirection, RTCRtpTransceiverDirection.RecvOnly);
            Assert.AreEqual(transceiver2.CurrentDirection, RTCRtpTransceiverDirection.SendOnly);

            audioTrack.Dispose();
            peer1.Close();
            peer2.Close();
            peer1.Dispose();
            peer2.Dispose();
        }
示例#7
0
        public async Task <RTCSessionDescriptionInit> CreateAnswer(RTCAnswerOptions options = null)
        {
            var jsObjectRef = await JsRuntime.CallJsMethodAsync <JsObjectRef>(NativeObject,
                                                                              "createAnswer", options);

            var descriptor = JsRuntime.GetJsPropertyValue <RTCSessionDescriptionInit>(jsObjectRef, null);

            JsRuntime.DeleteJsObjectRef(jsObjectRef.JsObjectRefId);
            return(descriptor);
        }
示例#8
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);
        }
示例#9
0
        public async Task <string> HandleInitialRemoteOffer(string sdp)
        {
            Logger.Debug("PeerChannel", "HandleInitialRemoteOffer");

            if (Conn == null)
            {
                Logger.Debug("PeerChannel", "should initialize beforehand");
                return(string.Empty);
            }

            var sdpInit = new RTCSessionDescriptionInit()
            {
                Type = RTCSdpType.Offer,
                Sdp  = sdp,
            };

            Logger.Debug("PeerChannel", "SetRemoteOffer - SetRemoteDescription");

            await Conn.SetRemoteDescription(new RTCSessionDescription(sdpInit));

            if (mediaOption.VideoUpstreamEnabled)
            {
                Logger.Debug("PeerChannel", "video upstream setting");

                if (screen != null)
                {
                    await screen.StartCaptureAsync();
                }

                SetupVideoTrack();
            }

            if (mediaOption.AudioUpstreamEnabled)
            {
                Logger.Debug("PeerChannel", "audio upstream setting");

                SetupAudioTrack();
            }

            var opts = new RTCAnswerOptions();

            Logger.Debug("PeerChannel", "SetRemoteOffer - CreateAnswer");

            var answer = await Conn.CreateAnswer(opts);

            Logger.Debug("PeerChannel", answer.Sdp);

            await Conn.SetLocalDescription(answer);

            Logger.Debug("PeerChannel", "local description set");

            return(answer.Sdp);
        }
示例#10
0
        public async Task <RTCSessionDescriptionInit> CreateAnswer(RTCAnswerOptions options)
        {
            var tcs = new TaskCompletionSource <RTCSessionDescriptionInit>();

            ((Webrtc.PeerConnection)NativeObject).CreateAnswer(
                new SdpObserverProxy(tcs),
                new Webrtc.MediaConstraints() /*NativeDefaultMediaConstraints*/);
            var answer = await tcs.Task;

            // Android DOES NOT expose 'Type'!!! Set it manually here.
            answer.Type = RTCSdpType.Answer;
            return(answer);
        }
示例#11
0
        IEnumerator OnOffer(ISignaling signaling, DescData e)
        {
            var connectionId     = e.connectionId;
            RTCPeerConnection pc = null;

            if (!m_mapConnectionIdAndPeer.TryGetValue(connectionId, out pc))
            {
                pc = CreatePeerConnection(signaling, connectionId, false);
            }

            RTCSessionDescription _desc;

            _desc.type = RTCSdpType.Offer;
            _desc.sdp  = e.sdp;

            var opRemoteDesc = pc.SetRemoteDescription(ref _desc);

            yield return(opRemoteDesc);

            if (opRemoteDesc.IsError)
            {
                Debug.LogError($"Network Error: {opRemoteDesc.Error.message}");
                yield break;
            }

            AddTracks(connectionId, pc);

            RTCAnswerOptions options = default;
            var op = pc.CreateAnswer(ref options);

            yield return(op);

            if (op.IsError)
            {
                Debug.LogError($"Network Error: {op.Error.message}");
                yield break;
            }

            var desc        = op.Desc;
            var opLocalDesc = pc.SetLocalDescription(ref desc);

            yield return(opLocalDesc);

            if (opLocalDesc.IsError)
            {
                Debug.LogError($"Network Error: {opLocalDesc.Error.message}");
                yield break;
            }

            signaling.SendAnswer(connectionId, desc);
        }
示例#12
0
        public Task <RTCSessionDescriptionInit> CreateAnswer(RTCAnswerOptions options)
        {
            var tcs = new TaskCompletionSource <RTCSessionDescriptionInit>();

            ((Webrtc.RTCPeerConnection)NativeObject).AnswerForConstraints(
                new Webrtc.RTCMediaConstraints(null, null),////NativeDefaultRTCMediaConstraints,
                (nativeSessionDescription, err) =>
            {
                if (err != null)
                {
                    tcs.SetException(new Exception($"{err.LocalizedDescription}"));
                }
                tcs.SetResult(nativeSessionDescription.FromNative());
            });
            return(tcs.Task);
        }
示例#13
0
        public IEnumerator SetRemoteDescription()
        {
            var config   = GetConfiguration();
            var peer1    = new RTCPeerConnection(ref config);
            var peer2    = new RTCPeerConnection(ref config);
            var conf     = new RTCDataChannelInit(true);
            var channel1 = peer1.CreateDataChannel("data", ref conf);

            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 desc2 = peer1.RemoteDescription;

            Assert.AreEqual(desc.sdp, desc2.sdp);
            Assert.AreEqual(desc.type, desc2.type);

            channel1.Dispose();
            peer1.Close();
            peer2.Close();
            peer1.Dispose();
            peer2.Dispose();
        }
        public IEnumerator CreateAnswerFailed()
        {
            var config = GetConfiguration();
            var peer   = new RTCPeerConnection(ref config);
            RTCAnswerOptions options = default;
            var op = peer.CreateAnswer(ref options);

            yield return(op);

            Assert.True(op.IsDone);

            // This is failed
            Assert.True(op.IsError);

            peer.Close();
            peer.Dispose();
        }
        public IEnumerator PeerConnection_SetRemoteDescription()
        {
            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 channel1 = null;

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

            channel1.Dispose();
            peer1.Dispose();
            peer2.Dispose();
        }
示例#16
0
        public Task <SDP> createAnswer(RTCAnswerOptions options)
        {
            SDP answerSdp = new SDP(IPAddress.Loopback);

            answerSdp.SessionId = Crypto.GetRandomInt(5).ToString();

            answerSdp.Connection = new SDPConnectionInformation(IPAddress.Loopback);

            SDPMediaAnnouncement audioAnnouncement = new SDPMediaAnnouncement(
                SDPMediaTypesEnum.audio,
                1234,
                new List <SDPMediaFormat> {
                new SDPMediaFormat(SDPMediaFormatsEnum.PCMU)
            });

            audioAnnouncement.Transport = RTP_MEDIA_PROFILE;

            answerSdp.Media.Add(audioAnnouncement);

            return(Task.FromResult(answerSdp));
        }
示例#17
0
        public IEnumerator CreateAnswer()
        {
            var config = GetConfiguration();

            var peer1 = new RTCPeerConnection(ref config);
            var peer2 = new RTCPeerConnection(ref config);
            var conf  = new RTCDataChannelInit(true);

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

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

            Assert.True(op4.IsDone);
            Assert.False(op4.IsError);

            peer1.Close();
            peer2.Close();
            peer1.Dispose();
            peer2.Dispose();
        }
示例#18
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();
        }
示例#19
0
        private static async Task RunCommand(Options options, bool noOptions)
        {
            // Plumbing code to facilitate a graceful exit.
            CancellationTokenSource exitCts = new CancellationTokenSource(); // Cancellation token to stop the SIP transport and RTP stream.

            //ManualResetEvent exitMre = new ManualResetEvent(false);

            AddConsoleLogger();

            // Start MDNS server.
            var mdnsServer = new ServiceDiscovery();

            if (options.StunServer != null)
            {
                string[] fields = options.StunServer.Split(';');

                _stunServer = new RTCIceServer
                {
                    urls           = fields[0],
                    username       = fields.Length > 1 ? fields[1] : null,
                    credential     = fields.Length > 2 ? fields[2] : null,
                    credentialType = RTCIceCredentialType.password
                };
            }

            _relayOnly = options.RelayOnly;

            if (!string.IsNullOrEmpty(options.IceTypes))
            {
                options.IceTypes.Split().ToList().ForEach(x => {
                    if (Enum.TryParse <RTCIceCandidateType>(x, out var iceType))
                    {
                        _iceTypes.Add(iceType);
                    }
                });

                if (!_iceTypes.Any(x => x == RTCIceCandidateType.host))
                {
                    _offerOptions = new RTCOfferOptions {
                        X_ExcludeIceCandidates = true
                    };
                    _answerOptions = new RTCAnswerOptions {
                        X_ExcludeIceCandidates = true
                    };
                }
            }

            if (!string.IsNullOrEmpty(options.AcceptIceTypes))
            {
                options.AcceptIceTypes.Split().ToList().ForEach(x => {
                    if (Enum.TryParse <RTCIceCandidateType>(x, out var iceType))
                    {
                        _acceptIceTypes.Add(iceType);
                    }
                });
            }

            if (options.UseWebSocket || options.UseSecureWebSocket || noOptions)
            {
                // Start web socket.
                Console.WriteLine("Starting web socket server...");
                _webSocketServer = new WebSocketServer(IPAddress.Any, WEBSOCKET_PORT, options.UseSecureWebSocket);

                if (options.UseSecureWebSocket)
                {
                    _webSocketServer.SslConfiguration.ServerCertificate          = new System.Security.Cryptography.X509Certificates.X509Certificate2(LOCALHOST_CERTIFICATE_PATH);
                    _webSocketServer.SslConfiguration.CheckCertificateRevocation = false;
                }

                //_webSocketServer.Log.Level = WebSocketSharp.LogLevel.Debug;
                _webSocketServer.AddWebSocketService <WebRtcClient>("/sendoffer", (client) =>
                {
                    client.WebSocketOpened   += SendOffer;
                    client.OnMessageReceived += WebSocketMessageReceived;
                });
                _webSocketServer.AddWebSocketService <WebRtcClient>("/receiveoffer", (client) =>
                {
                    client.WebSocketOpened   += ReceiveOffer;
                    client.OnMessageReceived += WebSocketMessageReceived;
                });
                _webSocketServer.Start();

                Console.WriteLine($"Waiting for browser web socket connection to {_webSocketServer.Address}:{_webSocketServer.Port}...");
            }
            else if (options.CreateJsonOffer)
            {
                var pc = Createpc(null, _stunServer, _relayOnly);

                var offerSdp = pc.createOffer(null);
                await pc.setLocalDescription(offerSdp);

                Console.WriteLine(offerSdp.sdp);

                var offerJson   = JsonConvert.SerializeObject(offerSdp, new Newtonsoft.Json.Converters.StringEnumConverter());
                var offerBase64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(offerJson));

                Console.WriteLine(offerBase64);

                string remoteAnswerB64 = null;
                while (string.IsNullOrWhiteSpace(remoteAnswerB64))
                {
                    Console.Write("Remote Answer => ");
                    remoteAnswerB64 = Console.ReadLine();
                }

                string remoteAnswer = Encoding.UTF8.GetString(Convert.FromBase64String(remoteAnswerB64));

                Console.WriteLine(remoteAnswer);

                RTCSessionDescriptionInit answerInit = JsonConvert.DeserializeObject <RTCSessionDescriptionInit>(remoteAnswer);

                Console.WriteLine($"Remote answer: {answerInit.sdp}");

                var res = pc.setRemoteDescription(answerInit);
                if (res != SetDescriptionResultEnum.OK)
                {
                    // No point continuing. Something will need to change and then try again.
                    pc.Close("failed to set remote sdp");
                }
            }
            else if (options.NodeDssServer != null)
            {
                _nodeDssUri    = new Uri(options.NodeDssServer);
                _nodeDssclient = new HttpClient();

                Console.WriteLine($"node-dss server successfully set to {_nodeDssUri}.");
            }

            _ = Task.Run(() => ProcessInput(exitCts));

            // Ctrl-c will gracefully exit the call at any point.
            Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e)
            {
                e.Cancel = true;
                exitCts.Cancel();
            };

            // Wait for a signal saying the call failed, was cancelled with ctrl-c or completed.
            exitCts.Token.WaitHandle.WaitOne();

            Console.WriteLine();
            Console.WriteLine("Exiting...");

            _peerConnection?.Close("application exit");

            _webSocketServer?.Stop();

            Task.Delay(1000).Wait();
        }
示例#20
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();
        }
示例#21
0
        IEnumerator OnOffer(ISignaling signaling, DescData e)
        {
            var connectionId = e.connectionId;

            if (m_mapConnectionIdAndPeer.ContainsKey(connectionId))
            {
                Debug.LogError($"connection:{connectionId} peerConnection already exist");
                yield break;
            }

            var pc = CreatePeerConnection(signaling, connectionId, false);

            RTCSessionDescription _desc;

            _desc.type = RTCSdpType.Offer;
            _desc.sdp  = e.sdp;

            var opRemoteDesc = pc.SetRemoteDescription(ref _desc);

            yield return(opRemoteDesc);

            if (opRemoteDesc.IsError)
            {
                Debug.LogError($"Network Error: {opRemoteDesc.Error.message}");
                yield break;
            }

            // ToDo: need webrtc package version 2.3
            // foreach (var transceiver in pc.GetTransceivers()
            //     .Where(x => x.Receiver.Track.Kind == TrackKind.Video)
            //     .Select((x, index) => new {x, index})
            //     .Take(m_listVideoStreamTrack.Count))
            // {
            //     RTCRtpSender sender = transceiver.x.Sender;
            //     VideoStreamTrack track = m_listVideoStreamTrack[transceiver.index];
            //     transceiver.x.Sender.ReplaceTrack(track);
            //     transceiver.x.Direction = RTCRtpTransceiverDirection.SendOnly;
            //
            //     if (!m_mapTrackAndSenderList.TryGetValue(track, out List<RTCRtpSender> list))
            //     {
            //         list = new List<RTCRtpSender>();
            //         m_mapTrackAndSenderList.Add(track, list);
            //     }
            //
            //     list.Add(sender);
            // }

            foreach (var track in m_listVideoStreamTrack)
            {
                RTCRtpSender sender = pc.AddTrack(track);
                if (!m_mapTrackAndSenderList.TryGetValue(track, out List <RTCRtpSender> list))
                {
                    list = new List <RTCRtpSender>();
                    m_mapTrackAndSenderList.Add(track, list);
                }
                list.Add(sender);
            }

            foreach (var track in m_audioStream.GetTracks())
            {
                RTCRtpSender sender = pc.AddTrack(track);
                if (!m_mapTrackAndSenderList.TryGetValue(track, out List <RTCRtpSender> list))
                {
                    list = new List <RTCRtpSender>();
                    m_mapTrackAndSenderList.Add(track, list);
                }
                list.Add(sender);
            }

            RTCAnswerOptions options = default;
            var op = pc.CreateAnswer(ref options);

            yield return(op);

            if (op.IsError)
            {
                Debug.LogError($"Network Error: {op.Error.message}");
                yield break;
            }

            var desc        = op.Desc;
            var opLocalDesc = pc.SetLocalDescription(ref desc);

            yield return(opLocalDesc);

            if (opLocalDesc.IsError)
            {
                Debug.LogError($"Network Error: {opLocalDesc.Error.message}");
                yield break;
            }

            signaling.SendAnswer(connectionId, desc);
        }
示例#22
0
        void OnOffer(ISignaling signaling, DescData e)
        {
            RTCSessionDescription _desc;

            _desc.type = RTCSdpType.Offer;
            _desc.sdp  = e.sdp;
            var connectionId = e.connectionId;

            if (m_mapConnectionIdAndPeer.ContainsKey(connectionId))
            {
                return;
            }
            var pc = new RTCPeerConnection();

            m_mapConnectionIdAndPeer.Add(e.connectionId, pc);

            pc.OnDataChannel = new DelegateOnDataChannel(channel => { OnDataChannel(pc, channel); });
            pc.SetConfiguration(ref m_conf);
            pc.OnIceCandidate = new DelegateOnIceCandidate(candidate =>
            {
                signaling.SendCandidate(e.connectionId, candidate);
            });
            pc.OnIceConnectionChange = new DelegateOnIceConnectionChange(state =>
            {
                if (state == RTCIceConnectionState.Disconnected)
                {
                    pc.Close();
                    m_mapConnectionIdAndPeer.Remove(e.connectionId);
                }
            });
            //make video bit rate starts at 16000kbits, and 160000kbits at max.
            string pattern = @"(a=fmtp:\d+ .*level-asymmetry-allowed=.*)\r\n";

            _desc.sdp = Regex.Replace(_desc.sdp, pattern, "$1;x-google-start-bitrate=16000;x-google-max-bitrate=160000\r\n");
            pc.SetRemoteDescription(ref _desc);
            foreach (var track in m_listVideoStreamTrack)
            {
                pc.AddTrack(track);
            }
            foreach (var track in m_audioStream.GetTracks())
            {
                pc.AddTrack(track);
            }

            RTCAnswerOptions options = default;
            var op = pc.CreateAnswer(ref options);

            while (op.MoveNext())
            {
            }
            if (op.IsError)
            {
                Debug.LogError($"Network Error: {op.Error}");
                return;
            }

            var desc        = op.Desc;
            var opLocalDesc = pc.SetLocalDescription(ref desc);

            while (opLocalDesc.MoveNext())
            {
            }
            if (opLocalDesc.IsError)
            {
                Debug.LogError($"Network Error: {opLocalDesc.Error}");
                return;
            }

            signaling.SendAnswer(connectionId, desc);
        }
示例#23
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();
        }
示例#24
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();
    }
示例#25
0
        private static async Task RunCommand(Options options, bool noOptions)
        {
            // Plumbing code to facilitate a graceful exit.
            CancellationTokenSource exitCts = new CancellationTokenSource(); // Cancellation token to stop the SIP transport and RTP stream.

            //ManualResetEvent exitMre = new ManualResetEvent(false);

            logger = AddConsoleLogger();

            // Start MDNS server.
            var mdnsServer = new ServiceDiscovery();

            if (options.StunServer != null)
            {
                string[] fields = options.StunServer.Split(';');

                _stunServer = new RTCIceServer
                {
                    urls           = fields[0],
                    username       = fields.Length > 1 ? fields[1] : null,
                    credential     = fields.Length > 2 ? fields[2] : null,
                    credentialType = RTCIceCredentialType.password
                };
            }

            _relayOnly = options.RelayOnly;

            if (!string.IsNullOrEmpty(options.IceTypes))
            {
                options.IceTypes.Split().ToList().ForEach(x =>
                {
                    if (Enum.TryParse <RTCIceCandidateType>(x, out var iceType))
                    {
                        _iceTypes.Add(iceType);
                    }
                });

                if (!_iceTypes.Any(x => x == RTCIceCandidateType.host))
                {
                    _offerOptions = new RTCOfferOptions {
                        X_ExcludeIceCandidates = true
                    };
                    _answerOptions = new RTCAnswerOptions {
                        X_ExcludeIceCandidates = true
                    };
                }
            }

            if (!string.IsNullOrEmpty(options.AcceptIceTypes))
            {
                options.AcceptIceTypes.Split().ToList().ForEach(x =>
                {
                    if (Enum.TryParse <RTCIceCandidateType>(x, out var iceType))
                    {
                        _acceptIceTypes.Add(iceType);
                    }
                });
            }

            if (options.UseWebSocket || options.UseSecureWebSocket || noOptions)
            {
                // Start web socket.
                Console.WriteLine("Starting web socket server...");
                _webSocketServer = new WebSocketServer(IPAddress.Any, WEBSOCKET_PORT, options.UseSecureWebSocket);
                if (options.UseSecureWebSocket)
                {
                    _webSocketServer.SslConfiguration.ServerCertificate          = new X509Certificate2(LOCALHOST_CERTIFICATE_PATH);
                    _webSocketServer.SslConfiguration.CheckCertificateRevocation = false;
                }
                _webSocketServer.AddWebSocketService <WebRTCWebSocketPeer>("/", (peer) =>
                {
                    peer.OfferOptions = _offerOptions;
                    if (_acceptIceTypes != null && _acceptIceTypes.Count > 0)
                    {
                        peer.FilterRemoteICECandidates = (init) => _acceptIceTypes.Any(x => x == RTCIceCandidate.Parse(init.candidate).type);
                    }
                    peer.CreatePeerConnection = CreatePeerConnection;
                });
                _webSocketServer.Start();

                Console.WriteLine($"Waiting for browser web socket connection to {_webSocketServer.Address}:{_webSocketServer.Port}...");
            }
            else if (!string.IsNullOrWhiteSpace(options.WebSocketServer))
            {
                // We are the client for a web socket server. The JSON signalling exchange still occurs the same way as when the web socket
                // server option is used except that as the web socket client we receive the SDP offer from the server.
                WebRTCWebSocketClient wsockClient = new WebRTCWebSocketClient(options.WebSocketServer, CreatePeerConnection);
                await wsockClient.Start(exitCts.Token);

                Console.WriteLine("web socket client started.");
            }
            else if (options.CreateJsonOffer)
            {
                var pc = await Createpc(null, _stunServer, _relayOnly);

                var offerSdp = pc.createOffer(null);
                await pc.setLocalDescription(offerSdp);

                Console.WriteLine(offerSdp.sdp);

                var offerJson   = JsonConvert.SerializeObject(offerSdp, new Newtonsoft.Json.Converters.StringEnumConverter());
                var offerBase64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(offerJson));

                Console.WriteLine(offerBase64);

                string remoteAnswerB64 = null;
                while (string.IsNullOrWhiteSpace(remoteAnswerB64))
                {
                    Console.Write("Remote Answer => ");
                    remoteAnswerB64 = Console.ReadLine();
                }

                string remoteAnswer = Encoding.UTF8.GetString(Convert.FromBase64String(remoteAnswerB64));

                Console.WriteLine(remoteAnswer);

                RTCSessionDescriptionInit answerInit = JsonConvert.DeserializeObject <RTCSessionDescriptionInit>(remoteAnswer);

                Console.WriteLine($"Remote answer: {answerInit.sdp}");

                var res = pc.setRemoteDescription(answerInit);
                if (res != SetDescriptionResultEnum.OK)
                {
                    // No point continuing. Something will need to change and then try again.
                    pc.Close("failed to set remote sdp");
                }
            }
            else if (options.RestServer != null)
            {
                string[] fields = options.RestServer.Split(';');
                if (fields.Length < 3)
                {
                    throw new ArgumentException("The 'rest' option must contain 3 semi-colon separated fields, e.g. --rest=https://localhost:5001/api/webrtcsignal;myid;theirid.");
                }

                var webrtcRestPeer = new WebRTCRestSignalingPeer(fields[0], fields[1], fields[2], CreatePeerConnection);
                webrtcRestPeer.OfferOptions  = _offerOptions;
                webrtcRestPeer.AnswerOptions = _answerOptions;

                if (_acceptIceTypes != null && _acceptIceTypes.Count > 0)
                {
                    webrtcRestPeer.FilterRemoteICECandidates = (init) => _acceptIceTypes.Any(x => x == RTCIceCandidate.Parse(init.candidate).type);
                }
                await webrtcRestPeer.Start(exitCts);
            }

            _ = Task.Run(() => ProcessInput(exitCts));

            // Ctrl-c will gracefully exit the call at any point.
            Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e)
            {
                e.Cancel = true;
                exitCts.Cancel();
            };

            // Wait for a signal saying the call failed, was cancelled with ctrl-c or completed.
            exitCts.Token.WaitHandle.WaitOne();

            Console.WriteLine();
            Console.WriteLine("Exiting...");

            _peerConnection?.Close("application exit");

            _webSocketServer?.Stop();

            Task.Delay(1000).Wait();
        }
示例#26
0
        IEnumerator Start()
        {
            RTCConfiguration config = default;

            config.iceServers = new[]
            {
                new RTCIceServer {
                    urls = new[] { "stun:stun.l.google.com:19302" }
                }
            };

            peers[0] = new RTCPeerConnection(ref config);
            peers[1] = new RTCPeerConnection(ref config);
            dataChannels[peers[0]] = new List <RTCDataChannel>();
            dataChannels[peers[1]] = new List <RTCDataChannel>();

            RTCDataChannel channel = peers[0].CreateDataChannel("data");

            dataChannels[peers[0]].Add(channel);

            peers[0].OnIceCandidate = candidate =>
            {
                Assert.NotNull(candidate);
                Assert.NotNull(candidate.Candidate);
                peers[1].AddIceCandidate(candidate);
            };
            peers[1].OnIceCandidate = candidate =>
            {
                Assert.NotNull(candidate);
                Assert.NotNull(candidate.Candidate);
                peers[0].AddIceCandidate(candidate);
            };
            peers[1].OnTrack = e =>
            {
                Assert.NotNull(e);
                Assert.NotNull(e.Track);
                Assert.NotNull(e.Receiver);
                Assert.NotNull(e.Transceiver);
                peers[1].AddTrack(e.Track);
            };
            peers[0].OnDataChannel = e =>
            {
                if (peers[0].ConnectionState == RTCPeerConnectionState.Connected)
                {
                    dataChannels[peers[0]].Add(e);
                }
            };
            peers[1].OnDataChannel = e =>
            {
                if (peers[1].ConnectionState == RTCPeerConnectionState.Connected)
                {
                    dataChannels[peers[1]].Add(e);
                }
            };

            if (m_stream != null)
            {
                foreach (var track in m_stream.GetTracks())
                {
                    peers[0].AddTrack(track, m_stream);
                }
            }

            RTCOfferOptions  options1 = default;
            RTCAnswerOptions options2 = default;
            var op1 = peers[0].CreateOffer(ref options1);

            yield return(op1);

            Assert.False(op1.IsError);
            var desc = op1.Desc;
            var op2  = peers[0].SetLocalDescription(ref desc);

            yield return(op2);

            Assert.False(op2.IsError);

            desc.sdp = ReplaceOfferSdpForHardwareEncodeTest(desc.sdp);

            var op3 = peers[1].SetRemoteDescription(ref desc);

            yield return(op3);

            Assert.False(op3.IsError);
            var op4 = peers[1].CreateAnswer(ref options2);

            yield return(op4);

            Assert.False(op4.IsError);
            desc = op4.Desc;
            var op5 = peers[1].SetLocalDescription(ref desc);

            yield return(op5);

            Assert.False(op5.IsError);

            desc.sdp = ReplaceAnswerSdpForHardwareEncodeTest(desc.sdp);

            var op6 = peers[0].SetRemoteDescription(ref desc);

            yield return(op6);

            Assert.False(op6.IsError);

            var op7 = new WaitUntilWithTimeout(() =>
                                               peers[0].IceConnectionState == RTCIceConnectionState.Connected ||
                                               peers[0].IceConnectionState == RTCIceConnectionState.Completed, 5000);

            yield return(op7);

            Assert.True(op7.IsCompleted);

            var op8 = new WaitUntilWithTimeout(() =>
                                               peers[1].IceConnectionState == RTCIceConnectionState.Connected ||
                                               peers[1].IceConnectionState == RTCIceConnectionState.Completed, 5000);

            yield return(op8);

            Assert.True(op8.IsCompleted);

            if (m_stream != null)
            {
                var op9 = new WaitUntilWithTimeout(() => GetPeerSenders(0).Any(), 5000);
                yield return(op9);

                Assert.True(op9.IsCompleted);
            }

            IsTestFinished = true;
        }
示例#27
0
            IEnumerator Start()
            {
                RTCConfiguration config = default;

                config.iceServers = new[]
                {
                    new RTCIceServer {
                        urls = new[] { "stun:stun.l.google.com:19302" }
                    }
                };
                var pc1Senders = new List <RTCRtpSender>();
                var pc2Senders = new List <RTCRtpSender>();
                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); };
                peer2.OnTrack        = e => { pc2Senders.Add(peer2.AddTrack(e.Track)); };

                foreach (var track in _stream.GetTracks())
                {
                    pc1Senders.Add(peer1.AddTrack(track));
                }

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

                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(op7.IsCompleted);

                var op9 = new WaitUntilWithTimeout(() => pc2Senders.Count > 0, 5000);

                yield return(op9);

                Assert.True(op9.IsCompleted);

                foreach (var sender in pc1Senders)
                {
                    peer1.RemoveTrack(sender);
                }

                foreach (var sender in pc2Senders)
                {
                    peer2.RemoveTrack(sender);
                }
                pc1Senders.Clear();
                peer1.Close();
                peer2.Close();

                _isFinished = true;
            }
    public IEnumerator MediaStreamTest_AddAndRemoveMediaStream()
    {
        var camObj = new GameObject("Camera");
        var cam    = camObj.AddComponent <Camera>();
        RTCConfiguration config = default;

        config.iceServers = new RTCIceServer[]
        {
            new RTCIceServer
            {
                urls = new string[] { "stun:stun.l.google.com:19302" }
            }
        };
        if (!WebRTC.HWEncoderSupport)
        {
            Assert.Pass("Test environment does not support HW encoding");
        }

        var pc1Senders = new List <RTCRtpSender>();
        var pc2Senders = new List <RTCRtpSender>();
        var peer1      = new RTCPeerConnection(ref config);
        var peer2      = new RTCPeerConnection(ref config);

        peer1.OnIceCandidate = new DelegateOnIceCandidate(candidate => { peer2.AddIceCandidate(ref candidate); });
        peer2.OnIceCandidate = new DelegateOnIceCandidate(candidate => { peer1.AddIceCandidate(ref candidate); });
        peer2.OnTrack        = new DelegateOnTrack(e =>
        {
            pc2Senders.Add(peer2.AddTrack(e.Track));
        });
        foreach (var track in cam.CaptureStream(1280, 720).GetTracks())
        {
            pc1Senders.Add(peer1.AddTrack(track));
        }
        var conf = new RTCDataChannelInit(true);

        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(() => pc2Senders.Count > 0));

        foreach (var sender in pc1Senders)
        {
            peer1.RemoveTrack(sender);
        }
        foreach (var sender in pc2Senders)
        {
            peer2.RemoveTrack(sender);
        }
        pc1Senders.Clear();
        GameObject.DestroyImmediate(camObj);

        peer1.Close();
        peer2.Close();
    }
示例#29
0
        void OnOffer(ISignaling signaling, DescData e)
        {
            RTCSessionDescription _desc;

            _desc.type = RTCSdpType.Offer;
            _desc.sdp  = e.sdp;
            var connectionId = e.connectionId;

            if (m_mapConnectionIdAndPeer.ContainsKey(connectionId))
            {
                return;
            }
            var pc = new RTCPeerConnection();

            m_mapConnectionIdAndPeer.Add(e.connectionId, pc);

            pc.OnDataChannel = new DelegateOnDataChannel(channel => { OnDataChannel(pc, channel); });
            pc.SetConfiguration(ref m_conf);
            pc.OnIceCandidate = new DelegateOnIceCandidate(candidate =>
            {
                signaling.SendCandidate(e.connectionId, candidate);
            });
            pc.OnIceConnectionChange = new DelegateOnIceConnectionChange(state =>
            {
                if (state == RTCIceConnectionState.Disconnected)
                {
                    pc.Close();
                    m_mapConnectionIdAndPeer.Remove(e.connectionId);
                }
            });

            pc.SetRemoteDescription(ref _desc);
            foreach (var track in m_listVideoStreamTrack.Concat(m_audioStream.GetTracks()))
            {
                RTCRtpSender sender = pc.AddTrack(track);
                if (!m_mapTrackAndSenderList.TryGetValue(track, out List <RTCRtpSender> list))
                {
                    list = new List <RTCRtpSender>();
                    m_mapTrackAndSenderList.Add(track, list);
                }
                list.Add(sender);
            }

            RTCAnswerOptions options = default;
            var op = pc.CreateAnswer(ref options);

            while (op.MoveNext())
            {
            }
            if (op.IsError)
            {
                Debug.LogError($"Network Error: {op.Error}");
                return;
            }

            var desc        = op.Desc;
            var opLocalDesc = pc.SetLocalDescription(ref desc);

            while (opLocalDesc.MoveNext())
            {
            }
            if (opLocalDesc.IsError)
            {
                Debug.LogError($"Network Error: {opLocalDesc.Error}");
                return;
            }

            signaling.SendAnswer(connectionId, desc);
        }
示例#30
0
        private IEnumerator StartCreationWorkflow(RTCPeerConnection peer)
        {
            var offerOptions = new RTCOfferOptions
            {
                iceRestart          = false,
                offerToReceiveAudio = true,
                offerToReceiveVideo = false
            };

            var op1 = peer.CreateOffer(ref offerOptions);

            yield return(op1);

            if (op1.isError)
            {
                OnSetSessionDescriptionError(ref op1.error, "CreateOffer");
                yield break;
            }

            var op1desc = op1.desc;

            DebugUtility.Log(LoggerTags.Online, "Success to call CreateOffer. DESC.type : {0}, DESC.sdp : {0}", op1desc.type, op1desc.sdp);
            var op2 = peer.SetLocalDescription(ref op1desc);

            yield return(op2);

            if (op2.isError)
            {
                OnSetSessionDescriptionError(ref op2.error, "SetLocalDescription");
                yield break;
            }

            DebugUtility.Log(LoggerTags.Online, "Success to call SetLocalDescription.");
            var op3 = peer.SetRemoteDescription(ref op1desc);

            yield return(op3);

            if (op3.isError)
            {
                OnSetSessionDescriptionError(ref op3.error, "SetRemoteDescription");
                yield break;
            }

            DebugUtility.Log(LoggerTags.Online, "Success to call SetRemoteDescription.");
            RTCAnswerOptions answerOptions = new RTCAnswerOptions {
                iceRestart = false,
            };
            var op4 = peer.CreateAnswer(ref answerOptions);

            if (op4.isError)
            {
                OnSetSessionDescriptionError(ref op4.error, "CreateAnswer");
                yield break;
            }

            var op4desc = op4.desc;

            DebugUtility.Log(LoggerTags.Online, "Success to call CreateAnswer. DESC.type : {0}, DESC.sdp : {0}", op4desc.type, op4desc.sdp);
            var op5 = peer.SetLocalDescription(ref op4desc);

            if (op5.isError)
            {
                OnSetSessionDescriptionError(ref op4.error, "SetLocalDescription");
                yield break;
            }

            DebugUtility.Log(LoggerTags.Online, "Success to call SetLocalDescription.");
            var op6 = peer.SetRemoteDescription(ref op4desc);

            if (op6.isError)
            {
                OnSetSessionDescriptionError(ref op4.error, "SetRemoteDescription");
                yield break;
            }
            DebugUtility.Log(LoggerTags.Online, "Success to call SetRemoteDescription.");
        }