-
Notifications
You must be signed in to change notification settings - Fork 2
Move GCC rewrite from interceptor to this repo #61
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
a52709f
79f04e7
b0c8904
241f08b
27dddf4
437822b
a95d17c
32ce973
dd4e888
dbc0c6b
5362b62
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| // SPDX-FileCopyrightText: 2025 The Pion community <https://pion.ly> | ||
| // SPDX-License-Identifier: MIT | ||
|
|
||
| package gcc | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "time" | ||
| ) | ||
|
|
||
| // ECN represents the ECN bits of an IP packet header. | ||
| type ECN uint8 | ||
|
|
||
| const ( | ||
| // ECNNonECT signals Non ECN-Capable Transport, Non-ECT. | ||
| // nolint:misspell | ||
| ECNNonECT ECN = iota // 00 | ||
|
|
||
| // ECNECT1 signals ECN Capable Transport, ECT(0). | ||
| // nolint:misspell | ||
| ECNECT1 // 01 | ||
|
|
||
| // ECNECT0 signals ECN Capable Transport, ECT(1). | ||
| // nolint:misspell | ||
| ECNECT0 // 10 | ||
|
|
||
| // ECNCE signals ECN Congestion Encountered, CE. | ||
| // nolint:misspell | ||
| ECNCE // 11 | ||
| ) | ||
|
|
||
| // An Acknowledgment stores send and receive information about a packet. | ||
| type Acknowledgment struct { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps we could move this to a separate package? This would allow us to:
|
||
| SeqNr uint64 | ||
| Size uint16 | ||
| Departure time.Time | ||
| Arrived bool | ||
| Arrival time.Time | ||
| ECN ECN | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there a specific reason we’re avoiding rtcp.ECN? |
||
| } | ||
|
|
||
| func (a Acknowledgment) String() string { | ||
| return fmt.Sprintf("seq=%v, departure=%v, arrival=%v", a.SeqNr, a.Departure, a.Arrival) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| // SPDX-FileCopyrightText: 2025 The Pion community <https://pion.ly> | ||
| // SPDX-License-Identifier: MIT | ||
|
|
||
| package gcc | ||
|
|
||
| import ( | ||
| "time" | ||
| ) | ||
|
|
||
| type arrivalGroup []Acknowledgment | ||
|
|
||
| type arrivalGroupAccumulator struct { | ||
| next arrivalGroup | ||
| burstInterval time.Duration | ||
| maxBurstDuration time.Duration | ||
| } | ||
|
|
||
| func newArrivalGroupAccumulator() *arrivalGroupAccumulator { | ||
| return &arrivalGroupAccumulator{ | ||
| next: make([]Acknowledgment, 0), | ||
| burstInterval: 5 * time.Millisecond, | ||
| maxBurstDuration: 100 * time.Millisecond, | ||
| } | ||
| } | ||
|
|
||
| func (a *arrivalGroupAccumulator) onPacketAcked(ack Acknowledgment) arrivalGroup { | ||
| if len(a.next) == 0 { | ||
| a.next = append(a.next, ack) | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| sendTimeDelta := ack.Departure.Sub(a.next[0].Departure) | ||
| if sendTimeDelta < a.burstInterval { | ||
| a.next = append(a.next, ack) | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| arrivalTimeDeltaLast := ack.Arrival.Sub(a.next[len(a.next)-1].Arrival) | ||
| arrivalTimeDeltaFirst := ack.Arrival.Sub(a.next[0].Arrival) | ||
| propagationDelta := arrivalTimeDeltaFirst - sendTimeDelta | ||
|
|
||
| if propagationDelta < 0 && arrivalTimeDeltaLast <= a.burstInterval && arrivalTimeDeltaFirst < a.maxBurstDuration { | ||
| a.next = append(a.next, ack) | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| group := make(arrivalGroup, len(a.next)) | ||
| copy(group, a.next) | ||
| a.next = arrivalGroup{ack} | ||
|
|
||
| return group | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,210 @@ | ||
| // SPDX-FileCopyrightText: 2025 The Pion community <https://pion.ly> | ||
| // SPDX-License-Identifier: MIT | ||
|
|
||
| package gcc | ||
|
|
||
| import ( | ||
| "testing" | ||
| "time" | ||
|
|
||
| "github.com/stretchr/testify/assert" | ||
| ) | ||
|
|
||
| func TestArrivalGroupAccumulator(t *testing.T) { | ||
| triggerNewGroupElement := Acknowledgment{ | ||
| Departure: time.Time{}.Add(time.Second), | ||
| Arrival: time.Time{}.Add(time.Second), | ||
| } | ||
| cases := []struct { | ||
| name string | ||
| log []Acknowledgment | ||
| exp []arrivalGroup | ||
| }{ | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe add SeqNr to every packet for clarity? |
||
| { | ||
| name: "emptyCreatesNoGroups", | ||
| log: []Acknowledgment{}, | ||
| exp: []arrivalGroup{}, | ||
| }, | ||
| { | ||
| name: "createsSingleElementGroup", | ||
| log: []Acknowledgment{ | ||
| { | ||
| Departure: time.Time{}, | ||
| Arrival: time.Time{}.Add(time.Millisecond), | ||
| }, | ||
| triggerNewGroupElement, | ||
| }, | ||
| exp: []arrivalGroup{ | ||
| { | ||
| { | ||
| Departure: time.Time{}, | ||
| Arrival: time.Time{}.Add(time.Millisecond), | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| { | ||
| name: "createsTwoElementGroup", | ||
| log: []Acknowledgment{ | ||
| { | ||
| Departure: time.Time{}, | ||
| Arrival: time.Time{}.Add(15 * time.Millisecond), | ||
| }, | ||
| { | ||
| Departure: time.Time{}.Add(3 * time.Millisecond), | ||
| Arrival: time.Time{}.Add(20 * time.Millisecond), | ||
| }, | ||
| triggerNewGroupElement, | ||
| }, | ||
| exp: []arrivalGroup{{ | ||
| { | ||
| Departure: time.Time{}, | ||
| Arrival: time.Time{}.Add(15 * time.Millisecond), | ||
| }, | ||
| { | ||
| Departure: time.Time{}.Add(3 * time.Millisecond), | ||
| Arrival: time.Time{}.Add(20 * time.Millisecond), | ||
| }, | ||
| }}, | ||
| }, | ||
| { | ||
| name: "createsTwoArrivalGroups1", | ||
| log: []Acknowledgment{ | ||
| { | ||
| Departure: time.Time{}, | ||
| Arrival: time.Time{}.Add(15 * time.Millisecond), | ||
| }, | ||
| { | ||
| Departure: time.Time{}.Add(3 * time.Millisecond), | ||
| Arrival: time.Time{}.Add(20 * time.Millisecond), | ||
| }, | ||
| { | ||
| Departure: time.Time{}.Add(9 * time.Millisecond), | ||
| Arrival: time.Time{}.Add(24 * time.Millisecond), | ||
| }, | ||
| triggerNewGroupElement, | ||
| }, | ||
| exp: []arrivalGroup{ | ||
| { | ||
| { | ||
| Departure: time.Time{}, | ||
| Arrival: time.Time{}.Add(15 * time.Millisecond), | ||
| }, | ||
| { | ||
| Departure: time.Time{}.Add(3 * time.Millisecond), | ||
| Arrival: time.Time{}.Add(20 * time.Millisecond), | ||
| }, | ||
| }, | ||
| { | ||
| { | ||
| Departure: time.Time{}.Add(9 * time.Millisecond), | ||
| Arrival: time.Time{}.Add(24 * time.Millisecond), | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| { | ||
| name: "ignoresOutOfOrderPackets", | ||
| log: []Acknowledgment{ | ||
| { | ||
| Departure: time.Time{}, | ||
| Arrival: time.Time{}.Add(15 * time.Millisecond), | ||
| }, | ||
| { | ||
| Departure: time.Time{}.Add(6 * time.Millisecond), | ||
| Arrival: time.Time{}.Add(34 * time.Millisecond), | ||
| }, | ||
| { | ||
| Departure: time.Time{}.Add(8 * time.Millisecond), | ||
| Arrival: time.Time{}.Add(30 * time.Millisecond), | ||
| }, | ||
| triggerNewGroupElement, | ||
| }, | ||
| exp: []arrivalGroup{ | ||
| { | ||
| { | ||
| Departure: time.Time{}, | ||
| Arrival: time.Time{}.Add(15 * time.Millisecond), | ||
| }, | ||
| }, | ||
| { | ||
| { | ||
| Departure: time.Time{}.Add(6 * time.Millisecond), | ||
| Arrival: time.Time{}.Add(34 * time.Millisecond), | ||
| }, | ||
| { | ||
| Departure: time.Time{}.Add(8 * time.Millisecond), | ||
| Arrival: time.Time{}.Add(30 * time.Millisecond), | ||
| }, | ||
| }, | ||
| }, | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you clarify how out-of-order packets are being handled? I notice this packet appears in the expected output, which suggests it's being processed normally rather than ignored. |
||
| }, | ||
| { | ||
| name: "newGroupBecauseOfInterDepartureTime", | ||
| log: []Acknowledgment{ | ||
| { | ||
| SeqNr: 0, | ||
| Departure: time.Time{}, | ||
| Arrival: time.Time{}.Add(4 * time.Millisecond), | ||
| }, | ||
| { | ||
| SeqNr: 1, | ||
| Departure: time.Time{}.Add(3 * time.Millisecond), | ||
| Arrival: time.Time{}.Add(4 * time.Millisecond), | ||
| }, | ||
| { | ||
| SeqNr: 2, | ||
| Departure: time.Time{}.Add(6 * time.Millisecond), | ||
| Arrival: time.Time{}.Add(10 * time.Millisecond), | ||
| }, | ||
| { | ||
| SeqNr: 3, | ||
| Departure: time.Time{}.Add(9 * time.Millisecond), | ||
| Arrival: time.Time{}.Add(10 * time.Millisecond), | ||
| }, | ||
| triggerNewGroupElement, | ||
| }, | ||
| exp: []arrivalGroup{ | ||
| { | ||
| { | ||
| SeqNr: 0, | ||
| Departure: time.Time{}, | ||
| Arrival: time.Time{}.Add(4 * time.Millisecond), | ||
| }, | ||
| { | ||
| SeqNr: 1, | ||
| Departure: time.Time{}.Add(3 * time.Millisecond), | ||
| Arrival: time.Time{}.Add(4 * time.Millisecond), | ||
| }, | ||
| }, | ||
| { | ||
| { | ||
| SeqNr: 2, | ||
| Departure: time.Time{}.Add(6 * time.Millisecond), | ||
| Arrival: time.Time{}.Add(10 * time.Millisecond), | ||
| }, | ||
| { | ||
| SeqNr: 3, | ||
| Departure: time.Time{}.Add(9 * time.Millisecond), | ||
| Arrival: time.Time{}.Add(10 * time.Millisecond), | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are there any tests that cover adding extra packets in case of a burst? It seems for me like all tests cut groups because of large Departure interval. |
||
| } | ||
|
|
||
| for _, tc := range cases { | ||
| tc := tc | ||
| t.Run(tc.name, func(t *testing.T) { | ||
| aga := newArrivalGroupAccumulator() | ||
| received := []arrivalGroup{} | ||
| for _, ack := range tc.log { | ||
| next := aga.onPacketAcked(ack) | ||
| if next != nil { | ||
| received = append(received, next) | ||
| } | ||
| } | ||
| assert.Equal(t, tc.exp, received) | ||
| }) | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.