peerconnection_go_test.go 48 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625
  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. "crypto/ecdsa"
  10. "crypto/elliptic"
  11. "crypto/rand"
  12. "crypto/x509"
  13. "fmt"
  14. "math/big"
  15. "reflect"
  16. "regexp"
  17. "strings"
  18. "sync"
  19. "testing"
  20. "time"
  21. "github.com/pion/ice/v2"
  22. "github.com/pion/rtp"
  23. "github.com/pion/transport/v2/test"
  24. "github.com/pion/transport/v2/vnet"
  25. "github.com/pion/webrtc/v3/internal/util"
  26. "github.com/pion/webrtc/v3/pkg/rtcerr"
  27. "github.com/stretchr/testify/assert"
  28. )
  29. // newPair creates two new peer connections (an offerer and an answerer) using
  30. // the api.
  31. func (api *API) newPair(cfg Configuration) (pcOffer *PeerConnection, pcAnswer *PeerConnection, err error) {
  32. pca, err := api.NewPeerConnection(cfg)
  33. if err != nil {
  34. return nil, nil, err
  35. }
  36. pcb, err := api.NewPeerConnection(cfg)
  37. if err != nil {
  38. return nil, nil, err
  39. }
  40. return pca, pcb, nil
  41. }
  42. func TestNew_Go(t *testing.T) {
  43. report := test.CheckRoutines(t)
  44. defer report()
  45. api := NewAPI()
  46. t.Run("Success", func(t *testing.T) {
  47. secretKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
  48. assert.Nil(t, err)
  49. certificate, err := GenerateCertificate(secretKey)
  50. assert.Nil(t, err)
  51. pc, err := api.NewPeerConnection(Configuration{
  52. ICEServers: []ICEServer{
  53. {
  54. URLs: []string{
  55. "stun:stun.l.google.com:19302",
  56. "turns:google.de?transport=tcp",
  57. },
  58. Username: "unittest",
  59. Credential: OAuthCredential{
  60. MACKey: "WmtzanB3ZW9peFhtdm42NzUzNG0=",
  61. AccessToken: "AAwg3kPHWPfvk9bDFL936wYvkoctMADzQ==",
  62. },
  63. CredentialType: ICECredentialTypeOauth,
  64. },
  65. },
  66. ICETransportPolicy: ICETransportPolicyRelay,
  67. BundlePolicy: BundlePolicyMaxCompat,
  68. RTCPMuxPolicy: RTCPMuxPolicyNegotiate,
  69. PeerIdentity: "unittest",
  70. Certificates: []Certificate{*certificate},
  71. ICECandidatePoolSize: 5,
  72. })
  73. assert.Nil(t, err)
  74. assert.NotNil(t, pc)
  75. assert.NoError(t, pc.Close())
  76. })
  77. t.Run("Failure", func(t *testing.T) {
  78. testCases := []struct {
  79. initialize func() (*PeerConnection, error)
  80. expectedErr error
  81. }{
  82. {func() (*PeerConnection, error) {
  83. secretKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
  84. assert.Nil(t, err)
  85. certificate, err := NewCertificate(secretKey, x509.Certificate{
  86. Version: 2,
  87. SerialNumber: big.NewInt(1653),
  88. NotBefore: time.Now().AddDate(0, -2, 0),
  89. NotAfter: time.Now().AddDate(0, -1, 0),
  90. })
  91. assert.Nil(t, err)
  92. return api.NewPeerConnection(Configuration{
  93. Certificates: []Certificate{*certificate},
  94. })
  95. }, &rtcerr.InvalidAccessError{Err: ErrCertificateExpired}},
  96. {func() (*PeerConnection, error) {
  97. return api.NewPeerConnection(Configuration{
  98. ICEServers: []ICEServer{
  99. {
  100. URLs: []string{
  101. "stun:stun.l.google.com:19302",
  102. "turns:google.de?transport=tcp",
  103. },
  104. Username: "unittest",
  105. },
  106. },
  107. })
  108. }, &rtcerr.InvalidAccessError{Err: ErrNoTurnCredentials}},
  109. }
  110. for i, testCase := range testCases {
  111. pc, err := testCase.initialize()
  112. assert.EqualError(t, err, testCase.expectedErr.Error(),
  113. "testCase: %d %v", i, testCase,
  114. )
  115. if pc != nil {
  116. assert.NoError(t, pc.Close())
  117. }
  118. }
  119. })
  120. t.Run("ICEServers_Copy", func(t *testing.T) {
  121. const expectedURL = "stun:stun.l.google.com:19302?foo=bar"
  122. const expectedUsername = "username"
  123. const expectedPassword = "password"
  124. cfg := Configuration{
  125. ICEServers: []ICEServer{
  126. {
  127. URLs: []string{expectedURL},
  128. Username: expectedUsername,
  129. Credential: expectedPassword,
  130. },
  131. },
  132. }
  133. pc, err := api.NewPeerConnection(cfg)
  134. assert.NoError(t, err)
  135. assert.NotNil(t, pc)
  136. pc.configuration.ICEServers[0].Username = util.MathRandAlpha(15) // Tests doesn't need crypto random
  137. pc.configuration.ICEServers[0].Credential = util.MathRandAlpha(15)
  138. pc.configuration.ICEServers[0].URLs[0] = util.MathRandAlpha(15)
  139. assert.Equal(t, expectedUsername, cfg.ICEServers[0].Username)
  140. assert.Equal(t, expectedPassword, cfg.ICEServers[0].Credential)
  141. assert.Equal(t, expectedURL, cfg.ICEServers[0].URLs[0])
  142. assert.NoError(t, pc.Close())
  143. })
  144. }
  145. func TestPeerConnection_SetConfiguration_Go(t *testing.T) {
  146. // Note: this test includes all SetConfiguration features that are supported
  147. // by Go but not the WASM bindings, namely: ICEServer.Credential,
  148. // ICEServer.CredentialType, and Certificates.
  149. report := test.CheckRoutines(t)
  150. defer report()
  151. api := NewAPI()
  152. secretKey1, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
  153. assert.Nil(t, err)
  154. certificate1, err := GenerateCertificate(secretKey1)
  155. assert.Nil(t, err)
  156. secretKey2, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
  157. assert.Nil(t, err)
  158. certificate2, err := GenerateCertificate(secretKey2)
  159. assert.Nil(t, err)
  160. for _, test := range []struct {
  161. name string
  162. init func() (*PeerConnection, error)
  163. config Configuration
  164. wantErr error
  165. }{
  166. {
  167. name: "valid",
  168. init: func() (*PeerConnection, error) {
  169. pc, err := api.NewPeerConnection(Configuration{
  170. PeerIdentity: "unittest",
  171. Certificates: []Certificate{*certificate1},
  172. ICECandidatePoolSize: 5,
  173. })
  174. if err != nil {
  175. return pc, err
  176. }
  177. err = pc.SetConfiguration(Configuration{
  178. ICEServers: []ICEServer{
  179. {
  180. URLs: []string{
  181. "stun:stun.l.google.com:19302",
  182. "turns:google.de?transport=tcp",
  183. },
  184. Username: "unittest",
  185. Credential: OAuthCredential{
  186. MACKey: "WmtzanB3ZW9peFhtdm42NzUzNG0=",
  187. AccessToken: "AAwg3kPHWPfvk9bDFL936wYvkoctMADzQ==",
  188. },
  189. CredentialType: ICECredentialTypeOauth,
  190. },
  191. },
  192. ICETransportPolicy: ICETransportPolicyAll,
  193. BundlePolicy: BundlePolicyBalanced,
  194. RTCPMuxPolicy: RTCPMuxPolicyRequire,
  195. PeerIdentity: "unittest",
  196. Certificates: []Certificate{*certificate1},
  197. ICECandidatePoolSize: 5,
  198. })
  199. if err != nil {
  200. return pc, err
  201. }
  202. return pc, nil
  203. },
  204. config: Configuration{},
  205. wantErr: nil,
  206. },
  207. {
  208. name: "update multiple certificates",
  209. init: func() (*PeerConnection, error) {
  210. return api.NewPeerConnection(Configuration{})
  211. },
  212. config: Configuration{
  213. Certificates: []Certificate{*certificate1, *certificate2},
  214. },
  215. wantErr: &rtcerr.InvalidModificationError{Err: ErrModifyingCertificates},
  216. },
  217. {
  218. name: "update certificate",
  219. init: func() (*PeerConnection, error) {
  220. return api.NewPeerConnection(Configuration{})
  221. },
  222. config: Configuration{
  223. Certificates: []Certificate{*certificate1},
  224. },
  225. wantErr: &rtcerr.InvalidModificationError{Err: ErrModifyingCertificates},
  226. },
  227. {
  228. name: "update ICEServers, no TURN credentials",
  229. init: func() (*PeerConnection, error) {
  230. return NewPeerConnection(Configuration{})
  231. },
  232. config: Configuration{
  233. ICEServers: []ICEServer{
  234. {
  235. URLs: []string{
  236. "stun:stun.l.google.com:19302",
  237. "turns:google.de?transport=tcp",
  238. },
  239. Username: "unittest",
  240. },
  241. },
  242. },
  243. wantErr: &rtcerr.InvalidAccessError{Err: ErrNoTurnCredentials},
  244. },
  245. } {
  246. pc, err := test.init()
  247. if err != nil {
  248. t.Errorf("SetConfiguration %q: init failed: %v", test.name, err)
  249. }
  250. err = pc.SetConfiguration(test.config)
  251. if got, want := err, test.wantErr; !reflect.DeepEqual(got, want) {
  252. t.Errorf("SetConfiguration %q: err = %v, want %v", test.name, got, want)
  253. }
  254. assert.NoError(t, pc.Close())
  255. }
  256. }
  257. func TestPeerConnection_EventHandlers_Go(t *testing.T) {
  258. lim := test.TimeOut(time.Second * 5)
  259. defer lim.Stop()
  260. report := test.CheckRoutines(t)
  261. defer report()
  262. // Note: When testing the Go event handlers we peer into the state a bit more
  263. // than what is possible for the environment agnostic (Go or WASM/JavaScript)
  264. // EventHandlers test.
  265. api := NewAPI()
  266. pc, err := api.NewPeerConnection(Configuration{})
  267. assert.Nil(t, err)
  268. onTrackCalled := make(chan struct{})
  269. onICEConnectionStateChangeCalled := make(chan struct{})
  270. onDataChannelCalled := make(chan struct{})
  271. // Verify that the noop case works
  272. assert.NotPanics(t, func() { pc.onTrack(nil, nil) })
  273. assert.NotPanics(t, func() { pc.onICEConnectionStateChange(ICEConnectionStateNew) })
  274. pc.OnTrack(func(t *TrackRemote, r *RTPReceiver) {
  275. close(onTrackCalled)
  276. })
  277. pc.OnICEConnectionStateChange(func(cs ICEConnectionState) {
  278. close(onICEConnectionStateChangeCalled)
  279. })
  280. pc.OnDataChannel(func(dc *DataChannel) {
  281. // Questions:
  282. // (1) How come this callback is made with dc being nil?
  283. // (2) How come this callback is made without CreateDataChannel?
  284. if dc != nil {
  285. close(onDataChannelCalled)
  286. }
  287. })
  288. // Verify that the handlers deal with nil inputs
  289. assert.NotPanics(t, func() { pc.onTrack(nil, nil) })
  290. assert.NotPanics(t, func() { go pc.onDataChannelHandler(nil) })
  291. // Verify that the set handlers are called
  292. assert.NotPanics(t, func() { pc.onTrack(&TrackRemote{}, &RTPReceiver{}) })
  293. assert.NotPanics(t, func() { pc.onICEConnectionStateChange(ICEConnectionStateNew) })
  294. assert.NotPanics(t, func() { go pc.onDataChannelHandler(&DataChannel{api: api}) })
  295. <-onTrackCalled
  296. <-onICEConnectionStateChangeCalled
  297. <-onDataChannelCalled
  298. assert.NoError(t, pc.Close())
  299. }
  300. // This test asserts that nothing deadlocks we try to shutdown when DTLS is in flight
  301. // We ensure that DTLS is in flight by removing the mux func for it, so all inbound DTLS is lost
  302. func TestPeerConnection_ShutdownNoDTLS(t *testing.T) {
  303. lim := test.TimeOut(time.Second * 10)
  304. defer lim.Stop()
  305. report := test.CheckRoutines(t)
  306. defer report()
  307. api := NewAPI()
  308. offerPC, answerPC, err := api.newPair(Configuration{})
  309. if err != nil {
  310. t.Fatal(err)
  311. }
  312. // Drop all incoming DTLS traffic
  313. dropAllDTLS := func([]byte) bool {
  314. return false
  315. }
  316. offerPC.dtlsTransport.dtlsMatcher = dropAllDTLS
  317. answerPC.dtlsTransport.dtlsMatcher = dropAllDTLS
  318. if err = signalPair(offerPC, answerPC); err != nil {
  319. t.Fatal(err)
  320. }
  321. iceComplete := make(chan interface{})
  322. answerPC.OnICEConnectionStateChange(func(iceState ICEConnectionState) {
  323. if iceState == ICEConnectionStateConnected {
  324. time.Sleep(time.Second) // Give time for DTLS to start
  325. select {
  326. case <-iceComplete:
  327. default:
  328. close(iceComplete)
  329. }
  330. }
  331. })
  332. <-iceComplete
  333. closePairNow(t, offerPC, answerPC)
  334. }
  335. func TestPeerConnection_PropertyGetters(t *testing.T) {
  336. pc := &PeerConnection{
  337. currentLocalDescription: &SessionDescription{},
  338. pendingLocalDescription: &SessionDescription{},
  339. currentRemoteDescription: &SessionDescription{},
  340. pendingRemoteDescription: &SessionDescription{},
  341. signalingState: SignalingStateHaveLocalOffer,
  342. }
  343. pc.iceConnectionState.Store(ICEConnectionStateChecking)
  344. pc.connectionState.Store(PeerConnectionStateConnecting)
  345. assert.Equal(t, pc.currentLocalDescription, pc.CurrentLocalDescription(), "should match")
  346. assert.Equal(t, pc.pendingLocalDescription, pc.PendingLocalDescription(), "should match")
  347. assert.Equal(t, pc.currentRemoteDescription, pc.CurrentRemoteDescription(), "should match")
  348. assert.Equal(t, pc.pendingRemoteDescription, pc.PendingRemoteDescription(), "should match")
  349. assert.Equal(t, pc.signalingState, pc.SignalingState(), "should match")
  350. assert.Equal(t, pc.iceConnectionState.Load(), pc.ICEConnectionState(), "should match")
  351. assert.Equal(t, pc.connectionState.Load(), pc.ConnectionState(), "should match")
  352. }
  353. func TestPeerConnection_AnswerWithoutOffer(t *testing.T) {
  354. report := test.CheckRoutines(t)
  355. defer report()
  356. pc, err := NewPeerConnection(Configuration{})
  357. if err != nil {
  358. t.Errorf("New PeerConnection: got error: %v", err)
  359. }
  360. _, err = pc.CreateAnswer(nil)
  361. if !reflect.DeepEqual(&rtcerr.InvalidStateError{Err: ErrNoRemoteDescription}, err) {
  362. t.Errorf("CreateAnswer without RemoteDescription: got error: %v", err)
  363. }
  364. assert.NoError(t, pc.Close())
  365. }
  366. func TestPeerConnection_AnswerWithClosedConnection(t *testing.T) {
  367. report := test.CheckRoutines(t)
  368. defer report()
  369. offerPeerConn, answerPeerConn, err := newPair()
  370. assert.NoError(t, err)
  371. inChecking, inCheckingCancel := context.WithCancel(context.Background())
  372. answerPeerConn.OnICEConnectionStateChange(func(i ICEConnectionState) {
  373. if i == ICEConnectionStateChecking {
  374. inCheckingCancel()
  375. }
  376. })
  377. _, err = offerPeerConn.CreateDataChannel("test-channel", nil)
  378. assert.NoError(t, err)
  379. offer, err := offerPeerConn.CreateOffer(nil)
  380. assert.NoError(t, err)
  381. assert.NoError(t, offerPeerConn.SetLocalDescription(offer))
  382. assert.NoError(t, offerPeerConn.Close())
  383. assert.NoError(t, answerPeerConn.SetRemoteDescription(offer))
  384. <-inChecking.Done()
  385. assert.NoError(t, answerPeerConn.Close())
  386. _, err = answerPeerConn.CreateAnswer(nil)
  387. assert.Equal(t, err, &rtcerr.InvalidStateError{Err: ErrConnectionClosed})
  388. }
  389. func TestPeerConnection_satisfyTypeAndDirection(t *testing.T) {
  390. createTransceiver := func(kind RTPCodecType, direction RTPTransceiverDirection) *RTPTransceiver {
  391. r := &RTPTransceiver{kind: kind}
  392. r.setDirection(direction)
  393. return r
  394. }
  395. for _, test := range []struct {
  396. name string
  397. kinds []RTPCodecType
  398. directions []RTPTransceiverDirection
  399. localTransceivers []*RTPTransceiver
  400. want []*RTPTransceiver
  401. }{
  402. {
  403. "Audio and Video Transceivers can not satisfy each other",
  404. []RTPCodecType{RTPCodecTypeVideo},
  405. []RTPTransceiverDirection{RTPTransceiverDirectionSendrecv},
  406. []*RTPTransceiver{createTransceiver(RTPCodecTypeAudio, RTPTransceiverDirectionSendrecv)},
  407. []*RTPTransceiver{nil},
  408. },
  409. {
  410. "No local Transceivers, every remote should get nil",
  411. []RTPCodecType{RTPCodecTypeVideo, RTPCodecTypeAudio, RTPCodecTypeVideo, RTPCodecTypeVideo},
  412. []RTPTransceiverDirection{RTPTransceiverDirectionSendrecv, RTPTransceiverDirectionRecvonly, RTPTransceiverDirectionSendonly, RTPTransceiverDirectionInactive},
  413. []*RTPTransceiver{},
  414. []*RTPTransceiver{
  415. nil,
  416. nil,
  417. nil,
  418. nil,
  419. },
  420. },
  421. {
  422. "Local Recv can satisfy remote SendRecv",
  423. []RTPCodecType{RTPCodecTypeVideo},
  424. []RTPTransceiverDirection{RTPTransceiverDirectionSendrecv},
  425. []*RTPTransceiver{createTransceiver(RTPCodecTypeVideo, RTPTransceiverDirectionRecvonly)},
  426. []*RTPTransceiver{createTransceiver(RTPCodecTypeVideo, RTPTransceiverDirectionRecvonly)},
  427. },
  428. {
  429. "Don't satisfy a Sendonly with a SendRecv, later SendRecv will be marked as Inactive",
  430. []RTPCodecType{RTPCodecTypeVideo, RTPCodecTypeVideo},
  431. []RTPTransceiverDirection{RTPTransceiverDirectionSendonly, RTPTransceiverDirectionSendrecv},
  432. []*RTPTransceiver{
  433. createTransceiver(RTPCodecTypeVideo, RTPTransceiverDirectionSendrecv),
  434. createTransceiver(RTPCodecTypeVideo, RTPTransceiverDirectionRecvonly),
  435. },
  436. []*RTPTransceiver{
  437. createTransceiver(RTPCodecTypeVideo, RTPTransceiverDirectionRecvonly),
  438. createTransceiver(RTPCodecTypeVideo, RTPTransceiverDirectionSendrecv),
  439. },
  440. },
  441. } {
  442. if len(test.kinds) != len(test.directions) {
  443. t.Fatal("Kinds and Directions must be the same length")
  444. }
  445. got := []*RTPTransceiver{}
  446. for i := range test.kinds {
  447. res, filteredLocalTransceivers := satisfyTypeAndDirection(test.kinds[i], test.directions[i], test.localTransceivers)
  448. got = append(got, res)
  449. test.localTransceivers = filteredLocalTransceivers
  450. }
  451. if !reflect.DeepEqual(got, test.want) {
  452. gotStr := ""
  453. for _, t := range got {
  454. gotStr += fmt.Sprintf("%+v\n", t)
  455. }
  456. wantStr := ""
  457. for _, t := range test.want {
  458. wantStr += fmt.Sprintf("%+v\n", t)
  459. }
  460. t.Errorf("satisfyTypeAndDirection %q: \ngot\n%s \nwant\n%s", test.name, gotStr, wantStr)
  461. }
  462. }
  463. }
  464. func TestOneAttrKeyConnectionSetupPerMediaDescriptionInSDP(t *testing.T) {
  465. pc, err := NewPeerConnection(Configuration{})
  466. assert.NoError(t, err)
  467. _, err = pc.AddTransceiverFromKind(RTPCodecTypeVideo)
  468. assert.NoError(t, err)
  469. _, err = pc.AddTransceiverFromKind(RTPCodecTypeAudio)
  470. assert.NoError(t, err)
  471. _, err = pc.AddTransceiverFromKind(RTPCodecTypeAudio)
  472. assert.NoError(t, err)
  473. _, err = pc.AddTransceiverFromKind(RTPCodecTypeVideo)
  474. assert.NoError(t, err)
  475. sdp, err := pc.CreateOffer(nil)
  476. assert.NoError(t, err)
  477. re := regexp.MustCompile(`a=setup:[[:alpha:]]+`)
  478. matches := re.FindAllStringIndex(sdp.SDP, -1)
  479. assert.Len(t, matches, 4)
  480. assert.NoError(t, pc.Close())
  481. }
  482. func TestPeerConnection_IceLite(t *testing.T) {
  483. report := test.CheckRoutines(t)
  484. defer report()
  485. lim := test.TimeOut(time.Second * 10)
  486. defer lim.Stop()
  487. connectTwoAgents := func(offerIsLite, answerisLite bool) {
  488. offerSettingEngine := SettingEngine{}
  489. offerSettingEngine.SetLite(offerIsLite)
  490. offerPC, err := NewAPI(WithSettingEngine(offerSettingEngine)).NewPeerConnection(Configuration{})
  491. if err != nil {
  492. t.Fatal(err)
  493. }
  494. answerSettingEngine := SettingEngine{}
  495. answerSettingEngine.SetLite(answerisLite)
  496. answerPC, err := NewAPI(WithSettingEngine(answerSettingEngine)).NewPeerConnection(Configuration{})
  497. if err != nil {
  498. t.Fatal(err)
  499. }
  500. if err = signalPair(offerPC, answerPC); err != nil {
  501. t.Fatal(err)
  502. }
  503. dataChannelOpen := make(chan interface{})
  504. answerPC.OnDataChannel(func(_ *DataChannel) {
  505. close(dataChannelOpen)
  506. })
  507. <-dataChannelOpen
  508. closePairNow(t, offerPC, answerPC)
  509. }
  510. t.Run("Offerer", func(t *testing.T) {
  511. connectTwoAgents(true, false)
  512. })
  513. t.Run("Answerer", func(t *testing.T) {
  514. connectTwoAgents(false, true)
  515. })
  516. t.Run("Both", func(t *testing.T) {
  517. connectTwoAgents(true, true)
  518. })
  519. }
  520. func TestOnICEGatheringStateChange(t *testing.T) {
  521. seenGathering := &atomicBool{}
  522. seenComplete := &atomicBool{}
  523. seenGatheringAndComplete := make(chan interface{})
  524. seenClosed := make(chan interface{})
  525. peerConn, err := NewPeerConnection(Configuration{})
  526. assert.NoError(t, err)
  527. var onStateChange func(s ICEGathererState)
  528. onStateChange = func(s ICEGathererState) {
  529. // Access to ICEGatherer in the callback must not cause dead lock.
  530. peerConn.OnICEGatheringStateChange(onStateChange)
  531. if state := peerConn.iceGatherer.State(); state != s {
  532. t.Errorf("State change callback argument (%s) and State() (%s) result differs",
  533. s, state,
  534. )
  535. }
  536. switch s { // nolint:exhaustive
  537. case ICEGathererStateClosed:
  538. close(seenClosed)
  539. return
  540. case ICEGathererStateGathering:
  541. if seenComplete.get() {
  542. t.Error("Completed before gathering")
  543. }
  544. seenGathering.set(true)
  545. case ICEGathererStateComplete:
  546. seenComplete.set(true)
  547. }
  548. if seenGathering.get() && seenComplete.get() {
  549. close(seenGatheringAndComplete)
  550. }
  551. }
  552. peerConn.OnICEGatheringStateChange(onStateChange)
  553. offer, err := peerConn.CreateOffer(nil)
  554. assert.NoError(t, err)
  555. assert.NoError(t, peerConn.SetLocalDescription(offer))
  556. select {
  557. case <-time.After(time.Second * 10):
  558. t.Fatal("Gathering and Complete were never seen")
  559. case <-seenClosed:
  560. t.Fatal("Closed before PeerConnection Close")
  561. case <-seenGatheringAndComplete:
  562. }
  563. assert.NoError(t, peerConn.Close())
  564. select {
  565. case <-time.After(time.Second * 10):
  566. t.Fatal("Closed was never seen")
  567. case <-seenClosed:
  568. }
  569. }
  570. // Assert Trickle ICE behaviors
  571. func TestPeerConnectionTrickle(t *testing.T) {
  572. offerPC, answerPC, err := newPair()
  573. assert.NoError(t, err)
  574. _, err = offerPC.CreateDataChannel("test-channel", nil)
  575. assert.NoError(t, err)
  576. addOrCacheCandidate := func(pc *PeerConnection, c *ICECandidate, candidateCache []ICECandidateInit) []ICECandidateInit {
  577. if c == nil {
  578. return candidateCache
  579. }
  580. if pc.RemoteDescription() == nil {
  581. return append(candidateCache, c.ToJSON())
  582. }
  583. assert.NoError(t, pc.AddICECandidate(c.ToJSON()))
  584. return candidateCache
  585. }
  586. candidateLock := sync.RWMutex{}
  587. var offerCandidateDone, answerCandidateDone bool
  588. cachedOfferCandidates := []ICECandidateInit{}
  589. offerPC.OnICECandidate(func(c *ICECandidate) {
  590. if offerCandidateDone {
  591. t.Error("Received OnICECandidate after finishing gathering")
  592. }
  593. if c == nil {
  594. offerCandidateDone = true
  595. }
  596. candidateLock.Lock()
  597. defer candidateLock.Unlock()
  598. cachedOfferCandidates = addOrCacheCandidate(answerPC, c, cachedOfferCandidates)
  599. })
  600. cachedAnswerCandidates := []ICECandidateInit{}
  601. answerPC.OnICECandidate(func(c *ICECandidate) {
  602. if answerCandidateDone {
  603. t.Error("Received OnICECandidate after finishing gathering")
  604. }
  605. if c == nil {
  606. answerCandidateDone = true
  607. }
  608. candidateLock.Lock()
  609. defer candidateLock.Unlock()
  610. cachedAnswerCandidates = addOrCacheCandidate(offerPC, c, cachedAnswerCandidates)
  611. })
  612. offerPCConnected, offerPCConnectedCancel := context.WithCancel(context.Background())
  613. offerPC.OnICEConnectionStateChange(func(i ICEConnectionState) {
  614. if i == ICEConnectionStateConnected {
  615. offerPCConnectedCancel()
  616. }
  617. })
  618. answerPCConnected, answerPCConnectedCancel := context.WithCancel(context.Background())
  619. answerPC.OnICEConnectionStateChange(func(i ICEConnectionState) {
  620. if i == ICEConnectionStateConnected {
  621. answerPCConnectedCancel()
  622. }
  623. })
  624. offer, err := offerPC.CreateOffer(nil)
  625. assert.NoError(t, err)
  626. assert.NoError(t, offerPC.SetLocalDescription(offer))
  627. assert.NoError(t, answerPC.SetRemoteDescription(offer))
  628. answer, err := answerPC.CreateAnswer(nil)
  629. assert.NoError(t, err)
  630. assert.NoError(t, answerPC.SetLocalDescription(answer))
  631. assert.NoError(t, offerPC.SetRemoteDescription(answer))
  632. candidateLock.Lock()
  633. for _, c := range cachedAnswerCandidates {
  634. assert.NoError(t, offerPC.AddICECandidate(c))
  635. }
  636. for _, c := range cachedOfferCandidates {
  637. assert.NoError(t, answerPC.AddICECandidate(c))
  638. }
  639. candidateLock.Unlock()
  640. <-answerPCConnected.Done()
  641. <-offerPCConnected.Done()
  642. closePairNow(t, offerPC, answerPC)
  643. }
  644. // Issue #1121, assert populateLocalCandidates doesn't mutate
  645. func TestPopulateLocalCandidates(t *testing.T) {
  646. t.Run("PendingLocalDescription shouldn't add extra mutations", func(t *testing.T) {
  647. pc, err := NewPeerConnection(Configuration{})
  648. assert.NoError(t, err)
  649. offer, err := pc.CreateOffer(nil)
  650. assert.NoError(t, err)
  651. offerGatheringComplete := GatheringCompletePromise(pc)
  652. assert.NoError(t, pc.SetLocalDescription(offer))
  653. <-offerGatheringComplete
  654. assert.Equal(t, pc.PendingLocalDescription(), pc.PendingLocalDescription())
  655. assert.NoError(t, pc.Close())
  656. })
  657. t.Run("end-of-candidates only when gathering is complete", func(t *testing.T) {
  658. pc, err := NewAPI().NewPeerConnection(Configuration{})
  659. assert.NoError(t, err)
  660. _, err = pc.CreateDataChannel("test-channel", nil)
  661. assert.NoError(t, err)
  662. offer, err := pc.CreateOffer(nil)
  663. assert.NoError(t, err)
  664. assert.NotContains(t, offer.SDP, "a=candidate")
  665. assert.NotContains(t, offer.SDP, "a=end-of-candidates")
  666. offerGatheringComplete := GatheringCompletePromise(pc)
  667. assert.NoError(t, pc.SetLocalDescription(offer))
  668. <-offerGatheringComplete
  669. assert.Contains(t, pc.PendingLocalDescription().SDP, "a=candidate")
  670. assert.Contains(t, pc.PendingLocalDescription().SDP, "a=end-of-candidates")
  671. assert.NoError(t, pc.Close())
  672. })
  673. }
  674. // Assert that two agents that only generate mDNS candidates can connect
  675. func TestMulticastDNSCandidates(t *testing.T) {
  676. lim := test.TimeOut(time.Second * 30)
  677. defer lim.Stop()
  678. report := test.CheckRoutines(t)
  679. defer report()
  680. s := SettingEngine{}
  681. s.SetICEMulticastDNSMode(ice.MulticastDNSModeQueryAndGather)
  682. pcOffer, pcAnswer, err := NewAPI(WithSettingEngine(s)).newPair(Configuration{})
  683. assert.NoError(t, err)
  684. assert.NoError(t, signalPair(pcOffer, pcAnswer))
  685. onDataChannel, onDataChannelCancel := context.WithCancel(context.Background())
  686. pcAnswer.OnDataChannel(func(d *DataChannel) {
  687. onDataChannelCancel()
  688. })
  689. <-onDataChannel.Done()
  690. closePairNow(t, pcOffer, pcAnswer)
  691. }
  692. func TestICERestart(t *testing.T) {
  693. extractCandidates := func(sdp string) (candidates []string) {
  694. sc := bufio.NewScanner(strings.NewReader(sdp))
  695. for sc.Scan() {
  696. if strings.HasPrefix(sc.Text(), "a=candidate:") {
  697. candidates = append(candidates, sc.Text())
  698. }
  699. }
  700. return
  701. }
  702. lim := test.TimeOut(time.Second * 30)
  703. defer lim.Stop()
  704. report := test.CheckRoutines(t)
  705. defer report()
  706. offerPC, answerPC, err := newPair()
  707. assert.NoError(t, err)
  708. var connectedWaitGroup sync.WaitGroup
  709. connectedWaitGroup.Add(2)
  710. offerPC.OnICEConnectionStateChange(func(state ICEConnectionState) {
  711. if state == ICEConnectionStateConnected {
  712. connectedWaitGroup.Done()
  713. }
  714. })
  715. answerPC.OnICEConnectionStateChange(func(state ICEConnectionState) {
  716. if state == ICEConnectionStateConnected {
  717. connectedWaitGroup.Done()
  718. }
  719. })
  720. // Connect two PeerConnections and block until ICEConnectionStateConnected
  721. assert.NoError(t, signalPair(offerPC, answerPC))
  722. connectedWaitGroup.Wait()
  723. // Store candidates from first Offer/Answer, compare later to make sure we re-gathered
  724. firstOfferCandidates := extractCandidates(offerPC.LocalDescription().SDP)
  725. firstAnswerCandidates := extractCandidates(answerPC.LocalDescription().SDP)
  726. // Use Trickle ICE for ICE Restart
  727. offerPC.OnICECandidate(func(c *ICECandidate) {
  728. if c != nil {
  729. assert.NoError(t, answerPC.AddICECandidate(c.ToJSON()))
  730. }
  731. })
  732. answerPC.OnICECandidate(func(c *ICECandidate) {
  733. if c != nil {
  734. assert.NoError(t, offerPC.AddICECandidate(c.ToJSON()))
  735. }
  736. })
  737. // Re-signal with ICE Restart, block until ICEConnectionStateConnected
  738. connectedWaitGroup.Add(2)
  739. offer, err := offerPC.CreateOffer(&OfferOptions{ICERestart: true})
  740. assert.NoError(t, err)
  741. assert.NoError(t, offerPC.SetLocalDescription(offer))
  742. assert.NoError(t, answerPC.SetRemoteDescription(offer))
  743. answer, err := answerPC.CreateAnswer(nil)
  744. assert.NoError(t, err)
  745. assert.NoError(t, answerPC.SetLocalDescription(answer))
  746. assert.NoError(t, offerPC.SetRemoteDescription(answer))
  747. // Block until we have connected again
  748. connectedWaitGroup.Wait()
  749. // Compare ICE Candidates across each run, fail if they haven't changed
  750. assert.NotEqual(t, firstOfferCandidates, extractCandidates(offerPC.LocalDescription().SDP))
  751. assert.NotEqual(t, firstAnswerCandidates, extractCandidates(answerPC.LocalDescription().SDP))
  752. closePairNow(t, offerPC, answerPC)
  753. }
  754. // Assert error handling when an Agent is restart
  755. func TestICERestart_Error_Handling(t *testing.T) {
  756. iceStates := make(chan ICEConnectionState, 100)
  757. blockUntilICEState := func(wantedState ICEConnectionState) {
  758. stateCount := 0
  759. for i := range iceStates {
  760. if i == wantedState {
  761. stateCount++
  762. }
  763. if stateCount == 2 {
  764. return
  765. }
  766. }
  767. }
  768. connectWithICERestart := func(offerPeerConnection, answerPeerConnection *PeerConnection) {
  769. offer, err := offerPeerConnection.CreateOffer(&OfferOptions{ICERestart: true})
  770. assert.NoError(t, err)
  771. assert.NoError(t, offerPeerConnection.SetLocalDescription(offer))
  772. assert.NoError(t, answerPeerConnection.SetRemoteDescription(*offerPeerConnection.LocalDescription()))
  773. answer, err := answerPeerConnection.CreateAnswer(nil)
  774. assert.NoError(t, err)
  775. assert.NoError(t, answerPeerConnection.SetLocalDescription(answer))
  776. assert.NoError(t, offerPeerConnection.SetRemoteDescription(*answerPeerConnection.LocalDescription()))
  777. }
  778. lim := test.TimeOut(time.Second * 30)
  779. defer lim.Stop()
  780. report := test.CheckRoutines(t)
  781. defer report()
  782. offerPeerConnection, answerPeerConnection, wan := createVNetPair(t)
  783. pushICEState := func(i ICEConnectionState) { iceStates <- i }
  784. offerPeerConnection.OnICEConnectionStateChange(pushICEState)
  785. answerPeerConnection.OnICEConnectionStateChange(pushICEState)
  786. keepPackets := &atomicBool{}
  787. keepPackets.set(true)
  788. // Add a filter that monitors the traffic on the router
  789. wan.AddChunkFilter(func(c vnet.Chunk) bool {
  790. return keepPackets.get()
  791. })
  792. const testMessage = "testMessage"
  793. d, err := answerPeerConnection.CreateDataChannel("foo", nil)
  794. assert.NoError(t, err)
  795. dataChannelMessages := make(chan string, 100)
  796. d.OnMessage(func(m DataChannelMessage) {
  797. dataChannelMessages <- string(m.Data)
  798. })
  799. dataChannelAnswerer := make(chan *DataChannel)
  800. offerPeerConnection.OnDataChannel(func(d *DataChannel) {
  801. d.OnOpen(func() {
  802. dataChannelAnswerer <- d
  803. })
  804. })
  805. // Connect and Assert we have connected
  806. assert.NoError(t, signalPair(offerPeerConnection, answerPeerConnection))
  807. blockUntilICEState(ICEConnectionStateConnected)
  808. offerPeerConnection.OnICECandidate(func(c *ICECandidate) {
  809. if c != nil {
  810. assert.NoError(t, answerPeerConnection.AddICECandidate(c.ToJSON()))
  811. }
  812. })
  813. answerPeerConnection.OnICECandidate(func(c *ICECandidate) {
  814. if c != nil {
  815. assert.NoError(t, offerPeerConnection.AddICECandidate(c.ToJSON()))
  816. }
  817. })
  818. dataChannel := <-dataChannelAnswerer
  819. assert.NoError(t, dataChannel.SendText(testMessage))
  820. assert.Equal(t, testMessage, <-dataChannelMessages)
  821. // Drop all packets, assert we have disconnected
  822. // and send a DataChannel message when disconnected
  823. keepPackets.set(false)
  824. blockUntilICEState(ICEConnectionStateFailed)
  825. assert.NoError(t, dataChannel.SendText(testMessage))
  826. // ICE Restart and assert we have reconnected
  827. // block until our DataChannel message is delivered
  828. keepPackets.set(true)
  829. connectWithICERestart(offerPeerConnection, answerPeerConnection)
  830. blockUntilICEState(ICEConnectionStateConnected)
  831. assert.Equal(t, testMessage, <-dataChannelMessages)
  832. assert.NoError(t, wan.Stop())
  833. closePairNow(t, offerPeerConnection, answerPeerConnection)
  834. }
  835. type trackRecords struct {
  836. mu sync.Mutex
  837. trackIDs map[string]struct{}
  838. receivedTrackIDs map[string]struct{}
  839. }
  840. func (r *trackRecords) newTrack() (*TrackLocalStaticRTP, error) {
  841. trackID := fmt.Sprintf("pion-track-%d", len(r.trackIDs))
  842. track, err := NewTrackLocalStaticRTP(RTPCodecCapability{MimeType: MimeTypeVP8}, trackID, "pion")
  843. r.trackIDs[trackID] = struct{}{}
  844. return track, err
  845. }
  846. func (r *trackRecords) handleTrack(t *TrackRemote, _ *RTPReceiver) {
  847. r.mu.Lock()
  848. defer r.mu.Unlock()
  849. tID := t.ID()
  850. if _, exist := r.trackIDs[tID]; exist {
  851. r.receivedTrackIDs[tID] = struct{}{}
  852. }
  853. }
  854. func (r *trackRecords) remains() int {
  855. r.mu.Lock()
  856. defer r.mu.Unlock()
  857. return len(r.trackIDs) - len(r.receivedTrackIDs)
  858. }
  859. // This test assure that all track events emits.
  860. func TestPeerConnection_MassiveTracks(t *testing.T) {
  861. var (
  862. api = NewAPI()
  863. tRecs = &trackRecords{
  864. trackIDs: make(map[string]struct{}),
  865. receivedTrackIDs: make(map[string]struct{}),
  866. }
  867. tracks = []*TrackLocalStaticRTP{}
  868. trackCount = 256
  869. pingInterval = 1 * time.Second
  870. noiseInterval = 100 * time.Microsecond
  871. timeoutDuration = 20 * time.Second
  872. rawPkt = []byte{
  873. 0x90, 0xe0, 0x69, 0x8f, 0xd9, 0xc2, 0x93, 0xda, 0x1c, 0x64,
  874. 0x27, 0x82, 0x00, 0x01, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x98, 0x36, 0xbe, 0x88, 0x9e,
  875. }
  876. samplePkt = &rtp.Packet{
  877. Header: rtp.Header{
  878. Marker: true,
  879. Extension: false,
  880. ExtensionProfile: 1,
  881. Version: 2,
  882. SequenceNumber: 27023,
  883. Timestamp: 3653407706,
  884. CSRC: []uint32{},
  885. },
  886. Payload: rawPkt[20:],
  887. }
  888. connected = make(chan struct{})
  889. stopped = make(chan struct{})
  890. )
  891. assert.NoError(t, api.mediaEngine.RegisterDefaultCodecs())
  892. offerPC, answerPC, err := api.newPair(Configuration{})
  893. assert.NoError(t, err)
  894. // Create massive tracks.
  895. for range make([]struct{}, trackCount) {
  896. track, err := tRecs.newTrack()
  897. assert.NoError(t, err)
  898. _, err = offerPC.AddTrack(track)
  899. assert.NoError(t, err)
  900. tracks = append(tracks, track)
  901. }
  902. answerPC.OnTrack(tRecs.handleTrack)
  903. offerPC.OnICEConnectionStateChange(func(s ICEConnectionState) {
  904. if s == ICEConnectionStateConnected {
  905. close(connected)
  906. }
  907. })
  908. // A routine to periodically call GetTransceivers. This action might cause
  909. // the deadlock and prevent track event to emit.
  910. go func() {
  911. for {
  912. answerPC.GetTransceivers()
  913. time.Sleep(noiseInterval)
  914. select {
  915. case <-stopped:
  916. return
  917. default:
  918. }
  919. }
  920. }()
  921. assert.NoError(t, signalPair(offerPC, answerPC))
  922. // Send a RTP packets to each track to trigger track event after connected.
  923. <-connected
  924. time.Sleep(1 * time.Second)
  925. for _, track := range tracks {
  926. assert.NoError(t, track.WriteRTP(samplePkt))
  927. }
  928. // Ping trackRecords to see if any track event not received yet.
  929. tooLong := time.After(timeoutDuration)
  930. for {
  931. remains := tRecs.remains()
  932. if remains == 0 {
  933. break
  934. }
  935. t.Log("remain tracks", remains)
  936. time.Sleep(pingInterval)
  937. select {
  938. case <-tooLong:
  939. t.Error("unable to receive all track events in time")
  940. default:
  941. }
  942. }
  943. close(stopped)
  944. closePairNow(t, offerPC, answerPC)
  945. }
  946. func TestEmptyCandidate(t *testing.T) {
  947. testCases := []struct {
  948. ICECandidate ICECandidateInit
  949. expectError bool
  950. }{
  951. {ICECandidateInit{"", nil, nil, nil}, false},
  952. {ICECandidateInit{
  953. "211962667 1 udp 2122194687 10.0.3.1 40864 typ host generation 0",
  954. nil, nil, nil,
  955. }, false},
  956. {ICECandidateInit{
  957. "1234567",
  958. nil, nil, nil,
  959. }, true},
  960. }
  961. for i, testCase := range testCases {
  962. peerConn, err := NewPeerConnection(Configuration{})
  963. if err != nil {
  964. t.Errorf("Case %d: got error: %v", i, err)
  965. }
  966. err = peerConn.SetRemoteDescription(SessionDescription{Type: SDPTypeOffer, SDP: minimalOffer})
  967. if err != nil {
  968. t.Errorf("Case %d: got error: %v", i, err)
  969. }
  970. if testCase.expectError {
  971. assert.Error(t, peerConn.AddICECandidate(testCase.ICECandidate))
  972. } else {
  973. assert.NoError(t, peerConn.AddICECandidate(testCase.ICECandidate))
  974. }
  975. assert.NoError(t, peerConn.Close())
  976. }
  977. }
  978. const liteOffer = `v=0
  979. o=- 4596489990601351948 2 IN IP4 127.0.0.1
  980. s=-
  981. t=0 0
  982. a=msid-semantic: WMS
  983. a=ice-lite
  984. m=application 47299 DTLS/SCTP 5000
  985. c=IN IP4 192.168.20.129
  986. a=ice-ufrag:1/MvHwjAyVf27aLu
  987. a=ice-pwd:3dBU7cFOBl120v33cynDvN1E
  988. 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
  989. a=mid:data
  990. `
  991. // this test asserts that if an ice-lite offer is received,
  992. // pion will take the ICE-CONTROLLING role
  993. func TestICELite(t *testing.T) {
  994. peerConnection, err := NewPeerConnection(Configuration{})
  995. assert.NoError(t, err)
  996. assert.NoError(t, peerConnection.SetRemoteDescription(
  997. SessionDescription{SDP: liteOffer, Type: SDPTypeOffer},
  998. ))
  999. SDPAnswer, err := peerConnection.CreateAnswer(nil)
  1000. assert.NoError(t, err)
  1001. assert.NoError(t, peerConnection.SetLocalDescription(SDPAnswer))
  1002. assert.Equal(t, ICERoleControlling, peerConnection.iceTransport.Role(),
  1003. "pion did not set state to ICE-CONTROLLED against ice-light offer")
  1004. assert.NoError(t, peerConnection.Close())
  1005. }
  1006. func TestPeerConnection_TransceiverDirection(t *testing.T) {
  1007. lim := test.TimeOut(time.Second * 30)
  1008. defer lim.Stop()
  1009. report := test.CheckRoutines(t)
  1010. defer report()
  1011. createTransceiver := func(pc *PeerConnection, dir RTPTransceiverDirection) error {
  1012. // AddTransceiverFromKind() can't be used with sendonly
  1013. if dir == RTPTransceiverDirectionSendonly {
  1014. codecs := pc.api.mediaEngine.getCodecsByKind(RTPCodecTypeVideo)
  1015. track, err := NewTrackLocalStaticSample(codecs[0].RTPCodecCapability, util.MathRandAlpha(16), util.MathRandAlpha(16))
  1016. if err != nil {
  1017. return err
  1018. }
  1019. _, err = pc.AddTransceiverFromTrack(track, []RTPTransceiverInit{
  1020. {Direction: dir},
  1021. }...)
  1022. return err
  1023. }
  1024. _, err := pc.AddTransceiverFromKind(
  1025. RTPCodecTypeVideo,
  1026. RTPTransceiverInit{Direction: dir},
  1027. )
  1028. return err
  1029. }
  1030. for _, test := range []struct {
  1031. name string
  1032. offerDirection RTPTransceiverDirection
  1033. answerStartDirection RTPTransceiverDirection
  1034. answerFinalDirections []RTPTransceiverDirection
  1035. }{
  1036. {
  1037. "offer sendrecv answer sendrecv",
  1038. RTPTransceiverDirectionSendrecv,
  1039. RTPTransceiverDirectionSendrecv,
  1040. []RTPTransceiverDirection{RTPTransceiverDirectionSendrecv},
  1041. },
  1042. {
  1043. "offer sendonly answer sendrecv",
  1044. RTPTransceiverDirectionSendonly,
  1045. RTPTransceiverDirectionSendrecv,
  1046. []RTPTransceiverDirection{RTPTransceiverDirectionSendrecv},
  1047. },
  1048. {
  1049. "offer recvonly answer sendrecv",
  1050. RTPTransceiverDirectionRecvonly,
  1051. RTPTransceiverDirectionSendrecv,
  1052. []RTPTransceiverDirection{RTPTransceiverDirectionSendonly},
  1053. },
  1054. {
  1055. "offer sendrecv answer sendonly",
  1056. RTPTransceiverDirectionSendrecv,
  1057. RTPTransceiverDirectionSendonly,
  1058. []RTPTransceiverDirection{RTPTransceiverDirectionSendrecv},
  1059. },
  1060. {
  1061. "offer sendonly answer sendonly",
  1062. RTPTransceiverDirectionSendonly,
  1063. RTPTransceiverDirectionSendonly,
  1064. []RTPTransceiverDirection{RTPTransceiverDirectionSendonly, RTPTransceiverDirectionRecvonly},
  1065. },
  1066. {
  1067. "offer recvonly answer sendonly",
  1068. RTPTransceiverDirectionRecvonly,
  1069. RTPTransceiverDirectionSendonly,
  1070. []RTPTransceiverDirection{RTPTransceiverDirectionSendonly},
  1071. },
  1072. {
  1073. "offer sendrecv answer recvonly",
  1074. RTPTransceiverDirectionSendrecv,
  1075. RTPTransceiverDirectionRecvonly,
  1076. []RTPTransceiverDirection{RTPTransceiverDirectionRecvonly},
  1077. },
  1078. {
  1079. "offer sendonly answer recvonly",
  1080. RTPTransceiverDirectionSendonly,
  1081. RTPTransceiverDirectionRecvonly,
  1082. []RTPTransceiverDirection{RTPTransceiverDirectionRecvonly},
  1083. },
  1084. {
  1085. "offer recvonly answer recvonly",
  1086. RTPTransceiverDirectionRecvonly,
  1087. RTPTransceiverDirectionRecvonly,
  1088. []RTPTransceiverDirection{RTPTransceiverDirectionRecvonly, RTPTransceiverDirectionSendonly},
  1089. },
  1090. } {
  1091. offerDirection := test.offerDirection
  1092. answerStartDirection := test.answerStartDirection
  1093. answerFinalDirections := test.answerFinalDirections
  1094. t.Run(test.name, func(t *testing.T) {
  1095. pcOffer, pcAnswer, err := newPair()
  1096. assert.NoError(t, err)
  1097. err = createTransceiver(pcOffer, offerDirection)
  1098. assert.NoError(t, err)
  1099. offer, err := pcOffer.CreateOffer(nil)
  1100. assert.NoError(t, err)
  1101. err = createTransceiver(pcAnswer, answerStartDirection)
  1102. assert.NoError(t, err)
  1103. assert.NoError(t, pcAnswer.SetRemoteDescription(offer))
  1104. assert.Equal(t, len(answerFinalDirections), len(pcAnswer.GetTransceivers()))
  1105. for i, tr := range pcAnswer.GetTransceivers() {
  1106. assert.Equal(t, answerFinalDirections[i], tr.Direction())
  1107. }
  1108. assert.NoError(t, pcOffer.Close())
  1109. assert.NoError(t, pcAnswer.Close())
  1110. })
  1111. }
  1112. }
  1113. func TestPeerConnection_SessionID(t *testing.T) {
  1114. defer test.TimeOut(time.Second * 10).Stop()
  1115. defer test.CheckRoutines(t)()
  1116. pcOffer, pcAnswer, err := newPair()
  1117. assert.NoError(t, err)
  1118. var offerSessionID uint64
  1119. var offerSessionVersion uint64
  1120. var answerSessionID uint64
  1121. var answerSessionVersion uint64
  1122. for i := 0; i < 10; i++ {
  1123. assert.NoError(t, signalPair(pcOffer, pcAnswer))
  1124. offer := pcOffer.LocalDescription().parsed
  1125. sessionID := offer.Origin.SessionID
  1126. sessionVersion := offer.Origin.SessionVersion
  1127. if offerSessionID == 0 {
  1128. offerSessionID = sessionID
  1129. offerSessionVersion = sessionVersion
  1130. } else {
  1131. if offerSessionID != sessionID {
  1132. t.Errorf("offer[%v] session id mismatch: expected=%v, got=%v", i, offerSessionID, sessionID)
  1133. }
  1134. if offerSessionVersion+1 != sessionVersion {
  1135. t.Errorf("offer[%v] session version mismatch: expected=%v, got=%v", i, offerSessionVersion+1, sessionVersion)
  1136. }
  1137. offerSessionVersion++
  1138. }
  1139. answer := pcAnswer.LocalDescription().parsed
  1140. sessionID = answer.Origin.SessionID
  1141. sessionVersion = answer.Origin.SessionVersion
  1142. if answerSessionID == 0 {
  1143. answerSessionID = sessionID
  1144. answerSessionVersion = sessionVersion
  1145. } else {
  1146. if answerSessionID != sessionID {
  1147. t.Errorf("answer[%v] session id mismatch: expected=%v, got=%v", i, answerSessionID, sessionID)
  1148. }
  1149. if answerSessionVersion+1 != sessionVersion {
  1150. t.Errorf("answer[%v] session version mismatch: expected=%v, got=%v", i, answerSessionVersion+1, sessionVersion)
  1151. }
  1152. answerSessionVersion++
  1153. }
  1154. }
  1155. closePairNow(t, pcOffer, pcAnswer)
  1156. }
  1157. func TestPeerConnectionNilCallback(t *testing.T) {
  1158. pc, err := NewPeerConnection(Configuration{})
  1159. assert.NoError(t, err)
  1160. pc.onSignalingStateChange(SignalingStateStable)
  1161. pc.OnSignalingStateChange(func(ss SignalingState) {
  1162. t.Error("OnSignalingStateChange called")
  1163. })
  1164. pc.OnSignalingStateChange(nil)
  1165. pc.onSignalingStateChange(SignalingStateStable)
  1166. pc.onConnectionStateChange(PeerConnectionStateNew)
  1167. pc.OnConnectionStateChange(func(pcs PeerConnectionState) {
  1168. t.Error("OnConnectionStateChange called")
  1169. })
  1170. pc.OnConnectionStateChange(nil)
  1171. pc.onConnectionStateChange(PeerConnectionStateNew)
  1172. pc.onICEConnectionStateChange(ICEConnectionStateNew)
  1173. pc.OnICEConnectionStateChange(func(ics ICEConnectionState) {
  1174. t.Error("OnConnectionStateChange called")
  1175. })
  1176. pc.OnICEConnectionStateChange(nil)
  1177. pc.onICEConnectionStateChange(ICEConnectionStateNew)
  1178. pc.onNegotiationNeeded()
  1179. pc.negotiationNeededOp()
  1180. pc.OnNegotiationNeeded(func() {
  1181. t.Error("OnNegotiationNeeded called")
  1182. })
  1183. pc.OnNegotiationNeeded(nil)
  1184. pc.onNegotiationNeeded()
  1185. pc.negotiationNeededOp()
  1186. assert.NoError(t, pc.Close())
  1187. }
  1188. func TestTransceiverCreatedByRemoteSdpHasSameCodecOrderAsRemote(t *testing.T) {
  1189. t.Run("Codec MatchExact", func(t *testing.T) { //nolint:dupl
  1190. const remoteSdp = `v=0
  1191. o=- 4596489990601351948 2 IN IP4 127.0.0.1
  1192. s=-
  1193. t=0 0
  1194. m=video 60323 UDP/TLS/RTP/SAVPF 98 94 106
  1195. a=ice-ufrag:1/MvHwjAyVf27aLu
  1196. a=ice-pwd:3dBU7cFOBl120v33cynDvN1E
  1197. a=ice-options:google-ice
  1198. 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
  1199. a=mid:0
  1200. a=rtpmap:98 H264/90000
  1201. a=fmtp:98 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f
  1202. a=rtpmap:94 VP8/90000
  1203. a=rtpmap:106 H264/90000
  1204. a=fmtp:106 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f
  1205. a=sendonly
  1206. m=video 60323 UDP/TLS/RTP/SAVPF 108 98 125
  1207. a=ice-ufrag:1/MvHwjAyVf27aLu
  1208. a=ice-pwd:3dBU7cFOBl120v33cynDvN1E
  1209. a=ice-options:google-ice
  1210. 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
  1211. a=mid:1
  1212. a=rtpmap:98 H264/90000
  1213. a=fmtp:98 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f
  1214. a=rtpmap:108 VP8/90000
  1215. a=sendonly
  1216. a=rtpmap:125 H264/90000
  1217. a=fmtp:125 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f
  1218. `
  1219. m := MediaEngine{}
  1220. assert.NoError(t, m.RegisterCodec(RTPCodecParameters{
  1221. RTPCodecCapability: RTPCodecCapability{MimeTypeVP8, 90000, 0, "", nil},
  1222. PayloadType: 94,
  1223. }, RTPCodecTypeVideo))
  1224. assert.NoError(t, m.RegisterCodec(RTPCodecParameters{
  1225. RTPCodecCapability: RTPCodecCapability{MimeTypeH264, 90000, 0, "level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f", nil},
  1226. PayloadType: 98,
  1227. }, RTPCodecTypeVideo))
  1228. api := NewAPI(WithMediaEngine(&m))
  1229. pc, err := api.NewPeerConnection(Configuration{})
  1230. assert.NoError(t, err)
  1231. assert.NoError(t, pc.SetRemoteDescription(SessionDescription{
  1232. Type: SDPTypeOffer,
  1233. SDP: remoteSdp,
  1234. }))
  1235. ans, _ := pc.CreateAnswer(nil)
  1236. assert.NoError(t, pc.SetLocalDescription(ans))
  1237. codecOfTr1 := pc.GetTransceivers()[0].getCodecs()[0]
  1238. codecs := pc.api.mediaEngine.getCodecsByKind(RTPCodecTypeVideo)
  1239. _, matchType := codecParametersFuzzySearch(codecOfTr1, codecs)
  1240. assert.Equal(t, codecMatchExact, matchType)
  1241. codecOfTr2 := pc.GetTransceivers()[1].getCodecs()[0]
  1242. _, matchType = codecParametersFuzzySearch(codecOfTr2, codecs)
  1243. assert.Equal(t, codecMatchExact, matchType)
  1244. assert.EqualValues(t, 94, codecOfTr2.PayloadType)
  1245. assert.NoError(t, pc.Close())
  1246. })
  1247. t.Run("Codec PartialExact Only", func(t *testing.T) { //nolint:dupl
  1248. const remoteSdp = `v=0
  1249. o=- 4596489990601351948 2 IN IP4 127.0.0.1
  1250. s=-
  1251. t=0 0
  1252. m=video 60323 UDP/TLS/RTP/SAVPF 98 106
  1253. a=ice-ufrag:1/MvHwjAyVf27aLu
  1254. a=ice-pwd:3dBU7cFOBl120v33cynDvN1E
  1255. a=ice-options:google-ice
  1256. 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
  1257. a=mid:0
  1258. a=rtpmap:98 H264/90000
  1259. a=fmtp:98 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f
  1260. a=rtpmap:106 H264/90000
  1261. a=fmtp:106 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032
  1262. a=sendonly
  1263. m=video 60323 UDP/TLS/RTP/SAVPF 125 98
  1264. a=ice-ufrag:1/MvHwjAyVf27aLu
  1265. a=ice-pwd:3dBU7cFOBl120v33cynDvN1E
  1266. a=ice-options:google-ice
  1267. 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
  1268. a=mid:1
  1269. a=rtpmap:125 H264/90000
  1270. a=fmtp:125 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032
  1271. a=rtpmap:98 H264/90000
  1272. a=fmtp:98 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f
  1273. a=sendonly
  1274. `
  1275. m := MediaEngine{}
  1276. assert.NoError(t, m.RegisterCodec(RTPCodecParameters{
  1277. RTPCodecCapability: RTPCodecCapability{MimeTypeVP8, 90000, 0, "", nil},
  1278. PayloadType: 94,
  1279. }, RTPCodecTypeVideo))
  1280. assert.NoError(t, m.RegisterCodec(RTPCodecParameters{
  1281. RTPCodecCapability: RTPCodecCapability{MimeTypeH264, 90000, 0, "level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f", nil},
  1282. PayloadType: 98,
  1283. }, RTPCodecTypeVideo))
  1284. api := NewAPI(WithMediaEngine(&m))
  1285. pc, err := api.NewPeerConnection(Configuration{})
  1286. assert.NoError(t, err)
  1287. assert.NoError(t, pc.SetRemoteDescription(SessionDescription{
  1288. Type: SDPTypeOffer,
  1289. SDP: remoteSdp,
  1290. }))
  1291. ans, _ := pc.CreateAnswer(nil)
  1292. assert.NoError(t, pc.SetLocalDescription(ans))
  1293. codecOfTr1 := pc.GetTransceivers()[0].getCodecs()[0]
  1294. codecs := pc.api.mediaEngine.getCodecsByKind(RTPCodecTypeVideo)
  1295. _, matchType := codecParametersFuzzySearch(codecOfTr1, codecs)
  1296. assert.Equal(t, codecMatchExact, matchType)
  1297. codecOfTr2 := pc.GetTransceivers()[1].getCodecs()[0]
  1298. _, matchType = codecParametersFuzzySearch(codecOfTr2, codecs)
  1299. assert.Equal(t, codecMatchExact, matchType)
  1300. // h.264/profile-id=640032 should be remap to 106 as same as transceiver 1
  1301. assert.EqualValues(t, 106, codecOfTr2.PayloadType)
  1302. assert.NoError(t, pc.Close())
  1303. })
  1304. }
  1305. // Assert that remote candidates with an unknown transport are ignored and logged.
  1306. // This allows us to accept SessionDescriptions with proprietary candidates
  1307. // like `ssltcp`.
  1308. func TestInvalidCandidateTransport(t *testing.T) {
  1309. const (
  1310. sslTCPCandidate = `candidate:1 1 ssltcp 1 127.0.0.1 443 typ host generation 0`
  1311. sslTCPOffer = `v=0
  1312. o=- 0 2 IN IP4 127.0.0.1
  1313. s=-
  1314. t=0 0
  1315. a=msid-semantic: WMS
  1316. m=application 9 DTLS/SCTP 5000
  1317. c=IN IP4 0.0.0.0
  1318. a=ice-ufrag:1/MvHwjAyVf27aLu
  1319. a=ice-pwd:3dBU7cFOBl120v33cynDvN1E
  1320. 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
  1321. a=mid:0
  1322. a=` + sslTCPCandidate + "\n"
  1323. )
  1324. peerConnection, err := NewPeerConnection(Configuration{})
  1325. assert.NoError(t, err)
  1326. assert.NoError(t, peerConnection.SetRemoteDescription(SessionDescription{Type: SDPTypeOffer, SDP: sslTCPOffer}))
  1327. assert.NoError(t, peerConnection.AddICECandidate(ICECandidateInit{Candidate: sslTCPCandidate}))
  1328. assert.NoError(t, peerConnection.Close())
  1329. }
  1330. func TestOfferWithInactiveDirection(t *testing.T) {
  1331. const remoteSDP = `v=0
  1332. o=- 4596489990601351948 2 IN IP4 127.0.0.1
  1333. s=-
  1334. t=0 0
  1335. a=fingerprint:sha-256 F7:BF:B4:42:5B:44:C0:B9:49:70:6D:26:D7:3E:E6:08:B1:5B:25:2E:32:88:50:B6:3C:BE:4E:18:A7:2C:85:7C
  1336. a=group:BUNDLE 0 1
  1337. a=msid-semantic:WMS *
  1338. m=video 9 UDP/TLS/RTP/SAVPF 97
  1339. c=IN IP4 0.0.0.0
  1340. a=inactive
  1341. a=ice-pwd:05d682b2902af03db90d9a9a5f2f8d7f
  1342. a=ice-ufrag:93cc7e4d
  1343. a=mid:0
  1344. a=rtpmap:97 H264/90000
  1345. a=setup:actpass
  1346. a=ssrc:1455629982 cname:{61fd3093-0326-4b12-8258-86bdc1fe677a}
  1347. `
  1348. peerConnection, err := NewPeerConnection(Configuration{})
  1349. assert.NoError(t, err)
  1350. assert.NoError(t, peerConnection.SetRemoteDescription(SessionDescription{Type: SDPTypeOffer, SDP: remoteSDP}))
  1351. assert.Equal(t, RTPTransceiverDirectionInactive, peerConnection.rtpTransceivers[0].direction.Load().(RTPTransceiverDirection)) //nolint:forcetypeassert
  1352. assert.NoError(t, peerConnection.Close())
  1353. }
  1354. func TestPeerConnectionState(t *testing.T) {
  1355. pc, err := NewPeerConnection(Configuration{})
  1356. assert.NoError(t, err)
  1357. assert.Equal(t, PeerConnectionStateNew, pc.ConnectionState())
  1358. pc.updateConnectionState(ICEConnectionStateChecking, DTLSTransportStateNew)
  1359. assert.Equal(t, PeerConnectionStateConnecting, pc.ConnectionState())
  1360. pc.updateConnectionState(ICEConnectionStateConnected, DTLSTransportStateNew)
  1361. assert.Equal(t, PeerConnectionStateConnecting, pc.ConnectionState())
  1362. pc.updateConnectionState(ICEConnectionStateConnected, DTLSTransportStateConnecting)
  1363. assert.Equal(t, PeerConnectionStateConnecting, pc.ConnectionState())
  1364. pc.updateConnectionState(ICEConnectionStateConnected, DTLSTransportStateConnected)
  1365. assert.Equal(t, PeerConnectionStateConnected, pc.ConnectionState())
  1366. pc.updateConnectionState(ICEConnectionStateCompleted, DTLSTransportStateConnected)
  1367. assert.Equal(t, PeerConnectionStateConnected, pc.ConnectionState())
  1368. pc.updateConnectionState(ICEConnectionStateConnected, DTLSTransportStateClosed)
  1369. assert.Equal(t, PeerConnectionStateConnected, pc.ConnectionState())
  1370. pc.updateConnectionState(ICEConnectionStateDisconnected, DTLSTransportStateConnected)
  1371. assert.Equal(t, PeerConnectionStateDisconnected, pc.ConnectionState())
  1372. pc.updateConnectionState(ICEConnectionStateFailed, DTLSTransportStateConnected)
  1373. assert.Equal(t, PeerConnectionStateFailed, pc.ConnectionState())
  1374. pc.updateConnectionState(ICEConnectionStateConnected, DTLSTransportStateFailed)
  1375. assert.Equal(t, PeerConnectionStateFailed, pc.ConnectionState())
  1376. assert.NoError(t, pc.Close())
  1377. assert.Equal(t, PeerConnectionStateClosed, pc.ConnectionState())
  1378. }