github.com/pion/webrtc/v3@v3.2.24/rtpreceiver.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  	"io"
    12  	"sync"
    13  	"time"
    14  
    15  	"github.com/pion/interceptor"
    16  	"github.com/pion/rtcp"
    17  	"github.com/pion/srtp/v2"
    18  	"github.com/pion/webrtc/v3/internal/util"
    19  )
    20  
    21  // trackStreams maintains a mapping of RTP/RTCP streams to a specific track
    22  // a RTPReceiver may contain multiple streams if we are dealing with Simulcast
    23  type trackStreams struct {
    24  	track *TrackRemote
    25  
    26  	streamInfo, repairStreamInfo *interceptor.StreamInfo
    27  
    28  	rtpReadStream  *srtp.ReadStreamSRTP
    29  	rtpInterceptor interceptor.RTPReader
    30  
    31  	rtcpReadStream  *srtp.ReadStreamSRTCP
    32  	rtcpInterceptor interceptor.RTCPReader
    33  
    34  	repairReadStream  *srtp.ReadStreamSRTP
    35  	repairInterceptor interceptor.RTPReader
    36  
    37  	repairRtcpReadStream  *srtp.ReadStreamSRTCP
    38  	repairRtcpInterceptor interceptor.RTCPReader
    39  }
    40  
    41  // RTPReceiver allows an application to inspect the receipt of a TrackRemote
    42  type RTPReceiver struct {
    43  	kind      RTPCodecType
    44  	transport *DTLSTransport
    45  
    46  	tracks []trackStreams
    47  
    48  	closed, received chan interface{}
    49  	mu               sync.RWMutex
    50  
    51  	tr *RTPTransceiver
    52  
    53  	// A reference to the associated api object
    54  	api *API
    55  }
    56  
    57  // NewRTPReceiver constructs a new RTPReceiver
    58  func (api *API) NewRTPReceiver(kind RTPCodecType, transport *DTLSTransport) (*RTPReceiver, error) {
    59  	if transport == nil {
    60  		return nil, errRTPReceiverDTLSTransportNil
    61  	}
    62  
    63  	r := &RTPReceiver{
    64  		kind:      kind,
    65  		transport: transport,
    66  		api:       api,
    67  		closed:    make(chan interface{}),
    68  		received:  make(chan interface{}),
    69  		tracks:    []trackStreams{},
    70  	}
    71  
    72  	return r, nil
    73  }
    74  
    75  func (r *RTPReceiver) setRTPTransceiver(tr *RTPTransceiver) {
    76  	r.mu.Lock()
    77  	defer r.mu.Unlock()
    78  	r.tr = tr
    79  }
    80  
    81  // Transport returns the currently-configured *DTLSTransport or nil
    82  // if one has not yet been configured
    83  func (r *RTPReceiver) Transport() *DTLSTransport {
    84  	r.mu.RLock()
    85  	defer r.mu.RUnlock()
    86  	return r.transport
    87  }
    88  
    89  func (r *RTPReceiver) getParameters() RTPParameters {
    90  	parameters := r.api.mediaEngine.getRTPParametersByKind(r.kind, []RTPTransceiverDirection{RTPTransceiverDirectionRecvonly})
    91  	if r.tr != nil {
    92  		parameters.Codecs = r.tr.getCodecs()
    93  	}
    94  	return parameters
    95  }
    96  
    97  // GetParameters describes the current configuration for the encoding and
    98  // transmission of media on the receiver's track.
    99  func (r *RTPReceiver) GetParameters() RTPParameters {
   100  	r.mu.RLock()
   101  	defer r.mu.RUnlock()
   102  	return r.getParameters()
   103  }
   104  
   105  // Track returns the RtpTransceiver TrackRemote
   106  func (r *RTPReceiver) Track() *TrackRemote {
   107  	r.mu.RLock()
   108  	defer r.mu.RUnlock()
   109  
   110  	if len(r.tracks) != 1 {
   111  		return nil
   112  	}
   113  	return r.tracks[0].track
   114  }
   115  
   116  // Tracks returns the RtpTransceiver tracks
   117  // A RTPReceiver to support Simulcast may now have multiple tracks
   118  func (r *RTPReceiver) Tracks() []*TrackRemote {
   119  	r.mu.RLock()
   120  	defer r.mu.RUnlock()
   121  
   122  	var tracks []*TrackRemote
   123  	for i := range r.tracks {
   124  		tracks = append(tracks, r.tracks[i].track)
   125  	}
   126  	return tracks
   127  }
   128  
   129  // RTPTransceiver returns the RTPTransceiver this
   130  // RTPReceiver belongs too, or nil if none
   131  func (r *RTPReceiver) RTPTransceiver() *RTPTransceiver {
   132  	r.mu.Lock()
   133  	defer r.mu.Unlock()
   134  
   135  	return r.tr
   136  }
   137  
   138  // configureReceive initialize the track
   139  func (r *RTPReceiver) configureReceive(parameters RTPReceiveParameters) {
   140  	r.mu.Lock()
   141  	defer r.mu.Unlock()
   142  
   143  	for i := range parameters.Encodings {
   144  		t := trackStreams{
   145  			track: newTrackRemote(
   146  				r.kind,
   147  				parameters.Encodings[i].SSRC,
   148  				parameters.Encodings[i].RID,
   149  				r,
   150  			),
   151  		}
   152  
   153  		r.tracks = append(r.tracks, t)
   154  	}
   155  }
   156  
   157  // startReceive starts all the transports
   158  func (r *RTPReceiver) startReceive(parameters RTPReceiveParameters) error {
   159  	r.mu.Lock()
   160  	defer r.mu.Unlock()
   161  	select {
   162  	case <-r.received:
   163  		return errRTPReceiverReceiveAlreadyCalled
   164  	default:
   165  	}
   166  	defer close(r.received)
   167  
   168  	globalParams := r.getParameters()
   169  	codec := RTPCodecCapability{}
   170  	if len(globalParams.Codecs) != 0 {
   171  		codec = globalParams.Codecs[0].RTPCodecCapability
   172  	}
   173  
   174  	for i := range parameters.Encodings {
   175  		if parameters.Encodings[i].RID != "" {
   176  			// RID based tracks will be set up in receiveForRid
   177  			continue
   178  		}
   179  
   180  		var t *trackStreams
   181  		for idx, ts := range r.tracks {
   182  			if ts.track != nil && parameters.Encodings[i].SSRC != 0 && ts.track.SSRC() == parameters.Encodings[i].SSRC {
   183  				t = &r.tracks[idx]
   184  				break
   185  			}
   186  		}
   187  		if t == nil {
   188  			return fmt.Errorf("%w: %d", errRTPReceiverWithSSRCTrackStreamNotFound, parameters.Encodings[i].SSRC)
   189  		}
   190  
   191  		if parameters.Encodings[i].SSRC != 0 {
   192  			t.streamInfo = createStreamInfo("", parameters.Encodings[i].SSRC, 0, codec, globalParams.HeaderExtensions)
   193  			var err error
   194  			if t.rtpReadStream, t.rtpInterceptor, t.rtcpReadStream, t.rtcpInterceptor, err = r.transport.streamsForSSRC(parameters.Encodings[i].SSRC, *t.streamInfo); err != nil {
   195  				return err
   196  			}
   197  		}
   198  
   199  		if rtxSsrc := parameters.Encodings[i].RTX.SSRC; rtxSsrc != 0 {
   200  			streamInfo := createStreamInfo("", rtxSsrc, 0, codec, globalParams.HeaderExtensions)
   201  			rtpReadStream, rtpInterceptor, rtcpReadStream, rtcpInterceptor, err := r.transport.streamsForSSRC(rtxSsrc, *streamInfo)
   202  			if err != nil {
   203  				return err
   204  			}
   205  
   206  			if err = r.receiveForRtx(rtxSsrc, "", streamInfo, rtpReadStream, rtpInterceptor, rtcpReadStream, rtcpInterceptor); err != nil {
   207  				return err
   208  			}
   209  		}
   210  	}
   211  
   212  	return nil
   213  }
   214  
   215  // Receive initialize the track and starts all the transports
   216  func (r *RTPReceiver) Receive(parameters RTPReceiveParameters) error {
   217  	r.configureReceive(parameters)
   218  	return r.startReceive(parameters)
   219  }
   220  
   221  // Read reads incoming RTCP for this RTPReceiver
   222  func (r *RTPReceiver) Read(b []byte) (n int, a interceptor.Attributes, err error) {
   223  	select {
   224  	case <-r.received:
   225  		return r.tracks[0].rtcpInterceptor.Read(b, a)
   226  	case <-r.closed:
   227  		return 0, nil, io.ErrClosedPipe
   228  	}
   229  }
   230  
   231  // ReadSimulcast reads incoming RTCP for this RTPReceiver for given rid
   232  func (r *RTPReceiver) ReadSimulcast(b []byte, rid string) (n int, a interceptor.Attributes, err error) {
   233  	select {
   234  	case <-r.received:
   235  		for _, t := range r.tracks {
   236  			if t.track != nil && t.track.rid == rid {
   237  				return t.rtcpInterceptor.Read(b, a)
   238  			}
   239  		}
   240  		return 0, nil, fmt.Errorf("%w: %s", errRTPReceiverForRIDTrackStreamNotFound, rid)
   241  	case <-r.closed:
   242  		return 0, nil, io.ErrClosedPipe
   243  	}
   244  }
   245  
   246  // ReadRTCP is a convenience method that wraps Read and unmarshal for you.
   247  // It also runs any configured interceptors.
   248  func (r *RTPReceiver) ReadRTCP() ([]rtcp.Packet, interceptor.Attributes, error) {
   249  	b := make([]byte, r.api.settingEngine.getReceiveMTU())
   250  	i, attributes, err := r.Read(b)
   251  	if err != nil {
   252  		return nil, nil, err
   253  	}
   254  
   255  	pkts, err := rtcp.Unmarshal(b[:i])
   256  	if err != nil {
   257  		return nil, nil, err
   258  	}
   259  
   260  	return pkts, attributes, nil
   261  }
   262  
   263  // ReadSimulcastRTCP is a convenience method that wraps ReadSimulcast and unmarshal for you
   264  func (r *RTPReceiver) ReadSimulcastRTCP(rid string) ([]rtcp.Packet, interceptor.Attributes, error) {
   265  	b := make([]byte, r.api.settingEngine.getReceiveMTU())
   266  	i, attributes, err := r.ReadSimulcast(b, rid)
   267  	if err != nil {
   268  		return nil, nil, err
   269  	}
   270  
   271  	pkts, err := rtcp.Unmarshal(b[:i])
   272  	return pkts, attributes, err
   273  }
   274  
   275  func (r *RTPReceiver) haveReceived() bool {
   276  	select {
   277  	case <-r.received:
   278  		return true
   279  	default:
   280  		return false
   281  	}
   282  }
   283  
   284  // Stop irreversibly stops the RTPReceiver
   285  func (r *RTPReceiver) Stop() error {
   286  	r.mu.Lock()
   287  	defer r.mu.Unlock()
   288  	var err error
   289  
   290  	select {
   291  	case <-r.closed:
   292  		return err
   293  	default:
   294  	}
   295  
   296  	select {
   297  	case <-r.received:
   298  		for i := range r.tracks {
   299  			errs := []error{}
   300  
   301  			if r.tracks[i].rtcpReadStream != nil {
   302  				errs = append(errs, r.tracks[i].rtcpReadStream.Close())
   303  			}
   304  
   305  			if r.tracks[i].rtpReadStream != nil {
   306  				errs = append(errs, r.tracks[i].rtpReadStream.Close())
   307  			}
   308  
   309  			if r.tracks[i].repairReadStream != nil {
   310  				errs = append(errs, r.tracks[i].repairReadStream.Close())
   311  			}
   312  
   313  			if r.tracks[i].repairRtcpReadStream != nil {
   314  				errs = append(errs, r.tracks[i].repairRtcpReadStream.Close())
   315  			}
   316  
   317  			if r.tracks[i].streamInfo != nil {
   318  				r.api.interceptor.UnbindRemoteStream(r.tracks[i].streamInfo)
   319  			}
   320  
   321  			if r.tracks[i].repairStreamInfo != nil {
   322  				r.api.interceptor.UnbindRemoteStream(r.tracks[i].repairStreamInfo)
   323  			}
   324  
   325  			err = util.FlattenErrs(errs)
   326  		}
   327  	default:
   328  	}
   329  
   330  	close(r.closed)
   331  	return err
   332  }
   333  
   334  func (r *RTPReceiver) streamsForTrack(t *TrackRemote) *trackStreams {
   335  	for i := range r.tracks {
   336  		if r.tracks[i].track == t {
   337  			return &r.tracks[i]
   338  		}
   339  	}
   340  	return nil
   341  }
   342  
   343  // readRTP should only be called by a track, this only exists so we can keep state in one place
   344  func (r *RTPReceiver) readRTP(b []byte, reader *TrackRemote) (n int, a interceptor.Attributes, err error) {
   345  	<-r.received
   346  	if t := r.streamsForTrack(reader); t != nil {
   347  		return t.rtpInterceptor.Read(b, a)
   348  	}
   349  
   350  	return 0, nil, fmt.Errorf("%w: %d", errRTPReceiverWithSSRCTrackStreamNotFound, reader.SSRC())
   351  }
   352  
   353  // receiveForRid is the sibling of Receive expect for RIDs instead of SSRCs
   354  // It populates all the internal state for the given RID
   355  func (r *RTPReceiver) receiveForRid(rid string, params RTPParameters, streamInfo *interceptor.StreamInfo, rtpReadStream *srtp.ReadStreamSRTP, rtpInterceptor interceptor.RTPReader, rtcpReadStream *srtp.ReadStreamSRTCP, rtcpInterceptor interceptor.RTCPReader) (*TrackRemote, error) {
   356  	r.mu.Lock()
   357  	defer r.mu.Unlock()
   358  
   359  	for i := range r.tracks {
   360  		if r.tracks[i].track.RID() == rid {
   361  			r.tracks[i].track.mu.Lock()
   362  			r.tracks[i].track.kind = r.kind
   363  			r.tracks[i].track.codec = params.Codecs[0]
   364  			r.tracks[i].track.params = params
   365  			r.tracks[i].track.ssrc = SSRC(streamInfo.SSRC)
   366  			r.tracks[i].track.mu.Unlock()
   367  
   368  			r.tracks[i].streamInfo = streamInfo
   369  			r.tracks[i].rtpReadStream = rtpReadStream
   370  			r.tracks[i].rtpInterceptor = rtpInterceptor
   371  			r.tracks[i].rtcpReadStream = rtcpReadStream
   372  			r.tracks[i].rtcpInterceptor = rtcpInterceptor
   373  
   374  			return r.tracks[i].track, nil
   375  		}
   376  	}
   377  
   378  	return nil, fmt.Errorf("%w: %s", errRTPReceiverForRIDTrackStreamNotFound, rid)
   379  }
   380  
   381  // receiveForRtx starts a routine that processes the repair stream
   382  // These packets aren't exposed to the user yet, but we need to process them for
   383  // TWCC
   384  func (r *RTPReceiver) receiveForRtx(ssrc SSRC, rsid string, streamInfo *interceptor.StreamInfo, rtpReadStream *srtp.ReadStreamSRTP, rtpInterceptor interceptor.RTPReader, rtcpReadStream *srtp.ReadStreamSRTCP, rtcpInterceptor interceptor.RTCPReader) error {
   385  	var track *trackStreams
   386  	if ssrc != 0 && len(r.tracks) == 1 {
   387  		track = &r.tracks[0]
   388  	} else {
   389  		for i := range r.tracks {
   390  			if r.tracks[i].track.RID() == rsid {
   391  				track = &r.tracks[i]
   392  			}
   393  		}
   394  	}
   395  
   396  	if track == nil {
   397  		return fmt.Errorf("%w: ssrc(%d) rsid(%s)", errRTPReceiverForRIDTrackStreamNotFound, ssrc, rsid)
   398  	}
   399  
   400  	track.repairStreamInfo = streamInfo
   401  	track.repairReadStream = rtpReadStream
   402  	track.repairInterceptor = rtpInterceptor
   403  	track.repairRtcpReadStream = rtcpReadStream
   404  	track.repairRtcpInterceptor = rtcpInterceptor
   405  
   406  	go func() {
   407  		b := make([]byte, r.api.settingEngine.getReceiveMTU())
   408  		for {
   409  			if _, _, readErr := track.repairInterceptor.Read(b, nil); readErr != nil {
   410  				return
   411  			}
   412  		}
   413  	}()
   414  	return nil
   415  }
   416  
   417  // SetReadDeadline sets the max amount of time the RTCP stream will block before returning. 0 is forever.
   418  func (r *RTPReceiver) SetReadDeadline(t time.Time) error {
   419  	r.mu.RLock()
   420  	defer r.mu.RUnlock()
   421  
   422  	return r.tracks[0].rtcpReadStream.SetReadDeadline(t)
   423  }
   424  
   425  // SetReadDeadlineSimulcast sets the max amount of time the RTCP stream for a given rid will block before returning. 0 is forever.
   426  func (r *RTPReceiver) SetReadDeadlineSimulcast(deadline time.Time, rid string) error {
   427  	r.mu.RLock()
   428  	defer r.mu.RUnlock()
   429  
   430  	for _, t := range r.tracks {
   431  		if t.track != nil && t.track.rid == rid {
   432  			return t.rtcpReadStream.SetReadDeadline(deadline)
   433  		}
   434  	}
   435  	return fmt.Errorf("%w: %s", errRTPReceiverForRIDTrackStreamNotFound, rid)
   436  }
   437  
   438  // setRTPReadDeadline sets the max amount of time the RTP stream will block before returning. 0 is forever.
   439  // This should be fired by calling SetReadDeadline on the TrackRemote
   440  func (r *RTPReceiver) setRTPReadDeadline(deadline time.Time, reader *TrackRemote) error {
   441  	r.mu.RLock()
   442  	defer r.mu.RUnlock()
   443  
   444  	if t := r.streamsForTrack(reader); t != nil {
   445  		return t.rtpReadStream.SetReadDeadline(deadline)
   446  	}
   447  	return fmt.Errorf("%w: %d", errRTPReceiverWithSSRCTrackStreamNotFound, reader.SSRC())
   448  }