@@ -39,8 +39,9 @@ import (
3939)
4040
4141const (
42- rtpOutboundMTU = 1200
43- rtpInboundMTU = 1500
42+ rtpOutboundMTU = 1200
43+ rtpInboundMTU = 1500
44+ absCaptureTimeURI = "http://www.webrtc.org/experiments/rtp-hdrext/abs-capture-time"
4445)
4546
4647var (
@@ -57,25 +58,27 @@ type SampleWriteOptions struct {
5758// publishing tracks at the right frequency
5859// This extends webrtc.TrackLocalStaticSample, and adds the ability to write RTP extensions
5960type LocalTrack struct {
60- log protoLogger.Logger
61- packetizer rtp.Packetizer
62- sequencer rtp.Sequencer
63- transceiver * webrtc.RTPTransceiver
64- rtpTrack * webrtc.TrackLocalStaticRTP
65- ssrc webrtc.SSRC
66- ssrcAcked bool
67- clockRate float64
68- bound atomic.Bool
69- lock sync.RWMutex
70- writeStartupLock sync.Mutex
71- audioLevelID uint8
72- sdesMidID uint8
73- sdesRtpStreamID uint8
74- lastTS time.Time
75- lastRTPTimestamp uint32
76- simulcastID string
77- videoLayer * livekit.VideoLayer
78- onRTCP func (rtcp.Packet )
61+ log protoLogger.Logger
62+ packetizer rtp.Packetizer
63+ sequencer rtp.Sequencer
64+ transceiver * webrtc.RTPTransceiver
65+ rtpTrack * webrtc.TrackLocalStaticRTP
66+ ssrc webrtc.SSRC
67+ ssrcAcked bool
68+ clockRate float64
69+ bound atomic.Bool
70+ lock sync.RWMutex
71+ writeStartupLock sync.Mutex
72+ audioLevelID uint8
73+ sdesMidID uint8
74+ sdesRtpStreamID uint8
75+ incomingAbsCaptureTimeID uint8
76+ absCaptureTimeID uint8
77+ lastTS time.Time
78+ lastRTPTimestamp uint32
79+ simulcastID string
80+ videoLayer * livekit.VideoLayer
81+ onRTCP func (rtcp.Packet )
7982
8083 muted atomic.Bool
8184 disconnected atomic.Bool
@@ -216,6 +219,10 @@ func (s *LocalTrack) Bind(t webrtc.TrackLocalContext) (webrtc.RTPCodecParameters
216219 if ext .URI == sdp .SDESRTPStreamIDURI {
217220 s .sdesRtpStreamID = uint8 (ext .ID )
218221 }
222+
223+ if ext .URI == absCaptureTimeURI {
224+ s .absCaptureTimeID = uint8 (ext .ID )
225+ }
219226 }
220227 s .sequencer = rtp .NewRandomSequencer ()
221228 s .packetizer = rtp .NewPacketizer (
@@ -316,12 +323,22 @@ func (s *LocalTrack) OnUnbind(f func()) {
316323 s .lock .Unlock ()
317324}
318325
326+ // This is used to translate abs-capture-time extension before writing to a peer connection when source provided
327+ // extension ID does not match negotiated extension ID on the peer connection
328+ func (s * LocalTrack ) SetIncomingAbsCaptureTimeExtensionID (id uint8 ) {
329+ s .lock .Lock ()
330+ s .incomingAbsCaptureTimeID = id
331+ s .lock .Unlock ()
332+ }
333+
319334// WriteRTP writes an RTP packet to the track with optional sample write options.
320335func (s * LocalTrack ) WriteRTP (p * rtp.Packet , opts * SampleWriteOptions ) error {
321336 s .lock .RLock ()
322337 transceiver := s .transceiver
323338 ssrcAcked := s .ssrcAcked
324339 audioLevelID := s .audioLevelID
340+ incomingAbsCaptureTimeID := s .incomingAbsCaptureTimeID
341+ absCaptureTimeID := s .absCaptureTimeID
325342 s .lock .RUnlock ()
326343
327344 if audioLevelID != 0 && opts != nil && opts .AudioLevel != nil {
@@ -337,6 +354,13 @@ func (s *LocalTrack) WriteRTP(p *rtp.Packet, opts *SampleWriteOptions) error {
337354 }
338355 }
339356
357+ if incomingAbsCaptureTimeID != 0 && absCaptureTimeID != 0 && incomingAbsCaptureTimeID != absCaptureTimeID && p .Header .Extension {
358+ if data := p .Header .GetExtension (incomingAbsCaptureTimeID ); len (data ) != 0 {
359+ _ = p .Header .DelExtension (incomingAbsCaptureTimeID )
360+ _ = p .Header .SetExtension (absCaptureTimeID , data )
361+ }
362+ }
363+
340364 if s .RID () != "" && transceiver != nil && transceiver .Mid () != "" && ! ssrcAcked {
341365 s .lock .RLock ()
342366 sdesMidID := s .sdesMidID
0 commit comments