github.com/pion/webrtc/v3@v3.2.24/rtpsender_test.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  	"context"
    11  	"errors"
    12  	"io"
    13  	"sync/atomic"
    14  	"testing"
    15  	"time"
    16  
    17  	"github.com/pion/transport/v2/test"
    18  	"github.com/pion/webrtc/v3/pkg/media"
    19  	"github.com/stretchr/testify/assert"
    20  )
    21  
    22  func Test_RTPSender_ReplaceTrack(t *testing.T) {
    23  	lim := test.TimeOut(time.Second * 10)
    24  	defer lim.Stop()
    25  
    26  	report := test.CheckRoutines(t)
    27  	defer report()
    28  
    29  	s := SettingEngine{}
    30  	s.DisableSRTPReplayProtection(true)
    31  
    32  	m := &MediaEngine{}
    33  	assert.NoError(t, m.RegisterDefaultCodecs())
    34  
    35  	sender, receiver, err := NewAPI(WithMediaEngine(m), WithSettingEngine(s)).newPair(Configuration{})
    36  	assert.NoError(t, err)
    37  
    38  	trackA, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion")
    39  	assert.NoError(t, err)
    40  
    41  	trackB, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeH264}, "video", "pion")
    42  	assert.NoError(t, err)
    43  
    44  	rtpSender, err := sender.AddTrack(trackA)
    45  	assert.NoError(t, err)
    46  
    47  	seenPacketA, seenPacketACancel := context.WithCancel(context.Background())
    48  	seenPacketB, seenPacketBCancel := context.WithCancel(context.Background())
    49  
    50  	var onTrackCount uint64
    51  	receiver.OnTrack(func(track *TrackRemote, _ *RTPReceiver) {
    52  		assert.Equal(t, uint64(1), atomic.AddUint64(&onTrackCount, 1))
    53  
    54  		for {
    55  			pkt, _, err := track.ReadRTP()
    56  			if err != nil {
    57  				assert.True(t, errors.Is(io.EOF, err))
    58  				return
    59  			}
    60  
    61  			switch {
    62  			case pkt.Payload[len(pkt.Payload)-1] == 0xAA:
    63  				assert.Equal(t, track.Codec().MimeType, MimeTypeVP8)
    64  				seenPacketACancel()
    65  			case pkt.Payload[len(pkt.Payload)-1] == 0xBB:
    66  				assert.Equal(t, track.Codec().MimeType, MimeTypeH264)
    67  				seenPacketBCancel()
    68  			default:
    69  				t.Fatalf("Unexpected RTP Data % 02x", pkt.Payload[len(pkt.Payload)-1])
    70  			}
    71  		}
    72  	})
    73  
    74  	assert.NoError(t, signalPair(sender, receiver))
    75  
    76  	// Block Until packet with 0xAA has been seen
    77  	func() {
    78  		for range time.Tick(time.Millisecond * 20) {
    79  			select {
    80  			case <-seenPacketA.Done():
    81  				return
    82  			default:
    83  				assert.NoError(t, trackA.WriteSample(media.Sample{Data: []byte{0xAA}, Duration: time.Second}))
    84  			}
    85  		}
    86  	}()
    87  
    88  	assert.NoError(t, rtpSender.ReplaceTrack(trackB))
    89  
    90  	// Block Until packet with 0xBB has been seen
    91  	func() {
    92  		for range time.Tick(time.Millisecond * 20) {
    93  			select {
    94  			case <-seenPacketB.Done():
    95  				return
    96  			default:
    97  				assert.NoError(t, trackB.WriteSample(media.Sample{Data: []byte{0xBB}, Duration: time.Second}))
    98  			}
    99  		}
   100  	}()
   101  
   102  	closePairNow(t, sender, receiver)
   103  }
   104  
   105  func Test_RTPSender_GetParameters(t *testing.T) {
   106  	lim := test.TimeOut(time.Second * 10)
   107  	defer lim.Stop()
   108  
   109  	report := test.CheckRoutines(t)
   110  	defer report()
   111  
   112  	offerer, answerer, err := newPair()
   113  	assert.NoError(t, err)
   114  
   115  	rtpTransceiver, err := offerer.AddTransceiverFromKind(RTPCodecTypeVideo)
   116  	assert.NoError(t, err)
   117  
   118  	assert.NoError(t, signalPair(offerer, answerer))
   119  
   120  	parameters := rtpTransceiver.Sender().GetParameters()
   121  	assert.NotEqual(t, 0, len(parameters.Codecs))
   122  	assert.Equal(t, 1, len(parameters.Encodings))
   123  	assert.Equal(t, rtpTransceiver.Sender().trackEncodings[0].ssrc, parameters.Encodings[0].SSRC)
   124  	assert.Equal(t, "", parameters.Encodings[0].RID)
   125  
   126  	closePairNow(t, offerer, answerer)
   127  }
   128  
   129  func Test_RTPSender_GetParameters_WithRID(t *testing.T) {
   130  	lim := test.TimeOut(time.Second * 10)
   131  	defer lim.Stop()
   132  
   133  	report := test.CheckRoutines(t)
   134  	defer report()
   135  
   136  	offerer, answerer, err := newPair()
   137  	assert.NoError(t, err)
   138  
   139  	rtpTransceiver, err := offerer.AddTransceiverFromKind(RTPCodecTypeVideo)
   140  	assert.NoError(t, err)
   141  
   142  	assert.NoError(t, signalPair(offerer, answerer))
   143  
   144  	track, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion", WithRTPStreamID("moo"))
   145  	assert.NoError(t, err)
   146  
   147  	err = rtpTransceiver.setSendingTrack(track)
   148  	assert.NoError(t, err)
   149  
   150  	parameters := rtpTransceiver.Sender().GetParameters()
   151  	assert.Equal(t, track.RID(), parameters.Encodings[0].RID)
   152  
   153  	closePairNow(t, offerer, answerer)
   154  }
   155  
   156  func Test_RTPSender_SetReadDeadline(t *testing.T) {
   157  	lim := test.TimeOut(time.Second * 30)
   158  	defer lim.Stop()
   159  
   160  	report := test.CheckRoutines(t)
   161  	defer report()
   162  
   163  	sender, receiver, wan := createVNetPair(t)
   164  
   165  	track, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion")
   166  	assert.NoError(t, err)
   167  
   168  	rtpSender, err := sender.AddTrack(track)
   169  	assert.NoError(t, err)
   170  
   171  	peerConnectionsConnected := untilConnectionState(PeerConnectionStateConnected, sender, receiver)
   172  
   173  	assert.NoError(t, signalPair(sender, receiver))
   174  
   175  	peerConnectionsConnected.Wait()
   176  
   177  	assert.NoError(t, rtpSender.SetReadDeadline(time.Now().Add(1*time.Second)))
   178  	_, _, err = rtpSender.ReadRTCP()
   179  	assert.Error(t, err)
   180  
   181  	assert.NoError(t, wan.Stop())
   182  	closePairNow(t, sender, receiver)
   183  }
   184  
   185  func Test_RTPSender_ReplaceTrack_InvalidTrackKindChange(t *testing.T) {
   186  	lim := test.TimeOut(time.Second * 10)
   187  	defer lim.Stop()
   188  
   189  	report := test.CheckRoutines(t)
   190  	defer report()
   191  
   192  	sender, receiver, err := newPair()
   193  	assert.NoError(t, err)
   194  
   195  	trackA, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion")
   196  	assert.NoError(t, err)
   197  
   198  	trackB, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeOpus}, "audio", "pion")
   199  	assert.NoError(t, err)
   200  
   201  	rtpSender, err := sender.AddTrack(trackA)
   202  	assert.NoError(t, err)
   203  
   204  	assert.NoError(t, signalPair(sender, receiver))
   205  
   206  	seenPacket, seenPacketCancel := context.WithCancel(context.Background())
   207  	receiver.OnTrack(func(_ *TrackRemote, _ *RTPReceiver) {
   208  		seenPacketCancel()
   209  	})
   210  
   211  	func() {
   212  		for range time.Tick(time.Millisecond * 20) {
   213  			select {
   214  			case <-seenPacket.Done():
   215  				return
   216  			default:
   217  				assert.NoError(t, trackA.WriteSample(media.Sample{Data: []byte{0xAA}, Duration: time.Second}))
   218  			}
   219  		}
   220  	}()
   221  
   222  	assert.True(t, errors.Is(rtpSender.ReplaceTrack(trackB), ErrRTPSenderNewTrackHasIncorrectKind))
   223  
   224  	closePairNow(t, sender, receiver)
   225  }
   226  
   227  func Test_RTPSender_ReplaceTrack_InvalidCodecChange(t *testing.T) {
   228  	lim := test.TimeOut(time.Second * 10)
   229  	defer lim.Stop()
   230  
   231  	report := test.CheckRoutines(t)
   232  	defer report()
   233  
   234  	sender, receiver, err := newPair()
   235  	assert.NoError(t, err)
   236  
   237  	trackA, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion")
   238  	assert.NoError(t, err)
   239  
   240  	trackB, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP9}, "video", "pion")
   241  	assert.NoError(t, err)
   242  
   243  	rtpSender, err := sender.AddTrack(trackA)
   244  	assert.NoError(t, err)
   245  
   246  	err = rtpSender.rtpTransceiver.SetCodecPreferences([]RTPCodecParameters{{
   247  		RTPCodecCapability: RTPCodecCapability{MimeType: MimeTypeVP8},
   248  		PayloadType:        96,
   249  	}})
   250  	assert.NoError(t, err)
   251  
   252  	assert.NoError(t, signalPair(sender, receiver))
   253  
   254  	seenPacket, seenPacketCancel := context.WithCancel(context.Background())
   255  	receiver.OnTrack(func(_ *TrackRemote, _ *RTPReceiver) {
   256  		seenPacketCancel()
   257  	})
   258  
   259  	func() {
   260  		for range time.Tick(time.Millisecond * 20) {
   261  			select {
   262  			case <-seenPacket.Done():
   263  				return
   264  			default:
   265  				assert.NoError(t, trackA.WriteSample(media.Sample{Data: []byte{0xAA}, Duration: time.Second}))
   266  			}
   267  		}
   268  	}()
   269  
   270  	assert.True(t, errors.Is(rtpSender.ReplaceTrack(trackB), ErrUnsupportedCodec))
   271  
   272  	closePairNow(t, sender, receiver)
   273  }
   274  
   275  func Test_RTPSender_GetParameters_NilTrack(t *testing.T) {
   276  	track, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion")
   277  	assert.NoError(t, err)
   278  
   279  	peerConnection, err := NewPeerConnection(Configuration{})
   280  	assert.NoError(t, err)
   281  
   282  	rtpSender, err := peerConnection.AddTrack(track)
   283  	assert.NoError(t, err)
   284  
   285  	assert.NoError(t, rtpSender.ReplaceTrack(nil))
   286  	rtpSender.GetParameters()
   287  
   288  	assert.NoError(t, peerConnection.Close())
   289  }
   290  
   291  func Test_RTPSender_Send(t *testing.T) {
   292  	track, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion")
   293  	assert.NoError(t, err)
   294  
   295  	peerConnection, err := NewPeerConnection(Configuration{})
   296  	assert.NoError(t, err)
   297  
   298  	rtpSender, err := peerConnection.AddTrack(track)
   299  	assert.NoError(t, err)
   300  
   301  	parameter := rtpSender.GetParameters()
   302  	err = rtpSender.Send(parameter)
   303  	<-rtpSender.sendCalled
   304  	assert.NoError(t, err)
   305  
   306  	assert.NoError(t, peerConnection.Close())
   307  }
   308  
   309  func Test_RTPSender_Send_Called_Once(t *testing.T) {
   310  	track, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion")
   311  	assert.NoError(t, err)
   312  
   313  	peerConnection, err := NewPeerConnection(Configuration{})
   314  	assert.NoError(t, err)
   315  
   316  	rtpSender, err := peerConnection.AddTrack(track)
   317  	assert.NoError(t, err)
   318  
   319  	parameter := rtpSender.GetParameters()
   320  	err = rtpSender.Send(parameter)
   321  	<-rtpSender.sendCalled
   322  	assert.NoError(t, err)
   323  
   324  	err = rtpSender.Send(parameter)
   325  	assert.Equal(t, errRTPSenderSendAlreadyCalled, err)
   326  
   327  	assert.NoError(t, peerConnection.Close())
   328  }
   329  
   330  func Test_RTPSender_Send_Track_Removed(t *testing.T) {
   331  	track, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion")
   332  	assert.NoError(t, err)
   333  
   334  	peerConnection, err := NewPeerConnection(Configuration{})
   335  	assert.NoError(t, err)
   336  
   337  	rtpSender, err := peerConnection.AddTrack(track)
   338  	assert.NoError(t, err)
   339  
   340  	parameter := rtpSender.GetParameters()
   341  	assert.NoError(t, peerConnection.RemoveTrack(rtpSender))
   342  	assert.Equal(t, errRTPSenderTrackRemoved, rtpSender.Send(parameter))
   343  
   344  	assert.NoError(t, peerConnection.Close())
   345  }
   346  
   347  func Test_RTPSender_Add_Encoding(t *testing.T) {
   348  	track, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion")
   349  	assert.NoError(t, err)
   350  
   351  	peerConnection, err := NewPeerConnection(Configuration{})
   352  	assert.NoError(t, err)
   353  
   354  	rtpSender, err := peerConnection.AddTrack(track)
   355  	assert.NoError(t, err)
   356  
   357  	assert.Equal(t, errRTPSenderTrackNil, rtpSender.AddEncoding(nil))
   358  
   359  	track1, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion")
   360  	assert.NoError(t, err)
   361  	assert.Equal(t, errRTPSenderRidNil, rtpSender.AddEncoding(track1))
   362  
   363  	track1, err = NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion", WithRTPStreamID("h"))
   364  	assert.NoError(t, err)
   365  	assert.Equal(t, errRTPSenderNoBaseEncoding, rtpSender.AddEncoding(track1))
   366  
   367  	track, err = NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion", WithRTPStreamID("q"))
   368  	assert.NoError(t, err)
   369  
   370  	rtpSender, err = peerConnection.AddTrack(track)
   371  	assert.NoError(t, err)
   372  
   373  	track1, err = NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video1", "pion", WithRTPStreamID("h"))
   374  	assert.NoError(t, err)
   375  	assert.Equal(t, errRTPSenderBaseEncodingMismatch, rtpSender.AddEncoding(track1))
   376  
   377  	track1, err = NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion1", WithRTPStreamID("h"))
   378  	assert.NoError(t, err)
   379  	assert.Equal(t, errRTPSenderBaseEncodingMismatch, rtpSender.AddEncoding(track1))
   380  
   381  	track1, err = NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeOpus}, "video", "pion", WithRTPStreamID("h"))
   382  	assert.NoError(t, err)
   383  	assert.Equal(t, errRTPSenderBaseEncodingMismatch, rtpSender.AddEncoding(track1))
   384  
   385  	track1, err = NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion", WithRTPStreamID("q"))
   386  	assert.NoError(t, err)
   387  	assert.Equal(t, errRTPSenderRIDCollision, rtpSender.AddEncoding(track1))
   388  
   389  	track1, err = NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion", WithRTPStreamID("h"))
   390  	assert.NoError(t, err)
   391  	assert.NoError(t, rtpSender.AddEncoding(track1))
   392  
   393  	err = rtpSender.Send(rtpSender.GetParameters())
   394  	assert.NoError(t, err)
   395  
   396  	track1, err = NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion", WithRTPStreamID("f"))
   397  	assert.NoError(t, err)
   398  	assert.Equal(t, errRTPSenderSendAlreadyCalled, rtpSender.AddEncoding(track1))
   399  
   400  	err = rtpSender.Stop()
   401  	assert.NoError(t, err)
   402  
   403  	assert.Equal(t, errRTPSenderStopped, rtpSender.AddEncoding(track1))
   404  
   405  	assert.NoError(t, peerConnection.Close())
   406  }