Exemplo n.º 1
0
        //
        // If data is collected from ConferenceRecorder, or some other class,
        // add an overloaded AddInstanceForCollection method here.
        //
        // Note: You could, if you wanted, make AddInstanceForCollection accept an object,
        // but that would be less performant (and this is a *Performance*Counter... :)
        //

        /// <summary>
        /// Remove an instance from the set of classes on which data is collected.
        /// </summary>
        internal void RemoveInstanceForCollection(BufferPlayer ss)
        {
            lock (buffers)
            {
                if (buffers.Contains(ss))
                {
                    buffers.Remove(ss);
                }
            }
        }
Exemplo n.º 2
0
 /// <summary>
 /// Accepts an instance of a class on which data is collected for this performance counter category.
 /// </summary>
 internal void AddInstanceForCollection(BufferPlayer ss)
 {
     lock (buffers)
     {
         if (!buffers.Contains(ss))
         {
             buffers.Add(ss);
         }
     }
 }
Exemplo n.º 3
0
        /// <summary>
        /// Skips this stream to a given time point, repopulating or adjusting buffers as necessary.
        /// </summary>
        public void JumpTo(long timeToJumpTo)
        {
            // We may need to "restart" after this jump, so don't pretend to be stopped:
            this.currentStreamEnded = false;

            // Find out if any of the buffers contain this time point
            int usefulBuffer = -1;

            for (int cnt = 0; cnt < buffers.Length; ++cnt)
            {
                BufferPlayer buffer = buffers[0];
                if (!buffer.Populating)  // If the buffer is populating, we can't read Ticks from it
                {
                    if (buffer.FirstTick <= timeToJumpTo && timeToJumpTo <= buffer.LastTick)
                    {
                        usefulBuffer = cnt;
                        break;
                    }
                }
            }

            // Setup the active buffer
            if (usefulBuffer != -1)
            {
                this.activeBufferIndex = usefulBuffer;
                this.activeBuffer      = buffers[usefulBuffer];

                this.activeBuffer.JumpToPointInBuffer(timeToJumpTo);
            }
            else
            {
                // do this synchronously so that we can populate the next buffer
                this.activeBuffer.Populate(timeToJumpTo);
            }

            // See if we need to dispose our sender because it's not in use
            //  Double the SenderCreationLeadTime, as we don't want to dispose a sender just to create a new one momentarily
            if (timeToJumpTo < this.firstStreamTicks - 2 * Constants.SenderCreationLeadTime)
            {
                DisposeSender();
            }

            // Make sure we have at least one other buffer with good data in it
            int          newBufferIndex = (activeBufferIndex + 1) % Constants.BuffersPerStream;
            BufferPlayer newBuffer      = buffers[newBufferIndex];

            newBuffer.EnablePopulation(activeBuffer.LastTick + 1, true);
        }
Exemplo n.º 4
0
        /// <summary>
        /// get details of the stream...raw data and start tiume etc
        /// set up the stream senders associated with us. we have n, one active and the rest acting as buffers
        /// </summary>
        public StreamPlayer(RtpSession session, int newStreamID, ConferencePlayerPC cppc)
        {
            int maxFrameSize, maxFrameCount, maxBufferSize;

            // This occasionally throws due to bad data.  Let ConferencePlayer handle it.
            DBHelper.GetStreamStatistics(newStreamID, out this.firstStreamTicks, out maxFrameSize, out maxFrameCount, out maxBufferSize);

            streamID        = newStreamID;
            totalFramesSent = 0;
            totalBytesSent  = 0;
            totalLateness   = 0;
            buffers         = new BufferPlayer[Constants.BuffersPerStream];
            perfCounter     = cppc;

            string payload;

            DBHelper.GetStreamAndParticipantDetails(streamID, out name, out payload, out cname, out privExtns);
            streamPayload = (PayloadType)Enum.Parse(typeof(PayloadType), payload, true);

            // for delayed buffers (late joiners), we create the rtpSender later
            this.rtpSession = session;

            Trace.WriteLine(string.Format(CultureInfo.CurrentCulture,
                                          "Playing back stream: {0}; payload: {1}; name: {2} : {3}", streamID, streamPayload, cname, name));

            // buffer n buffers worth of data
            long startingTick = this.firstStreamTicks;

            for (int i = 0; i < buffers.Length; i++)
            {
                buffers[i] = new BufferPlayer(streamID, maxFrameSize, maxFrameCount, maxBufferSize);
                buffers[i].Populate(startingTick);
                startingTick = buffers[i].LastTick + 1;

                perfCounter.AddInstanceForCollection(buffers[i]);
            }

            // first stream is initially active
            activeBufferIndex = 0;
            activeBuffer      = buffers[activeBufferIndex];
        }
Exemplo n.º 5
0
        /// <summary>
        /// get details of the stream...raw data and start tiume etc
        /// set up the stream senders associated with us. we have n, one active and the rest acting as buffers
        /// </summary>
        public StreamPlayer( RtpSession session, int newStreamID, ConferencePlayerPC cppc)
        {
            int maxFrameSize, maxFrameCount, maxBufferSize;

            // This occasionally throws due to bad data.  Let ConferencePlayer handle it.
            DBHelper.GetStreamStatistics( newStreamID, out this.firstStreamTicks, out maxFrameSize, out maxFrameCount, out maxBufferSize);

            streamID = newStreamID;
            totalFramesSent = 0;
            totalBytesSent = 0;
            totalLateness = 0;
            buffers = new BufferPlayer[Constants.BuffersPerStream];
            perfCounter = cppc;

            string payload;
            DBHelper.GetStreamAndParticipantDetails( streamID, out name, out payload, out cname, out privExtns );
            streamPayload = (PayloadType)Enum.Parse( typeof(PayloadType), payload, true );

            // for delayed buffers (late joiners), we create the rtpSender later
            this.rtpSession = session;

            Trace.WriteLine("Playing back stream: "+streamID+"; payload: "+streamPayload+"; name: "+ (cname + " : " +name));

            // buffer n buffers worth of data
            long startingTick = this.firstStreamTicks;
            for ( int i = 0; i < buffers.Length; i++)
            {
                buffers[i] = new BufferPlayer( streamID, maxFrameSize, maxFrameCount, maxBufferSize);
                buffers[i].Populate( startingTick );
                startingTick = buffers[i].LastTick + 1;

                perfCounter.AddInstanceForCollection(buffers[i]);
            }

            // first stream is initially active
            activeBufferIndex = 0;
            activeBuffer = buffers[activeBufferIndex];
        }
Exemplo n.º 6
0
        /// <summary>
        /// Sends all of the frames this stream needs to send by the given time boundary.
        /// Also calls populate on the underlying buffer as necessary
        /// </summary>
        /// <returns>the time of the next frame to be sent, in ticks</returns>
        public long OnWakeUp(long timeBoundary)
        {
            if( this.currentStreamEnded )
                return long.MaxValue;

            #if TIMING
            long startTimer, takenTime;
            #endif

            // We must return the time until the next frame.  Keep up with it via this variable.
            long timeUntilFrame = 0;

            // Allowing the rtpSender to be created late allows the playback to properly replicate the situation seen
            // during recording.  "Late joiner" support, if you will.  This also deals with the underlying 500ms delay
            // implanted into RtpSession.CreateRtpSender.

            if( rtpSender != null )
            {
            #if TIMING
                startTimer = DateTime.Now.Ticks;
            #endif

                #region Send Frames
                if( !activeBuffer.Populating && !activeBuffer.Empty )
                {
                    if( this.outOfDataLoggedFlag )
                        this.outOfDataLoggedFlag = false;

                    totalFramesSent += activeBuffer.SendFrames( rtpSender, timeBoundary, out timeUntilFrame, ref totalBytesSent, ref totalLateness );
                }
                #endregion

            #if TIMING
                takenTime = DateTime.Now.Ticks - startTimer;
                if( takenTime > Constants.TicksSpent )
                    Trace.WriteLine("TIMING: TIME WASTED SENDING FRAMES: "+(takenTime / Constants.TicksPerMs)+" ms");

                startTimer = DateTime.Now.Ticks;
            #endif

                #region Empty Buffer
                if( activeBuffer.Empty )
                {
                    if( !activeBuffer.EndOfStream ) // not the end of the stream, so we go get new data to play out
                    {
                        // guaranteed atomic
                        BufferPlayer oldBuffer = activeBuffer;

                        // Get the next buffer
                        int newBufferIndex = ( activeBufferIndex+1 ) % Constants.BuffersPerStream;
                        BufferPlayer newBuffer = buffers[newBufferIndex];

                        if ( !newBuffer.Populating ) // we can't enable population on the old buffer until we can get the 'LastTick' from the new buffer
                        {
                            if( !newBuffer.EndOfStream ) // if we're at the end of the stream, don't enable population on the old buffer
                            {
                                // Broken here so we only work with 2 buffers
                                oldBuffer.EnablePopulation( newBuffer.LastTick + 1 );
                            }
                        }
                        else // we're in a performance rut and have run out of data
                        {
                            // the "outOfDataLoggedFlag" prevents us from event-logging too much
                            if( !outOfDataLoggedFlag )
                            {
                                // The database can't keep up; both buffers are empty!
                                eventLog.WriteEntry("StreamPlayer::OnWakeUp reached and no data in buffers! ID: " + streamID, EventLogEntryType.Warning,
                                    ArchiveServiceEventLog.ID.EmptyBuffersInPlayback);

                                this.emptyErrors++;
                                this.outOfDataLoggedFlag = true;
                            }
                        }

                        timeUntilFrame = 0; // we need to come back quick to see when the first frame is in the next buffer

                        // save the "new" buffer as the "current" one
                        activeBufferIndex = newBufferIndex;
                        activeBuffer = buffers[newBufferIndex];
                    }
                    else // end of stream
                    {
                        if( !currentStreamEnded )
                        {
                            Trace.WriteLine("End of stream reached.  Stopping sending this stream.  ID: " + streamID);

                            currentStreamEnded = true;

                            DisposeSender();

                            ThreadPool.QueueUserWorkItem(new WaitCallback(FireEndOfStream), this);
                        }

                        timeUntilFrame = long.MaxValue;
                    }
                }
                #endregion

            #if TIMING
                takenTime = DateTime.Now.Ticks - startTimer;
                if( takenTime > Constants.TicksSpent )
                    Trace.WriteLine("TIMING: TIME WASTED ON EMPTY BUFFER: "+(takenTime / Constants.TicksPerMs)+" ms");
            #endif
            }
            else // Sender isn't created yet.  Check if we need to.
            {
            #if TIMING
                startTimer = DateTime.Now.Ticks;
            #endif

                // Pri2: Change this to be compatable with use of the "playback speed" feature.  TimeBoundary is speed-based...
                timeUntilFrame = (firstStreamTicks - timeBoundary);

                #region Sender creation
                if( timeUntilFrame <= Constants.SenderCreationLeadTime ) // <x> ms of "prep time" to get fired up
                {
                    if( !createSenderFired )
                    {
                        createSenderFired = true;
                        Trace.WriteLine("RtpSender being created for stream: "+streamID);
                        ThreadPool.QueueUserWorkItem(new WaitCallback(CreateSender));
                    }
                }
                else
                {
                    timeUntilFrame -= Constants.SenderCreationLeadTime;
                }
                #endregion

            #if TIMING
                takenTime = DateTime.Now.Ticks - startTimer;
                if( takenTime > Constants.TicksSpent )
                    Trace.WriteLine("TIMING: TIME WASTED CREATING SENDER: "+(takenTime / Constants.TicksPerMs)+" ms");
            #endif
            }

            return timeUntilFrame;
        }
Exemplo n.º 7
0
        /// <summary>
        /// Skips this stream to a given time point, repopulating or adjusting buffers as necessary.
        /// </summary>
        public void JumpTo(long timeToJumpTo)
        {
            // We may need to "restart" after this jump, so don't pretend to be stopped:
            this.currentStreamEnded = false;

            // Find out if any of the buffers contain this time point
            int usefulBuffer = -1;
            for( int cnt = 0; cnt < buffers.Length; ++cnt )
            {
                BufferPlayer buffer = buffers[0];
                if( !buffer.Populating ) // If the buffer is populating, we can't read Ticks from it
                {
                    if( buffer.FirstTick <= timeToJumpTo && timeToJumpTo <= buffer.LastTick )
                    {
                        usefulBuffer = cnt;
                        break;
                    }
                }
            }

            // Setup the active buffer
            if( usefulBuffer != -1 )
            {
                this.activeBufferIndex = usefulBuffer;
                this.activeBuffer = buffers[usefulBuffer];

                this.activeBuffer.JumpToPointInBuffer (timeToJumpTo);
            }
            else
            {
                // do this synchronously so that we can populate the next buffer
                this.activeBuffer.Populate (timeToJumpTo);
            }

            // See if we need to dispose our sender because it's not in use
            //  Double the SenderCreationLeadTime, as we don't want to dispose a sender just to create a new one momentarily
            if( timeToJumpTo < this.firstStreamTicks - 2*Constants.SenderCreationLeadTime )
            {
                DisposeSender();
            }

            // Make sure we have at least one other buffer with good data in it
            int newBufferIndex = (activeBufferIndex+1) % Constants.BuffersPerStream;
            BufferPlayer newBuffer = buffers[newBufferIndex];
            newBuffer.EnablePopulation (activeBuffer.LastTick + 1, true);
        }
Exemplo n.º 8
0
        //
        // If data is collected from ConferenceRecorder, or some other class,
        // add an overloaded AddInstanceForCollection method here.
        //
        // Note: You could, if you wanted, make AddInstanceForCollection accept an object,
        // but that would be less performant (and this is a *Performance*Counter... :)
        //

        /// <summary>
        /// Remove an instance from the set of classes on which data is collected.
        /// </summary>
        internal void RemoveInstanceForCollection(BufferPlayer ss)
        {
            lock(buffers)
            {
                if( buffers.Contains(ss) )
                    buffers.Remove(ss);
            }
        }
Exemplo n.º 9
0
 /// <summary>
 /// Accepts an instance of a class on which data is collected for this performance counter category.
 /// </summary>
 internal void AddInstanceForCollection(BufferPlayer ss)
 {
     lock(buffers)
     {
         if( !buffers.Contains(ss) )
             buffers.Add(ss);
     }
 }
Exemplo n.º 10
0
        /// <summary>
        /// Sends all of the frames this stream needs to send by the given time boundary.
        /// Also calls populate on the underlying buffer as necessary
        /// </summary>
        /// <returns>the time of the next frame to be sent, in ticks</returns>
        public long OnWakeUp(long timeBoundary)
        {
            if (this.currentStreamEnded)
            {
                return(long.MaxValue);
            }

#if TIMING
            long startTimer, takenTime;
#endif

            // We must return the time until the next frame.  Keep up with it via this variable.
            long timeUntilFrame = 0;

            // Allowing the rtpSender to be created late allows the playback to properly replicate the situation seen
            // during recording.  "Late joiner" support, if you will.  This also deals with the underlying 500ms delay
            // implanted into RtpSession.CreateRtpSender.

            if (rtpSender != null)
            {
#if TIMING
                startTimer = DateTime.Now.Ticks;
#endif

                #region Send Frames
                if (!activeBuffer.Populating && !activeBuffer.Empty)
                {
                    if (this.outOfDataLoggedFlag)
                    {
                        this.outOfDataLoggedFlag = false;
                    }

                    totalFramesSent += activeBuffer.SendFrames(rtpSender, timeBoundary, out timeUntilFrame, ref totalBytesSent, ref totalLateness);
                }
                #endregion

#if TIMING
                takenTime = DateTime.Now.Ticks - startTimer;
                if (takenTime > Constants.TicksSpent)
                {
                    Trace.WriteLine("TIMING: TIME WASTED SENDING FRAMES: " + (takenTime / Constants.TicksPerMs) + " ms");
                }

                startTimer = DateTime.Now.Ticks;
#endif

                #region Empty Buffer
                if (activeBuffer.Empty)
                {
                    if (!activeBuffer.EndOfStream)  // not the end of the stream, so we go get new data to play out
                    {
                        // guaranteed atomic
                        BufferPlayer oldBuffer = activeBuffer;

                        // Get the next buffer
                        int          newBufferIndex = (activeBufferIndex + 1) % Constants.BuffersPerStream;
                        BufferPlayer newBuffer      = buffers[newBufferIndex];

                        if (!newBuffer.Populating)      // we can't enable population on the old buffer until we can get the 'LastTick' from the new buffer
                        {
                            if (!newBuffer.EndOfStream) // if we're at the end of the stream, don't enable population on the old buffer
                            {
                                // Broken here so we only work with 2 buffers
                                oldBuffer.EnablePopulation(newBuffer.LastTick + 1);
                            }
                        }
                        else // we're in a performance rut and have run out of data
                        {
                            // the "outOfDataLoggedFlag" prevents us from event-logging too much
                            if (!outOfDataLoggedFlag)
                            {
                                // The database can't keep up; both buffers are empty!
                                eventLog.WriteEntry("StreamPlayer::OnWakeUp reached and no data in buffers! ID: " + streamID, EventLogEntryType.Warning,
                                                    ArchiveServiceEventLog.ID.EmptyBuffersInPlayback);

                                this.emptyErrors++;
                                this.outOfDataLoggedFlag = true;
                            }
                        }

                        timeUntilFrame = 0; // we need to come back quick to see when the first frame is in the next buffer

                        // save the "new" buffer as the "current" one
                        activeBufferIndex = newBufferIndex;
                        activeBuffer      = buffers[newBufferIndex];
                    }
                    else // end of stream
                    {
                        if (!currentStreamEnded)
                        {
                            Trace.WriteLine("End of stream reached.  Stopping sending this stream.  ID: " + streamID);

                            currentStreamEnded = true;

                            DisposeSender();

                            ThreadPool.QueueUserWorkItem(new WaitCallback(FireEndOfStream), this);
                        }

                        timeUntilFrame = long.MaxValue;
                    }
                }
                #endregion

#if TIMING
                takenTime = DateTime.Now.Ticks - startTimer;
                if (takenTime > Constants.TicksSpent)
                {
                    Trace.WriteLine("TIMING: TIME WASTED ON EMPTY BUFFER: " + (takenTime / Constants.TicksPerMs) + " ms");
                }
#endif
            }
            else // Sender isn't created yet.  Check if we need to.
            {
#if TIMING
                startTimer = DateTime.Now.Ticks;
#endif

                // Pri2: Change this to be compatable with use of the "playback speed" feature.  TimeBoundary is speed-based...
                timeUntilFrame = (firstStreamTicks - timeBoundary);

                #region Sender creation
                if (timeUntilFrame <= Constants.SenderCreationLeadTime)  // <x> ms of "prep time" to get fired up
                {
                    if (!createSenderFired)
                    {
                        createSenderFired = true;
                        Trace.WriteLine("RtpSender being created for stream: " + streamID);
                        ThreadPool.QueueUserWorkItem(new WaitCallback(CreateSender));
                    }
                }
                else
                {
                    timeUntilFrame -= Constants.SenderCreationLeadTime;
                }
                #endregion

#if TIMING
                takenTime = DateTime.Now.Ticks - startTimer;
                if (takenTime > Constants.TicksSpent)
                {
                    Trace.WriteLine("TIMING: TIME WASTED CREATING SENDER: " + (takenTime / Constants.TicksPerMs) + " ms");
                }
#endif
            }

            return(timeUntilFrame);
        }