using System;
using System.Collections.Generic;
using System.Threading;
namespace EyeTracking
{
///
/// Handles buffering and processing of eye tracking data with configurable buffer sizes
/// and analysis capabilities for smooth data processing
///
public class EyeTrackingBuffer
{
private readonly Queue _dataBuffer;
private readonly object _bufferLock = new object();
private readonly int _maxBufferSize;
private readonly int _minBufferSize;
private readonly Func, EyeTrackingData> _analyzeChunkData;
private readonly Action _processData;
private readonly Func _canProcess;
///
/// Initializes a new instance of the EyeTrackingBuffer class
///
/// Maximum number of data points to buffer
/// Minimum buffer size before processing begins
/// Function to analyze chunk data and return processed data
/// Action to process the analyzed data
/// Function to check if processing is allowed (optional)
public EyeTrackingBuffer(
int maxBufferSize = 40,
int minBufferSize = 10,
Func, EyeTrackingData> analyzeChunkData = null,
Action processData = null,
Func canProcess = null)
{
_maxBufferSize = maxBufferSize;
_minBufferSize = minBufferSize;
_analyzeChunkData = analyzeChunkData ?? DefaultAnalyzeChunkData;
_processData = processData ?? DefaultProcessData;
_canProcess = canProcess ?? (() => true);
_dataBuffer = new Queue();
}
///
/// Adds new eye tracking data to the buffer and triggers processing if conditions are met
///
/// Eye tracking data to add
public void AddData(EyeTrackingData data)
{
lock (_bufferLock)
{
// Add new data to buffer
_dataBuffer.Enqueue(data);
// Remove oldest data if buffer exceeds maximum size
while (_dataBuffer.Count > _maxBufferSize)
{
_dataBuffer.Dequeue();
}
}
ProcessBufferData();
}
///
/// Processes buffered data if conditions are met
///
public void ProcessBufferData()
{
if (!_canProcess())
return;
bool shouldProcess = false;
int bufferCount;
lock (_bufferLock)
{
bufferCount = _dataBuffer.Count;
shouldProcess = bufferCount >= _minBufferSize;
}
if (shouldProcess)
{
ProcessOneFrameFromBuffer();
}
}
///
/// Processes one frame from the buffer using the configured analysis function
///
private void ProcessOneFrameFromBuffer()
{
EyeTrackingData dataToProcess = null;
List currentBuffer = new List();
lock (_bufferLock)
{
if (_dataBuffer.Count > 0)
{
// Get the oldest data point to process
dataToProcess = _dataBuffer.Dequeue();
// Create a copy of the remaining buffer for analysis
currentBuffer = new List(_dataBuffer);
}
}
if (dataToProcess != null)
{
// Analyze the current buffer context (including the frame we're about to process)
// Add the frame we're processing to the analysis buffer
currentBuffer.Insert(0, dataToProcess);
EyeTrackingData processedData = _analyzeChunkData(currentBuffer);
// Process the analyzed data
_processData(processedData);
}
}
///
/// Clears all buffered data
///
public void Clear()
{
lock (_bufferLock)
{
_dataBuffer.Clear();
}
}
///
/// Gets the current number of items in the buffer
///
public int Count
{
get
{
lock (_bufferLock)
{
return _dataBuffer.Count;
}
}
}
///
/// Default analysis function that returns the first frame unchanged
///
/// List of eye tracking data
/// The first frame from the chunk
private static EyeTrackingData DefaultAnalyzeChunkData(List chunkData)
{
return chunkData.Count > 0 ? chunkData[0] : new EyeTrackingData();
}
///
/// Default process function that does nothing
///
/// Eye tracking data to process
private static void DefaultProcessData(EyeTrackingData data)
{
// Default implementation does nothing
}
}
}