Skip to content

Commit 82bca40

Browse files
nithu1991Sean-Der
authored andcommitted
Use SyncPool for NACKs with distinct SSRC
NACK storage would use a sync.Pool to reduce memory pressure. The new distinict SSRC feature did not properly use this pool. This change updates the RTPBuffer to use it for both paths. Fixes #281
1 parent d34a3c5 commit 82bca40

File tree

2 files changed

+139
-14
lines changed

2 files changed

+139
-14
lines changed

internal/rtpbuffer/packet_factory.go

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import (
1111
"github.com/pion/rtp"
1212
)
1313

14+
const rtxSsrcByteLength = 2
15+
1416
// PacketFactory allows custom logic around the handle of RTP Packets before they added to the RTPBuffer.
1517
// The NoOpPacketFactory doesn't copy packets, while the RetainablePacket will take a copy before adding
1618
type PacketFactory interface {
@@ -68,32 +70,38 @@ func (m *PacketFactoryCopy) NewPacket(header *rtp.Header, payload []byte, rtxSsr
6870
if !ok {
6971
return nil, errFailedToCastPayloadPool
7072
}
71-
72-
size := copy(*p.buffer, payload)
73-
p.payload = (*p.buffer)[:size]
73+
if rtxSsrc != 0 && rtxPayloadType != 0 {
74+
size := copy((*p.buffer)[rtxSsrcByteLength:], payload)
75+
p.payload = (*p.buffer)[:size+rtxSsrcByteLength]
76+
} else {
77+
size := copy(*p.buffer, payload)
78+
p.payload = (*p.buffer)[:size]
79+
}
7480
}
7581

7682
if rtxSsrc != 0 && rtxPayloadType != 0 {
77-
// Store the original sequence number and rewrite the sequence number.
78-
originalSequenceNumber := p.header.SequenceNumber
79-
p.header.SequenceNumber = m.rtxSequencer.NextSequenceNumber()
83+
if payload == nil {
84+
p.buffer, ok = m.payloadPool.Get().(*[]byte)
85+
if !ok {
86+
return nil, errFailedToCastPayloadPool
87+
}
88+
p.payload = (*p.buffer)[:rtxSsrcByteLength]
89+
}
90+
// Write the original sequence number at the beginning of the payload.
91+
binary.BigEndian.PutUint16(p.payload, p.header.SequenceNumber)
8092

8193
// Rewrite the SSRC.
8294
p.header.SSRC = rtxSsrc
8395
// Rewrite the payload type.
8496
p.header.PayloadType = rtxPayloadType
85-
97+
// Rewrite the sequence number.
98+
p.header.SequenceNumber = m.rtxSequencer.NextSequenceNumber()
8699
// Remove padding if present.
87-
paddingLength := 0
88100
if p.header.Padding && p.payload != nil && len(p.payload) > 0 {
89-
paddingLength = int(p.payload[len(p.payload)-1])
101+
paddingLength := int(p.payload[len(p.payload)-1])
90102
p.header.Padding = false
103+
p.payload = (*p.buffer)[:len(p.payload)-paddingLength]
91104
}
92-
93-
// Write the original sequence number at the beginning of the payload.
94-
payload := make([]byte, 2)
95-
binary.BigEndian.PutUint16(payload, originalSequenceNumber)
96-
p.payload = append(payload, p.payload[:len(p.payload)-paddingLength]...)
97105
}
98106

99107
return p, nil

internal/rtpbuffer/rtpbuffer_test.go

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,66 @@ func TestRTPBuffer(t *testing.T) {
7070
}
7171
}
7272

73+
func TestRTPBuffer_WithRTX(t *testing.T) {
74+
pm := NewPacketFactoryCopy()
75+
for _, start := range []uint16{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 511, 512, 513, 32767, 32768, 32769, 65527, 65528, 65529, 65530, 65531, 65532, 65533, 65534, 65535} {
76+
start := start
77+
78+
sb, err := NewRTPBuffer(8)
79+
require.NoError(t, err)
80+
81+
add := func(nums ...uint16) {
82+
for _, n := range nums {
83+
seq := start + n
84+
pkt, err := pm.NewPacket(&rtp.Header{SequenceNumber: seq, PayloadType: 2}, []byte("originalcontent"), 1, 1)
85+
require.NoError(t, err)
86+
sb.Add(pkt)
87+
}
88+
}
89+
90+
assertGet := func(nums ...uint16) {
91+
t.Helper()
92+
for _, n := range nums {
93+
seq := start + n
94+
packet := sb.Get(seq)
95+
if packet == nil {
96+
t.Errorf("packet not found: %d", seq)
97+
continue
98+
}
99+
if packet.Header().SSRC != 1 && packet.Header().PayloadType != 1 {
100+
t.Errorf("packet for %d returned with incorrect SSRC : %d and PayloadType: %d", seq, packet.Header().SSRC, packet.Header().PayloadType)
101+
}
102+
packet.Release()
103+
}
104+
}
105+
assertNOTGet := func(nums ...uint16) {
106+
t.Helper()
107+
for _, n := range nums {
108+
seq := start + n
109+
packet := sb.Get(seq)
110+
if packet != nil {
111+
t.Errorf("packet found for %d: %d", seq, packet.Header().SequenceNumber)
112+
}
113+
}
114+
}
115+
116+
add(0, 1, 2, 3, 4, 5, 6, 7)
117+
assertGet(0, 1, 2, 3, 4, 5, 6, 7)
118+
119+
add(8)
120+
assertGet(8)
121+
assertNOTGet(0)
122+
123+
add(10)
124+
assertGet(10)
125+
assertNOTGet(1, 2, 9)
126+
127+
add(22)
128+
assertGet(22)
129+
assertNOTGet(3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21)
130+
}
131+
}
132+
73133
func TestRTPBuffer_Overridden(t *testing.T) {
74134
// override original packet content and get
75135
pm := NewPacketFactoryCopy()
@@ -98,3 +158,60 @@ func TestRTPBuffer_Overridden(t *testing.T) {
98158

99159
require.Nil(t, sb.Get(1))
100160
}
161+
162+
func TestRTPBuffer_Overridden_WithRTX_AND_Padding(t *testing.T) {
163+
// override original packet content and get
164+
pm := NewPacketFactoryCopy()
165+
sb, err := NewRTPBuffer(1)
166+
require.NoError(t, err)
167+
require.Equal(t, uint16(1), sb.size)
168+
169+
originalBytes := []byte("originalContent\x01")
170+
pkt, err := pm.NewPacket(&rtp.Header{SequenceNumber: 1, Padding: true, SSRC: 2, PayloadType: 3}, originalBytes, 1, 1)
171+
require.NoError(t, err)
172+
sb.Add(pkt)
173+
174+
// change payload
175+
copy(originalBytes, "altered")
176+
retrieved := sb.Get(1)
177+
require.NotNil(t, retrieved)
178+
require.Equal(t, "\x00\x01originalContent", string(retrieved.Payload()))
179+
retrieved.Release()
180+
require.Equal(t, 1, retrieved.count)
181+
182+
// ensure original packet is released
183+
pkt, err = pm.NewPacket(&rtp.Header{SequenceNumber: 2}, originalBytes, 1, 1)
184+
require.NoError(t, err)
185+
sb.Add(pkt)
186+
require.Equal(t, 0, retrieved.count)
187+
188+
require.Nil(t, sb.Get(1))
189+
}
190+
191+
func TestRTPBuffer_Overridden_WithRTX_NILPayload(t *testing.T) {
192+
// override original packet content and get
193+
pm := NewPacketFactoryCopy()
194+
sb, err := NewRTPBuffer(1)
195+
require.NoError(t, err)
196+
require.Equal(t, uint16(1), sb.size)
197+
198+
pkt, err := pm.NewPacket(&rtp.Header{SequenceNumber: 1}, nil, 1, 1)
199+
require.NoError(t, err)
200+
sb.Add(pkt)
201+
202+
// change payload
203+
204+
retrieved := sb.Get(1)
205+
require.NotNil(t, retrieved)
206+
require.Equal(t, "\x00\x01", string(retrieved.Payload()))
207+
retrieved.Release()
208+
require.Equal(t, 1, retrieved.count)
209+
210+
// ensure original packet is released
211+
pkt, err = pm.NewPacket(&rtp.Header{SequenceNumber: 2}, []byte("altered"), 1, 1)
212+
require.NoError(t, err)
213+
sb.Add(pkt)
214+
require.Equal(t, 0, retrieved.count)
215+
216+
require.Nil(t, sb.Get(1))
217+
}

0 commit comments

Comments
 (0)