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) { 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); }
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); }
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); }
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); }