Exemple #1
0
        private void FrameReceived(object sender, RtpStream.FrameReceivedEventArgs frea)
        {
            FrameWithTicks frame = new FrameWithTicks(frea.Frame);

            /* A number of considerations caused this design...
             *
             * Due to wanting the most accurate timestamp possible, the frame is stamped with the time
             * (by putting it in the FrameWithTicks structure), and then the ProcessFrame method is
             * called from the ThreadPool.
             *
             * However, this caused problems because processing the frames and saving them to disk were
             * contending for time on the threadpool.  Due to the nature of the design of Archiver, it's
             * important that the frames are processed with higher priority than saving them to disk
             * (this minimizes the overhead of exceptions (cpu utilization) during high-stress periods,
             * causing the frames to be lost with the least amount of hiccups on the server.
             *
             * So here we choose to process the frame on this thread only if we know that it won't get
             * immediate attention on the threadpool.
             */

            int workerThreads, ioThreads;

            ThreadPool.GetAvailableThreads(out workerThreads, out ioThreads);

            if (workerThreads > 0)
            {
                ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessFrame), frame);
            }
            else
            {
                Trace.WriteLine("No threads available.  Processing frame on EventThrower thread.");
                ProcessFrame(frame);
            }
        }
Exemple #2
0
        /// <summary>
        /// add an incoming frame to the buffer...assumes we have room
        /// </summary>
        /// <param name="data">what to add</param>
        public void AddFrame(FrameWithTicks frame)
        {
            lock (this)
            {
                if (!HasRoom(frame.frame.Length))
                {
                    throw new InvalidOperationException("AddFrame called when the buffer does not have enough space available.");
                }

                long ticks = frame.ticks;

                indices[currentIndex].start     = bufferIndex;
                indices[currentIndex].end       = bufferIndex + frame.frame.Length - 1;
                indices[currentIndex].timestamp = ticks;

                // (jeffb) Handle two frames within a 100ns interval (surely this doesn't happen?)
                // (pbristow) This does happen as recording fires up, as there are frames waiting on the queue while the process is "ramping up"
                // NOTE: The next note can be disregarded, as the first 'if' below fixes it (with a poor hack, but one that works, nonetheless.
                // NOTE: this breaks from one BufferRecorder to another.  If the last frame in this buffer and the first frame in the next
                //   buffer arrive simultaneously, the timestamp could be identical.  So incredibly small of a possibility we don't deal w/ it.
                if (currentIndex == 0)
                {
                    indices[currentIndex].timestamp += 1;
                }
                else if (indices[currentIndex].timestamp <= indices[currentIndex - 1].timestamp)
                {
                    indices[currentIndex].timestamp = indices[currentIndex - 1].timestamp + 1;
                }

                Array.Copy(frame.frame.Buffer, frame.frame.Index, buffer, bufferIndex, frame.frame.Length);
                currentIndex++;
                bufferIndex += frame.frame.Length;
            }
        }
Exemple #3
0
        public static void DirectWrite(FrameWithTicks frame, int streamID)
        {
            Index ind = new Index();

            ind.start     = 0;
            ind.end       = frame.frame.Length - 1;
            ind.timestamp = frame.ticks;

            DBHelper.SaveBufferAndIndices(streamID, new Index[] { ind }, 1, (byte[])frame.frame);
        }
Exemple #4
0
        public static void DirectWrite(FrameWithTicks frame, int streamID)
        {
            Trace.WriteLine(String.Format("BufferRecorder::DirectWrite called with frame of size {0} bytes and steamID {1}.",
                                          frame.frame.Length, streamID));

            Index ind = new Index();

            ind.start     = 0;
            ind.end       = frame.frame.Length - 1;
            ind.timestamp = frame.ticks;

            DBHelper.SaveBufferAndIndices(streamID, new Index[] { ind }, 1, (byte[])frame.frame);
        }
Exemple #5
0
        private void ProcessFrame(object argument)
        {
            lock (this)
            {
                FrameWithTicks frame = (FrameWithTicks)argument;

                this.receivedBytes = this.receivedBytes + (long)frame.frame.Length;
                ++receivedFrames;

                // Verify the frame fits in a buffer.  If not, write it to the database directly.
                if (frame.frame.Length < Constants.BufferSize)
                {
                    // if there is no room in the current buffer
                    if (!currentBuffer.HasRoom(frame.frame.Length))
                    {
                        // With bufferAvailable we try to prevent writing the dropped frame event to the EventLog too often
                        //  Incidentally, that means we'll be writing once per every time we use up the buffer pool.  If we
                        //  have a sudden flood of data, that means it'll only get written once or twice, which helps perf.
                        bool bufferAvailable = false;

                        if (currentBuffer.Available)
                        {
                            currentBuffer.EnableWrite();
                            ++writtenBuffers;
                            bufferAvailable = true;
                        }

                        if (!IncrementBuffer())
                        {
                            // Discard the packet by doing nothing with it

                            if (bufferAvailable)
                            {
                                // Warn the user
                                eventLog.WriteEntry("Dropping a frame in StreamRecorder::OnFrameReceived due to no buffers being available.",
                                                    EventLogEntryType.Error, ArchiveServiceEventLog.ID.FrameDropped);
                            }

                            ++droppedFrames;
                            return;
                        }
                    }

                    currentBuffer.AddFrame(frame);
                }
                else
                {
                    Trace.WriteLine("Writing frame directly to disk.  Frame size: " + frame.frame.Length);

                    // Force pending data to be written to disk
                    if (currentBuffer.Available)
                    {
                        currentBuffer.EnableWrite();
                        ++writtenBuffers;
                    }

                    // Get our new buffer
                    IncrementBuffer();

                    // And write this frame directly to disk
                    BufferRecorder.DirectWrite(frame, this.streamID);
                }

                ++writtenFrames;
            }
        }
        private void FrameReceived(object sender, RtpStream.FrameReceivedEventArgs frea)
        {
            FrameWithTicks frame = new FrameWithTicks(frea.Frame);

            /* A number of considerations caused this design...
             * 
             * Due to wanting the most accurate timestamp possible, the frame is stamped with the time
             * (by putting it in the FrameWithTicks structure), and then the ProcessFrame method is
             * called from the ThreadPool.
             * 
             * However, this caused problems because processing the frames and saving them to disk were
             * contending for time on the threadpool.  Due to the nature of the design of Archiver, it's
             * important that the frames are processed with higher priority than saving them to disk
             * (this minimizes the overhead of exceptions (cpu utilization) during high-stress periods,
             * causing the frames to be lost with the least amount of hiccups on the server.
             * 
             * So here we choose to process the frame on this thread only if we know that it won't get
             * immediate attention on the threadpool.
             */

            int workerThreads, ioThreads;
            ThreadPool.GetAvailableThreads(out workerThreads, out ioThreads);

            if( workerThreads > 0 )
            {
                ThreadPool.QueueUserWorkItem( new WaitCallback(ProcessFrame), frame );
            }
            else
            {
                Trace.WriteLine("No threads available.  Processing frame on EventThrower thread.");
                ProcessFrame(frame);
            }
        }
        /// <summary>
        /// add an incoming frame to the buffer...assumes we have room
        /// </summary>
        /// <param name="data">what to add</param>
        public void AddFrame( FrameWithTicks frame )
        {
            lock(this)
            {
                if( !HasRoom( frame.frame.Length ) )
                    throw new InvalidOperationException("AddFrame called when the buffer does not have enough space available.");

                long ticks = frame.ticks;

                indices[currentIndex].start     = bufferIndex;
                indices[currentIndex].end       = bufferIndex + frame.frame.Length-1;
                indices[currentIndex].timestamp = ticks;

                // (jeffb) Handle two frames within a 100ns interval (surely this doesn't happen?)
                // (pbristow) This does happen as recording fires up, as there are frames waiting on the queue while the process is "ramping up"
                // NOTE: The next note can be disregarded, as the first 'if' below fixes it (with a poor hack, but one that works, nonetheless.
                // NOTE: this breaks from one BufferRecorder to another.  If the last frame in this buffer and the first frame in the next
                //   buffer arrive simultaneously, the timestamp could be identical.  So incredibly small of a possibility we don't deal w/ it.
                if ( currentIndex == 0 )
                    indices[currentIndex].timestamp += 1;
                else if ( indices[currentIndex].timestamp <= indices[currentIndex-1].timestamp )
                    indices[currentIndex].timestamp = indices[currentIndex-1].timestamp +1;

                Array.Copy(frame.frame.Buffer, frame.frame.Index, buffer, bufferIndex, frame.frame.Length);
                currentIndex++;
                bufferIndex += frame.frame.Length;
            }
        }
        public static void DirectWrite( FrameWithTicks frame, int streamID )
        {
            Trace.WriteLine(String.Format("BufferRecorder::DirectWrite called with frame of size {0} bytes and steamID {1}.",
                frame.frame.Length, streamID));

            Index ind = new Index();
            ind.start = 0;
            ind.end = frame.frame.Length-1;
            ind.timestamp = frame.ticks;

            DBHelper.SaveBufferAndIndices(streamID, new Index[]{ind}, 1, (byte[])frame.frame);
        }
Exemple #9
0
        public static void DirectWrite( FrameWithTicks frame, int streamID )
        {
            Index ind = new Index();
            ind.start = 0;
            ind.end = frame.frame.Length-1;
            ind.timestamp = frame.ticks;

            DBHelper.SaveBufferAndIndices(streamID, new Index[]{ind}, 1, (byte[])frame.frame);
        }