rtpsender_test.go 12 KB

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