Exemplo n.º 1
0
        public async void ChecklistProcessingToFailStateUnitTest()
        {
            logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name);
            logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name);

            RTPChannel rtpChannel = new RTPChannel(false, null);

            var iceSession = new IceSession(rtpChannel, RTCIceComponent.rtp, null);

            iceSession.StartGathering();

            Assert.NotNull(iceSession);
            Assert.NotEmpty(iceSession.Candidates);

            foreach (var hostCandidate in iceSession.Candidates)
            {
                logger.LogDebug($"host candidate: {hostCandidate}");
            }

            var remoteCandidate = RTCIceCandidate.Parse("candidate:408132416 1 udp 2113937151 192.168.11.50 51268 typ host generation 0 ufrag CI7o network-cost 999");
            await iceSession.AddRemoteCandidate(remoteCandidate);

            iceSession.SetRemoteCredentials("CI7o", "xxxxxxxxxxxx");
            iceSession.StartGathering();

            logger.LogDebug($"ICE session retry interval {iceSession.RTO}ms.");

            // The defaults are 5 STUN requests and for a checklist with one entry they will be 500ms apart.
            await Task.Delay(4000);

            Assert.Equal(IceSession.ChecklistEntryState.Failed, iceSession._checklist.Single().State);
            Assert.Equal(IceSession.ChecklistState.Failed, iceSession._checklistState);
            Assert.Equal(RTCIceConnectionState.failed, iceSession.ConnectionState);
        }
Exemplo n.º 2
0
        public async void ChecklistConstructionUnitTest()
        {
            logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name);
            logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name);

            RTPChannel rtpChannel = new RTPChannel(false, null);

            var iceSession = new IceSession(rtpChannel, RTCIceComponent.rtp, null);

            iceSession.StartGathering();

            Assert.NotNull(iceSession);
            Assert.NotEmpty(iceSession.Candidates);

            foreach (var hostCandidate in iceSession.Candidates)
            {
                logger.LogDebug($"host candidate: {hostCandidate}");
            }

            var remoteCandidate = RTCIceCandidate.Parse("candidate:408132416 1 udp 2113937151 192.168.11.50 51268 typ host generation 0 ufrag CI7o network-cost 999");
            await iceSession.AddRemoteCandidate(remoteCandidate);

            var remoteCandidate2 = RTCIceCandidate.Parse("candidate:408132417 1 udp 2113937150 192.168.11.50 51268 typ host generation 0 ufrag CI7o network-cost 999");
            await iceSession.AddRemoteCandidate(remoteCandidate2);

            foreach (var entry in iceSession._checklist)
            {
                logger.LogDebug($"checklist entry: {entry.LocalCandidate} -> {entry.RemoteCandidate}");
            }

            Assert.Single(iceSession._checklist);
        }
Exemplo n.º 3
0
        public async void ChecklistProcessingUnitTest()
        {
            logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name);
            logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name);

            RTPChannel rtpChannel = new RTPChannel(false, null);

            var iceSession = new IceSession(rtpChannel, RTCIceComponent.rtp, null);

            iceSession.StartGathering();

            Assert.NotNull(iceSession);
            Assert.NotEmpty(iceSession.Candidates);

            foreach (var hostCandidate in iceSession.Candidates)
            {
                logger.LogDebug($"host candidate: {hostCandidate}");
            }

            var remoteCandidate = RTCIceCandidate.Parse("candidate:408132416 1 udp 2113937151 192.168.11.50 51268 typ host generation 0 ufrag CI7o network-cost 999");
            await iceSession.AddRemoteCandidate(remoteCandidate);

            iceSession.SetRemoteCredentials("CI7o", "xxxxxxxxxxxx");
            iceSession.StartGathering();

            await Task.Delay(2000);

            var checklistEntry = iceSession._checklist.Single();

            logger.LogDebug($"Checklist entry state {checklistEntry.State}, last check sent at {checklistEntry.LastCheckSentAt}.");

            Assert.Equal(IceSession.ChecklistEntryState.InProgress, checklistEntry.State);
        }
Exemplo n.º 4
0
        public async void ChecklistProcessingToFailStateUnitTest()
        {
            logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name);
            logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name);

            var rtpIceChannel = new RtpIceChannel(null, RTCIceComponent.rtp, null);

            rtpIceChannel.StartGathering();

            Assert.NotNull(rtpIceChannel);
            Assert.NotEmpty(rtpIceChannel.Candidates);

            foreach (var hostCandidate in rtpIceChannel.Candidates)
            {
                logger.LogDebug($"host candidate: {hostCandidate}");
            }

            var remoteCandidate = RTCIceCandidate.Parse("candidate:408132416 1 udp 2113937151 192.168.11.50 51268 typ host generation 0 ufrag CI7o network-cost 999");

            rtpIceChannel.AddRemoteCandidate(remoteCandidate);

            rtpIceChannel.SetRemoteCredentials("CI7o", "xxxxxxxxxxxx");

            logger.LogDebug($"ICE session retry interval {rtpIceChannel.RTO}ms.");

            await Task.Delay(1000);

            rtpIceChannel._checklist.Single().FirstCheckSentAt = DateTime.Now.Subtract(TimeSpan.FromSeconds(RtpIceChannel.FAILED_TIMEOUT_PERIOD));

            await Task.Delay(1000);

            Assert.Equal(ChecklistEntryState.Failed, rtpIceChannel._checklist.Single().State);
            Assert.Equal(ChecklistState.Failed, rtpIceChannel._checklistState);
            Assert.Equal(RTCIceConnectionState.failed, rtpIceChannel.IceConnectionState);
        }
Exemplo n.º 5
0
        public async void SortChecklistUnitTest()
        {
            logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name);
            logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name);

            RTPSession       rtpSession = new RTPSession(true, true, true);
            MediaStreamTrack dummyTrack = new MediaStreamTrack(null, SDPMediaTypesEnum.audio, false, new List <SDPMediaFormat> {
                new SDPMediaFormat(SDPMediaFormatsEnum.PCMU)
            });

            rtpSession.addTrack(dummyTrack);

            var iceSession = new IceSession(rtpSession.GetRtpChannel(SDPMediaTypesEnum.audio), RTCIceComponent.rtp, null);

            iceSession.StartGathering();

            Assert.NotNull(iceSession);
            Assert.NotEmpty(iceSession.Candidates);

            foreach (var hostCandidate in iceSession.Candidates)
            {
                logger.LogDebug(hostCandidate.ToString());
            }

            var remoteCandidate = RTCIceCandidate.Parse("candidate:408132416 1 udp 2113937151 192.168.11.50 51268 typ host generation 0 ufrag CI7o network-cost 999");
            await iceSession.AddRemoteCandidate(remoteCandidate);

            var remoteCandidate2 = RTCIceCandidate.Parse("candidate:408132417 1 udp 2113937150 192.168.11.51 51268 typ host generation 0 ufrag CI7o network-cost 999");
            await iceSession.AddRemoteCandidate(remoteCandidate2);

            foreach (var entry in iceSession._checklist)
            {
                logger.LogDebug($"checklist entry priority {entry.Priority}.");
            }
        }
Exemplo n.º 6
0
        public void SortChecklistUnitTest()
        {
            logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name);
            logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name);

            var rtpIceChannel = new RtpIceChannel(null, RTCIceComponent.rtp, null);

            rtpIceChannel.StartGathering();

            Assert.NotNull(rtpIceChannel);
            Assert.NotEmpty(rtpIceChannel.Candidates);

            foreach (var hostCandidate in rtpIceChannel.Candidates)
            {
                logger.LogDebug(hostCandidate.ToString());
            }

            var remoteCandidate = RTCIceCandidate.Parse("candidate:408132416 1 udp 2113937151 192.168.11.50 51268 typ host generation 0 ufrag CI7o network-cost 999");

            rtpIceChannel.AddRemoteCandidate(remoteCandidate);

            var remoteCandidate2 = RTCIceCandidate.Parse("candidate:408132417 1 udp 2113937150 192.168.11.51 51268 typ host generation 0 ufrag CI7o network-cost 999");

            rtpIceChannel.AddRemoteCandidate(remoteCandidate2);

            foreach (var entry in rtpIceChannel._checklist)
            {
                logger.LogDebug($"checklist entry priority {entry.Priority}.");
            }
        }
        public void ToJsonUnitTest()
        {
            logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name);
            logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name);

            var candidate = RTCIceCandidate.Parse("1390596646 1 udp 1880747346 192.168.11.50 61680 typ host generation 0");

            Assert.NotNull(candidate);
            Assert.Equal(RTCIceCandidateType.host, candidate.type);
            Assert.Equal(RTCIceProtocol.udp, candidate.protocol);

            logger.LogDebug(candidate.toJSON());

            bool parseResult = RTCIceCandidateInit.TryParse(candidate.toJSON(), out var init);

            Assert.True(parseResult);

            Assert.Equal(0, init.sdpMLineIndex);
            Assert.Equal("0", init.sdpMid);

            var initCandidate = RTCIceCandidate.Parse(init.candidate);

            Assert.Equal(RTCIceCandidateType.host, initCandidate.type);
            Assert.Equal(RTCIceProtocol.udp, initCandidate.protocol);
        }
Exemplo n.º 8
0
        public void ParseSvrRflxCandidateUnitTest()
        {
            logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name);
            logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name);

            var candidate = RTCIceCandidate.Parse("842163049 1 udp 1677729535 8.8.8.8 12767 typ srflx raddr 0.0.0.0 rport 0 generation 0 network-cost 999");

            Assert.NotNull(candidate);
            Assert.Equal(RTCIceCandidateType.srflx, candidate.type);
            Assert.Equal(RTCIceProtocol.udp, candidate.protocol);

            logger.LogDebug(candidate.ToString());
        }
Exemplo n.º 9
0
        public void ParseHostCandidateUnitTest()
        {
            logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name);
            logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name);

            var candidate = RTCIceCandidate.Parse("1390596646 1 udp 1880747346 192.168.11.50 61680 typ host generation 0");

            Assert.NotNull(candidate);
            Assert.Equal(RTCIceCandidateType.host, candidate.type);
            Assert.Equal(RTCIceProtocol.udp, candidate.protocol);

            logger.LogDebug(candidate.ToString());
        }
        public async void ChecklistConstructionUnitTest()
        {
            logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name);
            logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name);

            var rtpIceChannel = new RtpIceChannel(null, RTCIceComponent.rtp, null);

            rtpIceChannel.StartGathering();

            Assert.NotNull(rtpIceChannel);
            Assert.NotEmpty(rtpIceChannel.Candidates);

            foreach (var hostCandidate in rtpIceChannel.Candidates)
            {
                logger.LogDebug($"host candidate: {hostCandidate}");
            }

            var remoteCandidate = RTCIceCandidate.Parse("candidate:408132416 1 udp 2113937151 192.168.11.50 51268 typ host generation 0 ufrag CI7o network-cost 999");

            rtpIceChannel.AddRemoteCandidate(remoteCandidate);

            var remoteCandidate2 = RTCIceCandidate.Parse("candidate:408132417 1 udp 2113937150 192.168.11.50 51268 typ host generation 0 ufrag CI7o network-cost 999");

            rtpIceChannel.AddRemoteCandidate(remoteCandidate2);

#pragma warning disable RCS1090 // Add call to 'ConfigureAwait' (or vice versa).
            await Task.Delay(500);

#pragma warning restore RCS1090 // Add call to 'ConfigureAwait' (or vice versa).

            foreach (var entry in rtpIceChannel._checklist)
            {
                logger.LogDebug($"checklist entry: {entry.LocalCandidate.ToShortString()}->{entry.RemoteCandidate.ToShortString()}");
            }

            Assert.Single(rtpIceChannel._checklist);
        }
Exemplo n.º 11
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();
        }
Exemplo n.º 12
0
        private static async Task WebSocketMessageReceived(WebSocketContext context, RTCPeerConnection pc, string message)
        {
            try
            {
                if (pc.localDescription == null)
                {
                    //logger.LogDebug("Offer SDP: " + message);
                    logger.LogDebug("Offer SDP received.");

                    // Add local media tracks depending on what was offered. Also add local tracks with the same media ID as
                    // the remote tracks so that the media announcement in the SDP answer are in the same order.
                    var offerInit = JsonConvert.DeserializeObject <RTCSessionDescriptionInit>(message, new Newtonsoft.Json.Converters.StringEnumConverter());

                    logger.LogDebug(SDP.ParseSDPDescription(offerInit.sdp).ToString());

                    var res = pc.setRemoteDescription(offerInit);

                    if (res != SetDescriptionResultEnum.OK)
                    {
                        // No point continuing. Something will need to change and then try again.
                        pc.Close("failed to set remote sdp");
                    }
                    else
                    {
                        var answer = pc.createAnswer(_answerOptions);
                        await pc.setLocalDescription(answer);

                        context.WebSocket.Send(JsonConvert.SerializeObject(answer, new Newtonsoft.Json.Converters.StringEnumConverter()));
                    }
                }
                else if (pc.remoteDescription == null)
                {
                    logger.LogDebug("Answer SDP received:");

                    var answerInit = JsonConvert.DeserializeObject <RTCSessionDescriptionInit>(message, new Newtonsoft.Json.Converters.StringEnumConverter());

                    logger.LogDebug(SDP.ParseSDPDescription(answerInit.sdp).ToString());

                    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
                {
                    logger.LogDebug("ICE Candidate: " + message);

                    if (string.IsNullOrWhiteSpace(message) || message.Trim().ToLower() == SDP.END_ICE_CANDIDATES_ATTRIBUTE)
                    {
                        logger.LogDebug("End of candidates message received.");
                    }
                    else
                    {
                        var candInit = Newtonsoft.Json.JsonConvert.DeserializeObject <RTCIceCandidateInit>(message);

                        if (_acceptIceTypes.Count > 0 && !_acceptIceTypes.Any(x => x == RTCIceCandidate.Parse(candInit.candidate).type))
                        {
                            logger.LogDebug($"Ignoring remote ICE candidate as type not in accept list.");
                        }
                        else
                        {
                            pc.addIceCandidate(candInit);
                        }
                    }
                }
            }
            catch (Exception excp)
            {
                logger.LogError("Exception WebSocketMessageReceived. " + excp.Message);
            }
        }