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  }