Skip to content

Commit f68b789

Browse files
adriancablecnderrauber
authored andcommittedFeb 5, 2024
Allocationless handling of RTX pkts
1 parent 5da7278 commit f68b789

File tree

2 files changed

+34
-28
lines changed

2 files changed

+34
-28
lines changed
 

‎rtpreceiver.go

+30-22
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import (
1515

1616
"github.com/pion/interceptor"
1717
"github.com/pion/rtcp"
18-
"github.com/pion/rtp"
1918
"github.com/pion/srtp/v2"
2019
"github.com/pion/webrtc/v3/internal/util"
2120
)
@@ -42,7 +41,7 @@ type trackStreams struct {
4241
}
4342

4443
type rtxPacketWithAttributes struct {
45-
rtxPacket rtp.Packet
44+
pkt []byte
4645
attributes interceptor.Attributes
4746
}
4847

@@ -419,31 +418,40 @@ func (r *RTPReceiver) receiveForRtx(ssrc SSRC, rsid string, streamInfo *intercep
419418
return
420419
}
421420

422-
pkt := &rtp.Packet{}
423-
if err := pkt.Unmarshal(b[:i]); err != nil {
424-
return
421+
// RTX packets have a different payload format. Move the OSN in the payload to the RTP header and rewrite the
422+
// payload type and SSRC, so that we can return RTX packets to the caller 'transparently' i.e. in the same format
423+
// as non-RTX RTP packets
424+
hasExtension := b[0]&0b10000 > 0
425+
hasPadding := b[0]&0b100000 > 0
426+
csrcCount := b[0] & 0b1111
427+
headerLength := uint16(12 + (4 * csrcCount))
428+
paddingLength := 0
429+
if hasExtension {
430+
headerLength += 4 * (1 + binary.BigEndian.Uint16(b[headerLength+2:headerLength+4]))
431+
}
432+
if hasPadding {
433+
paddingLength = int(b[i-1])
425434
}
426435

427-
if len(pkt.Payload) < 2 {
436+
if i-int(headerLength)-paddingLength < 2 {
428437
// BWE probe packet, ignore
429438
continue
430439
}
431440

432-
// RTX packets have a different payload format. Move the OSN in the payload to the RTP header and rewrite the
433-
// payload type and SSRC, so that we can return RTX packets to the caller 'transparently' i.e. in the same format
434-
// as non-RTX RTP packets
435-
attributes.Set(attributeRtxPayloadType, pkt.Header.PayloadType)
436-
attributes.Set(attributeRtxSsrc, pkt.Header.SSRC)
437-
attributes.Set(attributeRtxSequenceNumber, pkt.Header.SequenceNumber)
438-
pkt.Header.PayloadType = uint8(track.track.PayloadType())
439-
pkt.Header.SSRC = uint32(track.track.SSRC())
440-
pkt.Header.SequenceNumber = binary.BigEndian.Uint16(pkt.Payload[:2])
441-
pkt.Payload = pkt.Payload[2:]
441+
attributes.Set(attributeRtxPayloadType, b[1]&0x7F)
442+
attributes.Set(attributeRtxSequenceNumber, binary.BigEndian.Uint16(b[2:4]))
443+
attributes.Set(attributeRtxSsrc, binary.BigEndian.Uint32(b[8:12]))
444+
445+
b[1] = (b[1] & 0x80) | uint8(track.track.PayloadType())
446+
b[2] = b[headerLength]
447+
b[3] = b[headerLength+1]
448+
binary.BigEndian.PutUint32(b[8:12], uint32(track.track.SSRC()))
449+
copy(b[headerLength:i-2], b[headerLength+2:i])
442450

443451
select {
444452
case <-r.closed:
445453
return
446-
case track.repairStreamChannel <- rtxPacketWithAttributes{rtxPacket: *pkt, attributes: attributes}:
454+
case track.repairStreamChannel <- rtxPacketWithAttributes{pkt: b[:i-2], attributes: attributes}:
447455
}
448456
}
449457
}()
@@ -484,23 +492,23 @@ func (r *RTPReceiver) setRTPReadDeadline(deadline time.Time, reader *TrackRemote
484492
}
485493

486494
// readRTX returns an RTX packet if one is available on the RTX track, otherwise returns nil
487-
func (r *RTPReceiver) readRTX(reader *TrackRemote) (*rtp.Packet, interceptor.Attributes) {
495+
func (r *RTPReceiver) readRTX(reader *TrackRemote) *rtxPacketWithAttributes {
488496
if !reader.HasRTX() {
489-
return nil, interceptor.Attributes{}
497+
return nil
490498
}
491499

492500
select {
493501
case <-r.received:
494502
default:
495-
return nil, interceptor.Attributes{}
503+
return nil
496504
}
497505

498506
if t := r.streamsForTrack(reader); t != nil {
499507
select {
500508
case rtxPacketReceived := <-t.repairStreamChannel:
501-
return &rtxPacketReceived.rtxPacket, rtxPacketReceived.attributes
509+
return &rtxPacketReceived
502510
default:
503511
}
504512
}
505-
return nil, interceptor.Attributes{}
513+
return nil
506514
}

‎track_remote.go

+4-6
Original file line numberDiff line numberDiff line change
@@ -128,12 +128,10 @@ func (t *TrackRemote) Read(b []byte) (n int, attributes interceptor.Attributes,
128128
}
129129

130130
// If there's a separate RTX track and an RTX packet is available, return that
131-
if rtxPacket, rtxAttributes := r.readRTX(t); rtxPacket != nil {
132-
n, err = rtxPacket.MarshalTo(b)
133-
attributes = rtxAttributes
134-
if err != nil {
135-
return 0, nil, err
136-
}
131+
if rtxPacketReceived := r.readRTX(t); rtxPacketReceived != nil {
132+
n = copy(b, rtxPacketReceived.pkt)
133+
attributes = rtxPacketReceived.attributes
134+
err = nil
137135
} else {
138136
// If there's no separate RTX track (or there's a separate RTX track but no RTX packet waiting), wait for and return
139137
// a packet from the main track

0 commit comments

Comments
 (0)
Please sign in to comment.