11use crate :: rtp:: RtpPacket ;
22use pulsebeam_runtime:: collections:: ring:: RingBuffer ;
33use str0m:: rtp:: SeqNo ;
4+ use tokio:: time:: Instant ;
45
56const KEYFRAME_BUFFER_CAPACITY : usize = 256 ;
67
@@ -32,7 +33,7 @@ pub struct KeyframeBuffer {
3233 ring : RingBuffer < RtpPacket > ,
3334 state : State ,
3435 /// The sequence number of the keyframe that we are currently buffering or draining.
35- keyframe_start_seq : Option < SeqNo > ,
36+ keyframe_segment : Option < ( SeqNo , Instant ) > ,
3637 /// The next sequence number we expect to pop. This is used to handle out-of-order
3738 /// packets and to detect and skip gaps.
3839 next_pop_seq : Option < SeqNo > ,
@@ -49,14 +50,19 @@ impl KeyframeBuffer {
4950 Self {
5051 ring : RingBuffer :: new ( KEYFRAME_BUFFER_CAPACITY ) ,
5152 state : State :: Waiting ,
52- keyframe_start_seq : None ,
53+ keyframe_segment : None ,
5354 next_pop_seq : None ,
5455 }
5556 }
5657
5758 /// Returns `true` if a keyframe has been received and the buffer is ready to be drained.
58- pub fn is_ready ( & self ) -> bool {
59- self . state == State :: Buffering || self . state == State :: Draining
59+ pub fn is_ready ( & self , target_playout : Instant ) -> bool {
60+ self . state == State :: Buffering
61+ && self
62+ . keyframe_segment
63+ . map ( |s| s. 1 >= target_playout)
64+ . unwrap_or_default ( )
65+ || self . state == State :: Draining
6066 }
6167
6268 /// Adds an RTP packet to the buffer, applying state-specific logic.
@@ -65,12 +71,15 @@ impl KeyframeBuffer {
6571 // A new keyframe has arrived. We must handle it based on our current state.
6672 match self . state {
6773 State :: Waiting | State :: Buffering => {
68- // If we were waiting for a keyframe, or buffering an old one that
69- // the consumer hasn't started reading yet, we reset to this new keyframe.
70- self . ring . advance_tail_to ( * pkt. seq_no ) ; // Evict any older packets.
71- self . keyframe_start_seq = Some ( pkt. seq_no ) ;
72- self . next_pop_seq = Some ( pkt. seq_no ) ;
73- self . state = State :: Buffering ;
74+ if * pkt. seq_no > self . ring . head ( ) {
75+ // If we were waiting for a keyframe, or buffering an old one that
76+ // the consumer hasn't started reading yet, we reset to this new keyframe.
77+ self . ring . advance_tail_to ( * pkt. seq_no ) ; // Evict any older packets.
78+ self . keyframe_segment
79+ . replace ( ( pkt. seq_no , pkt. playout_time ) ) ;
80+ self . next_pop_seq = Some ( pkt. seq_no ) ;
81+ self . state = State :: Buffering ;
82+ }
7483 }
7584 State :: Draining => {
7685 // We are already draining a keyframe. We will buffer this new one,
@@ -113,8 +122,8 @@ impl KeyframeBuffer {
113122 let mut next_seq = self . next_pop_seq ?;
114123
115124 // Search for the next available packet, starting from `next_pop_seq`.
116- // We limit the search to the buffer's capacity to prevent infinite loops.
117- for _ in 0 ..KEYFRAME_BUFFER_CAPACITY {
125+ // We limit the search to the buffer's len to prevent infinite loops.
126+ for _ in 0 ..self . ring . len ( ) {
118127 if let Some ( pkt) = self . ring . remove ( * next_seq) {
119128 // Found the next packet. Update our expected sequence and return it.
120129 self . next_pop_seq = Some ( next_seq. wrapping_add ( 1 ) . into ( ) ) ;
0 commit comments