peerconnection_test.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756
  1. // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
  2. // SPDX-License-Identifier: MIT
  3. package webrtc
  4. import (
  5. "reflect"
  6. "sync"
  7. "sync/atomic"
  8. "testing"
  9. "time"
  10. "github.com/pion/sdp/v3"
  11. "github.com/pion/transport/v2/test"
  12. "github.com/pion/webrtc/v3/pkg/rtcerr"
  13. "github.com/stretchr/testify/assert"
  14. )
  15. // newPair creates two new peer connections (an offerer and an answerer)
  16. // *without* using an api (i.e. using the default settings).
  17. func newPair() (pcOffer *PeerConnection, pcAnswer *PeerConnection, err error) {
  18. pca, err := NewPeerConnection(Configuration{})
  19. if err != nil {
  20. return nil, nil, err
  21. }
  22. pcb, err := NewPeerConnection(Configuration{})
  23. if err != nil {
  24. return nil, nil, err
  25. }
  26. return pca, pcb, nil
  27. }
  28. func signalPairWithModification(pcOffer *PeerConnection, pcAnswer *PeerConnection, modificationFunc func(string) string) error {
  29. // Note(albrow): We need to create a data channel in order to trigger ICE
  30. // candidate gathering in the background for the JavaScript/Wasm bindings. If
  31. // we don't do this, the complete offer including ICE candidates will never be
  32. // generated.
  33. if _, err := pcOffer.CreateDataChannel("initial_data_channel", nil); err != nil {
  34. return err
  35. }
  36. offer, err := pcOffer.CreateOffer(nil)
  37. if err != nil {
  38. return err
  39. }
  40. offerGatheringComplete := GatheringCompletePromise(pcOffer)
  41. if err = pcOffer.SetLocalDescription(offer); err != nil {
  42. return err
  43. }
  44. <-offerGatheringComplete
  45. offer.SDP = modificationFunc(pcOffer.LocalDescription().SDP)
  46. if err = pcAnswer.SetRemoteDescription(offer); err != nil {
  47. return err
  48. }
  49. answer, err := pcAnswer.CreateAnswer(nil)
  50. if err != nil {
  51. return err
  52. }
  53. answerGatheringComplete := GatheringCompletePromise(pcAnswer)
  54. if err = pcAnswer.SetLocalDescription(answer); err != nil {
  55. return err
  56. }
  57. <-answerGatheringComplete
  58. return pcOffer.SetRemoteDescription(*pcAnswer.LocalDescription())
  59. }
  60. func signalPair(pcOffer *PeerConnection, pcAnswer *PeerConnection) error {
  61. return signalPairWithModification(pcOffer, pcAnswer, func(sessionDescription string) string { return sessionDescription })
  62. }
  63. func offerMediaHasDirection(offer SessionDescription, kind RTPCodecType, direction RTPTransceiverDirection) bool {
  64. parsed := &sdp.SessionDescription{}
  65. if err := parsed.Unmarshal([]byte(offer.SDP)); err != nil {
  66. return false
  67. }
  68. for _, media := range parsed.MediaDescriptions {
  69. if media.MediaName.Media == kind.String() {
  70. _, exists := media.Attribute(direction.String())
  71. return exists
  72. }
  73. }
  74. return false
  75. }
  76. func untilConnectionState(state PeerConnectionState, peers ...*PeerConnection) *sync.WaitGroup {
  77. var triggered sync.WaitGroup
  78. triggered.Add(len(peers))
  79. for _, p := range peers {
  80. var done atomic.Value
  81. done.Store(false)
  82. hdlr := func(p PeerConnectionState) {
  83. if val, ok := done.Load().(bool); ok && (!val && p == state) {
  84. done.Store(true)
  85. triggered.Done()
  86. }
  87. }
  88. p.OnConnectionStateChange(hdlr)
  89. }
  90. return &triggered
  91. }
  92. func TestNew(t *testing.T) {
  93. pc, err := NewPeerConnection(Configuration{
  94. ICEServers: []ICEServer{
  95. {
  96. URLs: []string{
  97. "stun:stun.l.google.com:19302",
  98. },
  99. Username: "unittest",
  100. },
  101. },
  102. ICETransportPolicy: ICETransportPolicyRelay,
  103. BundlePolicy: BundlePolicyMaxCompat,
  104. RTCPMuxPolicy: RTCPMuxPolicyNegotiate,
  105. PeerIdentity: "unittest",
  106. ICECandidatePoolSize: 5,
  107. })
  108. assert.NoError(t, err)
  109. assert.NotNil(t, pc)
  110. assert.NoError(t, pc.Close())
  111. }
  112. func TestPeerConnection_SetConfiguration(t *testing.T) {
  113. // Note: These tests don't include ICEServer.Credential,
  114. // ICEServer.CredentialType, or Certificates because those are not supported
  115. // in the WASM bindings.
  116. for _, test := range []struct {
  117. name string
  118. init func() (*PeerConnection, error)
  119. config Configuration
  120. wantErr error
  121. }{
  122. {
  123. name: "valid",
  124. init: func() (*PeerConnection, error) {
  125. pc, err := NewPeerConnection(Configuration{
  126. ICECandidatePoolSize: 5,
  127. })
  128. if err != nil {
  129. return pc, err
  130. }
  131. err = pc.SetConfiguration(Configuration{
  132. ICEServers: []ICEServer{
  133. {
  134. URLs: []string{
  135. "stun:stun.l.google.com:19302",
  136. },
  137. Username: "unittest",
  138. },
  139. },
  140. ICETransportPolicy: ICETransportPolicyAll,
  141. BundlePolicy: BundlePolicyBalanced,
  142. RTCPMuxPolicy: RTCPMuxPolicyRequire,
  143. ICECandidatePoolSize: 5,
  144. })
  145. if err != nil {
  146. return pc, err
  147. }
  148. return pc, nil
  149. },
  150. config: Configuration{},
  151. wantErr: nil,
  152. },
  153. {
  154. name: "closed connection",
  155. init: func() (*PeerConnection, error) {
  156. pc, err := NewPeerConnection(Configuration{})
  157. assert.Nil(t, err)
  158. err = pc.Close()
  159. assert.Nil(t, err)
  160. return pc, err
  161. },
  162. config: Configuration{},
  163. wantErr: &rtcerr.InvalidStateError{Err: ErrConnectionClosed},
  164. },
  165. {
  166. name: "update PeerIdentity",
  167. init: func() (*PeerConnection, error) {
  168. return NewPeerConnection(Configuration{})
  169. },
  170. config: Configuration{
  171. PeerIdentity: "unittest",
  172. },
  173. wantErr: &rtcerr.InvalidModificationError{Err: ErrModifyingPeerIdentity},
  174. },
  175. {
  176. name: "update BundlePolicy",
  177. init: func() (*PeerConnection, error) {
  178. return NewPeerConnection(Configuration{})
  179. },
  180. config: Configuration{
  181. BundlePolicy: BundlePolicyMaxCompat,
  182. },
  183. wantErr: &rtcerr.InvalidModificationError{Err: ErrModifyingBundlePolicy},
  184. },
  185. {
  186. name: "update RTCPMuxPolicy",
  187. init: func() (*PeerConnection, error) {
  188. return NewPeerConnection(Configuration{})
  189. },
  190. config: Configuration{
  191. RTCPMuxPolicy: RTCPMuxPolicyNegotiate,
  192. },
  193. wantErr: &rtcerr.InvalidModificationError{Err: ErrModifyingRTCPMuxPolicy},
  194. },
  195. {
  196. name: "update ICECandidatePoolSize",
  197. init: func() (*PeerConnection, error) {
  198. pc, err := NewPeerConnection(Configuration{
  199. ICECandidatePoolSize: 0,
  200. })
  201. if err != nil {
  202. return pc, err
  203. }
  204. offer, err := pc.CreateOffer(nil)
  205. if err != nil {
  206. return pc, err
  207. }
  208. err = pc.SetLocalDescription(offer)
  209. if err != nil {
  210. return pc, err
  211. }
  212. return pc, nil
  213. },
  214. config: Configuration{
  215. ICECandidatePoolSize: 1,
  216. },
  217. wantErr: &rtcerr.InvalidModificationError{Err: ErrModifyingICECandidatePoolSize},
  218. },
  219. } {
  220. pc, err := test.init()
  221. if err != nil {
  222. t.Errorf("SetConfiguration %q: init failed: %v", test.name, err)
  223. }
  224. err = pc.SetConfiguration(test.config)
  225. if got, want := err, test.wantErr; !reflect.DeepEqual(got, want) {
  226. t.Errorf("SetConfiguration %q: err = %v, want %v", test.name, got, want)
  227. }
  228. assert.NoError(t, pc.Close())
  229. }
  230. }
  231. func TestPeerConnection_GetConfiguration(t *testing.T) {
  232. pc, err := NewPeerConnection(Configuration{})
  233. assert.NoError(t, err)
  234. expected := Configuration{
  235. ICEServers: []ICEServer{},
  236. ICETransportPolicy: ICETransportPolicyAll,
  237. BundlePolicy: BundlePolicyBalanced,
  238. RTCPMuxPolicy: RTCPMuxPolicyRequire,
  239. ICECandidatePoolSize: 0,
  240. }
  241. actual := pc.GetConfiguration()
  242. assert.True(t, &expected != &actual)
  243. assert.Equal(t, expected.ICEServers, actual.ICEServers)
  244. assert.Equal(t, expected.ICETransportPolicy, actual.ICETransportPolicy)
  245. assert.Equal(t, expected.BundlePolicy, actual.BundlePolicy)
  246. assert.Equal(t, expected.RTCPMuxPolicy, actual.RTCPMuxPolicy)
  247. // nolint:godox
  248. // TODO(albrow): Uncomment this after #513 is fixed.
  249. // See: https://github.com/pion/webrtc/issues/513.
  250. // assert.Equal(t, len(expected.Certificates), len(actual.Certificates))
  251. assert.Equal(t, expected.ICECandidatePoolSize, actual.ICECandidatePoolSize)
  252. assert.NoError(t, pc.Close())
  253. }
  254. const minimalOffer = `v=0
  255. o=- 4596489990601351948 2 IN IP4 127.0.0.1
  256. s=-
  257. t=0 0
  258. a=msid-semantic: WMS
  259. m=application 47299 DTLS/SCTP 5000
  260. c=IN IP4 192.168.20.129
  261. a=candidate:1966762134 1 udp 2122260223 192.168.20.129 47299 typ host generation 0
  262. a=candidate:1966762134 1 udp 2122262783 2001:db8::1 47199 typ host generation 0
  263. a=candidate:211962667 1 udp 2122194687 10.0.3.1 40864 typ host generation 0
  264. a=candidate:1002017894 1 tcp 1518280447 192.168.20.129 0 typ host tcptype active generation 0
  265. a=candidate:1109506011 1 tcp 1518214911 10.0.3.1 0 typ host tcptype active generation 0
  266. a=ice-ufrag:1/MvHwjAyVf27aLu
  267. a=ice-pwd:3dBU7cFOBl120v33cynDvN1E
  268. a=ice-options:google-ice
  269. a=fingerprint:sha-256 75:74:5A:A6:A4:E5:52:F4:A7:67:4C:01:C7:EE:91:3F:21:3D:A2:E3:53:7B:6F:30:86:F2:30:AA:65:FB:04:24
  270. a=setup:actpass
  271. a=mid:data
  272. a=sctpmap:5000 webrtc-datachannel 1024
  273. `
  274. func TestSetRemoteDescription(t *testing.T) {
  275. testCases := []struct {
  276. desc SessionDescription
  277. expectError bool
  278. }{
  279. {SessionDescription{Type: SDPTypeOffer, SDP: minimalOffer}, false},
  280. {SessionDescription{Type: 0, SDP: ""}, true},
  281. }
  282. for i, testCase := range testCases {
  283. peerConn, err := NewPeerConnection(Configuration{})
  284. if err != nil {
  285. t.Errorf("Case %d: got error: %v", i, err)
  286. }
  287. if testCase.expectError {
  288. assert.Error(t, peerConn.SetRemoteDescription(testCase.desc))
  289. } else {
  290. assert.NoError(t, peerConn.SetRemoteDescription(testCase.desc))
  291. }
  292. assert.NoError(t, peerConn.Close())
  293. }
  294. }
  295. func TestCreateOfferAnswer(t *testing.T) {
  296. offerPeerConn, err := NewPeerConnection(Configuration{})
  297. assert.NoError(t, err)
  298. answerPeerConn, err := NewPeerConnection(Configuration{})
  299. assert.NoError(t, err)
  300. _, err = offerPeerConn.CreateDataChannel("test-channel", nil)
  301. assert.NoError(t, err)
  302. offer, err := offerPeerConn.CreateOffer(nil)
  303. assert.NoError(t, err)
  304. assert.NoError(t, offerPeerConn.SetLocalDescription(offer))
  305. assert.NoError(t, answerPeerConn.SetRemoteDescription(offer))
  306. answer, err := answerPeerConn.CreateAnswer(nil)
  307. assert.NoError(t, err)
  308. assert.NoError(t, answerPeerConn.SetLocalDescription(answer))
  309. assert.NoError(t, offerPeerConn.SetRemoteDescription(answer))
  310. // after setLocalDescription(answer), signaling state should be stable.
  311. // so CreateAnswer should return an InvalidStateError
  312. assert.Equal(t, answerPeerConn.SignalingState(), SignalingStateStable)
  313. _, err = answerPeerConn.CreateAnswer(nil)
  314. assert.Error(t, err)
  315. closePairNow(t, offerPeerConn, answerPeerConn)
  316. }
  317. func TestPeerConnection_EventHandlers(t *testing.T) {
  318. pcOffer, err := NewPeerConnection(Configuration{})
  319. assert.NoError(t, err)
  320. pcAnswer, err := NewPeerConnection(Configuration{})
  321. assert.NoError(t, err)
  322. // wasCalled is a list of event handlers that were called.
  323. wasCalled := []string{}
  324. wasCalledMut := &sync.Mutex{}
  325. // wg is used to wait for all event handlers to be called.
  326. wg := &sync.WaitGroup{}
  327. wg.Add(6)
  328. // Each sync.Once is used to ensure that we call wg.Done once for each event
  329. // handler and don't add multiple entries to wasCalled. The event handlers can
  330. // be called more than once in some cases.
  331. onceOffererOnICEConnectionStateChange := &sync.Once{}
  332. onceOffererOnConnectionStateChange := &sync.Once{}
  333. onceOffererOnSignalingStateChange := &sync.Once{}
  334. onceAnswererOnICEConnectionStateChange := &sync.Once{}
  335. onceAnswererOnConnectionStateChange := &sync.Once{}
  336. onceAnswererOnSignalingStateChange := &sync.Once{}
  337. // Register all the event handlers.
  338. pcOffer.OnICEConnectionStateChange(func(ICEConnectionState) {
  339. onceOffererOnICEConnectionStateChange.Do(func() {
  340. wasCalledMut.Lock()
  341. defer wasCalledMut.Unlock()
  342. wasCalled = append(wasCalled, "offerer OnICEConnectionStateChange")
  343. wg.Done()
  344. })
  345. })
  346. pcOffer.OnConnectionStateChange(func(callbackState PeerConnectionState) {
  347. if storedState := pcOffer.ConnectionState(); callbackState != storedState {
  348. t.Errorf("State in callback argument is different from ConnectionState(): callbackState=%s, storedState=%s", callbackState, storedState)
  349. }
  350. onceOffererOnConnectionStateChange.Do(func() {
  351. wasCalledMut.Lock()
  352. defer wasCalledMut.Unlock()
  353. wasCalled = append(wasCalled, "offerer OnConnectionStateChange")
  354. wg.Done()
  355. })
  356. })
  357. pcOffer.OnSignalingStateChange(func(SignalingState) {
  358. onceOffererOnSignalingStateChange.Do(func() {
  359. wasCalledMut.Lock()
  360. defer wasCalledMut.Unlock()
  361. wasCalled = append(wasCalled, "offerer OnSignalingStateChange")
  362. wg.Done()
  363. })
  364. })
  365. pcAnswer.OnICEConnectionStateChange(func(ICEConnectionState) {
  366. onceAnswererOnICEConnectionStateChange.Do(func() {
  367. wasCalledMut.Lock()
  368. defer wasCalledMut.Unlock()
  369. wasCalled = append(wasCalled, "answerer OnICEConnectionStateChange")
  370. wg.Done()
  371. })
  372. })
  373. pcAnswer.OnConnectionStateChange(func(PeerConnectionState) {
  374. onceAnswererOnConnectionStateChange.Do(func() {
  375. wasCalledMut.Lock()
  376. defer wasCalledMut.Unlock()
  377. wasCalled = append(wasCalled, "answerer OnConnectionStateChange")
  378. wg.Done()
  379. })
  380. })
  381. pcAnswer.OnSignalingStateChange(func(SignalingState) {
  382. onceAnswererOnSignalingStateChange.Do(func() {
  383. wasCalledMut.Lock()
  384. defer wasCalledMut.Unlock()
  385. wasCalled = append(wasCalled, "answerer OnSignalingStateChange")
  386. wg.Done()
  387. })
  388. })
  389. // Use signalPair to establish a connection between pcOffer and pcAnswer. This
  390. // process should trigger the above event handlers.
  391. assert.NoError(t, signalPair(pcOffer, pcAnswer))
  392. // Wait for all of the event handlers to be triggered.
  393. done := make(chan struct{})
  394. go func() {
  395. wg.Wait()
  396. done <- struct{}{}
  397. }()
  398. timeout := time.After(5 * time.Second)
  399. select {
  400. case <-done:
  401. break
  402. case <-timeout:
  403. t.Fatalf("timed out waiting for one or more events handlers to be called (these *were* called: %+v)", wasCalled)
  404. }
  405. closePairNow(t, pcOffer, pcAnswer)
  406. }
  407. func TestMultipleOfferAnswer(t *testing.T) {
  408. firstPeerConn, err := NewPeerConnection(Configuration{})
  409. if err != nil {
  410. t.Errorf("New PeerConnection: got error: %v", err)
  411. }
  412. if _, err = firstPeerConn.CreateOffer(nil); err != nil {
  413. t.Errorf("First Offer: got error: %v", err)
  414. }
  415. if _, err = firstPeerConn.CreateOffer(nil); err != nil {
  416. t.Errorf("Second Offer: got error: %v", err)
  417. }
  418. secondPeerConn, err := NewPeerConnection(Configuration{})
  419. if err != nil {
  420. t.Errorf("New PeerConnection: got error: %v", err)
  421. }
  422. secondPeerConn.OnICECandidate(func(i *ICECandidate) {
  423. })
  424. if _, err = secondPeerConn.CreateOffer(nil); err != nil {
  425. t.Errorf("First Offer: got error: %v", err)
  426. }
  427. if _, err = secondPeerConn.CreateOffer(nil); err != nil {
  428. t.Errorf("Second Offer: got error: %v", err)
  429. }
  430. closePairNow(t, firstPeerConn, secondPeerConn)
  431. }
  432. func TestNoFingerprintInFirstMediaIfSetRemoteDescription(t *testing.T) {
  433. const sdpNoFingerprintInFirstMedia = `v=0
  434. o=- 143087887 1561022767 IN IP4 192.168.84.254
  435. s=VideoRoom 404986692241682
  436. t=0 0
  437. a=group:BUNDLE audio
  438. a=msid-semantic: WMS 2867270241552712
  439. m=video 0 UDP/TLS/RTP/SAVPF 0
  440. a=mid:video
  441. c=IN IP4 192.168.84.254
  442. a=inactive
  443. m=audio 9 UDP/TLS/RTP/SAVPF 111
  444. c=IN IP4 192.168.84.254
  445. a=recvonly
  446. a=mid:audio
  447. a=rtcp-mux
  448. a=ice-ufrag:AS/w
  449. a=ice-pwd:9NOgoAOMALYu/LOpA1iqg/
  450. a=ice-options:trickle
  451. a=fingerprint:sha-256 D2:B9:31:8F:DF:24:D8:0E:ED:D2:EF:25:9E:AF:6F:B8:34:AE:53:9C:E6:F3:8F:F2:64:15:FA:E8:7F:53:2D:38
  452. a=setup:active
  453. a=rtpmap:111 opus/48000/2
  454. a=candidate:1 1 udp 2013266431 192.168.84.254 46492 typ host
  455. a=end-of-candidates
  456. `
  457. report := test.CheckRoutines(t)
  458. defer report()
  459. pc, err := NewPeerConnection(Configuration{})
  460. if err != nil {
  461. t.Error(err.Error())
  462. }
  463. desc := SessionDescription{
  464. Type: SDPTypeOffer,
  465. SDP: sdpNoFingerprintInFirstMedia,
  466. }
  467. if err = pc.SetRemoteDescription(desc); err != nil {
  468. t.Error(err.Error())
  469. }
  470. assert.NoError(t, pc.Close())
  471. }
  472. func TestNegotiationNeeded(t *testing.T) {
  473. lim := test.TimeOut(time.Second * 30)
  474. defer lim.Stop()
  475. report := test.CheckRoutines(t)
  476. defer report()
  477. pc, err := NewPeerConnection(Configuration{})
  478. if err != nil {
  479. t.Error(err.Error())
  480. }
  481. var wg sync.WaitGroup
  482. wg.Add(1)
  483. pc.OnNegotiationNeeded(wg.Done)
  484. _, err = pc.CreateDataChannel("initial_data_channel", nil)
  485. assert.NoError(t, err)
  486. wg.Wait()
  487. assert.NoError(t, pc.Close())
  488. }
  489. func TestMultipleCreateChannel(t *testing.T) {
  490. var wg sync.WaitGroup
  491. report := test.CheckRoutines(t)
  492. defer report()
  493. // Two OnDataChannel
  494. // One OnNegotiationNeeded
  495. wg.Add(3)
  496. pcOffer, _ := NewPeerConnection(Configuration{})
  497. pcAnswer, _ := NewPeerConnection(Configuration{})
  498. pcAnswer.OnDataChannel(func(d *DataChannel) {
  499. wg.Done()
  500. })
  501. pcOffer.OnNegotiationNeeded(func() {
  502. offer, err := pcOffer.CreateOffer(nil)
  503. assert.NoError(t, err)
  504. offerGatheringComplete := GatheringCompletePromise(pcOffer)
  505. if err = pcOffer.SetLocalDescription(offer); err != nil {
  506. t.Error(err)
  507. }
  508. <-offerGatheringComplete
  509. if err = pcAnswer.SetRemoteDescription(*pcOffer.LocalDescription()); err != nil {
  510. t.Error(err)
  511. }
  512. answer, err := pcAnswer.CreateAnswer(nil)
  513. assert.NoError(t, err)
  514. answerGatheringComplete := GatheringCompletePromise(pcAnswer)
  515. if err = pcAnswer.SetLocalDescription(answer); err != nil {
  516. t.Error(err)
  517. }
  518. <-answerGatheringComplete
  519. if err = pcOffer.SetRemoteDescription(*pcAnswer.LocalDescription()); err != nil {
  520. t.Error(err)
  521. }
  522. wg.Done()
  523. })
  524. if _, err := pcOffer.CreateDataChannel("initial_data_channel_0", nil); err != nil {
  525. t.Error(err)
  526. }
  527. if _, err := pcOffer.CreateDataChannel("initial_data_channel_1", nil); err != nil {
  528. t.Error(err)
  529. }
  530. wg.Wait()
  531. closePairNow(t, pcOffer, pcAnswer)
  532. }
  533. // Assert that candidates are gathered by calling SetLocalDescription, not SetRemoteDescription
  534. func TestGatherOnSetLocalDescription(t *testing.T) {
  535. lim := test.TimeOut(time.Second * 30)
  536. defer lim.Stop()
  537. report := test.CheckRoutines(t)
  538. defer report()
  539. pcOfferGathered := make(chan SessionDescription)
  540. pcAnswerGathered := make(chan SessionDescription)
  541. s := SettingEngine{}
  542. api := NewAPI(WithSettingEngine(s))
  543. pcOffer, err := api.NewPeerConnection(Configuration{})
  544. if err != nil {
  545. t.Error(err.Error())
  546. }
  547. // We need to create a data channel in order to trigger ICE
  548. if _, err = pcOffer.CreateDataChannel("initial_data_channel", nil); err != nil {
  549. t.Error(err.Error())
  550. }
  551. pcOffer.OnICECandidate(func(i *ICECandidate) {
  552. if i == nil {
  553. close(pcOfferGathered)
  554. }
  555. })
  556. offer, err := pcOffer.CreateOffer(nil)
  557. if err != nil {
  558. t.Error(err.Error())
  559. } else if err = pcOffer.SetLocalDescription(offer); err != nil {
  560. t.Error(err.Error())
  561. }
  562. <-pcOfferGathered
  563. pcAnswer, err := api.NewPeerConnection(Configuration{})
  564. if err != nil {
  565. t.Error(err.Error())
  566. }
  567. pcAnswer.OnICECandidate(func(i *ICECandidate) {
  568. if i == nil {
  569. close(pcAnswerGathered)
  570. }
  571. })
  572. if err = pcAnswer.SetRemoteDescription(offer); err != nil {
  573. t.Error(err.Error())
  574. }
  575. select {
  576. case <-pcAnswerGathered:
  577. t.Fatal("pcAnswer started gathering with no SetLocalDescription")
  578. // Gathering is async, not sure of a better way to catch this currently
  579. case <-time.After(3 * time.Second):
  580. }
  581. answer, err := pcAnswer.CreateAnswer(nil)
  582. if err != nil {
  583. t.Error(err.Error())
  584. } else if err = pcAnswer.SetLocalDescription(answer); err != nil {
  585. t.Error(err.Error())
  586. }
  587. <-pcAnswerGathered
  588. closePairNow(t, pcOffer, pcAnswer)
  589. }
  590. // Assert that SetRemoteDescription handles invalid states
  591. func TestSetRemoteDescriptionInvalid(t *testing.T) {
  592. t.Run("local-offer+SetRemoteDescription(Offer)", func(t *testing.T) {
  593. pc, err := NewPeerConnection(Configuration{})
  594. assert.NoError(t, err)
  595. offer, err := pc.CreateOffer(nil)
  596. assert.NoError(t, err)
  597. assert.NoError(t, pc.SetLocalDescription(offer))
  598. assert.Error(t, pc.SetRemoteDescription(offer))
  599. assert.NoError(t, pc.Close())
  600. })
  601. }
  602. func TestAddTransceiver(t *testing.T) {
  603. lim := test.TimeOut(time.Second * 30)
  604. defer lim.Stop()
  605. report := test.CheckRoutines(t)
  606. defer report()
  607. for _, testCase := range []struct {
  608. expectSender, expectReceiver bool
  609. direction RTPTransceiverDirection
  610. }{
  611. {true, true, RTPTransceiverDirectionSendrecv},
  612. // Go and WASM diverge
  613. // {true, false, RTPTransceiverDirectionSendonly},
  614. // {false, true, RTPTransceiverDirectionRecvonly},
  615. } {
  616. pc, err := NewPeerConnection(Configuration{})
  617. assert.NoError(t, err)
  618. transceiver, err := pc.AddTransceiverFromKind(RTPCodecTypeVideo, RTPTransceiverInit{
  619. Direction: testCase.direction,
  620. })
  621. assert.NoError(t, err)
  622. if testCase.expectReceiver {
  623. assert.NotNil(t, transceiver.Receiver())
  624. } else {
  625. assert.Nil(t, transceiver.Receiver())
  626. }
  627. if testCase.expectSender {
  628. assert.NotNil(t, transceiver.Sender())
  629. } else {
  630. assert.Nil(t, transceiver.Sender())
  631. }
  632. offer, err := pc.CreateOffer(nil)
  633. assert.NoError(t, err)
  634. assert.True(t, offerMediaHasDirection(offer, RTPCodecTypeVideo, testCase.direction))
  635. assert.NoError(t, pc.Close())
  636. }
  637. }
  638. // Assert that SCTPTransport -> DTLSTransport -> ICETransport works after connected
  639. func TestTransportChain(t *testing.T) {
  640. offer, answer, err := newPair()
  641. assert.NoError(t, err)
  642. peerConnectionsConnected := untilConnectionState(PeerConnectionStateConnected, offer, answer)
  643. assert.NoError(t, signalPair(offer, answer))
  644. peerConnectionsConnected.Wait()
  645. assert.NotNil(t, offer.SCTP().Transport().ICETransport())
  646. closePairNow(t, offer, answer)
  647. }