github.com/pion/webrtc/v4@v4.0.1/rtptransceiver.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 "fmt" 11 "sync" 12 "sync/atomic" 13 14 "github.com/pion/rtp" 15 ) 16 17 // RTPTransceiver represents a combination of an RTPSender and an RTPReceiver that share a common mid. 18 type RTPTransceiver struct { 19 mid atomic.Value // string 20 sender atomic.Value // *RTPSender 21 receiver atomic.Value // *RTPReceiver 22 direction atomic.Value // RTPTransceiverDirection 23 currentDirection atomic.Value // RTPTransceiverDirection 24 25 codecs []RTPCodecParameters // User provided codecs via SetCodecPreferences 26 27 stopped bool 28 kind RTPCodecType 29 30 api *API 31 mu sync.RWMutex 32 } 33 34 func newRTPTransceiver( 35 receiver *RTPReceiver, 36 sender *RTPSender, 37 direction RTPTransceiverDirection, 38 kind RTPCodecType, 39 api *API, 40 ) *RTPTransceiver { 41 t := &RTPTransceiver{kind: kind, api: api} 42 t.setReceiver(receiver) 43 t.setSender(sender) 44 t.setDirection(direction) 45 t.setCurrentDirection(RTPTransceiverDirectionUnknown) 46 return t 47 } 48 49 // SetCodecPreferences sets preferred list of supported codecs 50 // if codecs is empty or nil we reset to default from MediaEngine 51 func (t *RTPTransceiver) SetCodecPreferences(codecs []RTPCodecParameters) error { 52 t.mu.Lock() 53 defer t.mu.Unlock() 54 55 for _, codec := range codecs { 56 if _, matchType := codecParametersFuzzySearch(codec, t.api.mediaEngine.getCodecsByKind(t.kind)); matchType == codecMatchNone { 57 return fmt.Errorf("%w %s", errRTPTransceiverCodecUnsupported, codec.MimeType) 58 } 59 } 60 61 t.codecs = codecs 62 return nil 63 } 64 65 // Codecs returns list of supported codecs 66 func (t *RTPTransceiver) getCodecs() []RTPCodecParameters { 67 t.mu.RLock() 68 defer t.mu.RUnlock() 69 70 mediaEngineCodecs := t.api.mediaEngine.getCodecsByKind(t.kind) 71 if len(t.codecs) == 0 { 72 return mediaEngineCodecs 73 } 74 75 filteredCodecs := []RTPCodecParameters{} 76 for _, codec := range t.codecs { 77 if c, matchType := codecParametersFuzzySearch(codec, mediaEngineCodecs); matchType != codecMatchNone { 78 if codec.PayloadType == 0 { 79 codec.PayloadType = c.PayloadType 80 } 81 filteredCodecs = append(filteredCodecs, codec) 82 } 83 } 84 85 return filteredCodecs 86 } 87 88 // Sender returns the RTPTransceiver's RTPSender if it has one 89 func (t *RTPTransceiver) Sender() *RTPSender { 90 if v, ok := t.sender.Load().(*RTPSender); ok { 91 return v 92 } 93 94 return nil 95 } 96 97 // SetSender sets the RTPSender and Track to current transceiver 98 func (t *RTPTransceiver) SetSender(s *RTPSender, track TrackLocal) error { 99 t.setSender(s) 100 return t.setSendingTrack(track) 101 } 102 103 func (t *RTPTransceiver) setSender(s *RTPSender) { 104 if s != nil { 105 s.setRTPTransceiver(t) 106 } 107 108 if prevSender := t.Sender(); prevSender != nil { 109 prevSender.setRTPTransceiver(nil) 110 } 111 112 t.sender.Store(s) 113 } 114 115 // Receiver returns the RTPTransceiver's RTPReceiver if it has one 116 func (t *RTPTransceiver) Receiver() *RTPReceiver { 117 if v, ok := t.receiver.Load().(*RTPReceiver); ok { 118 return v 119 } 120 121 return nil 122 } 123 124 // SetMid sets the RTPTransceiver's mid. If it was already set, will return an error. 125 func (t *RTPTransceiver) SetMid(mid string) error { 126 if currentMid := t.Mid(); currentMid != "" { 127 return fmt.Errorf("%w: %s to %s", errRTPTransceiverCannotChangeMid, currentMid, mid) 128 } 129 t.mid.Store(mid) 130 return nil 131 } 132 133 // Mid gets the Transceiver's mid value. When not already set, this value will be set in CreateOffer or CreateAnswer. 134 func (t *RTPTransceiver) Mid() string { 135 if v, ok := t.mid.Load().(string); ok { 136 return v 137 } 138 return "" 139 } 140 141 // Kind returns RTPTransceiver's kind. 142 func (t *RTPTransceiver) Kind() RTPCodecType { 143 return t.kind 144 } 145 146 // Direction returns the RTPTransceiver's current direction 147 func (t *RTPTransceiver) Direction() RTPTransceiverDirection { 148 if direction, ok := t.direction.Load().(RTPTransceiverDirection); ok { 149 return direction 150 } 151 return RTPTransceiverDirection(0) 152 } 153 154 // Stop irreversibly stops the RTPTransceiver 155 func (t *RTPTransceiver) Stop() error { 156 if sender := t.Sender(); sender != nil { 157 if err := sender.Stop(); err != nil { 158 return err 159 } 160 } 161 if receiver := t.Receiver(); receiver != nil { 162 if err := receiver.Stop(); err != nil { 163 return err 164 } 165 } 166 167 t.setDirection(RTPTransceiverDirectionInactive) 168 t.setCurrentDirection(RTPTransceiverDirectionInactive) 169 return nil 170 } 171 172 func (t *RTPTransceiver) setReceiver(r *RTPReceiver) { 173 if r != nil { 174 r.setRTPTransceiver(t) 175 } 176 177 if prevReceiver := t.Receiver(); prevReceiver != nil { 178 prevReceiver.setRTPTransceiver(nil) 179 } 180 181 t.receiver.Store(r) 182 } 183 184 func (t *RTPTransceiver) setDirection(d RTPTransceiverDirection) { 185 t.direction.Store(d) 186 } 187 188 func (t *RTPTransceiver) setCurrentDirection(d RTPTransceiverDirection) { 189 t.currentDirection.Store(d) 190 } 191 192 func (t *RTPTransceiver) getCurrentDirection() RTPTransceiverDirection { 193 if v, ok := t.currentDirection.Load().(RTPTransceiverDirection); ok { 194 return v 195 } 196 return RTPTransceiverDirectionUnknown 197 } 198 199 func (t *RTPTransceiver) setSendingTrack(track TrackLocal) error { 200 if err := t.Sender().ReplaceTrack(track); err != nil { 201 return err 202 } 203 if track == nil { 204 t.setSender(nil) 205 } 206 207 switch { 208 case track != nil && t.Direction() == RTPTransceiverDirectionRecvonly: 209 t.setDirection(RTPTransceiverDirectionSendrecv) 210 case track != nil && t.Direction() == RTPTransceiverDirectionInactive: 211 t.setDirection(RTPTransceiverDirectionSendonly) 212 case track == nil && t.Direction() == RTPTransceiverDirectionSendrecv: 213 t.setDirection(RTPTransceiverDirectionRecvonly) 214 case track != nil && t.Direction() == RTPTransceiverDirectionSendonly: 215 // Handle the case where a sendonly transceiver was added by a negotiation 216 // initiated by remote peer. For example a remote peer added a transceiver 217 // with direction recvonly. 218 case track != nil && t.Direction() == RTPTransceiverDirectionSendrecv: 219 // Similar to above, but for sendrecv transceiver. 220 case track == nil && t.Direction() == RTPTransceiverDirectionSendonly: 221 t.setDirection(RTPTransceiverDirectionInactive) 222 default: 223 return errRTPTransceiverSetSendingInvalidState 224 } 225 return nil 226 } 227 228 func findByMid(mid string, localTransceivers []*RTPTransceiver) (*RTPTransceiver, []*RTPTransceiver) { 229 for i, t := range localTransceivers { 230 if t.Mid() == mid { 231 return t, append(localTransceivers[:i], localTransceivers[i+1:]...) 232 } 233 } 234 235 return nil, localTransceivers 236 } 237 238 // Given a direction+type pluck a transceiver from the passed list 239 // if no entry satisfies the requested type+direction return a inactive Transceiver 240 func satisfyTypeAndDirection(remoteKind RTPCodecType, remoteDirection RTPTransceiverDirection, localTransceivers []*RTPTransceiver) (*RTPTransceiver, []*RTPTransceiver) { 241 // Get direction order from most preferred to least 242 getPreferredDirections := func() []RTPTransceiverDirection { 243 switch remoteDirection { 244 case RTPTransceiverDirectionSendrecv: 245 return []RTPTransceiverDirection{RTPTransceiverDirectionRecvonly, RTPTransceiverDirectionSendrecv, RTPTransceiverDirectionSendonly} 246 case RTPTransceiverDirectionSendonly: 247 return []RTPTransceiverDirection{RTPTransceiverDirectionRecvonly, RTPTransceiverDirectionSendrecv} 248 case RTPTransceiverDirectionRecvonly: 249 return []RTPTransceiverDirection{RTPTransceiverDirectionSendonly, RTPTransceiverDirectionSendrecv} 250 default: 251 return []RTPTransceiverDirection{} 252 } 253 } 254 255 for _, possibleDirection := range getPreferredDirections() { 256 for i := range localTransceivers { 257 t := localTransceivers[i] 258 if t.Mid() == "" && t.kind == remoteKind && possibleDirection == t.Direction() { 259 return t, append(localTransceivers[:i], localTransceivers[i+1:]...) 260 } 261 } 262 } 263 264 return nil, localTransceivers 265 } 266 267 // handleUnknownRTPPacket consumes a single RTP Packet and returns information that is helpful 268 // for demuxing and handling an unknown SSRC (usually for Simulcast) 269 func handleUnknownRTPPacket(buf []byte, midExtensionID, streamIDExtensionID, repairStreamIDExtensionID uint8, mid, rid, rsid *string) (payloadType PayloadType, paddingOnly bool, err error) { 270 rp := &rtp.Packet{} 271 if err = rp.Unmarshal(buf); err != nil { 272 return 273 } 274 275 if rp.Padding && len(rp.Payload) == 0 { 276 paddingOnly = true 277 } 278 279 if !rp.Header.Extension { 280 return 281 } 282 283 payloadType = PayloadType(rp.PayloadType) 284 if payload := rp.GetExtension(midExtensionID); payload != nil { 285 *mid = string(payload) 286 } 287 288 if payload := rp.GetExtension(streamIDExtensionID); payload != nil { 289 *rid = string(payload) 290 } 291 292 if payload := rp.GetExtension(repairStreamIDExtensionID); payload != nil { 293 *rsid = string(payload) 294 } 295 296 return 297 }