track_local_static_test.go 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
  2. // SPDX-License-Identifier: MIT
  3. //go:build !js
  4. // +build !js
  5. package webrtc
  6. import (
  7. "context"
  8. "errors"
  9. "testing"
  10. "time"
  11. "github.com/pion/rtp"
  12. "github.com/pion/transport/v2/test"
  13. "github.com/stretchr/testify/assert"
  14. )
  15. // If a remote doesn't support a Codec used by a `TrackLocalStatic`
  16. // an error should be returned to the user
  17. func Test_TrackLocalStatic_NoCodecIntersection(t *testing.T) {
  18. lim := test.TimeOut(time.Second * 30)
  19. defer lim.Stop()
  20. report := test.CheckRoutines(t)
  21. defer report()
  22. track, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion")
  23. assert.NoError(t, err)
  24. t.Run("Offerer", func(t *testing.T) {
  25. pc, err := NewPeerConnection(Configuration{})
  26. assert.NoError(t, err)
  27. noCodecPC, err := NewAPI().NewPeerConnection(Configuration{})
  28. assert.NoError(t, err)
  29. _, err = pc.AddTrack(track)
  30. assert.NoError(t, err)
  31. assert.ErrorIs(t, signalPair(pc, noCodecPC), ErrUnsupportedCodec)
  32. closePairNow(t, noCodecPC, pc)
  33. })
  34. t.Run("Answerer", func(t *testing.T) {
  35. pc, err := NewPeerConnection(Configuration{})
  36. assert.NoError(t, err)
  37. m := &MediaEngine{}
  38. assert.NoError(t, m.RegisterCodec(RTPCodecParameters{
  39. RTPCodecCapability: RTPCodecCapability{MimeType: "video/VP9", ClockRate: 90000, Channels: 0, SDPFmtpLine: "", RTCPFeedback: nil},
  40. PayloadType: 96,
  41. }, RTPCodecTypeVideo))
  42. vp9OnlyPC, err := NewAPI(WithMediaEngine(m)).NewPeerConnection(Configuration{})
  43. assert.NoError(t, err)
  44. _, err = vp9OnlyPC.AddTransceiverFromKind(RTPCodecTypeVideo)
  45. assert.NoError(t, err)
  46. _, err = pc.AddTrack(track)
  47. assert.NoError(t, err)
  48. assert.True(t, errors.Is(signalPair(vp9OnlyPC, pc), ErrUnsupportedCodec))
  49. closePairNow(t, vp9OnlyPC, pc)
  50. })
  51. t.Run("Local", func(t *testing.T) {
  52. offerer, answerer, err := newPair()
  53. assert.NoError(t, err)
  54. invalidCodecTrack, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: "video/invalid-codec"}, "video", "pion")
  55. assert.NoError(t, err)
  56. _, err = offerer.AddTrack(invalidCodecTrack)
  57. assert.NoError(t, err)
  58. assert.True(t, errors.Is(signalPair(offerer, answerer), ErrUnsupportedCodec))
  59. closePairNow(t, offerer, answerer)
  60. })
  61. }
  62. // Assert that Bind/Unbind happens when expected
  63. func Test_TrackLocalStatic_Closed(t *testing.T) {
  64. lim := test.TimeOut(time.Second * 30)
  65. defer lim.Stop()
  66. report := test.CheckRoutines(t)
  67. defer report()
  68. pcOffer, pcAnswer, err := newPair()
  69. assert.NoError(t, err)
  70. _, err = pcAnswer.AddTransceiverFromKind(RTPCodecTypeVideo)
  71. assert.NoError(t, err)
  72. vp8Writer, err := NewTrackLocalStaticRTP(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion")
  73. assert.NoError(t, err)
  74. _, err = pcOffer.AddTrack(vp8Writer)
  75. assert.NoError(t, err)
  76. assert.Equal(t, len(vp8Writer.bindings), 0, "No binding should exist before signaling")
  77. assert.NoError(t, signalPair(pcOffer, pcAnswer))
  78. assert.Equal(t, len(vp8Writer.bindings), 1, "binding should exist after signaling")
  79. closePairNow(t, pcOffer, pcAnswer)
  80. assert.Equal(t, len(vp8Writer.bindings), 0, "No binding should exist after close")
  81. }
  82. func Test_TrackLocalStatic_PayloadType(t *testing.T) {
  83. lim := test.TimeOut(time.Second * 30)
  84. defer lim.Stop()
  85. report := test.CheckRoutines(t)
  86. defer report()
  87. mediaEngineOne := &MediaEngine{}
  88. assert.NoError(t, mediaEngineOne.RegisterCodec(RTPCodecParameters{
  89. RTPCodecCapability: RTPCodecCapability{MimeType: "video/VP8", ClockRate: 90000, Channels: 0, SDPFmtpLine: "", RTCPFeedback: nil},
  90. PayloadType: 100,
  91. }, RTPCodecTypeVideo))
  92. mediaEngineTwo := &MediaEngine{}
  93. assert.NoError(t, mediaEngineTwo.RegisterCodec(RTPCodecParameters{
  94. RTPCodecCapability: RTPCodecCapability{MimeType: "video/VP8", ClockRate: 90000, Channels: 0, SDPFmtpLine: "", RTCPFeedback: nil},
  95. PayloadType: 200,
  96. }, RTPCodecTypeVideo))
  97. offerer, err := NewAPI(WithMediaEngine(mediaEngineOne)).NewPeerConnection(Configuration{})
  98. assert.NoError(t, err)
  99. answerer, err := NewAPI(WithMediaEngine(mediaEngineTwo)).NewPeerConnection(Configuration{})
  100. assert.NoError(t, err)
  101. track, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion")
  102. assert.NoError(t, err)
  103. _, err = offerer.AddTransceiverFromKind(RTPCodecTypeVideo)
  104. assert.NoError(t, err)
  105. _, err = answerer.AddTrack(track)
  106. assert.NoError(t, err)
  107. onTrackFired, onTrackFiredFunc := context.WithCancel(context.Background())
  108. offerer.OnTrack(func(track *TrackRemote, r *RTPReceiver) {
  109. assert.Equal(t, track.PayloadType(), PayloadType(100))
  110. assert.Equal(t, track.Codec().RTPCodecCapability.MimeType, "video/VP8")
  111. onTrackFiredFunc()
  112. })
  113. assert.NoError(t, signalPair(offerer, answerer))
  114. sendVideoUntilDone(onTrackFired.Done(), t, []*TrackLocalStaticSample{track})
  115. closePairNow(t, offerer, answerer)
  116. }
  117. // Assert that writing to a Track doesn't modify the input
  118. // Even though we can pass a pointer we shouldn't modify the incoming value
  119. func Test_TrackLocalStatic_Mutate_Input(t *testing.T) {
  120. lim := test.TimeOut(time.Second * 30)
  121. defer lim.Stop()
  122. report := test.CheckRoutines(t)
  123. defer report()
  124. pcOffer, pcAnswer, err := newPair()
  125. assert.NoError(t, err)
  126. vp8Writer, err := NewTrackLocalStaticRTP(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion")
  127. assert.NoError(t, err)
  128. _, err = pcOffer.AddTrack(vp8Writer)
  129. assert.NoError(t, err)
  130. assert.NoError(t, signalPair(pcOffer, pcAnswer))
  131. pkt := &rtp.Packet{Header: rtp.Header{SSRC: 1, PayloadType: 1}}
  132. assert.NoError(t, vp8Writer.WriteRTP(pkt))
  133. assert.Equal(t, pkt.Header.SSRC, uint32(1))
  134. assert.Equal(t, pkt.Header.PayloadType, uint8(1))
  135. closePairNow(t, pcOffer, pcAnswer)
  136. }
  137. // Assert that writing to a Track that has Binded (but not connected)
  138. // does not block
  139. func Test_TrackLocalStatic_Binding_NonBlocking(t *testing.T) {
  140. lim := test.TimeOut(time.Second * 5)
  141. defer lim.Stop()
  142. report := test.CheckRoutines(t)
  143. defer report()
  144. pcOffer, pcAnswer, err := newPair()
  145. assert.NoError(t, err)
  146. _, err = pcOffer.AddTransceiverFromKind(RTPCodecTypeVideo)
  147. assert.NoError(t, err)
  148. vp8Writer, err := NewTrackLocalStaticRTP(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion")
  149. assert.NoError(t, err)
  150. _, err = pcAnswer.AddTrack(vp8Writer)
  151. assert.NoError(t, err)
  152. offer, err := pcOffer.CreateOffer(nil)
  153. assert.NoError(t, err)
  154. assert.NoError(t, pcAnswer.SetRemoteDescription(offer))
  155. answer, err := pcAnswer.CreateAnswer(nil)
  156. assert.NoError(t, err)
  157. assert.NoError(t, pcAnswer.SetLocalDescription(answer))
  158. _, err = vp8Writer.Write(make([]byte, 20))
  159. assert.NoError(t, err)
  160. closePairNow(t, pcOffer, pcAnswer)
  161. }
  162. func BenchmarkTrackLocalWrite(b *testing.B) {
  163. offerPC, answerPC, err := newPair()
  164. defer closePairNow(b, offerPC, answerPC)
  165. if err != nil {
  166. b.Fatalf("Failed to create a PC pair for testing")
  167. }
  168. track, err := NewTrackLocalStaticRTP(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion")
  169. assert.NoError(b, err)
  170. _, err = offerPC.AddTrack(track)
  171. assert.NoError(b, err)
  172. _, err = answerPC.AddTransceiverFromKind(RTPCodecTypeVideo)
  173. assert.NoError(b, err)
  174. b.SetBytes(1024)
  175. buf := make([]byte, 1024)
  176. for i := 0; i < b.N; i++ {
  177. _, err := track.Write(buf)
  178. assert.NoError(b, err)
  179. }
  180. }