Files
webrtc/rtptransceiver.go
Pion 0466659207 Update CI configs to v0.4.5
Update lint scripts and CI configs.
2020-09-09 22:09:23 -07:00

180 lines
5.1 KiB
Go

// +build !js
package webrtc
import (
"fmt"
"sync/atomic"
"github.com/pion/rtp"
"github.com/pion/sdp/v2"
)
// 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
}
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("cannot change transceiver mid from: %s to %s", 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 *Track) error {
t.Sender().setTrack(track)
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 fmt.Errorf("invalid state change in RTPTransceiver.setSending")
}
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, RTPTransceiverDirectionSendrecv}
case RTPTransceiverDirectionRecvonly:
return []RTPTransceiverDirection{RTPTransceiverDirectionSendonly, RTPTransceiverDirectionSendrecv}
}
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, sdesMidExtMap, sdesStreamIDExtMap *sdp.ExtMap) (mid, rid string, payloadType uint8, err error) {
rp := &rtp.Packet{}
if err = rp.Unmarshal(buf); err != nil {
return
}
if !rp.Header.Extension {
return
}
payloadType = rp.PayloadType
if payload := rp.GetExtension(uint8(sdesMidExtMap.Value)); payload != nil {
mid = string(payload)
}
if payload := rp.GetExtension(uint8(sdesStreamIDExtMap.Value)); payload != nil {
rid = string(payload)
}
return
}