peerconnection_renegotiation_test.go 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325
  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. "bufio"
  8. "context"
  9. "errors"
  10. "io"
  11. "strconv"
  12. "strings"
  13. "sync"
  14. "sync/atomic"
  15. "testing"
  16. "time"
  17. "github.com/pion/rtp"
  18. "github.com/pion/transport/v2/test"
  19. "github.com/pion/webrtc/v3/internal/util"
  20. "github.com/pion/webrtc/v3/pkg/media"
  21. "github.com/pion/webrtc/v3/pkg/rtcerr"
  22. "github.com/stretchr/testify/assert"
  23. "github.com/stretchr/testify/require"
  24. )
  25. func sendVideoUntilDone(done <-chan struct{}, t *testing.T, tracks []*TrackLocalStaticSample) {
  26. for {
  27. select {
  28. case <-time.After(20 * time.Millisecond):
  29. for _, track := range tracks {
  30. assert.NoError(t, track.WriteSample(media.Sample{Data: []byte{0x00}, Duration: time.Second}))
  31. }
  32. case <-done:
  33. return
  34. }
  35. }
  36. }
  37. func sdpMidHasSsrc(offer SessionDescription, mid string, ssrc SSRC) bool {
  38. for _, media := range offer.parsed.MediaDescriptions {
  39. cmid, ok := media.Attribute("mid")
  40. if !ok {
  41. continue
  42. }
  43. if cmid != mid {
  44. continue
  45. }
  46. cssrc, ok := media.Attribute("ssrc")
  47. if !ok {
  48. continue
  49. }
  50. parts := strings.Split(cssrc, " ")
  51. ssrcInt64, err := strconv.ParseUint(parts[0], 10, 32)
  52. if err != nil {
  53. continue
  54. }
  55. if uint32(ssrcInt64) == uint32(ssrc) {
  56. return true
  57. }
  58. }
  59. return false
  60. }
  61. func TestPeerConnection_Renegotiation_AddRecvonlyTransceiver(t *testing.T) {
  62. type testCase struct {
  63. name string
  64. answererSends bool
  65. }
  66. testCases := []testCase{
  67. // Assert the following behaviors:
  68. // - Offerer can add a recvonly transceiver
  69. // - During negotiation, answerer peer adds an inactive (or sendonly) transceiver
  70. // - Offerer can add a track
  71. // - Answerer can receive the RTP packets.
  72. {"add recvonly, then receive from answerer", false},
  73. // Assert the following behaviors:
  74. // - Offerer can add a recvonly transceiver
  75. // - During negotiation, answerer peer adds an inactive (or sendonly) transceiver
  76. // - Answerer can add a track to the existing sendonly transceiver
  77. // - Offerer can receive the RTP packets.
  78. {"add recvonly, then send to answerer", true},
  79. }
  80. for _, tc := range testCases {
  81. tc := tc
  82. t.Run(tc.name, func(t *testing.T) {
  83. lim := test.TimeOut(time.Second * 30)
  84. defer lim.Stop()
  85. report := test.CheckRoutines(t)
  86. defer report()
  87. pcOffer, pcAnswer, err := newPair()
  88. if err != nil {
  89. t.Fatal(err)
  90. }
  91. _, err = pcOffer.AddTransceiverFromKind(
  92. RTPCodecTypeVideo,
  93. RTPTransceiverInit{
  94. Direction: RTPTransceiverDirectionRecvonly,
  95. },
  96. )
  97. assert.NoError(t, err)
  98. assert.NoError(t, signalPair(pcOffer, pcAnswer))
  99. localTrack, err := NewTrackLocalStaticSample(
  100. RTPCodecCapability{MimeType: "video/VP8"}, "track-one", "stream-one",
  101. )
  102. require.NoError(t, err)
  103. if tc.answererSends {
  104. _, err = pcAnswer.AddTrack(localTrack)
  105. } else {
  106. _, err = pcOffer.AddTrack(localTrack)
  107. }
  108. require.NoError(t, err)
  109. onTrackFired, onTrackFiredFunc := context.WithCancel(context.Background())
  110. if tc.answererSends {
  111. pcOffer.OnTrack(func(track *TrackRemote, r *RTPReceiver) {
  112. onTrackFiredFunc()
  113. })
  114. assert.NoError(t, signalPair(pcAnswer, pcOffer))
  115. } else {
  116. pcAnswer.OnTrack(func(track *TrackRemote, r *RTPReceiver) {
  117. onTrackFiredFunc()
  118. })
  119. assert.NoError(t, signalPair(pcOffer, pcAnswer))
  120. }
  121. sendVideoUntilDone(onTrackFired.Done(), t, []*TrackLocalStaticSample{localTrack})
  122. closePairNow(t, pcOffer, pcAnswer)
  123. })
  124. }
  125. }
  126. /*
  127. * Assert the following behaviors
  128. * - We are able to call AddTrack after signaling
  129. * - OnTrack is NOT called on the other side until after SetRemoteDescription
  130. * - We are able to re-negotiate and AddTrack is properly called
  131. */
  132. func TestPeerConnection_Renegotiation_AddTrack(t *testing.T) {
  133. lim := test.TimeOut(time.Second * 30)
  134. defer lim.Stop()
  135. report := test.CheckRoutines(t)
  136. defer report()
  137. pcOffer, pcAnswer, err := newPair()
  138. if err != nil {
  139. t.Fatal(err)
  140. }
  141. haveRenegotiated := &atomicBool{}
  142. onTrackFired, onTrackFiredFunc := context.WithCancel(context.Background())
  143. pcAnswer.OnTrack(func(track *TrackRemote, r *RTPReceiver) {
  144. if !haveRenegotiated.get() {
  145. t.Fatal("OnTrack was called before renegotiation")
  146. }
  147. onTrackFiredFunc()
  148. })
  149. assert.NoError(t, signalPair(pcOffer, pcAnswer))
  150. _, err = pcAnswer.AddTransceiverFromKind(RTPCodecTypeVideo, RTPTransceiverInit{Direction: RTPTransceiverDirectionRecvonly})
  151. assert.NoError(t, err)
  152. vp8Track, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "foo", "bar")
  153. assert.NoError(t, err)
  154. sender, err := pcOffer.AddTrack(vp8Track)
  155. assert.NoError(t, err)
  156. // Send 10 packets, OnTrack MUST not be fired
  157. for i := 0; i <= 10; i++ {
  158. assert.NoError(t, vp8Track.WriteSample(media.Sample{Data: []byte{0x00}, Duration: time.Second}))
  159. time.Sleep(20 * time.Millisecond)
  160. }
  161. haveRenegotiated.set(true)
  162. assert.False(t, sender.isNegotiated())
  163. offer, err := pcOffer.CreateOffer(nil)
  164. assert.True(t, sender.isNegotiated())
  165. assert.NoError(t, err)
  166. assert.NoError(t, pcOffer.SetLocalDescription(offer))
  167. assert.NoError(t, pcAnswer.SetRemoteDescription(offer))
  168. answer, err := pcAnswer.CreateAnswer(nil)
  169. assert.NoError(t, err)
  170. assert.NoError(t, pcAnswer.SetLocalDescription(answer))
  171. pcOffer.ops.Done()
  172. assert.Equal(t, 0, len(vp8Track.rtpTrack.bindings))
  173. assert.NoError(t, pcOffer.SetRemoteDescription(answer))
  174. pcOffer.ops.Done()
  175. assert.Equal(t, 1, len(vp8Track.rtpTrack.bindings))
  176. sendVideoUntilDone(onTrackFired.Done(), t, []*TrackLocalStaticSample{vp8Track})
  177. closePairNow(t, pcOffer, pcAnswer)
  178. }
  179. // Assert that adding tracks across multiple renegotiations performs as expected
  180. func TestPeerConnection_Renegotiation_AddTrack_Multiple(t *testing.T) {
  181. addTrackWithLabel := func(trackID string, pcOffer, pcAnswer *PeerConnection) *TrackLocalStaticSample {
  182. _, err := pcAnswer.AddTransceiverFromKind(RTPCodecTypeVideo, RTPTransceiverInit{Direction: RTPTransceiverDirectionRecvonly})
  183. assert.NoError(t, err)
  184. track, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, trackID, trackID)
  185. assert.NoError(t, err)
  186. _, err = pcOffer.AddTrack(track)
  187. assert.NoError(t, err)
  188. return track
  189. }
  190. trackIDs := []string{util.MathRandAlpha(16), util.MathRandAlpha(16), util.MathRandAlpha(16)}
  191. outboundTracks := []*TrackLocalStaticSample{}
  192. onTrackCount := map[string]int{}
  193. onTrackChan := make(chan struct{}, 1)
  194. lim := test.TimeOut(time.Second * 30)
  195. defer lim.Stop()
  196. report := test.CheckRoutines(t)
  197. defer report()
  198. pcOffer, pcAnswer, err := newPair()
  199. if err != nil {
  200. t.Fatal(err)
  201. }
  202. pcAnswer.OnTrack(func(track *TrackRemote, r *RTPReceiver) {
  203. onTrackCount[track.ID()]++
  204. onTrackChan <- struct{}{}
  205. })
  206. assert.NoError(t, signalPair(pcOffer, pcAnswer))
  207. for i := range trackIDs {
  208. outboundTracks = append(outboundTracks, addTrackWithLabel(trackIDs[i], pcOffer, pcAnswer))
  209. assert.NoError(t, signalPair(pcOffer, pcAnswer))
  210. sendVideoUntilDone(onTrackChan, t, outboundTracks)
  211. }
  212. closePairNow(t, pcOffer, pcAnswer)
  213. assert.Equal(t, onTrackCount[trackIDs[0]], 1)
  214. assert.Equal(t, onTrackCount[trackIDs[1]], 1)
  215. assert.Equal(t, onTrackCount[trackIDs[2]], 1)
  216. }
  217. // Assert that renegotiation triggers OnTrack() with correct ID and label from
  218. // remote side, even when a transceiver was added before the actual track data
  219. // was received. This happens when we add a transceiver on the server, create
  220. // an offer on the server and the browser's answer contains the same SSRC, but
  221. // a track hasn't been added on the browser side yet. The browser can add a
  222. // track later and renegotiate, and track ID and label will be set by the time
  223. // first packets are received.
  224. func TestPeerConnection_Renegotiation_AddTrack_Rename(t *testing.T) {
  225. lim := test.TimeOut(time.Second * 30)
  226. defer lim.Stop()
  227. report := test.CheckRoutines(t)
  228. defer report()
  229. pcOffer, pcAnswer, err := newPair()
  230. if err != nil {
  231. t.Fatal(err)
  232. }
  233. haveRenegotiated := &atomicBool{}
  234. onTrackFired, onTrackFiredFunc := context.WithCancel(context.Background())
  235. var atomicRemoteTrack atomic.Value
  236. pcOffer.OnTrack(func(track *TrackRemote, r *RTPReceiver) {
  237. if !haveRenegotiated.get() {
  238. t.Fatal("OnTrack was called before renegotiation")
  239. }
  240. onTrackFiredFunc()
  241. atomicRemoteTrack.Store(track)
  242. })
  243. _, err = pcOffer.AddTransceiverFromKind(RTPCodecTypeVideo, RTPTransceiverInit{Direction: RTPTransceiverDirectionRecvonly})
  244. assert.NoError(t, err)
  245. vp8Track, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "foo1", "bar1")
  246. assert.NoError(t, err)
  247. _, err = pcAnswer.AddTrack(vp8Track)
  248. assert.NoError(t, err)
  249. assert.NoError(t, signalPair(pcOffer, pcAnswer))
  250. vp8Track.rtpTrack.id = "foo2"
  251. vp8Track.rtpTrack.streamID = "bar2"
  252. haveRenegotiated.set(true)
  253. assert.NoError(t, signalPair(pcOffer, pcAnswer))
  254. sendVideoUntilDone(onTrackFired.Done(), t, []*TrackLocalStaticSample{vp8Track})
  255. closePairNow(t, pcOffer, pcAnswer)
  256. remoteTrack, ok := atomicRemoteTrack.Load().(*TrackRemote)
  257. require.True(t, ok)
  258. require.NotNil(t, remoteTrack)
  259. assert.Equal(t, "foo2", remoteTrack.ID())
  260. assert.Equal(t, "bar2", remoteTrack.StreamID())
  261. }
  262. // TestPeerConnection_Transceiver_Mid tests that we'll provide the same
  263. // transceiver for a media id on successive offer/answer
  264. func TestPeerConnection_Transceiver_Mid(t *testing.T) {
  265. lim := test.TimeOut(time.Second * 30)
  266. defer lim.Stop()
  267. report := test.CheckRoutines(t)
  268. defer report()
  269. pcOffer, err := NewPeerConnection(Configuration{})
  270. assert.NoError(t, err)
  271. pcAnswer, err := NewPeerConnection(Configuration{})
  272. assert.NoError(t, err)
  273. track1, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion1")
  274. require.NoError(t, err)
  275. sender1, err := pcOffer.AddTrack(track1)
  276. require.NoError(t, err)
  277. track2, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion2")
  278. require.NoError(t, err)
  279. sender2, err := pcOffer.AddTrack(track2)
  280. require.NoError(t, err)
  281. // this will create the initial offer using generateUnmatchedSDP
  282. offer, err := pcOffer.CreateOffer(nil)
  283. assert.NoError(t, err)
  284. offerGatheringComplete := GatheringCompletePromise(pcOffer)
  285. assert.NoError(t, pcOffer.SetLocalDescription(offer))
  286. <-offerGatheringComplete
  287. assert.NoError(t, pcAnswer.SetRemoteDescription(*pcOffer.LocalDescription()))
  288. answer, err := pcAnswer.CreateAnswer(nil)
  289. assert.NoError(t, err)
  290. answerGatheringComplete := GatheringCompletePromise(pcAnswer)
  291. assert.NoError(t, pcAnswer.SetLocalDescription(answer))
  292. <-answerGatheringComplete
  293. // apply answer so we'll test generateMatchedSDP
  294. assert.NoError(t, pcOffer.SetRemoteDescription(*pcAnswer.LocalDescription()))
  295. pcOffer.ops.Done()
  296. pcAnswer.ops.Done()
  297. // Must have 3 media descriptions (2 video channels)
  298. assert.Equal(t, len(offer.parsed.MediaDescriptions), 2)
  299. assert.True(t, sdpMidHasSsrc(offer, "0", sender1.trackEncodings[0].ssrc), "Expected mid %q with ssrc %d, offer.SDP: %s", "0", sender1.trackEncodings[0].ssrc, offer.SDP)
  300. // Remove first track, must keep same number of media
  301. // descriptions and same track ssrc for mid 1 as previous
  302. assert.NoError(t, pcOffer.RemoveTrack(sender1))
  303. offer, err = pcOffer.CreateOffer(nil)
  304. assert.NoError(t, err)
  305. assert.NoError(t, pcOffer.SetLocalDescription(offer))
  306. assert.Equal(t, len(offer.parsed.MediaDescriptions), 2)
  307. assert.True(t, sdpMidHasSsrc(offer, "1", sender2.trackEncodings[0].ssrc), "Expected mid %q with ssrc %d, offer.SDP: %s", "1", sender2.trackEncodings[0].ssrc, offer.SDP)
  308. _, err = pcAnswer.CreateAnswer(nil)
  309. assert.Equal(t, err, &rtcerr.InvalidStateError{Err: ErrIncorrectSignalingState})
  310. pcOffer.ops.Done()
  311. pcAnswer.ops.Done()
  312. assert.NoError(t, pcAnswer.SetRemoteDescription(offer))
  313. answer, err = pcAnswer.CreateAnswer(nil)
  314. assert.NoError(t, err)
  315. assert.NoError(t, pcOffer.SetRemoteDescription(answer))
  316. track3, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion3")
  317. require.NoError(t, err)
  318. sender3, err := pcOffer.AddTrack(track3)
  319. require.NoError(t, err)
  320. offer, err = pcOffer.CreateOffer(nil)
  321. assert.NoError(t, err)
  322. // We reuse the existing non-sending transceiver
  323. assert.Equal(t, len(offer.parsed.MediaDescriptions), 2)
  324. assert.True(t, sdpMidHasSsrc(offer, "0", sender3.trackEncodings[0].ssrc), "Expected mid %q with ssrc %d, offer.sdp: %s", "0", sender3.trackEncodings[0].ssrc, offer.SDP)
  325. assert.True(t, sdpMidHasSsrc(offer, "1", sender2.trackEncodings[0].ssrc), "Expected mid %q with ssrc %d, offer.sdp: %s", "1", sender2.trackEncodings[0].ssrc, offer.SDP)
  326. closePairNow(t, pcOffer, pcAnswer)
  327. }
  328. func TestPeerConnection_Renegotiation_CodecChange(t *testing.T) {
  329. lim := test.TimeOut(time.Second * 30)
  330. defer lim.Stop()
  331. report := test.CheckRoutines(t)
  332. defer report()
  333. pcOffer, err := NewPeerConnection(Configuration{})
  334. assert.NoError(t, err)
  335. pcAnswer, err := NewPeerConnection(Configuration{})
  336. assert.NoError(t, err)
  337. track1, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video1", "pion1")
  338. require.NoError(t, err)
  339. track2, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video2", "pion2")
  340. require.NoError(t, err)
  341. sender1, err := pcOffer.AddTrack(track1)
  342. require.NoError(t, err)
  343. _, err = pcAnswer.AddTransceiverFromKind(RTPCodecTypeVideo, RTPTransceiverInit{Direction: RTPTransceiverDirectionRecvonly})
  344. require.NoError(t, err)
  345. tracksCh := make(chan *TrackRemote)
  346. tracksClosed := make(chan struct{})
  347. pcAnswer.OnTrack(func(track *TrackRemote, r *RTPReceiver) {
  348. tracksCh <- track
  349. for {
  350. if _, _, readErr := track.ReadRTP(); errors.Is(readErr, io.EOF) {
  351. tracksClosed <- struct{}{}
  352. return
  353. }
  354. }
  355. })
  356. err = signalPair(pcOffer, pcAnswer)
  357. require.NoError(t, err)
  358. transceivers := pcOffer.GetTransceivers()
  359. require.Equal(t, 1, len(transceivers))
  360. require.Equal(t, "0", transceivers[0].Mid())
  361. transceivers = pcAnswer.GetTransceivers()
  362. require.Equal(t, 1, len(transceivers))
  363. require.Equal(t, "0", transceivers[0].Mid())
  364. ctx, cancel := context.WithCancel(context.Background())
  365. go sendVideoUntilDone(ctx.Done(), t, []*TrackLocalStaticSample{track1})
  366. remoteTrack1 := <-tracksCh
  367. cancel()
  368. assert.Equal(t, "video1", remoteTrack1.ID())
  369. assert.Equal(t, "pion1", remoteTrack1.StreamID())
  370. require.NoError(t, pcOffer.RemoveTrack(sender1))
  371. require.NoError(t, signalPair(pcOffer, pcAnswer))
  372. <-tracksClosed
  373. sender2, err := pcOffer.AddTrack(track2)
  374. require.NoError(t, err)
  375. require.NoError(t, signalPair(pcOffer, pcAnswer))
  376. transceivers = pcOffer.GetTransceivers()
  377. require.Equal(t, 1, len(transceivers))
  378. require.Equal(t, "0", transceivers[0].Mid())
  379. transceivers = pcAnswer.GetTransceivers()
  380. require.Equal(t, 1, len(transceivers))
  381. require.Equal(t, "0", transceivers[0].Mid())
  382. ctx, cancel = context.WithCancel(context.Background())
  383. go sendVideoUntilDone(ctx.Done(), t, []*TrackLocalStaticSample{track2})
  384. remoteTrack2 := <-tracksCh
  385. cancel()
  386. require.NoError(t, pcOffer.RemoveTrack(sender2))
  387. err = signalPair(pcOffer, pcAnswer)
  388. require.NoError(t, err)
  389. <-tracksClosed
  390. assert.Equal(t, "video2", remoteTrack2.ID())
  391. assert.Equal(t, "pion2", remoteTrack2.StreamID())
  392. closePairNow(t, pcOffer, pcAnswer)
  393. }
  394. func TestPeerConnection_Renegotiation_RemoveTrack(t *testing.T) {
  395. lim := test.TimeOut(time.Second * 30)
  396. defer lim.Stop()
  397. report := test.CheckRoutines(t)
  398. defer report()
  399. pcOffer, pcAnswer, err := newPair()
  400. if err != nil {
  401. t.Fatal(err)
  402. }
  403. _, err = pcAnswer.AddTransceiverFromKind(RTPCodecTypeVideo, RTPTransceiverInit{Direction: RTPTransceiverDirectionRecvonly})
  404. assert.NoError(t, err)
  405. vp8Track, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "foo", "bar")
  406. assert.NoError(t, err)
  407. sender, err := pcOffer.AddTrack(vp8Track)
  408. assert.NoError(t, err)
  409. onTrackFired, onTrackFiredFunc := context.WithCancel(context.Background())
  410. trackClosed, trackClosedFunc := context.WithCancel(context.Background())
  411. pcAnswer.OnTrack(func(track *TrackRemote, r *RTPReceiver) {
  412. onTrackFiredFunc()
  413. for {
  414. if _, _, err := track.ReadRTP(); errors.Is(err, io.EOF) {
  415. trackClosedFunc()
  416. return
  417. }
  418. }
  419. })
  420. assert.NoError(t, signalPair(pcOffer, pcAnswer))
  421. sendVideoUntilDone(onTrackFired.Done(), t, []*TrackLocalStaticSample{vp8Track})
  422. assert.NoError(t, pcOffer.RemoveTrack(sender))
  423. assert.NoError(t, signalPair(pcOffer, pcAnswer))
  424. <-trackClosed.Done()
  425. closePairNow(t, pcOffer, pcAnswer)
  426. }
  427. func TestPeerConnection_RoleSwitch(t *testing.T) {
  428. lim := test.TimeOut(time.Second * 30)
  429. defer lim.Stop()
  430. report := test.CheckRoutines(t)
  431. defer report()
  432. pcFirstOfferer, pcSecondOfferer, err := newPair()
  433. if err != nil {
  434. t.Fatal(err)
  435. }
  436. onTrackFired, onTrackFiredFunc := context.WithCancel(context.Background())
  437. pcFirstOfferer.OnTrack(func(track *TrackRemote, r *RTPReceiver) {
  438. onTrackFiredFunc()
  439. })
  440. assert.NoError(t, signalPair(pcFirstOfferer, pcSecondOfferer))
  441. // Add a new Track to the second offerer
  442. // This asserts that it will match the ordering of the last RemoteDescription, but then also add new Transceivers to the end
  443. _, err = pcFirstOfferer.AddTransceiverFromKind(RTPCodecTypeVideo, RTPTransceiverInit{Direction: RTPTransceiverDirectionRecvonly})
  444. assert.NoError(t, err)
  445. vp8Track, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "foo", "bar")
  446. assert.NoError(t, err)
  447. _, err = pcSecondOfferer.AddTrack(vp8Track)
  448. assert.NoError(t, err)
  449. assert.NoError(t, signalPair(pcSecondOfferer, pcFirstOfferer))
  450. sendVideoUntilDone(onTrackFired.Done(), t, []*TrackLocalStaticSample{vp8Track})
  451. closePairNow(t, pcFirstOfferer, pcSecondOfferer)
  452. }
  453. // Assert that renegotiation doesn't attempt to gather ICE twice
  454. // Before we would attempt to gather multiple times and would put
  455. // the PeerConnection into a broken state
  456. func TestPeerConnection_Renegotiation_Trickle(t *testing.T) {
  457. lim := test.TimeOut(time.Second * 30)
  458. defer lim.Stop()
  459. report := test.CheckRoutines(t)
  460. defer report()
  461. settingEngine := SettingEngine{}
  462. api := NewAPI(WithSettingEngine(settingEngine))
  463. assert.NoError(t, api.mediaEngine.RegisterDefaultCodecs())
  464. // Invalid STUN server on purpose, will stop ICE Gathering from completing in time
  465. pcOffer, pcAnswer, err := api.newPair(Configuration{
  466. ICEServers: []ICEServer{
  467. {
  468. URLs: []string{"stun:127.0.0.1:5000"},
  469. },
  470. },
  471. })
  472. if err != nil {
  473. t.Fatal(err)
  474. }
  475. _, err = pcOffer.CreateDataChannel("test-channel", nil)
  476. assert.NoError(t, err)
  477. var wg sync.WaitGroup
  478. wg.Add(2)
  479. pcOffer.OnICECandidate(func(c *ICECandidate) {
  480. if c != nil {
  481. assert.NoError(t, pcAnswer.AddICECandidate(c.ToJSON()))
  482. } else {
  483. wg.Done()
  484. }
  485. })
  486. pcAnswer.OnICECandidate(func(c *ICECandidate) {
  487. if c != nil {
  488. assert.NoError(t, pcOffer.AddICECandidate(c.ToJSON()))
  489. } else {
  490. wg.Done()
  491. }
  492. })
  493. negotiate := func() {
  494. offer, err := pcOffer.CreateOffer(nil)
  495. assert.NoError(t, err)
  496. assert.NoError(t, pcAnswer.SetRemoteDescription(offer))
  497. assert.NoError(t, pcOffer.SetLocalDescription(offer))
  498. answer, err := pcAnswer.CreateAnswer(nil)
  499. assert.NoError(t, err)
  500. assert.NoError(t, pcOffer.SetRemoteDescription(answer))
  501. assert.NoError(t, pcAnswer.SetLocalDescription(answer))
  502. }
  503. negotiate()
  504. negotiate()
  505. pcOffer.ops.Done()
  506. pcAnswer.ops.Done()
  507. wg.Wait()
  508. closePairNow(t, pcOffer, pcAnswer)
  509. }
  510. func TestPeerConnection_Renegotiation_SetLocalDescription(t *testing.T) {
  511. lim := test.TimeOut(time.Second * 30)
  512. defer lim.Stop()
  513. report := test.CheckRoutines(t)
  514. defer report()
  515. pcOffer, pcAnswer, err := newPair()
  516. if err != nil {
  517. t.Fatal(err)
  518. }
  519. onTrackFired, onTrackFiredFunc := context.WithCancel(context.Background())
  520. pcOffer.OnTrack(func(track *TrackRemote, r *RTPReceiver) {
  521. onTrackFiredFunc()
  522. })
  523. assert.NoError(t, signalPair(pcOffer, pcAnswer))
  524. pcOffer.ops.Done()
  525. pcAnswer.ops.Done()
  526. _, err = pcOffer.AddTransceiverFromKind(RTPCodecTypeVideo, RTPTransceiverInit{Direction: RTPTransceiverDirectionRecvonly})
  527. assert.NoError(t, err)
  528. localTrack, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "foo", "bar")
  529. assert.NoError(t, err)
  530. sender, err := pcAnswer.AddTrack(localTrack)
  531. assert.NoError(t, err)
  532. offer, err := pcOffer.CreateOffer(nil)
  533. assert.NoError(t, err)
  534. assert.NoError(t, pcOffer.SetLocalDescription(offer))
  535. assert.NoError(t, pcAnswer.SetRemoteDescription(offer))
  536. assert.False(t, sender.isNegotiated())
  537. answer, err := pcAnswer.CreateAnswer(nil)
  538. assert.NoError(t, err)
  539. assert.True(t, sender.isNegotiated())
  540. pcAnswer.ops.Done()
  541. assert.Equal(t, 0, len(localTrack.rtpTrack.bindings))
  542. assert.NoError(t, pcAnswer.SetLocalDescription(answer))
  543. pcAnswer.ops.Done()
  544. assert.Equal(t, 1, len(localTrack.rtpTrack.bindings))
  545. assert.NoError(t, pcOffer.SetRemoteDescription(answer))
  546. sendVideoUntilDone(onTrackFired.Done(), t, []*TrackLocalStaticSample{localTrack})
  547. closePairNow(t, pcOffer, pcAnswer)
  548. }
  549. // Issue #346, don't start the SCTP Subsystem if the RemoteDescription doesn't contain one
  550. // Before we would always start it, and re-negotiations would fail because SCTP was in flight
  551. func TestPeerConnection_Renegotiation_NoApplication(t *testing.T) {
  552. signalPairExcludeDataChannel := func(pcOffer, pcAnswer *PeerConnection) {
  553. offer, err := pcOffer.CreateOffer(nil)
  554. assert.NoError(t, err)
  555. offerGatheringComplete := GatheringCompletePromise(pcOffer)
  556. assert.NoError(t, pcOffer.SetLocalDescription(offer))
  557. <-offerGatheringComplete
  558. assert.NoError(t, pcAnswer.SetRemoteDescription(*pcOffer.LocalDescription()))
  559. answer, err := pcAnswer.CreateAnswer(nil)
  560. assert.NoError(t, err)
  561. answerGatheringComplete := GatheringCompletePromise(pcAnswer)
  562. assert.NoError(t, pcAnswer.SetLocalDescription(answer))
  563. <-answerGatheringComplete
  564. assert.NoError(t, pcOffer.SetRemoteDescription(*pcAnswer.LocalDescription()))
  565. }
  566. lim := test.TimeOut(time.Second * 30)
  567. defer lim.Stop()
  568. report := test.CheckRoutines(t)
  569. defer report()
  570. pcOffer, pcAnswer, err := newPair()
  571. if err != nil {
  572. t.Fatal(err)
  573. }
  574. pcOfferConnected, pcOfferConnectedCancel := context.WithCancel(context.Background())
  575. pcOffer.OnICEConnectionStateChange(func(i ICEConnectionState) {
  576. if i == ICEConnectionStateConnected {
  577. pcOfferConnectedCancel()
  578. }
  579. })
  580. pcAnswerConnected, pcAnswerConnectedCancel := context.WithCancel(context.Background())
  581. pcAnswer.OnICEConnectionStateChange(func(i ICEConnectionState) {
  582. if i == ICEConnectionStateConnected {
  583. pcAnswerConnectedCancel()
  584. }
  585. })
  586. _, err = pcOffer.AddTransceiverFromKind(RTPCodecTypeVideo, RTPTransceiverInit{Direction: RTPTransceiverDirectionSendrecv})
  587. assert.NoError(t, err)
  588. _, err = pcAnswer.AddTransceiverFromKind(RTPCodecTypeVideo, RTPTransceiverInit{Direction: RTPTransceiverDirectionSendrecv})
  589. assert.NoError(t, err)
  590. signalPairExcludeDataChannel(pcOffer, pcAnswer)
  591. pcOffer.ops.Done()
  592. pcAnswer.ops.Done()
  593. signalPairExcludeDataChannel(pcOffer, pcAnswer)
  594. pcOffer.ops.Done()
  595. pcAnswer.ops.Done()
  596. <-pcAnswerConnected.Done()
  597. <-pcOfferConnected.Done()
  598. assert.Equal(t, pcOffer.SCTP().State(), SCTPTransportStateConnecting)
  599. assert.Equal(t, pcAnswer.SCTP().State(), SCTPTransportStateConnecting)
  600. closePairNow(t, pcOffer, pcAnswer)
  601. }
  602. func TestAddDataChannelDuringRenegotiation(t *testing.T) {
  603. lim := test.TimeOut(time.Second * 10)
  604. defer lim.Stop()
  605. report := test.CheckRoutines(t)
  606. defer report()
  607. pcOffer, err := NewPeerConnection(Configuration{})
  608. assert.NoError(t, err)
  609. pcAnswer, err := NewPeerConnection(Configuration{})
  610. assert.NoError(t, err)
  611. track, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion")
  612. assert.NoError(t, err)
  613. _, err = pcOffer.AddTrack(track)
  614. assert.NoError(t, err)
  615. offer, err := pcOffer.CreateOffer(nil)
  616. assert.NoError(t, err)
  617. offerGatheringComplete := GatheringCompletePromise(pcOffer)
  618. assert.NoError(t, pcOffer.SetLocalDescription(offer))
  619. <-offerGatheringComplete
  620. assert.NoError(t, pcAnswer.SetRemoteDescription(*pcOffer.LocalDescription()))
  621. answer, err := pcAnswer.CreateAnswer(nil)
  622. assert.NoError(t, err)
  623. answerGatheringComplete := GatheringCompletePromise(pcAnswer)
  624. assert.NoError(t, pcAnswer.SetLocalDescription(answer))
  625. <-answerGatheringComplete
  626. assert.NoError(t, pcOffer.SetRemoteDescription(*pcAnswer.LocalDescription()))
  627. _, err = pcOffer.CreateDataChannel("data-channel", nil)
  628. assert.NoError(t, err)
  629. // Assert that DataChannel is in offer now
  630. offer, err = pcOffer.CreateOffer(nil)
  631. assert.NoError(t, err)
  632. applicationMediaSectionCount := 0
  633. for _, d := range offer.parsed.MediaDescriptions {
  634. if d.MediaName.Media == mediaSectionApplication {
  635. applicationMediaSectionCount++
  636. }
  637. }
  638. assert.Equal(t, applicationMediaSectionCount, 1)
  639. onDataChannelFired, onDataChannelFiredFunc := context.WithCancel(context.Background())
  640. pcAnswer.OnDataChannel(func(*DataChannel) {
  641. onDataChannelFiredFunc()
  642. })
  643. assert.NoError(t, signalPair(pcOffer, pcAnswer))
  644. <-onDataChannelFired.Done()
  645. closePairNow(t, pcOffer, pcAnswer)
  646. }
  647. // Assert that CreateDataChannel fires OnNegotiationNeeded
  648. func TestNegotiationCreateDataChannel(t *testing.T) {
  649. lim := test.TimeOut(time.Second * 30)
  650. defer lim.Stop()
  651. report := test.CheckRoutines(t)
  652. defer report()
  653. pc, err := NewPeerConnection(Configuration{})
  654. assert.NoError(t, err)
  655. var wg sync.WaitGroup
  656. wg.Add(1)
  657. pc.OnNegotiationNeeded(func() {
  658. defer func() {
  659. wg.Done()
  660. }()
  661. })
  662. // Create DataChannel, wait until OnNegotiationNeeded is fired
  663. if _, err = pc.CreateDataChannel("testChannel", nil); err != nil {
  664. t.Error(err.Error())
  665. }
  666. // Wait until OnNegotiationNeeded is fired
  667. wg.Wait()
  668. assert.NoError(t, pc.Close())
  669. }
  670. func TestNegotiationNeededRemoveTrack(t *testing.T) {
  671. var wg sync.WaitGroup
  672. wg.Add(1)
  673. report := test.CheckRoutines(t)
  674. defer report()
  675. pcOffer, err := NewPeerConnection(Configuration{})
  676. assert.NoError(t, err)
  677. pcAnswer, err := NewPeerConnection(Configuration{})
  678. assert.NoError(t, err)
  679. track, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion")
  680. assert.NoError(t, err)
  681. pcOffer.OnNegotiationNeeded(func() {
  682. wg.Add(1)
  683. offer, createOfferErr := pcOffer.CreateOffer(nil)
  684. assert.NoError(t, createOfferErr)
  685. offerGatheringComplete := GatheringCompletePromise(pcOffer)
  686. assert.NoError(t, pcOffer.SetLocalDescription(offer))
  687. <-offerGatheringComplete
  688. assert.NoError(t, pcAnswer.SetRemoteDescription(*pcOffer.LocalDescription()))
  689. answer, createAnswerErr := pcAnswer.CreateAnswer(nil)
  690. assert.NoError(t, createAnswerErr)
  691. answerGatheringComplete := GatheringCompletePromise(pcAnswer)
  692. assert.NoError(t, pcAnswer.SetLocalDescription(answer))
  693. <-answerGatheringComplete
  694. assert.NoError(t, pcOffer.SetRemoteDescription(*pcAnswer.LocalDescription()))
  695. wg.Done()
  696. wg.Done()
  697. })
  698. sender, err := pcOffer.AddTrack(track)
  699. assert.NoError(t, err)
  700. assert.NoError(t, track.WriteSample(media.Sample{Data: []byte{0x00}, Duration: time.Second}))
  701. wg.Wait()
  702. wg.Add(1)
  703. assert.NoError(t, pcOffer.RemoveTrack(sender))
  704. wg.Wait()
  705. closePairNow(t, pcOffer, pcAnswer)
  706. }
  707. func TestNegotiationNeededStressOneSided(t *testing.T) {
  708. lim := test.TimeOut(time.Second * 30)
  709. defer lim.Stop()
  710. report := test.CheckRoutines(t)
  711. defer report()
  712. pcA, pcB, err := newPair()
  713. assert.NoError(t, err)
  714. const expectedTrackCount = 500
  715. ctx, done := context.WithCancel(context.Background())
  716. pcA.OnNegotiationNeeded(func() {
  717. count := len(pcA.GetTransceivers())
  718. assert.NoError(t, signalPair(pcA, pcB))
  719. if count == expectedTrackCount {
  720. done()
  721. }
  722. })
  723. for i := 0; i < expectedTrackCount; i++ {
  724. track, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion")
  725. assert.NoError(t, err)
  726. _, err = pcA.AddTrack(track)
  727. assert.NoError(t, err)
  728. }
  729. <-ctx.Done()
  730. assert.Equal(t, expectedTrackCount, len(pcB.GetTransceivers()))
  731. closePairNow(t, pcA, pcB)
  732. }
  733. // TestPeerConnection_Renegotiation_DisableTrack asserts that if a remote track is set inactive
  734. // that locally it goes inactive as well
  735. func TestPeerConnection_Renegotiation_DisableTrack(t *testing.T) {
  736. lim := test.TimeOut(time.Second * 30)
  737. defer lim.Stop()
  738. report := test.CheckRoutines(t)
  739. defer report()
  740. pcOffer, pcAnswer, err := newPair()
  741. assert.NoError(t, err)
  742. // Create two transceivers
  743. _, err = pcOffer.AddTransceiverFromKind(RTPCodecTypeVideo)
  744. assert.NoError(t, err)
  745. transceiver, err := pcOffer.AddTransceiverFromKind(RTPCodecTypeVideo)
  746. assert.NoError(t, err)
  747. assert.NoError(t, signalPair(pcOffer, pcAnswer))
  748. // Assert we have three active transceivers
  749. offer, err := pcOffer.CreateOffer(nil)
  750. assert.NoError(t, err)
  751. assert.Equal(t, strings.Count(offer.SDP, "a=sendrecv"), 3)
  752. // Assert we have two active transceivers, one inactive
  753. assert.NoError(t, transceiver.Stop())
  754. offer, err = pcOffer.CreateOffer(nil)
  755. assert.NoError(t, err)
  756. assert.Equal(t, strings.Count(offer.SDP, "a=sendrecv"), 2)
  757. assert.Equal(t, strings.Count(offer.SDP, "a=inactive"), 1)
  758. // Assert that the offer disabled one of our transceivers
  759. assert.NoError(t, pcAnswer.SetRemoteDescription(offer))
  760. answer, err := pcAnswer.CreateAnswer(nil)
  761. assert.NoError(t, err)
  762. assert.Equal(t, strings.Count(answer.SDP, "a=sendrecv"), 1) // DataChannel
  763. assert.Equal(t, strings.Count(answer.SDP, "a=recvonly"), 1)
  764. assert.Equal(t, strings.Count(answer.SDP, "a=inactive"), 1)
  765. closePairNow(t, pcOffer, pcAnswer)
  766. }
  767. func TestPeerConnection_Renegotiation_Simulcast(t *testing.T) {
  768. lim := test.TimeOut(time.Second * 30)
  769. defer lim.Stop()
  770. report := test.CheckRoutines(t)
  771. defer report()
  772. m := &MediaEngine{}
  773. if err := m.RegisterDefaultCodecs(); err != nil {
  774. panic(err)
  775. }
  776. registerSimulcastHeaderExtensions(m, RTPCodecTypeVideo)
  777. originalRids := []string{"a", "b", "c"}
  778. signalWithRids := func(sessionDescription string, rids []string) string {
  779. sessionDescription = strings.SplitAfter(sessionDescription, "a=end-of-candidates\r\n")[0]
  780. sessionDescription = filterSsrc(sessionDescription)
  781. for _, rid := range rids {
  782. sessionDescription += "a=" + sdpAttributeRid + ":" + rid + " send\r\n"
  783. }
  784. return sessionDescription + "a=simulcast:send " + strings.Join(rids, ";") + "\r\n"
  785. }
  786. var trackMapLock sync.RWMutex
  787. trackMap := map[string]*TrackRemote{}
  788. onTrackHandler := func(track *TrackRemote, _ *RTPReceiver) {
  789. trackMapLock.Lock()
  790. defer trackMapLock.Unlock()
  791. trackMap[track.RID()] = track
  792. }
  793. sendUntilAllTracksFired := func(vp8Writer *TrackLocalStaticRTP, rids []string) {
  794. allTracksFired := func() bool {
  795. trackMapLock.Lock()
  796. defer trackMapLock.Unlock()
  797. return len(trackMap) == len(rids)
  798. }
  799. for sequenceNumber := uint16(0); !allTracksFired(); sequenceNumber++ {
  800. time.Sleep(20 * time.Millisecond)
  801. for ssrc, rid := range rids {
  802. header := &rtp.Header{
  803. Version: 2,
  804. SSRC: uint32(ssrc),
  805. SequenceNumber: sequenceNumber,
  806. PayloadType: 96,
  807. }
  808. assert.NoError(t, header.SetExtension(1, []byte("0")))
  809. assert.NoError(t, header.SetExtension(2, []byte(rid)))
  810. _, err := vp8Writer.bindings[0].writeStream.WriteRTP(header, []byte{0x00})
  811. assert.NoError(t, err)
  812. }
  813. }
  814. }
  815. assertTracksClosed := func(t *testing.T) {
  816. trackMapLock.Lock()
  817. defer trackMapLock.Unlock()
  818. for _, track := range trackMap {
  819. _, _, err := track.ReadRTP() // Ignore first Read, this is our peeked data
  820. assert.Nil(t, err)
  821. _, _, err = track.ReadRTP()
  822. assert.Equal(t, err, io.EOF)
  823. }
  824. }
  825. t.Run("Disable Transceiver", func(t *testing.T) {
  826. trackMap = map[string]*TrackRemote{}
  827. pcOffer, pcAnswer, err := NewAPI(WithMediaEngine(m)).newPair(Configuration{})
  828. assert.NoError(t, err)
  829. vp8Writer, err := NewTrackLocalStaticRTP(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion2")
  830. assert.NoError(t, err)
  831. rtpTransceiver, err := pcOffer.AddTransceiverFromTrack(
  832. vp8Writer,
  833. RTPTransceiverInit{
  834. Direction: RTPTransceiverDirectionSendonly,
  835. },
  836. )
  837. assert.NoError(t, err)
  838. assert.NoError(t, signalPairWithModification(pcOffer, pcAnswer, func(sessionDescription string) string {
  839. return signalWithRids(sessionDescription, originalRids)
  840. }))
  841. pcAnswer.OnTrack(onTrackHandler)
  842. sendUntilAllTracksFired(vp8Writer, originalRids)
  843. assert.NoError(t, pcOffer.RemoveTrack(rtpTransceiver.Sender()))
  844. assert.NoError(t, signalPairWithModification(pcOffer, pcAnswer, func(sessionDescription string) string {
  845. sessionDescription = strings.SplitAfter(sessionDescription, "a=end-of-candidates\r\n")[0]
  846. return sessionDescription
  847. }))
  848. assertTracksClosed(t)
  849. closePairNow(t, pcOffer, pcAnswer)
  850. })
  851. t.Run("Change RID", func(t *testing.T) {
  852. trackMap = map[string]*TrackRemote{}
  853. pcOffer, pcAnswer, err := NewAPI(WithMediaEngine(m)).newPair(Configuration{})
  854. assert.NoError(t, err)
  855. vp8Writer, err := NewTrackLocalStaticRTP(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion2")
  856. assert.NoError(t, err)
  857. _, err = pcOffer.AddTransceiverFromTrack(
  858. vp8Writer,
  859. RTPTransceiverInit{
  860. Direction: RTPTransceiverDirectionSendonly,
  861. },
  862. )
  863. assert.NoError(t, err)
  864. assert.NoError(t, signalPairWithModification(pcOffer, pcAnswer, func(sessionDescription string) string {
  865. return signalWithRids(sessionDescription, originalRids)
  866. }))
  867. pcAnswer.OnTrack(onTrackHandler)
  868. sendUntilAllTracksFired(vp8Writer, originalRids)
  869. newRids := []string{"d", "e", "f"}
  870. assert.NoError(t, signalPairWithModification(pcOffer, pcAnswer, func(sessionDescription string) string {
  871. scanner := bufio.NewScanner(strings.NewReader(sessionDescription))
  872. sessionDescription = ""
  873. for scanner.Scan() {
  874. l := scanner.Text()
  875. if strings.HasPrefix(l, "a=rid") || strings.HasPrefix(l, "a=simulcast") {
  876. continue
  877. }
  878. sessionDescription += l + "\n"
  879. }
  880. return signalWithRids(sessionDescription, newRids)
  881. }))
  882. assertTracksClosed(t)
  883. closePairNow(t, pcOffer, pcAnswer)
  884. })
  885. }
  886. func TestPeerConnection_Regegotiation_ReuseTransceiver(t *testing.T) {
  887. lim := test.TimeOut(time.Second * 30)
  888. defer lim.Stop()
  889. report := test.CheckRoutines(t)
  890. defer report()
  891. pcOffer, pcAnswer, err := newPair()
  892. if err != nil {
  893. t.Fatal(err)
  894. }
  895. vp8Track, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "foo", "bar")
  896. assert.NoError(t, err)
  897. sender, err := pcOffer.AddTrack(vp8Track)
  898. assert.NoError(t, err)
  899. assert.NoError(t, signalPair(pcOffer, pcAnswer))
  900. assert.Equal(t, len(pcOffer.GetTransceivers()), 1)
  901. assert.Equal(t, pcOffer.GetTransceivers()[0].getCurrentDirection(), RTPTransceiverDirectionSendonly)
  902. assert.NoError(t, pcOffer.RemoveTrack(sender))
  903. assert.Equal(t, pcOffer.GetTransceivers()[0].getCurrentDirection(), RTPTransceiverDirectionSendonly)
  904. // should not reuse tranceiver
  905. vp8Track2, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "foo", "bar")
  906. assert.NoError(t, err)
  907. sender2, err := pcOffer.AddTrack(vp8Track2)
  908. assert.NoError(t, err)
  909. assert.Equal(t, len(pcOffer.GetTransceivers()), 2)
  910. assert.NoError(t, signalPair(pcOffer, pcAnswer))
  911. assert.True(t, sender2.rtpTransceiver == pcOffer.GetTransceivers()[1])
  912. // should reuse first transceiver
  913. sender, err = pcOffer.AddTrack(vp8Track)
  914. assert.NoError(t, err)
  915. assert.Equal(t, len(pcOffer.GetTransceivers()), 2)
  916. assert.True(t, sender.rtpTransceiver == pcOffer.GetTransceivers()[0])
  917. closePairNow(t, pcOffer, pcAnswer)
  918. }
  919. func TestPeerConnection_Renegotiation_MidConflict(t *testing.T) {
  920. lim := test.TimeOut(time.Second * 30)
  921. defer lim.Stop()
  922. report := test.CheckRoutines(t)
  923. defer report()
  924. offerPC, err := NewPeerConnection(Configuration{})
  925. assert.NoError(t, err)
  926. answerPC, err := NewPeerConnection(Configuration{})
  927. assert.NoError(t, err)
  928. _, err = offerPC.CreateDataChannel("test", nil)
  929. assert.NoError(t, err)
  930. _, err = offerPC.AddTransceiverFromKind(RTPCodecTypeVideo, RtpTransceiverInit{Direction: RTPTransceiverDirectionSendonly})
  931. assert.NoError(t, err)
  932. _, err = offerPC.AddTransceiverFromKind(RTPCodecTypeAudio, RtpTransceiverInit{Direction: RTPTransceiverDirectionSendonly})
  933. assert.NoError(t, err)
  934. offer, err := offerPC.CreateOffer(nil)
  935. assert.NoError(t, err)
  936. assert.NoError(t, offerPC.SetLocalDescription(offer))
  937. assert.NoError(t, answerPC.SetRemoteDescription(offer), offer.SDP)
  938. answer, err := answerPC.CreateAnswer(nil)
  939. assert.NoError(t, err)
  940. assert.NoError(t, answerPC.SetLocalDescription(answer))
  941. assert.NoError(t, offerPC.SetRemoteDescription(answer))
  942. assert.Equal(t, SignalingStateStable, offerPC.SignalingState())
  943. tr, err := offerPC.AddTransceiverFromKind(RTPCodecTypeVideo, RtpTransceiverInit{Direction: RTPTransceiverDirectionSendonly})
  944. assert.NoError(t, err)
  945. assert.NoError(t, tr.SetMid("3"))
  946. _, err = offerPC.AddTransceiverFromKind(RTPCodecTypeVideo, RtpTransceiverInit{Direction: RTPTransceiverDirectionSendrecv})
  947. assert.NoError(t, err)
  948. _, err = offerPC.CreateOffer(nil)
  949. assert.NoError(t, err)
  950. assert.NoError(t, offerPC.Close())
  951. assert.NoError(t, answerPC.Close())
  952. }
  953. func TestPeerConnection_Regegotiation_AnswerAddsTrack(t *testing.T) {
  954. lim := test.TimeOut(time.Second * 30)
  955. defer lim.Stop()
  956. report := test.CheckRoutines(t)
  957. defer report()
  958. pcOffer, pcAnswer, err := newPair()
  959. if err != nil {
  960. t.Fatal(err)
  961. }
  962. tracksCh := make(chan *TrackRemote)
  963. pcOffer.OnTrack(func(track *TrackRemote, r *RTPReceiver) {
  964. tracksCh <- track
  965. for {
  966. if _, _, readErr := track.ReadRTP(); errors.Is(readErr, io.EOF) {
  967. return
  968. }
  969. }
  970. })
  971. vp8Track, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "foo", "bar")
  972. assert.NoError(t, err)
  973. assert.NoError(t, signalPair(pcOffer, pcAnswer))
  974. _, err = pcOffer.AddTransceiverFromKind(RTPCodecTypeVideo, RtpTransceiverInit{
  975. Direction: RTPTransceiverDirectionRecvonly,
  976. })
  977. assert.NoError(t, err)
  978. assert.NoError(t, signalPair(pcOffer, pcAnswer))
  979. _, err = pcAnswer.AddTransceiverFromKind(RTPCodecTypeVideo, RtpTransceiverInit{
  980. Direction: RTPTransceiverDirectionSendonly,
  981. })
  982. assert.NoError(t, err)
  983. assert.NoError(t, err)
  984. _, err = pcAnswer.AddTrack(vp8Track)
  985. assert.NoError(t, err)
  986. assert.NoError(t, signalPair(pcOffer, pcAnswer))
  987. ctx, cancel := context.WithCancel(context.Background())
  988. go sendVideoUntilDone(ctx.Done(), t, []*TrackLocalStaticSample{vp8Track})
  989. <-tracksCh
  990. cancel()
  991. closePairNow(t, pcOffer, pcAnswer)
  992. }
  993. func TestNegotiationNeededWithRecvonlyTrack(t *testing.T) {
  994. lim := test.TimeOut(time.Second * 30)
  995. defer lim.Stop()
  996. report := test.CheckRoutines(t)
  997. defer report()
  998. pcOffer, pcAnswer, err := newPair()
  999. if err != nil {
  1000. t.Fatal(err)
  1001. }
  1002. var wg sync.WaitGroup
  1003. wg.Add(1)
  1004. pcAnswer.OnNegotiationNeeded(wg.Done)
  1005. _, err = pcOffer.AddTransceiverFromKind(RTPCodecTypeVideo, RTPTransceiverInit{Direction: RTPTransceiverDirectionRecvonly})
  1006. if err != nil {
  1007. t.Fatal(err)
  1008. }
  1009. if err := signalPair(pcOffer, pcAnswer); err != nil {
  1010. t.Fatal(err)
  1011. }
  1012. onDataChannel, onDataChannelCancel := context.WithCancel(context.Background())
  1013. pcAnswer.OnDataChannel(func(d *DataChannel) {
  1014. onDataChannelCancel()
  1015. })
  1016. <-onDataChannel.Done()
  1017. wg.Wait()
  1018. closePairNow(t, pcOffer, pcAnswer)
  1019. }