github.com/pion/webrtc/v4@v4.0.1/track_remote.go (about) 1 // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly> 2 // SPDX-License-Identifier: MIT 3 4 //go:build !js 5 // +build !js 6 7 package webrtc 8 9 import ( 10 "sync" 11 "time" 12 13 "github.com/pion/interceptor" 14 "github.com/pion/rtp" 15 ) 16 17 // TrackRemote represents a single inbound source of media 18 type TrackRemote struct { 19 mu sync.RWMutex 20 21 id string 22 streamID string 23 24 payloadType PayloadType 25 kind RTPCodecType 26 ssrc SSRC 27 rtxSsrc SSRC 28 codec RTPCodecParameters 29 params RTPParameters 30 rid string 31 32 receiver *RTPReceiver 33 peeked []byte 34 peekedAttributes interceptor.Attributes 35 } 36 37 func newTrackRemote(kind RTPCodecType, ssrc, rtxSsrc SSRC, rid string, receiver *RTPReceiver) *TrackRemote { 38 return &TrackRemote{ 39 kind: kind, 40 ssrc: ssrc, 41 rtxSsrc: rtxSsrc, 42 rid: rid, 43 receiver: receiver, 44 } 45 } 46 47 // ID is the unique identifier for this Track. This should be unique for the 48 // stream, but doesn't have to globally unique. A common example would be 'audio' or 'video' 49 // and StreamID would be 'desktop' or 'webcam' 50 func (t *TrackRemote) ID() string { 51 t.mu.RLock() 52 defer t.mu.RUnlock() 53 return t.id 54 } 55 56 // RID gets the RTP Stream ID of this Track 57 // With Simulcast you will have multiple tracks with the same ID, but different RID values. 58 // In many cases a TrackRemote will not have an RID, so it is important to assert it is non-zero 59 func (t *TrackRemote) RID() string { 60 t.mu.RLock() 61 defer t.mu.RUnlock() 62 63 return t.rid 64 } 65 66 // PayloadType gets the PayloadType of the track 67 func (t *TrackRemote) PayloadType() PayloadType { 68 t.mu.RLock() 69 defer t.mu.RUnlock() 70 return t.payloadType 71 } 72 73 // Kind gets the Kind of the track 74 func (t *TrackRemote) Kind() RTPCodecType { 75 t.mu.RLock() 76 defer t.mu.RUnlock() 77 return t.kind 78 } 79 80 // StreamID is the group this track belongs too. This must be unique 81 func (t *TrackRemote) StreamID() string { 82 t.mu.RLock() 83 defer t.mu.RUnlock() 84 return t.streamID 85 } 86 87 // SSRC gets the SSRC of the track 88 func (t *TrackRemote) SSRC() SSRC { 89 t.mu.RLock() 90 defer t.mu.RUnlock() 91 return t.ssrc 92 } 93 94 // Msid gets the Msid of the track 95 func (t *TrackRemote) Msid() string { 96 return t.StreamID() + " " + t.ID() 97 } 98 99 // Codec gets the Codec of the track 100 func (t *TrackRemote) Codec() RTPCodecParameters { 101 t.mu.RLock() 102 defer t.mu.RUnlock() 103 return t.codec 104 } 105 106 // Read reads data from the track. 107 func (t *TrackRemote) Read(b []byte) (n int, attributes interceptor.Attributes, err error) { 108 t.mu.RLock() 109 r := t.receiver 110 peeked := t.peeked != nil 111 t.mu.RUnlock() 112 113 if peeked { 114 t.mu.Lock() 115 data := t.peeked 116 attributes = t.peekedAttributes 117 118 t.peeked = nil 119 t.peekedAttributes = nil 120 t.mu.Unlock() 121 // someone else may have stolen our packet when we 122 // released the lock. Deal with it. 123 if data != nil { 124 n = copy(b, data) 125 err = t.checkAndUpdateTrack(b) 126 return 127 } 128 } 129 130 // If there's a separate RTX track and an RTX packet is available, return that 131 if rtxPacketReceived := r.readRTX(t); rtxPacketReceived != nil { 132 n = copy(b, rtxPacketReceived.pkt) 133 attributes = rtxPacketReceived.attributes 134 rtxPacketReceived.release() 135 err = nil 136 } else { 137 // If there's no separate RTX track (or there's a separate RTX track but no RTX packet waiting), wait for and return 138 // a packet from the main track 139 n, attributes, err = r.readRTP(b, t) 140 if err != nil { 141 return 142 } 143 err = t.checkAndUpdateTrack(b) 144 } 145 146 return n, attributes, err 147 } 148 149 // checkAndUpdateTrack checks payloadType for every incoming packet 150 // once a different payloadType is detected the track will be updated 151 func (t *TrackRemote) checkAndUpdateTrack(b []byte) error { 152 if len(b) < 2 { 153 return errRTPTooShort 154 } 155 156 payloadType := PayloadType(b[1] & rtpPayloadTypeBitmask) 157 if payloadType != t.PayloadType() || len(t.params.Codecs) == 0 { 158 t.mu.Lock() 159 defer t.mu.Unlock() 160 161 params, err := t.receiver.api.mediaEngine.getRTPParametersByPayloadType(payloadType) 162 if err != nil { 163 return err 164 } 165 166 t.kind = t.receiver.kind 167 t.payloadType = payloadType 168 t.codec = params.Codecs[0] 169 t.params = params 170 } 171 172 return nil 173 } 174 175 // ReadRTP is a convenience method that wraps Read and unmarshals for you. 176 func (t *TrackRemote) ReadRTP() (*rtp.Packet, interceptor.Attributes, error) { 177 b := make([]byte, t.receiver.api.settingEngine.getReceiveMTU()) 178 i, attributes, err := t.Read(b) 179 if err != nil { 180 return nil, nil, err 181 } 182 183 r := &rtp.Packet{} 184 if err := r.Unmarshal(b[:i]); err != nil { 185 return nil, nil, err 186 } 187 return r, attributes, nil 188 } 189 190 // peek is like Read, but it doesn't discard the packet read 191 func (t *TrackRemote) peek(b []byte) (n int, a interceptor.Attributes, err error) { 192 n, a, err = t.Read(b) 193 if err != nil { 194 return 195 } 196 197 t.mu.Lock() 198 // this might overwrite data if somebody peeked between the Read 199 // and us getting the lock. Oh well, we'll just drop a packet in 200 // that case. 201 data := make([]byte, n) 202 n = copy(data, b[:n]) 203 t.peeked = data 204 t.peekedAttributes = a 205 t.mu.Unlock() 206 return 207 } 208 209 // SetReadDeadline sets the max amount of time the RTP stream will block before returning. 0 is forever. 210 func (t *TrackRemote) SetReadDeadline(deadline time.Time) error { 211 return t.receiver.setRTPReadDeadline(deadline, t) 212 } 213 214 // RtxSSRC returns the RTX SSRC for a track, or 0 if track does not have a separate RTX stream 215 func (t *TrackRemote) RtxSSRC() SSRC { 216 t.mu.RLock() 217 defer t.mu.RUnlock() 218 return t.rtxSsrc 219 } 220 221 // HasRTX returns true if the track has a separate RTX stream 222 func (t *TrackRemote) HasRTX() bool { 223 t.mu.RLock() 224 defer t.mu.RUnlock() 225 return t.rtxSsrc != 0 226 } 227 228 func (t *TrackRemote) setRtxSSRC(ssrc SSRC) { 229 t.mu.Lock() 230 defer t.mu.Unlock() 231 t.rtxSsrc = ssrc 232 }