/// <summary> /// Initialises the RTP session state and starts the RTP channel UDP sockets. /// </summary> /// <param name="addrFamily">Whether the RTP channel should use IPv4 or IPv6.</param> /// <param name="isRtcpMultiplexed">If true RTCP reports will be multiplexed with RTP on a single channel. /// If false (standard mode) then a separate socket is used to send and receive RTCP reports.</param> private void InitialiseRtpChannel(AddressFamily addrFamily, bool isRtcpMultiplexed) { var channelAddress = (addrFamily == AddressFamily.InterNetworkV6) ? IPAddress.IPv6Any : IPAddress.Any; RtpChannel = new RTPChannel(channelAddress, !isRtcpMultiplexed); RtpChannel.OnRTPDataReceived += RtpPacketReceived; RtpChannel.OnClosed += OnRTPChannelClosed; RtcpSession = new RTCPSession(m_sessionStreams.First().Ssrc, RtpChannel, isRtcpMultiplexed); OnRtpPacketReceived += RtcpSession.RtpPacketReceived; RtpChannel.OnControlDataReceived += RtcpSession.ControlDataReceived; OnRtpPacketSent += RtcpSession.RtpPacketSent; // Start the RTP and Control socket receivers and the RTCP session. RtpChannel.Start(); RtcpSession.Start(); }
/// <summary> /// Initialises the RTP session state and starts the RTP channel UDP sockets. /// </summary> private void Initialise(AddressFamily addrFamily, ProtectRtpPacket srtcpProtect) { Ssrc = Convert.ToUInt32(Crypto.GetRandomInt(0, Int32.MaxValue)); SeqNum = Convert.ToUInt16(Crypto.GetRandomInt(0, UInt16.MaxValue)); RtpChannel = new RTPChannel((addrFamily == AddressFamily.InterNetworkV6) ? IPAddress.IPv6Any : IPAddress.Any, true); MediaAnnouncement.Port = RtpChannel.RTPPort; RtpChannel.OnRTPDataReceived += RtpPacketReceived; RtpChannel.OnClosed += OnRTPChannelClosed; RtcpSession = new RTCPSession(Ssrc, RtpChannel, srtcpProtect); OnRtpPacketReceived += RtcpSession.RtpPacketReceived; RtpChannel.OnControlDataReceived += RtcpSession.ControlDataReceived; OnRtpPacketSent += RtcpSession.RtpPacketSent; // Start the RTP and Control socket receivers and the RTCP session. RtpChannel.Start(); RtcpSession.Start(); }
/// <summary> /// Adds an additional RTP stream to this session. The effect of this is to multiplex /// two or more RTP sessions on a single socket. Multiplexing is used by WebRTC. /// </summary> /// <param name="mediaType">The type of media for this stream. When multiplexing streams on an /// RTP session there can be only one stream per media type.</param> /// <param name="payloadTypeID">The payload type ID for this RTP stream. It's what gets set in the payload /// type ID field in the RTP header.</param> /// <param name="remotePayloadIDs">A list of the payload IDs the remote party can set in their RTP headers.</param> public void AddStream(SDPMediaTypesEnum mediaType, int payloadTypeID, List <int> remotePayloadIDs) { if (!(mediaType == SDPMediaTypesEnum.audio || mediaType == SDPMediaTypesEnum.video)) { throw new ApplicationException($"The RTPSession does not know how to transmit media type {mediaType}."); } else if (mediaType == SDPMediaTypesEnum.audio && m_audioStream != null) { m_audioStream.UpdateRemotePayloadIDs(remotePayloadIDs); } else if (mediaType == SDPMediaTypesEnum.video && m_videoStream != null) { m_videoStream.UpdateRemotePayloadIDs(remotePayloadIDs); } else { if (mediaType == SDPMediaTypesEnum.audio) { m_audioStream = new RTPSessionStream(SDPMediaTypesEnum.audio, payloadTypeID, remotePayloadIDs); m_audioRtcpSession = new RTCPSession(SDPMediaTypesEnum.audio, m_audioStream.Ssrc); m_audioRtcpSession.OnReportReadyToSend += SendRtcpReport; if (!IsSecure) { m_audioRtcpSession.Start(); } } else if (mediaType == SDPMediaTypesEnum.video) { m_videoStream = new RTPSessionStream(SDPMediaTypesEnum.video, payloadTypeID, remotePayloadIDs); m_videoRtcpSession = new RTCPSession(SDPMediaTypesEnum.video, m_videoStream.Ssrc); m_videoRtcpSession.OnReportReadyToSend += SendRtcpReport; if (!IsSecure) { m_videoRtcpSession.Start(); } } } }
/// <summary> /// Does the actual sending of an RTP packet using the specified data and header values. /// </summary> /// <param name="rtpChannel">The RTP channel to send from.</param> /// <param name="dstRtpSocket">Destination to send to.</param> /// <param name="data">The RTP packet payload.</param> /// <param name="timestamp">The RTP header timestamp.</param> /// <param name="markerBit">The RTP header marker bit.</param> /// <param name="payloadType">The RTP header payload type.</param> private void SendRtpPacket(RTPChannel rtpChannel, IPEndPoint dstRtpSocket, byte[] data, uint timestamp, int markerBit, int payloadType, uint ssrc, ushort seqNum, RTCPSession rtcpSession) { if (IsSecure && !IsSecureContextReady) { logger.LogWarning("SendRtpPacket cannot be called on a secure session before calling SetSecurityContext."); } else { int srtpProtectionLength = (m_srtpProtect != null) ? SRTP_MAX_PREFIX_LENGTH : 0; RTPPacket rtpPacket = new RTPPacket(data.Length + srtpProtectionLength); rtpPacket.Header.SyncSource = ssrc; rtpPacket.Header.SequenceNumber = seqNum; rtpPacket.Header.Timestamp = timestamp; rtpPacket.Header.MarkerBit = markerBit; rtpPacket.Header.PayloadType = payloadType; Buffer.BlockCopy(data, 0, rtpPacket.Payload, 0, data.Length); var rtpBuffer = rtpPacket.GetBytes(); if (m_srtpProtect == null) { rtpChannel.SendAsync(RTPChannelSocketsEnum.RTP, dstRtpSocket, rtpBuffer); } else { int outBufLen = 0; int rtperr = m_srtpProtect(rtpBuffer, rtpBuffer.Length - srtpProtectionLength, out outBufLen); if (rtperr != 0) { logger.LogError("SendRTPPacket protection failed, result " + rtperr + "."); } else { rtpChannel.SendAsync(RTPChannelSocketsEnum.RTP, dstRtpSocket, rtpBuffer.Take(outBufLen).ToArray()); } } m_lastRtpTimestamp = timestamp; rtcpSession?.RecordRtpPacketSend(rtpPacket); } }