package audio import ( "errors" "testing" "github.com/pion/rtp" ) func pkt(seq uint16) *rtp.Packet { return &rtp.Packet{ Header: rtp.Header{SequenceNumber: seq, PayloadType: opusPayloadType}, Payload: []byte{0x00}, } } func TestPlayoutLateDrop(t *testing.T) { p := NewPlayout(2) p.Push(pkt(500)) p.Push(pkt(501)) // Drain to set the playout head past 500. if _, _, err := p.PopOrSkip(); err != nil { t.Fatalf("first pop: %v", err) } if _, _, err := p.PopOrSkip(); err != nil { t.Fatalf("second pop: %v", err) } // A late packet with seq 499 must be dropped (not block, not surface // later). p.Push(pkt(499)) if _, _, err := p.PopOrSkip(); !errors.Is(err, ErrEmpty) { t.Fatalf("late packet should not have been buffered; got err=%v", err) } } func TestPlayoutSkipAhead(t *testing.T) { p := NewPlayout(2) // Push 600, 601 to prime, then drain so playoutHead = 602. p.Push(pkt(600)) p.Push(pkt(601)) if _, _, err := p.PopOrSkip(); err != nil { t.Fatalf("first pop: %v", err) } if _, _, err := p.PopOrSkip(); err != nil { t.Fatalf("second pop: %v", err) } // Now skip seq 602, 603; deliver 604, 605. p.Push(pkt(604)) p.Push(pkt(605)) got, gap, err := p.PopOrSkip() if err != nil { t.Fatalf("skip-ahead pop: %v", err) } if got.SequenceNumber != 604 { t.Errorf("got seq=%d, want 604", got.SequenceNumber) } if gap != 2 { t.Errorf("got gap=%d, want 2 (skipped 602, 603)", gap) } // Next pop should be 605 with no gap. got, gap, err = p.PopOrSkip() if err != nil { t.Fatalf("follow-up pop: %v", err) } if got.SequenceNumber != 605 { t.Errorf("got seq=%d, want 605", got.SequenceNumber) } if gap != 0 { t.Errorf("follow-up gap=%d, want 0", gap) } } func TestPlayoutHardCapTrim(t *testing.T) { p := NewPlayout(2) p.MaxDepth = 10 p.TargetDepth = 3 // Push one past the ceiling; the crossing push trims the oldest back to // TargetDepth in one shot. for seq := uint16(0); seq <= uint16(p.MaxDepth); seq++ { // seqs 0..10 p.Push(pkt(seq)) } if got := p.Depth(); got != p.TargetDepth { t.Fatalf("after overflow: depth=%d, want %d", got, p.TargetDepth) } // The three survivors are the newest packets (8, 9, 10); the next pop // returns 8, proving the oldest were the ones dropped. got, _, err := p.PopOrSkip() if err != nil { t.Fatalf("pop after trim: %v", err) } if got.SequenceNumber != 8 { t.Errorf("oldest survivor seq=%d, want 8", got.SequenceNumber) } } func TestPlayoutShedOne(t *testing.T) { p := NewPlayout(2) p.TargetDepth = 2 for seq := uint16(0); seq < 5; seq++ { p.Push(pkt(seq)) } // Depth 5, target 2: ShedOne drops the oldest and reports true until depth // reaches the target, then leaves the buffer alone. if !p.ShedOne(p.TargetDepth) || p.Depth() != 4 { t.Fatalf("first shed: dropped=%v depth=%d, want true/4", true, p.Depth()) } if !p.ShedOne(p.TargetDepth) || p.Depth() != 3 { t.Fatalf("second shed: depth=%d, want 3", p.Depth()) } p.ShedOne(p.TargetDepth) // depth 3 -> 2 if shed := p.ShedOne(p.TargetDepth); shed || p.Depth() != 2 { t.Errorf("at target: shed=%v depth=%d, want false/2", shed, p.Depth()) } // Shedding drops from the front: the oldest remaining is seq 3. got, _, err := p.PopOrSkip() if err != nil { t.Fatalf("pop after shed: %v", err) } if got.SequenceNumber != 3 { t.Errorf("oldest survivor seq=%d, want 3", got.SequenceNumber) } } func TestPlayoutSeqWraparound(t *testing.T) { p := NewPlayout(2) // Push packets straddling the uint16 boundary: 65534, 65535, 0, 1. for _, s := range []uint16{65534, 65535, 0, 1} { p.Push(pkt(s)) } // Should pop in correct order despite the wrap. wantOrder := []uint16{65534, 65535, 0, 1} for _, want := range wantOrder { got, gap, err := p.PopOrSkip() if err != nil { t.Fatalf("Pop want=%d: %v", want, err) } if got.SequenceNumber != want { t.Errorf("got seq=%d, want %d", got.SequenceNumber, want) } if gap != 0 { t.Errorf("seq=%d gap=%d, want 0", want, gap) } } }