Skip to content

Commit 9d45de5

Browse files
committed
WIP: Use GCC in tests
1 parent f037823 commit 9d45de5

File tree

11 files changed

+226
-162
lines changed

11 files changed

+226
-162
lines changed

gcc/arrival_group_accumulator.go

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,16 @@ package gcc
55

66
import (
77
"time"
8-
9-
"github.com/pion/bwe"
108
)
119

12-
type arrivalGroup []bwe.Packet
10+
type arrivalGroupItem struct {
11+
SequenceNumber uint64
12+
Departure time.Time
13+
Arrival time.Time
14+
Size int
15+
}
16+
17+
type arrivalGroup []arrivalGroupItem
1318

1419
type arrivalGroupAccumulator struct {
1520
next arrivalGroup
@@ -19,39 +24,63 @@ type arrivalGroupAccumulator struct {
1924

2025
func newArrivalGroupAccumulator() *arrivalGroupAccumulator {
2126
return &arrivalGroupAccumulator{
22-
next: make([]bwe.Packet, 0),
27+
next: make([]arrivalGroupItem, 0),
2328
burstInterval: 5 * time.Millisecond,
2429
maxBurstDuration: 100 * time.Millisecond,
2530
}
2631
}
2732

28-
func (a *arrivalGroupAccumulator) onPacketAcked(ack bwe.Packet) arrivalGroup {
33+
func (a *arrivalGroupAccumulator) onPacketAcked(
34+
sequenceNumber uint64,
35+
size int,
36+
departure, arrival time.Time,
37+
) arrivalGroup {
2938
if len(a.next) == 0 {
30-
a.next = append(a.next, ack)
39+
a.next = append(a.next, arrivalGroupItem{
40+
SequenceNumber: sequenceNumber,
41+
Size: size,
42+
Departure: departure,
43+
Arrival: arrival,
44+
})
3145

3246
return nil
3347
}
3448

35-
sendTimeDelta := ack.Departure.Sub(a.next[0].Departure)
49+
sendTimeDelta := departure.Sub(a.next[0].Departure)
3650
if sendTimeDelta < a.burstInterval {
37-
a.next = append(a.next, ack)
51+
a.next = append(a.next, arrivalGroupItem{
52+
SequenceNumber: sequenceNumber,
53+
Size: size,
54+
Departure: departure,
55+
Arrival: arrival,
56+
})
3857

3958
return nil
4059
}
4160

42-
arrivalTimeDeltaLast := ack.Arrival.Sub(a.next[len(a.next)-1].Arrival)
43-
arrivalTimeDeltaFirst := ack.Arrival.Sub(a.next[0].Arrival)
61+
arrivalTimeDeltaLast := arrival.Sub(a.next[len(a.next)-1].Arrival)
62+
arrivalTimeDeltaFirst := arrival.Sub(a.next[0].Arrival)
4463
propagationDelta := arrivalTimeDeltaFirst - sendTimeDelta
4564

4665
if propagationDelta < 0 && arrivalTimeDeltaLast <= a.burstInterval && arrivalTimeDeltaFirst < a.maxBurstDuration {
47-
a.next = append(a.next, ack)
66+
a.next = append(a.next, arrivalGroupItem{
67+
SequenceNumber: sequenceNumber,
68+
Size: size,
69+
Departure: departure,
70+
Arrival: arrival,
71+
})
4872

4973
return nil
5074
}
5175

5276
group := make(arrivalGroup, len(a.next))
5377
copy(group, a.next)
54-
a.next = arrivalGroup{ack}
78+
a.next = arrivalGroup{arrivalGroupItem{
79+
SequenceNumber: sequenceNumber,
80+
Size: size,
81+
Departure: departure,
82+
Arrival: arrival,
83+
}}
5584

5685
return group
5786
}

gcc/arrival_group_accumulator_test.go

Lines changed: 38 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,28 @@ import (
1111
)
1212

1313
func TestArrivalGroupAccumulator(t *testing.T) {
14-
triggerNewGroupElement := Acknowledgment{
14+
type logItem struct {
15+
SequenceNumber uint64
16+
Departure time.Time
17+
Arrival time.Time
18+
}
19+
triggerNewGroupElement := logItem{
1520
Departure: time.Time{}.Add(time.Second),
1621
Arrival: time.Time{}.Add(time.Second),
1722
}
1823
cases := []struct {
1924
name string
20-
log []Acknowledgment
25+
log []logItem
2126
exp []arrivalGroup
2227
}{
2328
{
2429
name: "emptyCreatesNoGroups",
25-
log: []Acknowledgment{},
30+
log: []logItem{},
2631
exp: []arrivalGroup{},
2732
},
2833
{
2934
name: "createsSingleElementGroup",
30-
log: []Acknowledgment{
35+
log: []logItem{
3136
{
3237
Departure: time.Time{},
3338
Arrival: time.Time{}.Add(time.Millisecond),
@@ -45,7 +50,7 @@ func TestArrivalGroupAccumulator(t *testing.T) {
4550
},
4651
{
4752
name: "createsTwoElementGroup",
48-
log: []Acknowledgment{
53+
log: []logItem{
4954
{
5055
Departure: time.Time{},
5156
Arrival: time.Time{}.Add(15 * time.Millisecond),
@@ -69,7 +74,7 @@ func TestArrivalGroupAccumulator(t *testing.T) {
6974
},
7075
{
7176
name: "createsTwoArrivalGroups1",
72-
log: []Acknowledgment{
77+
log: []logItem{
7378
{
7479
Departure: time.Time{},
7580
Arrival: time.Time{}.Add(15 * time.Millisecond),
@@ -105,7 +110,7 @@ func TestArrivalGroupAccumulator(t *testing.T) {
105110
},
106111
{
107112
name: "ignoresOutOfOrderPackets",
108-
log: []Acknowledgment{
113+
log: []logItem{
109114
{
110115
Departure: time.Time{},
111116
Arrival: time.Time{}.Add(15 * time.Millisecond),
@@ -141,65 +146,64 @@ func TestArrivalGroupAccumulator(t *testing.T) {
141146
},
142147
{
143148
name: "newGroupBecauseOfInterDepartureTime",
144-
log: []Acknowledgment{
149+
log: []logItem{
145150
{
146-
SeqNr: 0,
147-
Departure: time.Time{},
148-
Arrival: time.Time{}.Add(4 * time.Millisecond),
151+
SequenceNumber: 0,
152+
Departure: time.Time{},
153+
Arrival: time.Time{}.Add(4 * time.Millisecond),
149154
},
150155
{
151-
SeqNr: 1,
152-
Departure: time.Time{}.Add(3 * time.Millisecond),
153-
Arrival: time.Time{}.Add(4 * time.Millisecond),
156+
SequenceNumber: 1,
157+
Departure: time.Time{}.Add(3 * time.Millisecond),
158+
Arrival: time.Time{}.Add(4 * time.Millisecond),
154159
},
155160
{
156-
SeqNr: 2,
157-
Departure: time.Time{}.Add(6 * time.Millisecond),
158-
Arrival: time.Time{}.Add(10 * time.Millisecond),
161+
SequenceNumber: 2,
162+
Departure: time.Time{}.Add(6 * time.Millisecond),
163+
Arrival: time.Time{}.Add(10 * time.Millisecond),
159164
},
160165
{
161-
SeqNr: 3,
162-
Departure: time.Time{}.Add(9 * time.Millisecond),
163-
Arrival: time.Time{}.Add(10 * time.Millisecond),
166+
SequenceNumber: 3,
167+
Departure: time.Time{}.Add(9 * time.Millisecond),
168+
Arrival: time.Time{}.Add(10 * time.Millisecond),
164169
},
165170
triggerNewGroupElement,
166171
},
167172
exp: []arrivalGroup{
168173
{
169174
{
170-
SeqNr: 0,
171-
Departure: time.Time{},
172-
Arrival: time.Time{}.Add(4 * time.Millisecond),
175+
SequenceNumber: 0,
176+
Departure: time.Time{},
177+
Arrival: time.Time{}.Add(4 * time.Millisecond),
173178
},
174179
{
175-
SeqNr: 1,
176-
Departure: time.Time{}.Add(3 * time.Millisecond),
177-
Arrival: time.Time{}.Add(4 * time.Millisecond),
180+
SequenceNumber: 1,
181+
Departure: time.Time{}.Add(3 * time.Millisecond),
182+
Arrival: time.Time{}.Add(4 * time.Millisecond),
178183
},
179184
},
180185
{
181186
{
182-
SeqNr: 2,
183-
Departure: time.Time{}.Add(6 * time.Millisecond),
184-
Arrival: time.Time{}.Add(10 * time.Millisecond),
187+
SequenceNumber: 2,
188+
Departure: time.Time{}.Add(6 * time.Millisecond),
189+
Arrival: time.Time{}.Add(10 * time.Millisecond),
185190
},
186191
{
187-
SeqNr: 3,
188-
Departure: time.Time{}.Add(9 * time.Millisecond),
189-
Arrival: time.Time{}.Add(10 * time.Millisecond),
192+
SequenceNumber: 3,
193+
Departure: time.Time{}.Add(9 * time.Millisecond),
194+
Arrival: time.Time{}.Add(10 * time.Millisecond),
190195
},
191196
},
192197
},
193198
},
194199
}
195200

196201
for _, tc := range cases {
197-
tc := tc
198202
t.Run(tc.name, func(t *testing.T) {
199203
aga := newArrivalGroupAccumulator()
200204
received := []arrivalGroup{}
201205
for _, ack := range tc.log {
202-
next := aga.onPacketAcked(ack)
206+
next := aga.onPacketAcked(ack.SequenceNumber, 0, ack.Departure, ack.Arrival)
203207
if next != nil {
204208
received = append(received, next)
205209
}

gcc/delay_rate_controller.go

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ package gcc
66
import (
77
"time"
88

9-
"github.com/pion/bwe"
109
"github.com/pion/logging"
1110
)
1211

@@ -21,11 +20,11 @@ type delayRateController struct {
2120
samples int
2221
}
2322

24-
func newDelayRateController(initialRate int, logger logging.LeveledLogger) *delayRateController {
23+
func newDelayRateController(initialRate int) *delayRateController {
2524
return &delayRateController{
26-
log: logger,
25+
log: logging.NewDefaultLoggerFactory().NewLogger("bwe_delay_rate_controller"),
2726
aga: newArrivalGroupAccumulator(),
28-
last: []bwe.Packet{},
27+
last: []arrivalGroupItem{},
2928
kf: newKalmanFilter(),
3029
od: newOveruseDetector(true),
3130
rc: newRateController(initialRate),
@@ -34,8 +33,13 @@ func newDelayRateController(initialRate int, logger logging.LeveledLogger) *dela
3433
}
3534
}
3635

37-
func (c *delayRateController) onPacketAcked(ack bwe.Packet) {
38-
next := c.aga.onPacketAcked(ack)
36+
func (c *delayRateController) onPacketAcked(sequenceNumber uint64, size int, departure, arrival time.Time) {
37+
next := c.aga.onPacketAcked(
38+
sequenceNumber,
39+
size,
40+
departure,
41+
arrival,
42+
)
3943
if next == nil {
4044
return
4145
}
@@ -58,7 +62,7 @@ func (c *delayRateController) onPacketAcked(ack bwe.Packet) {
5862
interGroupDelay := interArrivalTime - interDepartureTime
5963
estimate := c.kf.update(float64(interGroupDelay.Milliseconds()), float64(sizeDelta))
6064
c.samples++
61-
c.latestUsage = c.od.update(ack.Arrival, estimate, c.samples)
65+
c.latestUsage = c.od.update(arrival, estimate, c.samples)
6266
c.last = next
6367
c.log.Tracef(
6468
"ts=%v.%06d, seq=%v, size=%v, interArrivalTime=%v, interDepartureTime=%v, interGroupDelay=%v, estimate=%v, threshold=%v, usage=%v, state=%v", // nolint
@@ -82,8 +86,8 @@ func (c *delayRateController) update(ts time.Time, lastDeliveryRate int, rtt tim
8286

8387
func groupSize(group arrivalGroup) int {
8488
sum := 0
85-
for _, ack := range group {
86-
sum += int(ack.Size)
89+
for _, item := range group {
90+
sum += item.Size
8791
}
8892

8993
return sum

gcc/gcc.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
// SPDX-FileCopyrightText: 2025 The Pion community <https://pion.ly>
2+
// SPDX-License-Identifier: MIT
3+
14
// Package gcc implements a congestion controller based on
25
// https://datatracker.ietf.org/doc/html/draft-ietf-rmcat-gcc-02.
36
package gcc

gcc/send_side_bwe.go

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ package gcc
66
import (
77
"time"
88

9-
"github.com/pion/bwe"
109
"github.com/pion/logging"
1110
)
1211

@@ -39,7 +38,7 @@ func NewSendSideController(initialRate, minRate, maxRate int, opts ...Option) (*
3938
log: logging.NewDefaultLoggerFactory().NewLogger("bwe_send_side_controller"),
4039
dre: newDeliveryRateEstimator(time.Second),
4140
lrc: newLossRateController(initialRate, minRate, maxRate),
42-
drc: newDelayRateController(initialRate, logging.NewDefaultLoggerFactory().NewLogger("bwe_delay_rate_controller")),
41+
drc: newDelayRateController(initialRate),
4342
targetRate: initialRate,
4443
}
4544
for _, opt := range opts {
@@ -51,30 +50,32 @@ func NewSendSideController(initialRate, minRate, maxRate int, opts ...Option) (*
5150
return ssc, nil
5251
}
5352

54-
// OnAcks must be called when new acknowledgments arrive. arrival is the arrival
55-
// time of the feedback, RTT is the last measured RTT and acks is a list of
56-
// Acknowledgments contained in the latest feedback. Packets MUST not be
57-
// acknowledged more than once.
58-
func (c *SendSideController) OnAcks(arrival time.Time, rtt time.Duration, acks []bwe.Packet) int {
59-
if len(acks) == 0 {
60-
return c.targetRate
61-
}
53+
func (c *SendSideController) OnLoss() {
54+
c.lrc.onPacketLost()
55+
}
6256

63-
for _, ack := range acks {
64-
if ack.Arrived {
65-
c.lrc.onPacketAcked()
66-
if !ack.Arrival.IsZero() {
67-
c.dre.onPacketAcked(ack.Arrival, int(ack.Size))
68-
c.drc.onPacketAcked(ack)
69-
}
70-
} else {
71-
c.lrc.onPacketLost()
72-
}
57+
// OnAck must be called when new acknowledgments arrive. Packets MUST not be
58+
// acknowledged more than once.
59+
func (c *SendSideController) OnAck(sequenceNumber uint64, size int, departure, arrival time.Time) {
60+
c.lrc.onPacketAcked()
61+
if !arrival.IsZero() {
62+
c.dre.onPacketAcked(arrival, size)
63+
c.drc.onPacketAcked(
64+
sequenceNumber,
65+
size,
66+
departure,
67+
arrival,
68+
)
7369
}
70+
}
7471

72+
// OnFeedback must be called when a new feedback report arrives. ts is the
73+
// arrival timestamp of the feedback report. rtt is the latest RTT sample. It
74+
// returns the new target rate.
75+
func (c *SendSideController) OnFeedback(ts time.Time, rtt time.Duration) int {
7576
delivered := c.dre.getRate()
7677
lossTarget := c.lrc.update(delivered)
77-
delayTarget := c.drc.update(arrival, delivered, rtt)
78+
delayTarget := c.drc.update(ts, delivered, rtt)
7879
c.targetRate = min(lossTarget, delayTarget)
7980
c.log.Tracef(
8081
"rtt=%v, delivered=%v, lossTarget=%v, delayTarget=%v, target=%v",

go.mod

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ go 1.24
55
require (
66
github.com/pion/interceptor v0.1.41-0.20250918133005-ab70b00249ad
77
github.com/pion/logging v0.2.4
8-
github.com/pion/rtcp v1.2.15
8+
github.com/pion/rtcp v1.2.16-0.20251011202153-8aedb55aecbf
99
github.com/pion/rtp v1.8.23
1010
github.com/pion/transport/v3 v3.0.8
1111
github.com/pion/webrtc/v4 v4.1.4
@@ -32,3 +32,5 @@ require (
3232
golang.org/x/sys v0.30.0 // indirect
3333
gopkg.in/yaml.v3 v3.0.1 // indirect
3434
)
35+
36+
replace github.com/pion/interceptor v0.1.41-0.20250918133005-ab70b00249ad => ../interceptor

0 commit comments

Comments
 (0)