Beispiel #1
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);
        }