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  }