/// <summary>
        /// Adds specified source to participant if participant doesn't contain the specified source.
        /// </summary>
        /// <param name="source">RTP source.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>source</b> is null reference.</exception>
        internal void EnsureSource(RTP_Source source)
        {
            if (source == null)
            {
                throw new ArgumentNullException("source");
            }

            if (!m_pSources.Contains(source))
            {
                m_pSources.Add(source);

                OnSourceAdded(source);

                source.Disposing += delegate
                {
                    if (m_pSources.Remove(source))
                    {
                        OnSourceRemoved(source);

                        // If last source removed, the participant is dead, so dispose participant.
                        if (m_pSources.Count == 0)
                        {
                            OnRemoved();
                            Dispose();
                        }
                    }
                };
            }
        }
        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="source">RTP source.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>source</b> is null reference.</exception>
        public RTP_SourceEventArgs(RTP_Source source)
        {
            if (source == null)
            {
                throw new ArgumentNullException("source");
            }

            m_pSource = source;
        }
        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="source">RTP source.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>source</b> is null reference.</exception>
        public RTP_SourceEventArgs(RTP_Source source)
        {
            if (source == null)
            {
                throw new ArgumentNullException("source");
            }

            m_pSource = source;
        }
        /// <summary>
        /// Raises <b>SourceRemoved</b> event.
        /// </summary>
        /// <param name="source">RTP source.</param>
        private void OnSourceRemoved(RTP_Source source)
        {
            if (source == null)
            {
                throw new ArgumentNullException("source");
            }

            if (SourceRemoved != null)
            {
                SourceRemoved(this, new RTP_SourceEventArgs(source));
            }
        }
示例#5
0
        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="session">Owner RTP session.</param>
        /// <param name="ssrc">Onwer synchronization source.</param>
        /// <param name="packetSeqNo">RTP packet <b>SeqNo</b> value.</param>
        /// <exception cref="ArgumentNullException">Is riased when <b>session</b> or <b>ssrc</b> is null reference.</exception>
        internal RTP_ReceiveStream(RTP_Session session, RTP_Source ssrc, ushort packetSeqNo)
        {
            if (session == null)
            {
                throw new ArgumentNullException("session");
            }
            if (ssrc == null)
            {
                throw new ArgumentNullException("ssrc");
            }

            m_pSession = session;
            m_pSSRC    = ssrc;

            // RFC 3550 A.1.
            InitSeq(packetSeqNo);
            m_MaxSeqNo  = (ushort)(packetSeqNo - 1);
            m_Probation = MIN_SEQUENTIAL;
        }
        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="session">Owner RTP session.</param>
        /// <param name="ssrc">Onwer synchronization source.</param>
        /// <param name="packetSeqNo">RTP packet <b>SeqNo</b> value.</param>
        /// <exception cref="ArgumentNullException">Is riased when <b>session</b> or <b>ssrc</b> is null reference.</exception>
        internal RTP_ReceiveStream(RTP_Session session, RTP_Source ssrc, ushort packetSeqNo)
        {
            if (session == null)
            {
                throw new ArgumentNullException("session");
            }
            if (ssrc == null)
            {
                throw new ArgumentNullException("ssrc");
            }

            m_pSession = session;
            m_pSSRC = ssrc;

            // RFC 3550 A.1.
            InitSeq(packetSeqNo);
            m_MaxSeqNo = (ushort) (packetSeqNo - 1);
            m_Probation = MIN_SEQUENTIAL;
        }
示例#7
0
        /// <summary>
        /// Starts RTP session.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this class is Disposed and this method is accessed.</exception>
        public void Start()
        {
            if (m_IsDisposed)
            {
                throw new ObjectDisposedException(GetType().Name);
            }

            /* RFC 3550 6.3.2 Initialization
                Upon joining the session, the participant initializes tp to 0, tc to
                0, senders to 0, pmembers to 1, members to 1, we_sent to false,
                rtcp_bw to the specified fraction of the session bandwidth, initial
                to true, and avg_rtcp_size to the probable size of the first RTCP
                packet that the application will later construct.  The calculated
                interval T is then computed, and the first packet is scheduled for
                time tn = T.  This means that a transmission timer is set which
                expires at time T.  Note that an application MAY use any desired
                approach for implementing this timer.
    
                The participant adds its own SSRC to the member table.
            */

            m_PMembersCount = 1;
            m_RtcpAvgPacketSize = 100;

            // Add ourself to members list.
            m_pRtcpSource = CreateLocalSource();
            m_pMembers.Add(m_pRtcpSource.SSRC, m_pRtcpSource);

            #region IO completion ports

            if (Net_Utils.IsIoCompletionPortsSupported())
            {
                // Start receiving RTP packet.
                SocketAsyncEventArgs rtpArgs = new SocketAsyncEventArgs();
                rtpArgs.Completed += delegate(object s, SocketAsyncEventArgs e)
                                         {
                                             if (m_IsDisposed)
                                             {
                                                 return;
                                             }

                                             if (e.SocketError == SocketError.Success)
                                             {
                                                 ProcessRtp(m_pRtpReceiveBuffer,
                                                            e.BytesTransferred,
                                                            (IPEndPoint) rtpArgs.RemoteEndPoint);
                                             }

                                             // Start receiving next packet.
                                             RtpIOCompletionReceive(e);
                                         };
                // Move processing off the active thread, because ReceiveFromAsync can complete synchronously.
                ThreadPool.QueueUserWorkItem(delegate { RtpIOCompletionReceive(rtpArgs); });

                // Start receiving RTCP packet.
                SocketAsyncEventArgs rtcpArgs = new SocketAsyncEventArgs();
                rtcpArgs.SetBuffer(m_pRtcpReceiveBuffer, 0, m_pRtcpReceiveBuffer.Length);
                rtcpArgs.Completed += delegate(object s, SocketAsyncEventArgs e)
                                          {
                                              if (m_IsDisposed)
                                              {
                                                  return;
                                              }

                                              if (e.SocketError == SocketError.Success)
                                              {
                                                  ProcessRtcp(m_pRtcpReceiveBuffer,
                                                              e.BytesTransferred,
                                                              (IPEndPoint) e.RemoteEndPoint);
                                              }

                                              // Start receiving next packet.
                                              RtcpIOCompletionReceive(e);
                                          };
                // Move processing off the active thread, because ReceiveFromAsync can complete synchronously.
                ThreadPool.QueueUserWorkItem(delegate { RtcpIOCompletionReceive(rtcpArgs); });
            }

                #endregion

                #region Async sockets

            else
            {
                // Start receiving RTP packet.
                EndPoint rtpRemoteEP =
                    new IPEndPoint(
                        m_pRtpSocket.AddressFamily == AddressFamily.InterNetwork
                            ? IPAddress.Any
                            : IPAddress.IPv6Any,
                        0);
                m_pRtpSocket.BeginReceiveFrom(m_pRtpReceiveBuffer,
                                              0,
                                              m_pRtpReceiveBuffer.Length,
                                              SocketFlags.None,
                                              ref rtpRemoteEP,
                                              RtpAsyncSocketReceiveCompleted,
                                              null);

                // Start receiving RTCP packet.
                EndPoint rtcpRemoteEP =
                    new IPEndPoint(
                        m_pRtcpSocket.AddressFamily == AddressFamily.InterNetwork
                            ? IPAddress.Any
                            : IPAddress.IPv6Any,
                        0);
                m_pRtcpSocket.BeginReceiveFrom(m_pRtcpReceiveBuffer,
                                               0,
                                               m_pRtcpReceiveBuffer.Length,
                                               SocketFlags.None,
                                               ref rtcpRemoteEP,
                                               RtcpAsyncSocketReceiveCompleted,
                                               null);
            }

            #endregion

            // Start RTCP reporting.
            Schedule(ComputeRtcpTransmissionInterval(m_pMembers.Count,
                                                     m_pSenders.Count,
                                                     m_Bandwidth*0.25,
                                                     false,
                                                     m_RtcpAvgPacketSize,
                                                     true));
        }
示例#8
0
        /// <summary>
        /// Cleans up any resources being used.
        /// </summary>
        public void Dispose()
        {
            if (m_IsDisposed)
            {
                return;
            }
            m_IsDisposed = true;

            if (m_pRtcpTimer != null)
            {
                m_pRtcpTimer.Dispose();
                m_pRtcpTimer = null;
            }
            m_pSession = null;
            m_pLocalEP = null;
            m_pTargets = null;
            foreach (RTP_Source_Local source in m_pLocalSources.ToArray())
            {
                source.Dispose();
            }
            m_pLocalSources = null;
            m_pRtcpSource = null;
            foreach (RTP_Source source in m_pMembers.Values)
            {
                source.Dispose();
            }
            m_pMembers = null;
            m_pSenders = null;
            m_pConflictingEPs = null;
            m_pRtpReceiveBuffer = null;
            m_pRtcpReceiveBuffer = null;
            m_pRtpSocket.Close();
            m_pRtpSocket = null;
            m_pRtcpSocket.Close();
            m_pRtcpSocket = null;

            OnDisposed();

            Disposed = null;
            Closed = null;
            NewSendStream = null;
            NewReceiveStream = null;
        }
示例#9
0
        /// <summary>
        /// Does RFC 3550 6.3.5 Timing Out an SSRC.
        /// </summary>
        private void TimeOutSsrc()
        {
            /* RFC 3550 6.3.5 Timing Out an SSRC.
                At occasional intervals, the participant MUST check to see if any of
                the other participants time out.  To do this, the participant
                computes the deterministic (without the randomization factor)
                calculated interval Td for a receiver, that is, with we_sent false.
                Any other session member who has not sent an RTP or RTCP packet since
                time tc - MTd (M is the timeout multiplier, and defaults to 5) is
                timed out.  This means that its SSRC is removed from the member list,
                and members is updated.  A similar check is performed on the sender
                list.  Any member on the sender list who has not sent an RTP packet
                since time tc - 2T (within the last two RTCP report intervals) is
                removed from the sender list, and senders is updated.

                If any members time out, the reverse reconsideration algorithm
                described in Section 6.3.4 SHOULD be performed.

                The participant MUST perform this check at least once per RTCP
                transmission interval.
            */

            bool membersUpdated = false;

            // Senders check.
            RTP_Source[] senders = new RTP_Source[m_pSenders.Count];
            m_pSenders.Values.CopyTo(senders, 0);
            foreach (RTP_Source sender in senders)
            {
                // Sender has not sent RTP data since last two RTCP intervals.
                if (sender.LastRtpPacket.AddMilliseconds(2*m_pRtcpTimer.Interval) < DateTime.Now)
                {
                    m_pSenders.Remove(sender.SSRC);

                    // Mark source "passive".
                    sender.SetActivePassive(false);
                }
            }

            int Td = ComputeRtcpTransmissionInterval(m_pMembers.Count,
                                                     m_pSenders.Count,
                                                     m_Bandwidth*0.25,
                                                     false,
                                                     m_RtcpAvgPacketSize,
                                                     false);

            // Members check.
            foreach (RTP_Source member in Members)
            {
                // Source timed out.
                if (member.LastActivity.AddSeconds(5*Td) < DateTime.Now)
                {
                    m_pMembers.Remove(member.SSRC);
                    // Don't dispose local source, just remove only from members.
                    if (!member.IsLocal)
                    {
                        member.Dispose();
                    }
                    membersUpdated = true;
                }
            }

            if (membersUpdated)
            {
                DoReverseReconsideration();
            }
        }
        /// <summary>
        /// Adds specified source to participant if participant doesn't contain the specified source.
        /// </summary>
        /// <param name="source">RTP source.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>source</b> is null reference.</exception>
        internal void EnsureSource(RTP_Source source)
        {
            if (source == null)
            {
                throw new ArgumentNullException("source");
            }

            if (!m_pSources.Contains(source))
            {
                m_pSources.Add(source);

                OnSourceAdded(source);

                source.Disposing += delegate
                                        {
                                            if (m_pSources.Remove(source))
                                            {
                                                OnSourceRemoved(source);

                                                // If last source removed, the participant is dead, so dispose participant.
                                                if (m_pSources.Count == 0)
                                                {
                                                    OnRemoved();
                                                    Dispose();
                                                }
                                            }
                                        };
            }
        }
        /// <summary>
        /// Raises <b>SourceRemoved</b> event.
        /// </summary>
        /// <param name="source">RTP source.</param>
        private void OnSourceRemoved(RTP_Source source)
        {
            if (source == null)
            {
                throw new ArgumentNullException("source");
            }

            if (SourceRemoved != null)
            {
                SourceRemoved(this, new RTP_SourceEventArgs(source));
            }
        }