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