github.com/pion/webrtc/v3@v3.2.24/track_local_static_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  	"testing"
    13  	"time"
    14  
    15  	"github.com/pion/rtp"
    16  	"github.com/pion/transport/v2/test"
    17  	"github.com/stretchr/testify/assert"
    18  )
    19  
    20  // If a remote doesn't support a Codec used by a `TrackLocalStatic`
    21  // an error should be returned to the user
    22  func Test_TrackLocalStatic_NoCodecIntersection(t *testing.T) {
    23  	lim := test.TimeOut(time.Second * 30)
    24  	defer lim.Stop()
    25  
    26  	report := test.CheckRoutines(t)
    27  	defer report()
    28  
    29  	track, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion")
    30  	assert.NoError(t, err)
    31  
    32  	t.Run("Offerer", func(t *testing.T) {
    33  		pc, err := NewPeerConnection(Configuration{})
    34  		assert.NoError(t, err)
    35  
    36  		noCodecPC, err := NewAPI().NewPeerConnection(Configuration{})
    37  		assert.NoError(t, err)
    38  
    39  		_, err = pc.AddTrack(track)
    40  		assert.NoError(t, err)
    41  
    42  		assert.ErrorIs(t, signalPair(pc, noCodecPC), ErrUnsupportedCodec)
    43  
    44  		closePairNow(t, noCodecPC, pc)
    45  	})
    46  
    47  	t.Run("Answerer", func(t *testing.T) {
    48  		pc, err := NewPeerConnection(Configuration{})
    49  		assert.NoError(t, err)
    50  
    51  		m := &MediaEngine{}
    52  		assert.NoError(t, m.RegisterCodec(RTPCodecParameters{
    53  			RTPCodecCapability: RTPCodecCapability{MimeType: "video/VP9", ClockRate: 90000, Channels: 0, SDPFmtpLine: "", RTCPFeedback: nil},
    54  			PayloadType:        96,
    55  		}, RTPCodecTypeVideo))
    56  
    57  		vp9OnlyPC, err := NewAPI(WithMediaEngine(m)).NewPeerConnection(Configuration{})
    58  		assert.NoError(t, err)
    59  
    60  		_, err = vp9OnlyPC.AddTransceiverFromKind(RTPCodecTypeVideo)
    61  		assert.NoError(t, err)
    62  
    63  		_, err = pc.AddTrack(track)
    64  		assert.NoError(t, err)
    65  
    66  		assert.True(t, errors.Is(signalPair(vp9OnlyPC, pc), ErrUnsupportedCodec))
    67  
    68  		closePairNow(t, vp9OnlyPC, pc)
    69  	})
    70  
    71  	t.Run("Local", func(t *testing.T) {
    72  		offerer, answerer, err := newPair()
    73  		assert.NoError(t, err)
    74  
    75  		invalidCodecTrack, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: "video/invalid-codec"}, "video", "pion")
    76  		assert.NoError(t, err)
    77  
    78  		_, err = offerer.AddTrack(invalidCodecTrack)
    79  		assert.NoError(t, err)
    80  
    81  		assert.True(t, errors.Is(signalPair(offerer, answerer), ErrUnsupportedCodec))
    82  		closePairNow(t, offerer, answerer)
    83  	})
    84  }
    85  
    86  // Assert that Bind/Unbind happens when expected
    87  func Test_TrackLocalStatic_Closed(t *testing.T) {
    88  	lim := test.TimeOut(time.Second * 30)
    89  	defer lim.Stop()
    90  
    91  	report := test.CheckRoutines(t)
    92  	defer report()
    93  
    94  	pcOffer, pcAnswer, err := newPair()
    95  	assert.NoError(t, err)
    96  
    97  	_, err = pcAnswer.AddTransceiverFromKind(RTPCodecTypeVideo)
    98  	assert.NoError(t, err)
    99  
   100  	vp8Writer, err := NewTrackLocalStaticRTP(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion")
   101  	assert.NoError(t, err)
   102  
   103  	_, err = pcOffer.AddTrack(vp8Writer)
   104  	assert.NoError(t, err)
   105  
   106  	assert.Equal(t, len(vp8Writer.bindings), 0, "No binding should exist before signaling")
   107  
   108  	assert.NoError(t, signalPair(pcOffer, pcAnswer))
   109  
   110  	assert.Equal(t, len(vp8Writer.bindings), 1, "binding should exist after signaling")
   111  
   112  	closePairNow(t, pcOffer, pcAnswer)
   113  
   114  	assert.Equal(t, len(vp8Writer.bindings), 0, "No binding should exist after close")
   115  }
   116  
   117  func Test_TrackLocalStatic_PayloadType(t *testing.T) {
   118  	lim := test.TimeOut(time.Second * 30)
   119  	defer lim.Stop()
   120  
   121  	report := test.CheckRoutines(t)
   122  	defer report()
   123  
   124  	mediaEngineOne := &MediaEngine{}
   125  	assert.NoError(t, mediaEngineOne.RegisterCodec(RTPCodecParameters{
   126  		RTPCodecCapability: RTPCodecCapability{MimeType: "video/VP8", ClockRate: 90000, Channels: 0, SDPFmtpLine: "", RTCPFeedback: nil},
   127  		PayloadType:        100,
   128  	}, RTPCodecTypeVideo))
   129  
   130  	mediaEngineTwo := &MediaEngine{}
   131  	assert.NoError(t, mediaEngineTwo.RegisterCodec(RTPCodecParameters{
   132  		RTPCodecCapability: RTPCodecCapability{MimeType: "video/VP8", ClockRate: 90000, Channels: 0, SDPFmtpLine: "", RTCPFeedback: nil},
   133  		PayloadType:        200,
   134  	}, RTPCodecTypeVideo))
   135  
   136  	offerer, err := NewAPI(WithMediaEngine(mediaEngineOne)).NewPeerConnection(Configuration{})
   137  	assert.NoError(t, err)
   138  
   139  	answerer, err := NewAPI(WithMediaEngine(mediaEngineTwo)).NewPeerConnection(Configuration{})
   140  	assert.NoError(t, err)
   141  
   142  	track, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion")
   143  	assert.NoError(t, err)
   144  
   145  	_, err = offerer.AddTransceiverFromKind(RTPCodecTypeVideo)
   146  	assert.NoError(t, err)
   147  
   148  	_, err = answerer.AddTrack(track)
   149  	assert.NoError(t, err)
   150  
   151  	onTrackFired, onTrackFiredFunc := context.WithCancel(context.Background())
   152  	offerer.OnTrack(func(track *TrackRemote, r *RTPReceiver) {
   153  		assert.Equal(t, track.PayloadType(), PayloadType(100))
   154  		assert.Equal(t, track.Codec().RTPCodecCapability.MimeType, "video/VP8")
   155  
   156  		onTrackFiredFunc()
   157  	})
   158  
   159  	assert.NoError(t, signalPair(offerer, answerer))
   160  
   161  	sendVideoUntilDone(onTrackFired.Done(), t, []*TrackLocalStaticSample{track})
   162  
   163  	closePairNow(t, offerer, answerer)
   164  }
   165  
   166  // Assert that writing to a Track doesn't modify the input
   167  // Even though we can pass a pointer we shouldn't modify the incoming value
   168  func Test_TrackLocalStatic_Mutate_Input(t *testing.T) {
   169  	lim := test.TimeOut(time.Second * 30)
   170  	defer lim.Stop()
   171  
   172  	report := test.CheckRoutines(t)
   173  	defer report()
   174  
   175  	pcOffer, pcAnswer, err := newPair()
   176  	assert.NoError(t, err)
   177  
   178  	vp8Writer, err := NewTrackLocalStaticRTP(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion")
   179  	assert.NoError(t, err)
   180  
   181  	_, err = pcOffer.AddTrack(vp8Writer)
   182  	assert.NoError(t, err)
   183  
   184  	assert.NoError(t, signalPair(pcOffer, pcAnswer))
   185  
   186  	pkt := &rtp.Packet{Header: rtp.Header{SSRC: 1, PayloadType: 1}}
   187  	assert.NoError(t, vp8Writer.WriteRTP(pkt))
   188  
   189  	assert.Equal(t, pkt.Header.SSRC, uint32(1))
   190  	assert.Equal(t, pkt.Header.PayloadType, uint8(1))
   191  
   192  	closePairNow(t, pcOffer, pcAnswer)
   193  }
   194  
   195  // Assert that writing to a Track that has Binded (but not connected)
   196  // does not block
   197  func Test_TrackLocalStatic_Binding_NonBlocking(t *testing.T) {
   198  	lim := test.TimeOut(time.Second * 5)
   199  	defer lim.Stop()
   200  
   201  	report := test.CheckRoutines(t)
   202  	defer report()
   203  
   204  	pcOffer, pcAnswer, err := newPair()
   205  	assert.NoError(t, err)
   206  
   207  	_, err = pcOffer.AddTransceiverFromKind(RTPCodecTypeVideo)
   208  	assert.NoError(t, err)
   209  
   210  	vp8Writer, err := NewTrackLocalStaticRTP(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion")
   211  	assert.NoError(t, err)
   212  
   213  	_, err = pcAnswer.AddTrack(vp8Writer)
   214  	assert.NoError(t, err)
   215  
   216  	offer, err := pcOffer.CreateOffer(nil)
   217  	assert.NoError(t, err)
   218  
   219  	assert.NoError(t, pcAnswer.SetRemoteDescription(offer))
   220  
   221  	answer, err := pcAnswer.CreateAnswer(nil)
   222  	assert.NoError(t, err)
   223  	assert.NoError(t, pcAnswer.SetLocalDescription(answer))
   224  
   225  	_, err = vp8Writer.Write(make([]byte, 20))
   226  	assert.NoError(t, err)
   227  
   228  	closePairNow(t, pcOffer, pcAnswer)
   229  }
   230  
   231  func BenchmarkTrackLocalWrite(b *testing.B) {
   232  	offerPC, answerPC, err := newPair()
   233  	defer closePairNow(b, offerPC, answerPC)
   234  	if err != nil {
   235  		b.Fatalf("Failed to create a PC pair for testing")
   236  	}
   237  
   238  	track, err := NewTrackLocalStaticRTP(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion")
   239  	assert.NoError(b, err)
   240  
   241  	_, err = offerPC.AddTrack(track)
   242  	assert.NoError(b, err)
   243  
   244  	_, err = answerPC.AddTransceiverFromKind(RTPCodecTypeVideo)
   245  	assert.NoError(b, err)
   246  
   247  	b.SetBytes(1024)
   248  
   249  	buf := make([]byte, 1024)
   250  	for i := 0; i < b.N; i++ {
   251  		_, err := track.Write(buf)
   252  		assert.NoError(b, err)
   253  	}
   254  }