@@ -2,10 +2,12 @@ package peer
22
33import (
44 "errors"
5+ "io"
56 "sync"
67 "time"
78
89 "github.com/matrix-org/waterfall/pkg/common"
10+ "github.com/pion/rtcp"
911 "github.com/pion/webrtc/v3"
1012 "github.com/sirupsen/logrus"
1113 "maunium.net/go/mautrix/event"
2224 ErrCantSubscribeToTrack = errors .New ("can't subscribe to track" )
2325)
2426
27+ const minimalPLIInterval = time .Millisecond * 500
28+
2529// A wrapped representation of the peer connection (single peer in the call).
2630// The peer gets information about the things happening outside via public methods
2731// and informs the outside world about the things happening inside the peer by posting
@@ -98,17 +102,69 @@ func (p *Peer[ID]) SubscribeTo(track *webrtc.TrackLocalStaticRTP) error {
98102 // Before these packets are returned they are processed by interceptors. For things
99103 // like NACK this needs to be called.
100104 go func () {
101- rtcpBuf := make ([]byte , 1500 )
102105 for {
103- if _ , _ , rtcpErr := rtpSender .Read (rtcpBuf ); rtcpErr != nil {
104- return
106+ packets , _ , err := rtpSender .ReadRTCP ()
107+ if err != nil {
108+ if errors .Is (err , io .ErrClosedPipe ) || errors .Is (err , io .EOF ) {
109+ return
110+ }
111+
112+ p .logger .WithError (err ).Warn ("failed to read RTCP on track" )
105113 }
114+
115+ p .sink .Send (ForwardRTCP {Packets : packets , TrackID : track .ID (), StreamID : track .StreamID ()})
106116 }
107117 }()
108118
109119 return nil
110120}
111121
122+ func (p * Peer [ID ]) WriteRTCP (packets []rtcp.Packet , streamID string , trackID string , lastPLITimestamp int64 ) {
123+ packetsToSend := []rtcp.Packet {}
124+ var mediaSSRC uint32
125+ for _ , receiver := range p .peerConnection .GetReceivers () {
126+ if receiver .Track ().ID () == trackID && receiver .Track ().StreamID () == streamID {
127+ mediaSSRC = uint32 (receiver .Track ().SSRC ())
128+ break
129+ }
130+ }
131+
132+ for _ , packet := range packets {
133+ switch typedPacket := packet .(type ) {
134+ // We mung the packets here, so that the SSRCs match what the
135+ // receiver expects:
136+ // The media SSRC is the SSRC of the media about which the packet is
137+ // reporting; therefore, we mung it to be the SSRC of the publishing
138+ // participant's track. Without this, it would be SSRC of the SFU's
139+ // track which isn't right
140+ case * rtcp.PictureLossIndication :
141+ // Since we sometimes spam the sender with PLIs, make sure we don't send
142+ // them way too often
143+ if time .Now ().UnixNano ()- lastPLITimestamp < minimalPLIInterval .Nanoseconds () {
144+ continue
145+ }
146+
147+ p .sink .Send (PLISent {Timestamp : time .Now ().UnixNano (), StreamID : streamID , TrackID : trackID })
148+
149+ typedPacket .MediaSSRC = mediaSSRC
150+ packetsToSend = append (packetsToSend , typedPacket )
151+ case * rtcp.FullIntraRequest :
152+ typedPacket .MediaSSRC = mediaSSRC
153+ packetsToSend = append (packetsToSend , typedPacket )
154+ }
155+
156+ packetsToSend = append (packetsToSend , packet )
157+ }
158+
159+ if len (packetsToSend ) != 0 {
160+ if err := p .peerConnection .WriteRTCP (packetsToSend ); err != nil {
161+ if ! errors .Is (err , io .ErrClosedPipe ) {
162+ p .logger .WithError (err ).Warn ("failed to write RTCP on track" )
163+ }
164+ }
165+ }
166+ }
167+
112168// Unsubscribes from the given list of tracks.
113169func (p * Peer [ID ]) UnsubscribeFrom (tracks []* webrtc.TrackLocalStaticRTP ) {
114170 // That's unfortunately an O(m*n) operation, but we don't expect the number of tracks to be big.
0 commit comments