8
8
"math"
9
9
"time"
10
10
11
+ "github.com/pion/interceptor/pkg/jitterbuffer"
11
12
"github.com/pion/rtp"
12
13
"github.com/pion/webrtc/v4/pkg/media"
13
14
)
@@ -16,7 +17,7 @@ import (
16
17
type SampleBuilder struct {
17
18
maxLate uint16 // how many packets to wait until we get a valid Sample
18
19
maxLateTimestamp uint32 // max timestamp between old and new timestamps before dropping packets
19
- buffer [ math . MaxUint16 + 1 ] * rtp. Packet
20
+ buffer * jitterbuffer. JitterBuffer
20
21
preparedSamples [math .MaxUint16 + 1 ]* media.Sample
21
22
22
23
// Interface that allows us to take RTP packets to samples
@@ -60,7 +61,7 @@ type SampleBuilder struct {
60
61
// The depacketizer extracts media samples from RTP packets.
61
62
// Several depacketizers are available in package github.com/pion/rtp/codecs.
62
63
func New (maxLate uint16 , depacketizer rtp.Depacketizer , sampleRate uint32 , opts ... Option ) * SampleBuilder {
63
- s := & SampleBuilder {maxLate : maxLate , depacketizer : depacketizer , sampleRate : sampleRate }
64
+ s := & SampleBuilder {maxLate : maxLate , depacketizer : depacketizer , sampleRate : sampleRate , buffer : jitterbuffer . New ( jitterbuffer . WithMinimumPacketCount ( 1 )) }
64
65
for _ , o := range opts {
65
66
o (s )
66
67
}
@@ -76,7 +77,7 @@ func (s *SampleBuilder) tooOld(location sampleSequenceLocation) bool {
76
77
var foundTail * rtp.Packet
77
78
78
79
for i := location .head ; i != location .tail ; i ++ {
79
- if packet := s .buffer [ i ] ; packet != nil {
80
+ if packet , _ := s .buffer . PeekAtSequence ( i ) ; packet != nil {
80
81
foundHead = packet
81
82
break
82
83
}
@@ -87,7 +88,7 @@ func (s *SampleBuilder) tooOld(location sampleSequenceLocation) bool {
87
88
}
88
89
89
90
for i := location .tail - 1 ; i != location .head ; i -- {
90
- if packet := s .buffer [ i ] ; packet != nil {
91
+ if packet , _ := s .buffer . PeekAtSequence ( i ) ; packet != nil {
91
92
foundTail = packet
92
93
break
93
94
}
@@ -105,16 +106,16 @@ func (s *SampleBuilder) fetchTimestamp(location sampleSequenceLocation) (timesta
105
106
if location .empty () {
106
107
return 0 , false
107
108
}
108
- packet := s .buffer [ location .head ]
109
- if packet == nil {
109
+ packet , err := s .buffer . PeekAtSequence ( location .head )
110
+ if packet == nil || err != nil {
110
111
return 0 , false
111
112
}
112
113
return packet .Timestamp , true
113
114
}
114
115
115
116
func (s * SampleBuilder ) releasePacket (i uint16 ) {
116
117
var p * rtp.Packet
117
- p , s . buffer [ i ] = s .buffer [ i ], nil
118
+ p , _ = s .buffer . PopAtSequence ( i )
118
119
if p != nil && s .packetReleaseHandler != nil {
119
120
s .packetReleaseHandler (p )
120
121
}
@@ -178,7 +179,7 @@ func (s *SampleBuilder) purgeBuffers(flush bool) {
178
179
// Push does not copy the input. If you wish to reuse
179
180
// this memory make sure to copy before calling Push
180
181
func (s * SampleBuilder ) Push (p * rtp.Packet ) {
181
- s .buffer [ p . SequenceNumber ] = p
182
+ s .buffer . Push ( p )
182
183
183
184
switch s .filled .compare (p .SequenceNumber ) {
184
185
case slCompareVoid :
@@ -220,14 +221,19 @@ func (s *SampleBuilder) buildSample(purgingBuffers bool) *media.Sample {
220
221
221
222
var consume sampleSequenceLocation
222
223
223
- for i := s .active .head ; s .buffer [i ] != nil && s .active .compare (i ) != slCompareAfter ; i ++ {
224
- if s .depacketizer .IsPartitionTail (s .buffer [i ].Marker , s .buffer [i ].Payload ) {
224
+ for i := s .active .head ; s .active .compare (i ) != slCompareAfter ; i ++ {
225
+ pkt , err := s .buffer .PeekAtSequence (i )
226
+ if pkt == nil || err != nil {
227
+ break
228
+ }
229
+
230
+ if s .depacketizer .IsPartitionTail (pkt .Marker , pkt .Payload ) {
225
231
consume .head = s .active .head
226
232
consume .tail = i + 1
227
233
break
228
234
}
229
235
headTimestamp , hasData := s .fetchTimestamp (s .active )
230
- if hasData && s . buffer [ i ] .Timestamp != headTimestamp {
236
+ if hasData && pkt .Timestamp != headTimestamp {
231
237
consume .head = s .active .head
232
238
consume .tail = i
233
239
break
@@ -237,8 +243,8 @@ func (s *SampleBuilder) buildSample(purgingBuffers bool) *media.Sample {
237
243
if consume .empty () {
238
244
return nil
239
245
}
240
-
241
- if ! purgingBuffers && s . buffer [ consume . tail ] == nil {
246
+ pkt , _ := s . buffer . PeekAtSequence ( consume . tail )
247
+ if ! purgingBuffers && pkt == nil {
242
248
// wait for the next packet after this set of packets to arrive
243
249
// to ensure at least one post sample timestamp is known
244
250
// (unless we have to release right now)
@@ -250,8 +256,10 @@ func (s *SampleBuilder) buildSample(purgingBuffers bool) *media.Sample {
250
256
251
257
// scan for any packet after the current and use that time stamp as the diff point
252
258
for i := consume .tail ; i < s .active .tail ; i ++ {
253
- if s .buffer [i ] != nil {
254
- afterTimestamp = s .buffer [i ].Timestamp
259
+ pkt , _ = s .buffer .PeekAtSequence (i )
260
+
261
+ if pkt != nil {
262
+ afterTimestamp = pkt .Timestamp
255
263
break
256
264
}
257
265
}
@@ -261,10 +269,11 @@ func (s *SampleBuilder) buildSample(purgingBuffers bool) *media.Sample {
261
269
262
270
// prior to decoding all the packets, check if this packet
263
271
// would end being disposed anyway
264
- if ! s .depacketizer .IsPartitionHead (s .buffer [consume .head ].Payload ) {
272
+ pkt , err := s .buffer .PeekAtSequence (consume .head )
273
+ if err == nil && ! s .depacketizer .IsPartitionHead (pkt .Payload ) {
265
274
isPadding := false
266
275
for i := consume .head ; i != consume .tail ; i ++ {
267
- if s .lastSampleTimestamp != nil && * s .lastSampleTimestamp == s . buffer [ i ]. Timestamp && len (s . buffer [ i ] .Payload ) == 0 {
276
+ if s .lastSampleTimestamp != nil && * s .lastSampleTimestamp == pkt . Timestamp && len (pkt .Payload ) == 0 {
268
277
isPadding = true
269
278
}
270
279
}
@@ -282,16 +291,22 @@ func (s *SampleBuilder) buildSample(purgingBuffers bool) *media.Sample {
282
291
var metadata interface {}
283
292
var rtpHeaders []* rtp.Header
284
293
for i := consume .head ; i != consume .tail ; i ++ {
285
- p , err := s .depacketizer .Unmarshal (s .buffer [i ].Payload )
294
+ pkt , err := s .buffer .PeekAtSequence (i )
295
+ if err != nil {
296
+ return nil
297
+ }
298
+ p , err := s .depacketizer .Unmarshal (pkt .Payload )
286
299
if err != nil {
287
300
return nil
288
301
}
289
302
if i == consume .head && s .packetHeadHandler != nil {
290
303
metadata = s .packetHeadHandler (s .depacketizer )
291
304
}
292
305
if s .returnRTPHeaders {
293
- h := s .buffer [i ].Header .Clone ()
294
- rtpHeaders = append (rtpHeaders , & h )
306
+ if packet , _ := s .buffer .PeekAtSequence (i ); packet != nil {
307
+ h := pkt .Header .Clone ()
308
+ rtpHeaders = append (rtpHeaders , & h )
309
+ }
295
310
}
296
311
297
312
data = append (data , p ... )
@@ -389,3 +404,11 @@ func WithRTPHeaders(enable bool) Option {
389
404
o .returnRTPHeaders = enable
390
405
}
391
406
}
407
+
408
+ // WithJitterBufferMinimumLength sets the minimum number of packets which must first
409
+ // be received before starting any playback
410
+ func WithJitterBufferMinimumLength (length uint16 ) Option {
411
+ return func (o * SampleBuilder ) {
412
+ o .buffer = jitterbuffer .New (jitterbuffer .WithMinimumPacketCount (length ))
413
+ }
414
+ }
0 commit comments