# Anti-Jitter Progress System Implementation ## Overview This document describes the implementation of Stash's anti-jitter mechanisms in NextAV to solve the streaming buffer jitter problem where progress bars jump backward as new data arrives. ## Problem Solved **Before**: The progress bar would jump backward when: - Buffer underruns occurred - Network delays caused time to "catch up" - Raw video time updates were directly reflected in the UI **After**: Smooth, consistent progress that: - Prevents backward jumps beyond a threshold - Throttles updates to prevent excessive re-renders - Allows small backward adjustments for smooth playback - Provides visual buffer state feedback ## Implementation Details ### 1. Custom Hook: `useAntiJitterProgress` **Location**: `src/lib/use-anti-jitter-progress.ts` **Key Features**: - **Jitter Threshold**: 0.5 seconds - maximum allowed backward jump - **Update Throttling**: 100ms minimum between updates - **Progress Reference**: Maintains stable progress state - **Buffer Monitoring**: Tracks actual buffer state **Core Logic**: ```typescript const handleTimeUpdate = () => { if (videoRef.current) { const now = Date.now(); const video = videoRef.current; const rawTime = video.currentTime; const currentProgress = progressRef.current; // Prevent backward jumps beyond threshold if (rawTime < currentProgress - jitterThreshold) { console.log(`[ANTI-JITTER] Blocked backward jump: ${rawTime}s -> ${currentProgress}s`); return; // Block this update } // Throttle updates to prevent excessive re-renders if (now - lastUpdateRef.current < updateThrottle) { return; } // Validate and update progress if (rawTime >= 0 && rawTime <= (duration || Infinity)) { if (rawTime >= currentProgress - 0.1) { // Forward progress or small adjustment progressRef.current = rawTime; setCurrentTime(rawTime); lastUpdateRef.current = now; } } } }; ``` ### 2. Enhanced Progress Bar **Features**: - **Buffer Visualization**: Blue overlay shows buffered content - **Smooth Progress**: Blue bar shows current playback position - **Seek Overlay**: Invisible range input for seeking - **Buffer Status**: Text display of buffered duration **Visual Elements**: ```tsx
{/* Buffer indicator */} {bufferState.buffered > 0 && (
)} {/* Progress indicator */}
{/* Seek input overlay */}
``` ### 3. Anti-Jitter Mechanisms #### A. Backward Jump Prevention - **Threshold**: 0.5 seconds maximum backward jump - **Logic**: Blocks updates that would cause large backward movement - **Benefit**: Prevents jarring progress bar jumps #### B. Update Throttling - **Frequency**: Maximum 10 updates per second (100ms throttle) - **Logic**: Skips updates that come too quickly - **Benefit**: Smoother UI performance, less CPU usage #### C. Small Adjustment Allowance - **Threshold**: 0.1 seconds for small backward adjustments - **Logic**: Allows minor corrections for smooth playback - **Benefit**: Maintains playback quality while preventing large jumps #### D. Progress Reference Management - **State**: Maintains stable progress reference - **Updates**: Only updates when progress is valid - **Reset**: Resets on video source changes ### 4. Buffer State Monitoring **Features**: - **Real-time Tracking**: Monitors `progress` events - **Visual Feedback**: Shows buffered content in progress bar - **Status Display**: Shows buffered duration below progress bar **Implementation**: ```typescript const handleProgress = () => { if (videoRef.current) { const video = videoRef.current; if (video.buffered.length > 0) { const bufferedEnd = video.buffered.end(video.buffered.length - 1); bufferStateRef.current = { buffered: bufferedEnd, lastBufferUpdate: Date.now() }; console.log(`[BUFFER] Buffered to ${bufferedEnd}s`); } } }; ``` ## Usage ### 1. In Video Components ```typescript import { useAntiJitterProgress } from '@/lib/use-anti-jitter-progress'; export default function VideoViewer({ video, isOpen, onClose }) { const videoRef = useRef(null); // Use the anti-jitter progress hook const { currentTime, bufferState, handleTimeUpdate, handleProgress, seekTo, resetProgress } = useAntiJitterProgress(videoRef, duration); // Add event listeners useEffect(() => { if (videoRef.current) { videoRef.current.addEventListener('timeupdate', handleTimeUpdate); videoRef.current.addEventListener('progress', handleProgress); return () => { videoRef.current?.removeEventListener('timeupdate', handleTimeUpdate); videoRef.current?.removeEventListener('progress', handleProgress); }; } }, []); // Handle seeking const handleSeek = (e: React.ChangeEvent) => { const newTime = parseFloat(e.target.value); seekTo(newTime); }; // Reset on video change useEffect(() => { resetProgress(); }, [video]); } ``` ### 2. Enhanced Progress Bar ```tsx {/* Enhanced Progress bar with buffer visualization */}
{/* Buffer indicator */} {bufferState.buffered > 0 && (
)} {/* Progress indicator */}
{/* Seek input overlay */}
{formatTime(currentTime)} {formatTime(duration)}
{/* Buffer status */} {bufferState.buffered > 0 && (
Buffered: {formatTime(bufferState.buffered)}
)}
``` ## Configuration ### Jitter Threshold ```typescript const jitterThreshold = 0.5; // Maximum allowed backward jump in seconds ``` - **Lower values**: More strict, less jitter but potentially choppy - **Higher values**: More lenient, smoother but potential for jumps - **Recommended**: 0.5 seconds (good balance) ### Update Throttle ```typescript const updateThrottle = 100; // Minimum ms between updates ``` - **Lower values**: More responsive but higher CPU usage - **Higher values**: Smoother but less responsive - **Recommended**: 100ms (10 FPS, good balance) ### Small Adjustment Threshold ```typescript if (rawTime >= currentProgress - 0.1) // 0.1 seconds ``` - **Lower values**: Stricter progress validation - **Higher values**: More lenient with small adjustments - **Recommended**: 0.1 seconds (allows smooth playback) ## Testing ### Test Script Run the test script to verify the anti-jitter system: ```bash node test-anti-jitter.mjs ``` ### Test Scenarios 1. **Normal Forward Progress**: All forward updates should pass 2. **Small Backward Adjustment**: Small adjustments should pass 3. **Large Backward Jump**: Large backward jumps should be blocked 4. **Rapid Updates**: Rapid updates should be throttled ## Benefits ### 1. User Experience - **Smooth Progress**: No more jarring backward jumps - **Visual Feedback**: Clear buffer state indication - **Consistent Behavior**: Predictable progress bar movement ### 2. Performance - **Reduced Re-renders**: Throttled updates improve performance - **Stable State**: Progress reference prevents unnecessary updates - **Efficient Monitoring**: Smart event handling ### 3. Reliability - **Jitter Prevention**: Blocks problematic time updates - **Buffer Awareness**: Tracks actual buffered content - **Error Handling**: Graceful fallbacks for edge cases ## Future Enhancements ### 1. Adaptive Thresholds - **Dynamic Jitter Threshold**: Adjust based on video quality - **Network-Aware Throttling**: Adapt to connection speed - **Quality-Based Settings**: Different thresholds for different scenarios ### 2. Advanced Buffer Management - **Predictive Buffering**: Anticipate buffer needs - **Quality Adaptation**: Switch quality based on buffer state - **Network Monitoring**: Track connection health ### 3. Enhanced Visualization - **Buffer Prediction**: Show predicted buffer state - **Quality Indicators**: Visual quality level indicators - **Network Status**: Connection health indicators ## Troubleshooting ### Common Issues #### 1. Progress Bar Not Moving - Check if `handleTimeUpdate` is being called - Verify `jitterThreshold` isn't too restrictive - Ensure video element has valid duration #### 2. Excessive Throttling - Increase `updateThrottle` value - Check for rapid timeupdate events - Verify video source stability #### 3. Buffer Not Showing - Ensure `handleProgress` is attached to `progress` event - Check if video has buffered ranges - Verify buffer state updates ### Debug Logging The system provides comprehensive logging: ``` [ANTI-JITTER] Blocked backward jump: 2s -> 5s [THROTTLE] Skipped update: 50ms < 100ms [BUFFER] Buffered to 10s [SEEK] Seeking to 15s, updated progress reference [PROGRESS] Forward progress: 16s ``` ## Conclusion The anti-jitter progress system successfully implements Stash's approach to solve streaming buffer jitter. By preventing backward jumps, throttling updates, and providing visual feedback, it creates a smooth, professional video playback experience. The system is: - **Configurable**: Easy to adjust thresholds and behavior - **Reusable**: Shared hook for multiple components - **Efficient**: Minimal performance impact - **Reliable**: Handles edge cases gracefully This implementation provides the foundation for professional-grade video streaming without the jittery behavior common in basic implementations.