github.com/pion/webrtc/v3@v3.2.24/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 codec RTPCodecParameters 28 params RTPParameters 29 rid string 30 31 receiver *RTPReceiver 32 peeked []byte 33 peekedAttributes interceptor.Attributes 34 } 35 36 func newTrackRemote(kind RTPCodecType, ssrc SSRC, rid string, receiver *RTPReceiver) *TrackRemote { 37 return &TrackRemote{ 38 kind: kind, 39 ssrc: ssrc, 40 rid: rid, 41 receiver: receiver, 42 } 43 } 44 45 // ID is the unique identifier for this Track. This should be unique for the 46 // stream, but doesn't have to globally unique. A common example would be 'audio' or 'video' 47 // and StreamID would be 'desktop' or 'webcam' 48 func (t *TrackRemote) ID() string { 49 t.mu.RLock() 50 defer t.mu.RUnlock() 51 return t.id 52 } 53 54 // RID gets the RTP Stream ID of this Track 55 // With Simulcast you will have multiple tracks with the same ID, but different RID values. 56 // In many cases a TrackRemote will not have an RID, so it is important to assert it is non-zero 57 func (t *TrackRemote) RID() string { 58 t.mu.RLock() 59 defer t.mu.RUnlock() 60 61 return t.rid 62 } 63 64 // PayloadType gets the PayloadType of the track 65 func (t *TrackRemote) PayloadType() PayloadType { 66 t.mu.RLock() 67 defer t.mu.RUnlock() 68 return t.payloadType 69 } 70 71 // Kind gets the Kind of the track 72 func (t *TrackRemote) Kind() RTPCodecType { 73 t.mu.RLock() 74 defer t.mu.RUnlock() 75 return t.kind 76 } 77 78 // StreamID is the group this track belongs too. This must be unique 79 func (t *TrackRemote) StreamID() string { 80 t.mu.RLock() 81 defer t.mu.RUnlock() 82 return t.streamID 83 } 84 85 // SSRC gets the SSRC of the track 86 func (t *TrackRemote) SSRC() SSRC { 87 t.mu.RLock() 88 defer t.mu.RUnlock() 89 return t.ssrc 90 } 91 92 // Msid gets the Msid of the track 93 func (t *TrackRemote) Msid() string { 94 return t.StreamID() + " " + t.ID() 95 } 96 97 // Codec gets the Codec of the track 98 func (t *TrackRemote) Codec() RTPCodecParameters { 99 t.mu.RLock() 100 defer t.mu.RUnlock() 101 return t.codec 102 } 103 104 // Read reads data from the track. 105 func (t *TrackRemote) Read(b []byte) (n int, attributes interceptor.Attributes, err error) { 106 t.mu.RLock() 107 r := t.receiver 108 peeked := t.peeked != nil 109 t.mu.RUnlock() 110 111 if peeked { 112 t.mu.Lock() 113 data := t.peeked 114 attributes = t.peekedAttributes 115 116 t.peeked = nil 117 t.peekedAttributes = nil 118 t.mu.Unlock() 119 // someone else may have stolen our packet when we 120 // released the lock. Deal with it. 121 if data != nil { 122 n = copy(b, data) 123 err = t.checkAndUpdateTrack(b) 124 return 125 } 126 } 127 128 n, attributes, err = r.readRTP(b, t) 129 if err != nil { 130 return 131 } 132 133 err = t.checkAndUpdateTrack(b) 134 return 135 } 136 137 // checkAndUpdateTrack checks payloadType for every incoming packet 138 // once a different payloadType is detected the track will be updated 139 func (t *TrackRemote) checkAndUpdateTrack(b []byte) error { 140 if len(b) < 2 { 141 return errRTPTooShort 142 } 143 144 if payloadType := PayloadType(b[1] & rtpPayloadTypeBitmask); payloadType != t.PayloadType() { 145 t.mu.Lock() 146 defer t.mu.Unlock() 147 148 params, err := t.receiver.api.mediaEngine.getRTPParametersByPayloadType(payloadType) 149 if err != nil { 150 return err 151 } 152 153 t.kind = t.receiver.kind 154 t.payloadType = payloadType 155 t.codec = params.Codecs[0] 156 t.params = params 157 } 158 159 return nil 160 } 161 162 // ReadRTP is a convenience method that wraps Read and unmarshals for you. 163 func (t *TrackRemote) ReadRTP() (*rtp.Packet, interceptor.Attributes, error) { 164 b := make([]byte, t.receiver.api.settingEngine.getReceiveMTU()) 165 i, attributes, err := t.Read(b) 166 if err != nil { 167 return nil, nil, err 168 } 169 170 r := &rtp.Packet{} 171 if err := r.Unmarshal(b[:i]); err != nil { 172 return nil, nil, err 173 } 174 return r, attributes, nil 175 } 176 177 // peek is like Read, but it doesn't discard the packet read 178 func (t *TrackRemote) peek(b []byte) (n int, a interceptor.Attributes, err error) { 179 n, a, err = t.Read(b) 180 if err != nil { 181 return 182 } 183 184 t.mu.Lock() 185 // this might overwrite data if somebody peeked between the Read 186 // and us getting the lock. Oh well, we'll just drop a packet in 187 // that case. 188 data := make([]byte, n) 189 n = copy(data, b[:n]) 190 t.peeked = data 191 t.peekedAttributes = a 192 t.mu.Unlock() 193 return 194 } 195 196 // SetReadDeadline sets the max amount of time the RTP stream will block before returning. 0 is forever. 197 func (t *TrackRemote) SetReadDeadline(deadline time.Time) error { 198 return t.receiver.setRTPReadDeadline(deadline, t) 199 }