Skip to content

Commit a877af5

Browse files
committed
Add an end-to-end test for the NACK sender.
1 parent fbf79c1 commit a877af5

File tree

1 file changed

+145
-0
lines changed

1 file changed

+145
-0
lines changed

interceptor_test.go

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@ package webrtc
99
//
1010
import (
1111
"context"
12+
"io"
1213
"sync/atomic"
1314
"testing"
1415
"time"
1516

1617
"github.com/pion/interceptor"
1718
mock_interceptor "github.com/pion/interceptor/pkg/mock"
19+
"github.com/pion/rtcp"
1820
"github.com/pion/rtp"
1921
"github.com/pion/transport/v3/test"
2022
"github.com/pion/webrtc/v4/pkg/media"
@@ -284,3 +286,146 @@ func Test_Interceptor_ZeroSSRC(t *testing.T) {
284286
<-probeReceiverCreated
285287
closePairNow(t, offerer, answerer)
286288
}
289+
290+
// TestInterceptorNack is an end-to-end test for the NACK sender.
291+
// It test that:
292+
// - we get a NACK if we negotiated generic NACks;
293+
// - we don't get a NACK if we did not negotiate generick NACKs;
294+
// - the NACK corresponds to the missing packet.
295+
func TestInterceptorNack(t *testing.T) {
296+
const numPackets = 20
297+
to := test.TimeOut(time.Second * 20)
298+
defer to.Stop()
299+
300+
t.Run("Nack", func(t *testing.T) { testInterceptorNack(t, true) })
301+
t.Run("NoNack", func(t *testing.T) { testInterceptorNack(t, false) })
302+
}
303+
304+
func testInterceptorNack(t *testing.T, requestNack bool) {
305+
ir := interceptor.Registry{}
306+
m := MediaEngine{}
307+
var capability []RTCPFeedback
308+
if requestNack {
309+
capability = append(capability, RTCPFeedback{"nack", ""})
310+
}
311+
err := m.RegisterCodec(
312+
RTPCodecParameters{
313+
RTPCodecCapability: RTPCodecCapability{
314+
"video/VP8", 90000, 0,
315+
"",
316+
capability,
317+
},
318+
PayloadType: 96,
319+
},
320+
RTPCodecTypeVideo,
321+
)
322+
assert.NoError(t, err)
323+
api := NewAPI(
324+
WithMediaEngine(&m),
325+
WithInterceptorRegistry(&ir),
326+
)
327+
328+
pc1, err := api.NewPeerConnection(Configuration{})
329+
assert.NoError(t, err)
330+
defer pc1.Close()
331+
332+
track1, err := NewTrackLocalStaticRTP(
333+
RTPCodecCapability{MimeType: MimeTypeVP8},
334+
"video", "pion",
335+
)
336+
assert.NoError(t, err)
337+
sender, err := pc1.AddTrack(track1)
338+
assert.NoError(t, err)
339+
340+
pc2, err := NewPeerConnection(Configuration{})
341+
assert.NoError(t, err)
342+
defer pc2.Close()
343+
344+
offer, err := pc1.CreateOffer(nil)
345+
assert.NoError(t, err)
346+
err = pc1.SetLocalDescription(offer)
347+
assert.NoError(t, err)
348+
<-GatheringCompletePromise(pc1)
349+
350+
err = pc2.SetRemoteDescription(*pc1.LocalDescription())
351+
assert.NoError(t, err)
352+
answer, err := pc2.CreateAnswer(nil)
353+
assert.NoError(t, err)
354+
err = pc2.SetLocalDescription(answer)
355+
assert.NoError(t, err)
356+
<-GatheringCompletePromise(pc2)
357+
358+
err = pc1.SetRemoteDescription(*pc2.LocalDescription())
359+
assert.NoError(t, err)
360+
361+
gotNack := false
362+
go func() {
363+
buf := make([]byte, 1500)
364+
for {
365+
n, _, err := sender.Read(buf)
366+
if err == io.EOF {
367+
break
368+
}
369+
assert.NoError(t, err)
370+
ps, err := rtcp.Unmarshal(buf[:n])
371+
assert.NoError(t, err)
372+
for _, p := range ps {
373+
if pn, ok := p.(*rtcp.TransportLayerNack); ok {
374+
assert.Equal(t, len(pn.Nacks), 1)
375+
assert.Equal(t,
376+
pn.Nacks[0].PacketID, uint16(1),
377+
)
378+
assert.Equal(t,
379+
pn.Nacks[0].LostPackets,
380+
rtcp.PacketBitmap(0),
381+
)
382+
gotNack = true
383+
}
384+
}
385+
}
386+
}()
387+
388+
const numPackets = 20
389+
done := make(chan struct{})
390+
pc2.OnTrack(func(track2 *TrackRemote, receiver *RTPReceiver) {
391+
for i := 0; i < numPackets; i++ {
392+
if i == 1 {
393+
continue
394+
}
395+
p, _, err := track2.ReadRTP()
396+
assert.NoError(t, err)
397+
assert.Equal(t, p.SequenceNumber, uint16(i))
398+
}
399+
done <- struct{}{}
400+
})
401+
402+
go func() {
403+
for i := 0; i < numPackets; i++ {
404+
time.Sleep(20 * time.Millisecond)
405+
if i == 1 {
406+
continue
407+
}
408+
var p rtp.Packet
409+
p.Version = 2
410+
p.Marker = true
411+
p.PayloadType = 96
412+
p.SequenceNumber = uint16(i)
413+
p.Timestamp = uint32(i * 90000 / 50)
414+
p.Payload = []byte{42}
415+
err := track1.WriteRTP(&p)
416+
assert.NoError(t, err)
417+
}
418+
}()
419+
420+
<-done
421+
422+
if requestNack {
423+
if !gotNack {
424+
t.Errorf("Expected to get a NACK, got none")
425+
}
426+
} else {
427+
if gotNack {
428+
t.Errorf("Expected to get no NACK, got one")
429+
}
430+
}
431+
}

0 commit comments

Comments
 (0)