diff options
Diffstat (limited to 'vendor/github.com/pion/webrtc/v3/rtptransceiver.go')
-rw-r--r-- | vendor/github.com/pion/webrtc/v3/rtptransceiver.go | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/vendor/github.com/pion/webrtc/v3/rtptransceiver.go b/vendor/github.com/pion/webrtc/v3/rtptransceiver.go new file mode 100644 index 0000000..ee9de2f --- /dev/null +++ b/vendor/github.com/pion/webrtc/v3/rtptransceiver.go @@ -0,0 +1,187 @@ +// +build !js + +package webrtc + +import ( + "fmt" + "sync/atomic" + + "github.com/pion/rtp" +) + +// RTPTransceiver represents a combination of an RTPSender and an RTPReceiver that share a common mid. +type RTPTransceiver struct { + mid atomic.Value // string + sender atomic.Value // *RTPSender + receiver atomic.Value // *RTPReceiver + direction atomic.Value // RTPTransceiverDirection + + stopped bool + kind RTPCodecType +} + +// Sender returns the RTPTransceiver's RTPSender if it has one +func (t *RTPTransceiver) Sender() *RTPSender { + if v := t.sender.Load(); v != nil { + return v.(*RTPSender) + } + + return nil +} + +// SetSender sets the RTPSender and Track to current transceiver +func (t *RTPTransceiver) SetSender(s *RTPSender, track TrackLocal) error { + t.setSender(s) + return t.setSendingTrack(track) +} + +func (t *RTPTransceiver) setSender(s *RTPSender) { + t.sender.Store(s) +} + +// Receiver returns the RTPTransceiver's RTPReceiver if it has one +func (t *RTPTransceiver) Receiver() *RTPReceiver { + if v := t.receiver.Load(); v != nil { + return v.(*RTPReceiver) + } + + return nil +} + +// setMid sets the RTPTransceiver's mid. If it was already set, will return an error. +func (t *RTPTransceiver) setMid(mid string) error { + if currentMid := t.Mid(); currentMid != "" { + return fmt.Errorf("%w: %s to %s", errRTPTransceiverCannotChangeMid, currentMid, mid) + } + t.mid.Store(mid) + return nil +} + +// Mid gets the Transceiver's mid value. When not already set, this value will be set in CreateOffer or CreateAnswer. +func (t *RTPTransceiver) Mid() string { + if v := t.mid.Load(); v != nil { + return v.(string) + } + return "" +} + +// Kind returns RTPTransceiver's kind. +func (t *RTPTransceiver) Kind() RTPCodecType { + return t.kind +} + +// Direction returns the RTPTransceiver's current direction +func (t *RTPTransceiver) Direction() RTPTransceiverDirection { + return t.direction.Load().(RTPTransceiverDirection) +} + +// Stop irreversibly stops the RTPTransceiver +func (t *RTPTransceiver) Stop() error { + if t.Sender() != nil { + if err := t.Sender().Stop(); err != nil { + return err + } + } + if t.Receiver() != nil { + if err := t.Receiver().Stop(); err != nil { + return err + } + } + + t.setDirection(RTPTransceiverDirectionInactive) + return nil +} + +func (t *RTPTransceiver) setReceiver(r *RTPReceiver) { + t.receiver.Store(r) +} + +func (t *RTPTransceiver) setDirection(d RTPTransceiverDirection) { + t.direction.Store(d) +} + +func (t *RTPTransceiver) setSendingTrack(track TrackLocal) error { + if err := t.Sender().ReplaceTrack(track); err != nil { + return err + } + if track == nil { + t.setSender(nil) + } + + switch { + case track != nil && t.Direction() == RTPTransceiverDirectionRecvonly: + t.setDirection(RTPTransceiverDirectionSendrecv) + case track != nil && t.Direction() == RTPTransceiverDirectionInactive: + t.setDirection(RTPTransceiverDirectionSendonly) + case track == nil && t.Direction() == RTPTransceiverDirectionSendrecv: + t.setDirection(RTPTransceiverDirectionRecvonly) + case track == nil && t.Direction() == RTPTransceiverDirectionSendonly: + t.setDirection(RTPTransceiverDirectionInactive) + default: + return errRTPTransceiverSetSendingInvalidState + } + return nil +} + +func findByMid(mid string, localTransceivers []*RTPTransceiver) (*RTPTransceiver, []*RTPTransceiver) { + for i, t := range localTransceivers { + if t.Mid() == mid { + return t, append(localTransceivers[:i], localTransceivers[i+1:]...) + } + } + + return nil, localTransceivers +} + +// Given a direction+type pluck a transceiver from the passed list +// if no entry satisfies the requested type+direction return a inactive Transceiver +func satisfyTypeAndDirection(remoteKind RTPCodecType, remoteDirection RTPTransceiverDirection, localTransceivers []*RTPTransceiver) (*RTPTransceiver, []*RTPTransceiver) { + // Get direction order from most preferred to least + getPreferredDirections := func() []RTPTransceiverDirection { + switch remoteDirection { + case RTPTransceiverDirectionSendrecv: + return []RTPTransceiverDirection{RTPTransceiverDirectionRecvonly, RTPTransceiverDirectionSendrecv} + case RTPTransceiverDirectionSendonly: + return []RTPTransceiverDirection{RTPTransceiverDirectionRecvonly} + case RTPTransceiverDirectionRecvonly: + return []RTPTransceiverDirection{RTPTransceiverDirectionSendonly, RTPTransceiverDirectionSendrecv} + default: + return []RTPTransceiverDirection{} + } + } + + for _, possibleDirection := range getPreferredDirections() { + for i := range localTransceivers { + t := localTransceivers[i] + if t.Mid() == "" && t.kind == remoteKind && possibleDirection == t.Direction() { + return t, append(localTransceivers[:i], localTransceivers[i+1:]...) + } + } + } + + return nil, localTransceivers +} + +// handleUnknownRTPPacket consumes a single RTP Packet and returns information that is helpful +// for demuxing and handling an unknown SSRC (usually for Simulcast) +func handleUnknownRTPPacket(buf []byte, midExtensionID, streamIDExtensionID uint8) (mid, rid string, payloadType PayloadType, err error) { + rp := &rtp.Packet{} + if err = rp.Unmarshal(buf); err != nil { + return + } + + if !rp.Header.Extension { + return + } + + payloadType = PayloadType(rp.PayloadType) + if payload := rp.GetExtension(midExtensionID); payload != nil { + mid = string(payload) + } + + if payload := rp.GetExtension(streamIDExtensionID); payload != nil { + rid = string(payload) + } + + return +} |