Exemple #1
0
        /// <summary>
        /// Event handler for receiving data on the RTP channel.
        /// </summary>
        /// <param name="remoteEndPoint">The remote end point the data was received from.</param>
        /// <param name="buffer">The data received.</param>
        private void RtpPacketReceived(IPEndPoint remoteEndPoint, byte[] buffer)
        {
            if (m_lastReceiveFromEndPoint == null || !m_lastReceiveFromEndPoint.Equals(remoteEndPoint))
            {
                OnReceiveFromEndPointChanged?.Invoke(m_lastReceiveFromEndPoint, remoteEndPoint);
                m_lastReceiveFromEndPoint = remoteEndPoint;
            }

            // Quick sanity check on whether this is not an RTP or RTCP packet.
            if (buffer?.Length > RTPHeader.MIN_HEADER_LEN && buffer[0] >= 128 && buffer[0] <= 191)
            {
                var rtpPacket = new RTPPacket(buffer);

                OnRtpPacketReceived?.Invoke(rtpPacket);

                if (RemoteRtpEventPayloadID != 0 && rtpPacket.Header.PayloadType == RemoteRtpEventPayloadID)
                {
                    RTPEvent rtpEvent = new RTPEvent(rtpPacket.Payload);
                    OnRtpEvent?.Invoke(rtpEvent);
                }
                else
                {
                    OnReceivedSampleReady?.Invoke(rtpPacket.Payload);
                }
            }
        }
Exemple #2
0
        /// <summary>
        /// Event handler for receiving data on the RTP channel.
        /// </summary>
        /// <param name="remoteEndPoint">The remote end point the data was received from.</param>
        /// <param name="buffer">The data received.</param>
        private void RtpPacketReceived(IPEndPoint remoteEndPoint, byte[] buffer)
        {
            if (m_lastReceiveFromEndPoint == null || !m_lastReceiveFromEndPoint.Equals(remoteEndPoint))
            {
                OnReceiveFromEndPointChanged?.Invoke(m_lastReceiveFromEndPoint, remoteEndPoint);
                m_lastReceiveFromEndPoint = remoteEndPoint;
            }

            var rtpPacket = new RTPPacket(buffer);

            OnRtpPacketReceived?.Invoke(rtpPacket);

            if (m_remoteRtpEventPayloadID != 0 && rtpPacket.Header.PayloadType == m_remoteRtpEventPayloadID)
            {
                RTPEvent rtpEvent = new RTPEvent(rtpPacket.Payload);
                OnRtpEvent?.Invoke(rtpEvent);
            }
            else
            {
                OnReceivedSampleReady?.Invoke(rtpPacket.Payload);
            }
        }
Exemple #3
0
        /// <summary>
        /// Sends an RTP event for a DTMF tone as per RFC2833. Sending the event requires multiple packets to be sent.
        /// This method will hold onto the socket until all the packets required for the event have been sent. The send
        /// can be cancelled using the cancellation token.
        /// </summary>
        /// <param name="srcRtpSocket">The local RTP socket to send the event from.</param>
        /// <param name="dstRtpSocket">The remote RTP socket to send the event to.</param>
        /// <param name="rtpEvent">The RTP event to send.</param>
        /// <param name="startTimestamp">The RTP timestamp at the start of the event.</param>
        /// <param name="samplePeriod">The sample period in milliseconds being used for the media stream that the event
        /// is being inserted into. Should be set to 50ms if main media stream is dynamic or sample period is unknown.</param>
        /// <param name="timestampStep">The RTP timestamp step corresponding to the sampling period. This can change depending
        /// on the codec being used. For example using PCMU with a sampling frequency of 8000Hz the timestamp step
        /// for a sample period of 50ms is 400 (8000 / (1000 / 50)). For a sample period of 20ms it's 160 (8000 / (1000 / 20)).</param>
        /// <param name="cts">Token source to allow the operation to be cancelled prematurely.</param>
        public async Task SendDtmfEvent(Socket srcRtpSocket,
                                        IPEndPoint dstRtpSocket,
                                        RTPEvent rtpEvent,
                                        uint startTimestamp,
                                        ushort samplePeriod,
                                        ushort timestampStep,
                                        CancellationTokenSource cts)
        {
            try
            {
                // If only the minimum number of packets are being sent then they are both the start and end of the event.
                rtpEvent.EndOfEvent = (rtpEvent.TotalDuration <= timestampStep);
                rtpEvent.Duration   = timestampStep;

                // Send the start of event packets.
                for (int i = 0; i < RTPEvent.DUPLICATE_COUNT && !cts.IsCancellationRequested; i++)
                {
                    byte[] buffer = rtpEvent.GetEventPayload();

                    int markerBit = (i == 0) ? 1 : 0;  // Set marker bit for the first packet in the event.
                    SendRtpPacket(srcRtpSocket, dstRtpSocket, buffer, startTimestamp, markerBit, rtpEvent.PayloadTypeID);

                    SeqNum++;
                    PacketsSent++;
                }

                await Task.Delay(samplePeriod, cts.Token);

                if (!rtpEvent.EndOfEvent)
                {
                    // Send the progressive event packets
                    while ((rtpEvent.Duration + timestampStep) < rtpEvent.TotalDuration && !cts.IsCancellationRequested)
                    {
                        rtpEvent.Duration += timestampStep;
                        byte[] buffer = rtpEvent.GetEventPayload();

                        SendRtpPacket(srcRtpSocket, dstRtpSocket, buffer, startTimestamp, 0, rtpEvent.PayloadTypeID);

                        PacketsSent++;
                        SeqNum++;

                        await Task.Delay(samplePeriod, cts.Token);
                    }

                    // Send the end of event packets.
                    for (int j = 0; j < RTPEvent.DUPLICATE_COUNT && !cts.IsCancellationRequested; j++)
                    {
                        rtpEvent.EndOfEvent = true;
                        rtpEvent.Duration   = rtpEvent.TotalDuration;
                        byte[] buffer = rtpEvent.GetEventPayload();

                        SendRtpPacket(srcRtpSocket, dstRtpSocket, buffer, startTimestamp, 0, rtpEvent.PayloadTypeID);

                        SeqNum++;
                        PacketsSent++;
                    }
                }
            }
            catch (System.Net.Sockets.SocketException sockExcp)
            {
                logger.LogError("SocketException SendDtmfEvent. " + sockExcp.Message);
            }
            catch (System.Threading.Tasks.TaskCanceledException)
            {
                logger.LogWarning("SendDtmfEvent was cancelled by caller.");
            }
        }
Exemple #4
0
        /// <summary>
        /// Sends an RTP event for a DTMF tone as per RFC2833. Sending the event requires multiple packets to be sent.
        /// This method will hold onto the socket until all the packets required for the event have been sent. The send
        /// can be cancelled using the cancellation token.
        /// </summary>
        /// <param name="rtpEvent">The RTP event to send.</param>
        ///  <param name="cancellationToken">CancellationToken to allow the operation to be cancelled prematurely.</param>
        public async Task SendDtmfEvent(
            RTPEvent rtpEvent,
            CancellationToken cancellationToken)
        {
            if (m_rtpEventInProgress == true || DestinationEndPoint == null)
            {
                logger.LogWarning("SendDtmfEvent request ignored as an RTP event is already in progress.");
            }

            try
            {
                m_rtpEventInProgress = true;
                uint startTimestamp = m_lastRtpTimestamp;

                // The sample period in milliseconds being used for the media stream that the event
                // is being inserted into. Should be set to 50ms if main media stream is dynamic or
                // sample period is unknown.
                int samplePeriod = RTP_EVENT_DEFAULT_SAMPLE_PERIOD_MS;

                int clockRate = MediaFormat.ClockRate;

                // If the clock rate is unknown or dynamic cross our fingers and use 8KHz.
                if (clockRate == 0)
                {
                    clockRate = DEFAULT_AUDIO_CLOCK_RATE;
                }

                // The RTP timestamp step corresponding to the sampling period. This can change depending
                // on the codec being used. For example using PCMU with a sampling frequency of 8000Hz and a sample period of 50ms
                // the timestamp step is 400 (8000 / (1000 / 50)). For a sample period of 20ms it's 160 (8000 / (1000 / 20)).
                ushort rtpTimestampStep = (ushort)(clockRate * samplePeriod / 1000);

                // If only the minimum number of packets are being sent then they are both the start and end of the event.
                rtpEvent.EndOfEvent = (rtpEvent.TotalDuration <= rtpTimestampStep);
                // The DTMF tone is generally multiple RTP events. Each event has a duration of the RTP timestamp step.
                rtpEvent.Duration = rtpTimestampStep;

                // Send the start of event packets.
                for (int i = 0; i < RTPEvent.DUPLICATE_COUNT && !cancellationToken.IsCancellationRequested; i++)
                {
                    byte[] buffer = rtpEvent.GetEventPayload();

                    int markerBit = (i == 0) ? 1 : 0;  // Set marker bit for the first packet in the event.
                    SendRtpPacket(RtpChannel, DestinationEndPoint, buffer, startTimestamp, markerBit, rtpEvent.PayloadTypeID);

                    SeqNum++;
                }

                await Task.Delay(samplePeriod, cancellationToken);

                if (!rtpEvent.EndOfEvent)
                {
                    // Send the progressive event packets
                    while ((rtpEvent.Duration + rtpTimestampStep) < rtpEvent.TotalDuration && !cancellationToken.IsCancellationRequested)
                    {
                        rtpEvent.Duration += rtpTimestampStep;
                        byte[] buffer = rtpEvent.GetEventPayload();

                        SendRtpPacket(RtpChannel, DestinationEndPoint, buffer, startTimestamp, 0, rtpEvent.PayloadTypeID);

                        SeqNum++;

                        await Task.Delay(samplePeriod, cancellationToken);
                    }

                    // Send the end of event packets.
                    for (int j = 0; j < RTPEvent.DUPLICATE_COUNT && !cancellationToken.IsCancellationRequested; j++)
                    {
                        rtpEvent.EndOfEvent = true;
                        rtpEvent.Duration   = rtpEvent.TotalDuration;
                        byte[] buffer = rtpEvent.GetEventPayload();

                        SendRtpPacket(RtpChannel, DestinationEndPoint, buffer, startTimestamp, 0, rtpEvent.PayloadTypeID);

                        SeqNum++;
                    }
                }
            }
            catch (SocketException sockExcp)
            {
                logger.LogError("SocketException SendDtmfEvent. " + sockExcp.Message);
            }
            catch (TaskCanceledException)
            {
                logger.LogWarning("SendDtmfEvent was cancelled by caller.");
            }
            finally
            {
                m_rtpEventInProgress = false;
            }
        }
Exemple #5
0
        /// <summary>
        /// Event handler for receiving data on the RTP and Control channels. For multiplexed
        /// sessions both RTP and RTCP packets will be received on the RTP channel.
        /// </summary>
        /// <param name="remoteEndPoint">The remote end point the data was received from.</param>
        /// <param name="buffer">The data received.</param>
        private void OnReceive(IPEndPoint remoteEndPoint, byte[] buffer)
        {
            //if (m_lastReceiveFromEndPoint == null || !m_lastReceiveFromEndPoint.Equals(remoteEndPoint))
            //{
            //    OnReceiveFromEndPointChanged?.Invoke(m_lastReceiveFromEndPoint, remoteEndPoint);
            //    m_lastReceiveFromEndPoint = remoteEndPoint;
            //}

            // Quick sanity check on whether this is not an RTP or RTCP packet.
            if (buffer?.Length > RTPHeader.MIN_HEADER_LEN && buffer[0] >= 128 && buffer[0] <= 191)
            {
                if (buffer[1] == 0xC8 /* RTCP SR */ || buffer[1] == 0xC9 /* RTCP RR */)
                {
                    //logger.LogDebug($"RTCP packet received from {remoteEndPoint} before: {buffer.HexStr()}");

                    #region RTCP packet.

                    if (m_srtcpControlUnprotect != null)
                    {
                        int outBufLen = 0;
                        int res       = m_srtcpControlUnprotect(buffer, buffer.Length, out outBufLen);

                        if (res != 0)
                        {
                            logger.LogWarning($"SRTCP unprotect failed, result {res}.");
                            return;
                        }
                        else
                        {
                            buffer = buffer.Take(outBufLen).ToArray();
                        }
                    }

                    var rtcpPkt = new RTCPCompoundPacket(buffer);

                    if (rtcpPkt != null)
                    {
                        if (rtcpPkt.Bye != null)
                        {
                            // TODO: Close stream and if only stream close session.
                            logger.LogDebug($"RTCP BYE received for SSRC ${rtcpPkt.Bye.SSRC}.");
                        }
                        else if (!m_isClosed)
                        {
                            var rtcpSession = GetRtcpSession(rtcpPkt);
                            if (rtcpSession != null)
                            {
                                rtcpSession.ReportReceived(remoteEndPoint, rtcpPkt);
                                OnReceiveReport?.Invoke(rtcpSession.MediaType, rtcpPkt);
                            }
                            else
                            {
                                logger.LogWarning("Could not match an RTCP packet against any SSRC's in the session.");
                            }
                        }
                    }
                    else
                    {
                        logger.LogWarning("Failed to parse RTCP compound report.");
                    }

                    #endregion
                }
                else
                {
                    #region RTP packet.

                    if (!m_isClosed)
                    {
                        if (m_srtpUnprotect != null)
                        {
                            int outBufLen = 0;
                            int res       = m_srtpUnprotect(buffer, buffer.Length, out outBufLen);

                            if (res != 0)
                            {
                                logger.LogWarning($"SRTP unprotect failed, result {res}.");
                                return;
                            }
                            else
                            {
                                buffer = buffer.Take(outBufLen).ToArray();
                            }
                        }

                        var rtpPacket = new RTPPacket(buffer);

                        SDPMediaTypesEnum?rtpMediaType = GetMediaTypeForRtpPacket(rtpPacket.Header);

                        if (RemoteRtpEventPayloadID != 0 && rtpPacket.Header.PayloadType == RemoteRtpEventPayloadID)
                        {
                            RTPEvent rtpEvent = new RTPEvent(rtpPacket.Payload);
                            OnRtpEvent?.Invoke(rtpEvent);
                        }
                        else
                        {
                            OnRtpPacketReceived?.Invoke(rtpPacket);
                        }

                        // Used for reporting purposes.
                        if (rtpMediaType == SDPMediaTypesEnum.audio)
                        {
                            m_audioRtcpSession.RecordRtpPacketReceived(rtpPacket);
                        }
                        else if (rtpMediaType == SDPMediaTypesEnum.video)
                        {
                            m_videoRtcpSession.RecordRtpPacketReceived(rtpPacket);
                        }
                    }

                    #endregion
                }
            }
        }