public void SendRtcpSenderReport(Socket srcRtpSocket, IPEndPoint dstRtpSocket, uint timestamp) { try { var ntp = RTSPSession.DateTimeToNptTimestamp(DateTime.Now); var rtcpSRPacket = new RTCPPacket(Ssrc, ntp, timestamp, PacketsSent, OctetsSent); if (SrtcpProtect == null) { srcRtpSocket.SendTo(rtcpSRPacket.GetBytes(), dstRtpSocket); } else { var rtcpSRBytes = rtcpSRPacket.GetBytes(); byte[] sendBuffer = new byte[rtcpSRBytes.Length + SRTP_AUTH_KEY_LENGTH]; Buffer.BlockCopy(rtcpSRBytes, 0, sendBuffer, 0, rtcpSRBytes.Length); int rtperr = SrtcpProtect(sendBuffer, sendBuffer.Length - SRTP_AUTH_KEY_LENGTH); if (rtperr != 0) { logger.LogWarning("SRTP RTCP packet protection failed, result " + rtperr + "."); } else { srcRtpSocket.SendTo(sendBuffer, dstRtpSocket); } } } catch (Exception excp) { logger.LogWarning("Exception SendRtcpSenderReport. " + excp.Message); } }
/// <summary> /// Creates a new RTSP session and intialises the RTP and control sockets for the session. /// </summary> /// <param name="remoteEndPoint">The remote end point of the RTSP client that requested the RTSP session be set up.</param> /// <returns>An RTSP session object.</returns> public RTSPSession CreateRTSPSession(IPEndPoint remoteEndPoint, IPEndPoint rtcpRemoteEndPoint) { var rtspSession = new RTSPSession(Guid.NewGuid().ToString(), remoteEndPoint, rtcpRemoteEndPoint); rtspSession.ReservePorts(); rtspSession.OnRTPSocketDisconnected += RTPSocketDisconnected; lock (m_rtspSessions) { m_rtspSessions.Add(rtspSession.SessionID, rtspSession); } return(rtspSession); }
public void Send(byte[] buffer) { try { Peer.LastTimestamp = (Peer.LastTimestamp == 0) ? RTSPSession.DateTimeToNptTimestamp32(DateTime.Now) : Peer.LastTimestamp + TIMESTAMP_SPACING; for (int index = 0; index *RTP_MAX_PAYLOAD < buffer.Length; index++) { int offset = (index == 0) ? 0 : (index * RTP_MAX_PAYLOAD); int payloadLength = (offset + RTP_MAX_PAYLOAD < buffer.Length) ? RTP_MAX_PAYLOAD : buffer.Length - offset; byte[] vp8HeaderBytes = (index == 0) ? new byte[] { 0x10 } : new byte[] { 0x00 }; RTPPacket rtpPacket = new RTPPacket(payloadLength + SRTP_AUTH_KEY_LENGTH + vp8HeaderBytes.Length); rtpPacket.Header.SyncSource = Peer.SSRC; rtpPacket.Header.SequenceNumber = Peer.SequenceNumber++; rtpPacket.Header.Timestamp = Peer.LastTimestamp; rtpPacket.Header.MarkerBit = ((offset + payloadLength) >= buffer.Length) ? 1 : 0; // Set marker bit for the last packet in the frame. rtpPacket.Header.PayloadType = PAYLOAD_TYPE_ID; Buffer.BlockCopy(vp8HeaderBytes, 0, rtpPacket.Payload, 0, vp8HeaderBytes.Length); Buffer.BlockCopy(buffer, offset, rtpPacket.Payload, vp8HeaderBytes.Length, payloadLength); var rtpBuffer = rtpPacket.GetBytes(); int rtperr = SrtpContext.ProtectRTP(rtpBuffer, rtpBuffer.Length - SRTP_AUTH_KEY_LENGTH); if (rtperr != 0) { logger.Warn("SRTP packet protection failed, result " + rtperr + "."); } else { var connectedIceCandidate = Peer.LocalIceCandidates.Where(y => y.RemoteRtpEndPoint != null).First(); connectedIceCandidate.LocalRtpSocket.SendTo(rtpBuffer, connectedIceCandidate.RemoteRtpEndPoint); } } } catch (Exception sendExcp) { // logger.Error("SendRTP exception sending to " + client.SocketAddress + ". " + sendExcp.Message); } }
/// <summary> /// Periodically checks the established connections and closes any that have not had a transmission for a specified /// period or where the number of connections allowed per IP address has been exceeded. /// </summary> private void PruneConnections(string threadName) { try { Thread.CurrentThread.Name = threadName; Thread.Sleep(INITIALPRUNE_CONNECTIONS_DELAY); while (!Closed) { // Check the TCP connections established by RTSP clients for any inactive ones. try { RTSPConnection inactiveConnection = null; lock (m_connectedSockets) { var inactiveConnectionQuery = from connection in m_connectedSockets where connection.Value.LastTransmission < DateTime.Now.AddMinutes(PRUNE_NOTRANSMISSION_MINUTES * -1) select connection.Key; var inactiveConnectionKey = inactiveConnectionQuery.FirstOrDefault(); while (inactiveConnectionKey != null) { if (inactiveConnectionKey != null) { inactiveConnection = m_connectedSockets[inactiveConnectionKey]; m_connectedSockets.Remove(inactiveConnectionKey); logger.Debug("Pruning inactive RTSP connection on to remote end point " + inactiveConnection.RemoteEndPoint + "."); inactiveConnection.Close(); } inactiveConnectionKey = inactiveConnectionQuery.FirstOrDefault(); } } } catch (SocketException) { // Will be thrown if the socket is already closed. } catch (Exception pruneExcp) { logger.Error("Exception RTSPServer PruneConnections (pruning). " + pruneExcp.Message); } // Check the list of active RTSP sessions for any that have stopped communicating or that have closed. try { RTSPSession inactiveSession = null; lock (m_rtspSessions) { var inactiveSessionQuery = from session in m_rtspSessions where (session.Value.DontTimeout == false && session.Value.RTPLastActivityAt < DateTime.Now.AddSeconds(CLOSE_RTSP_SESSION_NO_DATA_SECONDS * -1) && session.Value.ControlLastActivityAt < DateTime.Now.AddSeconds(CLOSE_RTSP_SESSION_NO_DATA_SECONDS * -1) && session.Value.StartedAt < DateTime.Now.AddSeconds(CLOSE_RTSP_SESSION_NO_DATA_SECONDS * -1) && session.Value.CreatedAt < DateTime.Now.AddSeconds(CLOSE_RTSP_SESSION_NO_DATA_SECONDS * -1)) || session.Value.IsClosed select session.Key; var inactiveSessionKey = inactiveSessionQuery.FirstOrDefault(); while (inactiveSessionKey != null) { inactiveSession = m_rtspSessions[inactiveSessionKey]; m_rtspSessions.Remove(inactiveSessionKey); if (!inactiveSession.IsClosed) { logger.Debug("Closing inactive RTSP session for session ID " + inactiveSession.SessionID + " established from RTSP client on " + inactiveSession.RemoteEndPoint + " (started at " + inactiveSession.StartedAt + ", RTP last activity at " + inactiveSession.RTPLastActivityAt + ", control last activity at " + inactiveSession.ControlLastActivityAt + ", is closed " + inactiveSession.IsClosed + ")."); inactiveSession.Close(); } inactiveSessionKey = inactiveSessionQuery.FirstOrDefault(); } } } catch (Exception rtspSessExcp) { logger.Error("Exception RTSPServer checking for inactive RTSP sessions. " + rtspSessExcp); } Thread.Sleep(PRUNE_CONNECTIONS_INTERVAL * 1000); } logger.Debug("RTSPServer socket on " + m_localIPEndPoint.ToString() + " pruning connections halted."); } catch (Exception excp) { logger.Error("Exception RTSPServer PruneConnections. " + excp.Message); } }
public void Start(string url) { _url = url; Match urlMatch = Regex.Match(url, @"rtsp://(?<hostname>\S+?)/", RegexOptions.IgnoreCase); if (!urlMatch.Success) { throw new ApplicationException("The URL provided to the RTSP client was not recognised, " + url + "."); } else { string hostname = urlMatch.Result("${hostname}"); int port = RTSP_PORT; if (hostname.Contains(':')) { port = SIPSorcery.Sys.IPSocket.ParsePortFromSocket(hostname); hostname = SIPSorcery.Sys.IPSocket.ParseHostFromSocket(hostname); } logger.LogDebug("RTSP client connecting to " + hostname + ", port " + port + "."); _rtspConnection = new TcpClient(hostname, port); _rtspStream = _rtspConnection.GetStream(); _rtspSession = new RTSPSession(); _rtspSession.RTPPayloadHeaderLength = _rtpPayloadHeaderLength; _rtspSession.ReservePorts(); _rtspSession.OnRTPQueueFull += RTPQueueFull; RTSPRequest rtspRequest = new RTSPRequest(RTSPMethodsEnum.SETUP, url); RTSPHeader rtspHeader = new RTSPHeader(_cseq++, null); rtspHeader.Transport = new RTSPTransportHeader() { ClientRTPPortRange = _rtspSession.RTPPort + "-" + _rtspSession.ControlPort }; rtspRequest.Header = rtspHeader; string rtspReqStr = rtspRequest.ToString(); RTSPMessage rtspMessage = null; System.Diagnostics.Debug.WriteLine(rtspReqStr); byte[] rtspRequestBuffer = Encoding.UTF8.GetBytes(rtspReqStr); _rtspStream.Write(rtspRequestBuffer, 0, rtspRequestBuffer.Length); byte[] buffer = new byte[2048]; int bytesRead = _rtspStream.Read(buffer, 0, 2048); if (bytesRead > 0) { System.Diagnostics.Debug.WriteLine(Encoding.UTF8.GetString(buffer, 0, bytesRead)); rtspMessage = RTSPMessage.ParseRTSPMessage(buffer, null, null); if (rtspMessage.RTSPMessageType == RTSPMessageTypesEnum.Response) { var setupResponse = RTSPResponse.ParseRTSPResponse(rtspMessage); if (setupResponse.Status == RTSPResponseStatusCodesEnum.OK) { _rtspSession.SessionID = setupResponse.Header.Session; _rtspSession.RemoteEndPoint = new IPEndPoint((_rtspConnection.Client.RemoteEndPoint as IPEndPoint).Address, setupResponse.Header.Transport.GetServerRTPPort()); _rtspSession.Start(); logger.LogDebug("RTSP Response received to SETUP: " + setupResponse.Status + ", session ID " + _rtspSession.SessionID + ", server RTP endpoint " + _rtspSession.RemoteEndPoint + "."); if (OnSetupSuccess != null) { OnSetupSuccess(this); } } else { logger.LogWarning("RTSP Response received to SETUP: " + setupResponse.Status + "."); throw new ApplicationException("An error response of " + setupResponse.Status + " was received for an RTSP setup request."); } } } else { throw new ApplicationException("Zero bytes were read from the RTSP client socket in response to a SETUP request."); } } }