private async Task ReceiveRtpFromUdpAsync(Socket client, RtpStream rtpStream,
                                                  RtcpReceiverReportsProvider reportsProvider,
                                                  CancellationToken token)
        {
            var readBuffer    = new byte[Constants.UdpReceiveBufferSize];
            var bufferSegment = new ArraySegment <byte>(readBuffer);

            int nextRtcpReportInterval  = GetNextRtcpReportIntervalMs();
            int lastTimeRtcpReportsSent = Environment.TickCount;
            var bufferStream            = new MemoryStream();

            while (!token.IsCancellationRequested)
            {
                int read = await client.ReceiveAsync(bufferSegment, SocketFlags.None);

                var payloadSegment = new ArraySegment <byte>(readBuffer, 0, read);
                rtpStream.Process(payloadSegment);

                int ticksNow = Environment.TickCount;
                if (!TimeUtils.IsTimeOver(ticksNow, lastTimeRtcpReportsSent, nextRtcpReportInterval))
                {
                    continue;
                }

                lastTimeRtcpReportsSent = ticksNow;
                nextRtcpReportInterval  = GetNextRtcpReportIntervalMs();

                IEnumerable <RtcpPacket> packets     = reportsProvider.GetReportPackets();
                ArraySegment <byte>      byteSegment = SerializeRtcpPackets(packets, bufferStream);

                await client.SendAsync(byteSegment, SocketFlags.None);
            }
        }
示例#2
0
        private Task ReceiveOverUdpAsync(CancellationToken token)
        {
            var waitList = new List <Task>(_udpClientsMap.Count / 2);

            foreach (KeyValuePair <int, Socket> pair in _udpClientsMap)
            {
                int    channelNumber = pair.Key;
                Socket client        = pair.Value;

                ITransportStream transportStream = _streamsMap[channelNumber];

                Task receiveTask;

                if (transportStream is RtpStream rtpStream)
                {
                    if (!_udpClientsMap.TryGetValue(_udpRtp2RtcpMap[channelNumber], out Socket clientRtcp))
                    {
                        throw new RtspClientException("RTP connection without RTCP");
                    }
                    RtcpReceiverReportsProvider receiverReportsProvider = _reportProvidersMap[channelNumber];
                    receiveTask = ReceiveRtpFromUdpAsync(client, clientRtcp, rtpStream, receiverReportsProvider, token);
                }
                else
                {
                    receiveTask = ReceiveRtcpFromUdpAsync(client, transportStream, token);
                }

                waitList.Add(receiveTask);
            }

            return(Task.WhenAll(waitList));
        }
        private Task ReceiveOverUdpAsync(CancellationToken token)
        {
            var waitList = new List <Task>(_udpClientsMap.Count / 2);

            foreach (KeyValuePair <int, Socket> pair in _udpClientsMap)
            {
                int    channelNumber = pair.Key;
                Socket client        = pair.Value;

                ITransportStream transportStream = _streamsMap[channelNumber];

                Task receiveTask;

                if (transportStream is RtpStream rtpStream)
                {
                    RtcpReceiverReportsProvider receiverReportsProvider = _reportProvidersMap[channelNumber];
                    receiveTask = ReceiveRtpFromUdpAsync(client, rtpStream, receiverReportsProvider, token);
                }
                else
                {
                    receiveTask = ReceiveRtcpFromUdpAsync(client, transportStream, token);
                }

                waitList.Add(receiveTask);
            }

            return(Task.WhenAll(waitList));
        }
示例#4
0
        public void GetReportPackets_FakeDataProviders_ResetStateOfRtpStatisticsProviderShouldBeCalled()
        {
            var rtpStatisticsProviderMock        = new Mock <IRtpStatisticsProvider>();
            var rtcpSenderStatisticsProviderFake = new Mock <IRtcpSenderStatisticsProvider>();

            var rtcpReportsProvider = new RtcpReceiverReportsProvider(rtpStatisticsProviderMock.Object,
                                                                      rtcpSenderStatisticsProviderFake.Object, 1);

            rtcpReportsProvider.GetReportPackets().ToList();

            rtpStatisticsProviderMock.Verify(x => x.ResetState());
        }
示例#5
0
        public void GetReportPackets_TestDataProviders_ReturnsPacketWithByeReport()
        {
            var rtpStatisticsProviderFake        = new Mock <IRtpStatisticsProvider>();
            var rtcpSenderStatisticsProviderFake = new Mock <IRtcpSenderStatisticsProvider>();

            var rtcpReportsProvider = new RtcpReceiverReportsProvider(rtpStatisticsProviderFake.Object,
                                                                      rtcpSenderStatisticsProviderFake.Object, 1112234);

            IReadOnlyList <RtcpPacket> packets = rtcpReportsProvider.GetReportByePackets().ToList();

            var byePacket = (RtcpByePacket)packets.First(p => p is RtcpByePacket);

            Assert.AreEqual(1112234u, byePacket.SyncSourcesIds.First());
        }
示例#6
0
        public void GetReportPackets_TestDataProviders_ReturnsPacketWithValidReceiverReport()
        {
            DateTime timestamp = DateTime.UtcNow;

            var rtpStatisticsProviderFake = new Mock <IRtpStatisticsProvider>();

            rtpStatisticsProviderFake.Setup(x => x.CumulativePacketLost).Returns(100);
            rtpStatisticsProviderFake.Setup(x => x.HighestSequenceNumberReceived).Returns(10);
            rtpStatisticsProviderFake.Setup(x => x.PacketsReceivedSinceLastReset).Returns(10);
            rtpStatisticsProviderFake.Setup(x => x.PacketsLostSinceLastReset).Returns(4);
            rtpStatisticsProviderFake.Setup(x => x.SequenceCycles).Returns(2);
            rtpStatisticsProviderFake.Setup(x => x.SyncSourceId).Returns(99987);

            var rtcpSenderStatisticsProviderFake = new Mock <IRtcpSenderStatisticsProvider>();

            rtcpSenderStatisticsProviderFake.Setup(x => x.LastTimeReportReceived).Returns(timestamp);
            rtcpSenderStatisticsProviderFake.Setup(x => x.LastNtpTimeReportReceived).Returns(1234 << 16);

            var rtcpReportsProvider = new RtcpReceiverReportsProvider(rtpStatisticsProviderFake.Object,
                                                                      rtcpSenderStatisticsProviderFake.Object, 1112234);

            IReadOnlyList <RtcpPacket> packets = rtcpReportsProvider.GetReportSdesPackets().ToList();

            var receiverReportPacket = (RtcpReceiverReportPacket)packets.First(p => p is RtcpReceiverReportPacket);

            Assert.IsFalse(receiverReportPacket.PaddingFlag);
            Assert.AreNotEqual(0, receiverReportPacket.SourceCount);
            Assert.AreEqual(201, receiverReportPacket.PayloadType);
            Assert.AreNotEqual(0, receiverReportPacket.DwordLength);
            Assert.AreNotEqual(0, receiverReportPacket.Length);
            Assert.AreEqual(1112234u, receiverReportPacket.SyncSourceId);
            Assert.AreEqual(99987u, receiverReportPacket.Reports[0].SyncSourceId);
            Assert.AreEqual(102, receiverReportPacket.Reports[0].FractionLost);
            Assert.AreEqual(100u, receiverReportPacket.Reports[0].CumulativePacketLost);
            Assert.AreEqual(2 << 16 | 10u, receiverReportPacket.Reports[0].ExtHighestSequenceNumberReceived);
            Assert.AreEqual(1234u, receiverReportPacket.Reports[0].LastNtpTimeSenderReportReceived);
            Assert.AreEqual(0u, receiverReportPacket.Reports[0].DelaySinceLastTimeSenderReportReceived);

            packets = rtcpReportsProvider.GetReportByePackets().ToList();

            var receiverReportByePacket = (RtcpByePacket)packets.First(p => p is RtcpByePacket);

            Assert.IsFalse(receiverReportByePacket.PaddingFlag);
            Assert.AreNotEqual(0, receiverReportByePacket.SourceCount);
            Assert.AreEqual(203, receiverReportByePacket.PayloadType);
            Assert.AreNotEqual(0, receiverReportByePacket.DwordLength);
            Assert.AreNotEqual(0, receiverReportByePacket.Length);
            Assert.AreEqual(1112234u, receiverReportByePacket.SyncSourcesIds.First());
        }
示例#7
0
        public void GetReportPackets_TestDataProviders_ReturnsPacketWithValidSdesReport()
        {
            var rtpStatisticsProviderFake        = new Mock <IRtpStatisticsProvider>();
            var rtcpSenderStatisticsProviderFake = new Mock <IRtcpSenderStatisticsProvider>();

            var rtcpReportsProvider = new RtcpReceiverReportsProvider(rtpStatisticsProviderFake.Object,
                                                                      rtcpSenderStatisticsProviderFake.Object, 1112234);

            IReadOnlyList <RtcpPacket> packets = rtcpReportsProvider.GetReportPackets().ToList();

            var sdesReportPacket = (RtcpSdesReportPacket)packets.First(p => p is RtcpSdesReportPacket);

            Assert.AreEqual(1112234u, sdesReportPacket.Chunks[0].SyncSourceId);

            var nameItem = (RtcpSdesNameItem)sdesReportPacket.Chunks[0].Items.First(i => i is RtcpSdesNameItem);

            Assert.IsNotNull(nameItem.DomainName);
        }
        private async Task SetupTrackAsync(RtspMediaTrackInfo track, CancellationToken token)
        {
            RtspRequestMessage  setupRequest;
            RtspResponseMessage setupResponse;

            int    rtpChannelNumber;
            int    rtcpChannelNumber;
            Socket rtpClient  = null;
            Socket rtcpClient = null;

            if (_connectionParameters.RtpTransport == RtpTransportProtocol.UDP)
            {
                rtpClient  = NetworkClientFactory.CreateUdpClient();
                rtcpClient = NetworkClientFactory.CreateUdpClient();

                try
                {
                    IPEndPoint endPoint = new IPEndPoint(IPAddress.Any, 0);
                    rtpClient.Bind(endPoint);

                    int rtpPort = ((IPEndPoint)rtpClient.LocalEndPoint).Port;

                    endPoint = new IPEndPoint(IPAddress.Any, rtpPort + 1);

                    try
                    {
                        rtcpClient.Bind(endPoint);
                    }
                    catch (SocketException e) when(e.SocketErrorCode == SocketError.AddressAlreadyInUse)
                    {
                        endPoint = new IPEndPoint(IPAddress.Any, 0);
                        rtcpClient.Bind(endPoint);
                    }

                    int rtcpPort = ((IPEndPoint)rtcpClient.LocalEndPoint).Port;

                    setupRequest = _requestMessageFactory.CreateSetupUdpUnicastRequest(track.TrackName,
                                                                                       rtpPort, rtcpPort);
                    setupResponse = await _rtspTransportClient.EnsureExecuteRequest(setupRequest, token);
                }
                catch
                {
                    rtpClient.Close();
                    rtcpClient.Close();
                    throw;
                }
            }
            else
            {
                int channelCounter = _streamsMap.Count;
                rtpChannelNumber  = channelCounter;
                rtcpChannelNumber = ++channelCounter;

                setupRequest = _requestMessageFactory.CreateSetupTcpInterleavedRequest(track.TrackName,
                                                                                       rtpChannelNumber, rtcpChannelNumber);
                setupResponse = await _rtspTransportClient.EnsureExecuteRequest(setupRequest, token);
            }

            string transportHeader = setupResponse.Headers[WellKnownHeaders.Transport];

            if (string.IsNullOrEmpty(transportHeader))
            {
                throw new RtspBadResponseException("Transport header is not found");
            }

            string portsAttributeName = _connectionParameters.RtpTransport == RtpTransportProtocol.UDP
                ? "server_port"
                : "interleaved";

            string[] transportAttributes = transportHeader.Split(TransportAttributesSeparator, StringSplitOptions.RemoveEmptyEntries);

            string portsAttribute = transportAttributes.FirstOrDefault(a => a.StartsWith(portsAttributeName, StringComparison.InvariantCultureIgnoreCase));

            if (portsAttribute == null || !TryParseSeverPorts(portsAttribute, out rtpChannelNumber, out rtcpChannelNumber))
            {
                throw new RtspBadResponseException("Server ports are not found");
            }

            if (_connectionParameters.RtpTransport == RtpTransportProtocol.UDP)
            {
                string sourceAttribute = transportAttributes.FirstOrDefault(a => a.StartsWith("source", StringComparison.InvariantCultureIgnoreCase));
                int    equalSignIndex;

                IPAddress sourceAddress;

                if (sourceAttribute != null && (equalSignIndex = sourceAttribute.IndexOf("=", StringComparison.CurrentCultureIgnoreCase)) != -1)
                {
                    sourceAddress = IPAddress.Parse(sourceAttribute.Substring(++equalSignIndex).Trim());
                }
                else
                {
                    sourceAddress = ((IPEndPoint)_rtspTransportClient.RemoteEndPoint).Address;
                }

                Debug.Assert(rtpClient != null, nameof(rtpClient) + " != null");
                rtpClient.Connect(new IPEndPoint(sourceAddress, rtpChannelNumber));
                Debug.Assert(rtcpClient != null, nameof(rtcpClient) + " != null");
                rtcpClient.Connect(new IPEndPoint(sourceAddress, rtcpChannelNumber));

                var udpHolePunchingPacketSegment = new ArraySegment <byte>(Array.Empty <byte>());

                await rtpClient.SendAsync(udpHolePunchingPacketSegment, SocketFlags.None);

                await rtcpClient.SendAsync(udpHolePunchingPacketSegment, SocketFlags.None);

                _udpClientsMap[rtpChannelNumber]  = rtpClient;
                _udpClientsMap[rtcpChannelNumber] = rtcpClient;
            }

            ParseSessionHeader(setupResponse.Headers[WellKnownHeaders.Session]);

            IMediaPayloadParser mediaPayloadParser = MediaPayloadParser.CreateFrom(track.Codec);

            IRtpSequenceAssembler rtpSequenceAssembler;

            if (_connectionParameters.RtpTransport == RtpTransportProtocol.TCP)
            {
                rtpSequenceAssembler = null;
                mediaPayloadParser.FrameGenerated = OnFrameGeneratedLockfree;
            }
            else
            {
                rtpSequenceAssembler = new RtpSequenceAssembler(Constants.UdpReceiveBufferSize, 256);
                mediaPayloadParser.FrameGenerated = OnFrameGeneratedThreadSafe;
            }

            var rtpStream = new RtpStream(mediaPayloadParser, track.SamplesFrequency, rtpSequenceAssembler);

            _streamsMap.Add(rtpChannelNumber, rtpStream);

            var rtcpStream = new RtcpStream();

            rtcpStream.SessionShutdown += (sender, args) => _serverCancellationTokenSource.Cancel();
            _streamsMap.Add(rtcpChannelNumber, rtcpStream);

            uint senderSyncSourceId = (uint)_random.Next();

            var rtcpReportsProvider = new RtcpReceiverReportsProvider(rtpStream, rtcpStream, senderSyncSourceId);

            _reportProvidersMap.Add(rtpChannelNumber, rtcpReportsProvider);
        }
示例#9
0
        private async Task ReceiveRtpFromUdpAsync(Socket client, Socket clientRtcp, RtpStream rtpStream,
                                                  RtcpReceiverReportsProvider reportsProvider,
                                                  CancellationToken token)
        {
            var readBuffer    = new byte[Constants.UdpReceiveBufferSize];
            var bufferSegment = new ArraySegment <byte>(readBuffer);

            int nextRtcpReportInterval  = GetNextRtcpReportIntervalMs();
            int lastTimeRtcpReportsSent = Environment.TickCount;
            var bufferStream            = new MemoryStream();

            IEnumerable <RtcpPacket> packets;
            ArraySegment <byte>      byteSegment;

            try
            {
                while (!token.IsCancellationRequested)
                {
                    int read = await client.ReceiveAsync(bufferSegment, SocketFlags.None).WithCancellation(token);

                    var payloadSegment = new ArraySegment <byte>(readBuffer, 0, read);
                    rtpStream.Process(payloadSegment);

                    int ticksNow = Environment.TickCount;
                    if (!TimeUtils.IsTimeOver(ticksNow, lastTimeRtcpReportsSent, nextRtcpReportInterval))
                    {
                        continue;
                    }

                    lastTimeRtcpReportsSent = ticksNow;
                    nextRtcpReportInterval  = GetNextRtcpReportIntervalMs();

                    packets     = reportsProvider.GetReportSdesPackets();
                    byteSegment = SerializeRtcpPackets(packets, bufferStream);

                    if (_connectionParameters.RtpTransport == RtpTransportProtocol.UDP)
                    {
                        await clientRtcp.SendAsync(byteSegment, SocketFlags.None).WithCancellation(token);
                    }
                    else if (_connectionParameters.RtpTransport == RtpTransportProtocol.MULTICAST)
                    {
                        await clientRtcp.SendToAsync(byteSegment, SocketFlags.None, _udpJoinedGroupsMap[clientRtcp]).WithCancellation(token);
                    }
                }
            }
            catch (OperationCanceledException)
            {
                if (!token.IsCancellationRequested)
                {
                    throw;
                }
            }

            packets     = reportsProvider.GetReportByePackets();
            byteSegment = SerializeRtcpPackets(packets, bufferStream);

            if (_connectionParameters.RtpTransport == RtpTransportProtocol.UDP)
            {
                await clientRtcp.SendAsync(byteSegment, SocketFlags.None);
            }
            else if (_connectionParameters.RtpTransport == RtpTransportProtocol.MULTICAST)
            {
                await clientRtcp.SendToAsync(byteSegment, SocketFlags.None, _udpJoinedGroupsMap[clientRtcp]);
            }
        }
        private async Task SetupTrackAsync(RtspMediaTrackInfo track, CancellationToken token)
        {
            RtspRequestMessage  setupRequest;
            RtspResponseMessage setupResponse;

            int    rtpChannelNumber;
            int    rtcpChannelNumber;
            Socket rtpClient  = null;
            Socket rtcpClient = null;

            if (_connectionParameters.RtpTransport == RtpTransportProtocol.UDP)
            {
                rtpClient  = NetworkClientFactory.CreateUdpClient();
                rtcpClient = NetworkClientFactory.CreateUdpClient();

                try
                {
                    IPEndPoint endPoint = new IPEndPoint(IPAddress.Any, 0);
                    rtpClient.Bind(endPoint);

                    int rtpPort = ((IPEndPoint)rtpClient.LocalEndPoint).Port;

                    endPoint = new IPEndPoint(IPAddress.Any, rtpPort + 1);

                    try
                    {
                        rtcpClient.Bind(endPoint);
                    }
                    catch (SocketException e) when(e.SocketErrorCode == SocketError.AddressAlreadyInUse)
                    {
                        endPoint = new IPEndPoint(IPAddress.Any, 0);
                        rtcpClient.Bind(endPoint);
                    }

                    int rtcpPort = ((IPEndPoint)rtcpClient.LocalEndPoint).Port;

                    setupRequest = _requestMessageFactory.CreateSetupUdpUnicastRequest(track.TrackName,
                                                                                       rtpPort, rtcpPort);
                    setupResponse = await _rtspTransportClient.EnsureExecuteRequest(setupRequest, token);
                }
                catch
                {
                    rtpClient.Close();
                    rtcpClient.Close();
                    throw;
                }
            }
            else
            {
                int channelCounter = _streamsMap.Count;
                rtpChannelNumber  = channelCounter;
                rtcpChannelNumber = ++channelCounter;

                setupRequest = _requestMessageFactory.CreateSetupTcpInterleavedRequest(track.TrackName,
                                                                                       rtpChannelNumber, rtcpChannelNumber);
                setupResponse = await _rtspTransportClient.EnsureExecuteRequest(setupRequest, token);
            }

            string transportHeader = setupResponse.Headers[WellKnownHeaders.Transport];

            if (string.IsNullOrEmpty(transportHeader))
            {
                throw new RtspBadResponseException("Transport header is not found");
            }

            string attributeName = _connectionParameters.RtpTransport == RtpTransportProtocol.UDP
                ? "server_port"
                : "interleaved";

            if (!ParseSeverPorts(transportHeader, attributeName, out rtpChannelNumber, out rtcpChannelNumber))
            {
                throw new RtspBadResponseException("Server ports are not found");
            }

            if (_connectionParameters.RtpTransport == RtpTransportProtocol.UDP)
            {
                IPEndPoint remoteEndPoint = (IPEndPoint)_rtspTransportClient.RemoteEndPoint;

                rtpClient?.Connect(new IPEndPoint(remoteEndPoint.Address, rtpChannelNumber));
                rtcpClient?.Connect(new IPEndPoint(remoteEndPoint.Address, rtcpChannelNumber));

                var udpHolePunchingPacketSegment = new ArraySegment <byte>(Array.Empty <byte>());

                await rtpClient.SendAsync(udpHolePunchingPacketSegment, SocketFlags.None);

                await rtcpClient.SendAsync(udpHolePunchingPacketSegment, SocketFlags.None);

                _udpClientsMap[rtpChannelNumber]  = rtpClient;
                _udpClientsMap[rtcpChannelNumber] = rtcpClient;
            }

            ParseSessionHeader(setupResponse.Headers[WellKnownHeaders.Session]);

            IMediaPayloadParser mediaPayloadParser = MediaPayloadParser.CreateFrom(track.Codec);

            IRtpSequenceAssembler rtpSequenceAssembler;

            if (_connectionParameters.RtpTransport == RtpTransportProtocol.TCP)
            {
                rtpSequenceAssembler = null;
                mediaPayloadParser.FrameGenerated = OnFrameGeneratedLockfree;
            }
            else
            {
                rtpSequenceAssembler = new RtpSequenceAssembler(Constants.UdpReceiveBufferSize, 8);
                mediaPayloadParser.FrameGenerated = OnFrameGeneratedThreadSafe;
            }

            var rtpStream = new RtpStream(mediaPayloadParser, track.SamplesFrequency, rtpSequenceAssembler);

            _streamsMap.Add(rtpChannelNumber, rtpStream);

            var rtcpStream = new RtcpStream();

            rtcpStream.SessionShutdown += (sender, args) => _serverCancellationTokenSource.Cancel();
            _streamsMap.Add(rtcpChannelNumber, rtcpStream);

            uint senderSyncSourceId = (uint)_random.Next();

            var rtcpReportsProvider = new RtcpReceiverReportsProvider(rtpStream, rtcpStream, senderSyncSourceId);

            _reportProvidersMap.Add(rtpChannelNumber, rtcpReportsProvider);
        }