@@ -143,6 +143,10 @@ func (*Conn) SetWriteDeadline(time.Time) error {
143
143
func (c * Conn ) LocalAddr () net.Addr {
144
144
addr := c .local
145
145
addr .ConnectionID = c .id
146
+ pair , _ := c .ice .GetSelectedCandidatePair ()
147
+ if pair != nil {
148
+ addr .SelectedCandidate = pair .Local
149
+ }
146
150
return & addr
147
151
}
148
152
@@ -154,6 +158,11 @@ func (c *Conn) RemoteAddr() net.Addr {
154
158
c .candidatesMu .Lock ()
155
159
addr .Candidates = slices .Clone (c .candidates )
156
160
c .candidatesMu .Unlock ()
161
+
162
+ pair , _ := c .ice .GetSelectedCandidatePair ()
163
+ if pair != nil {
164
+ addr .SelectedCandidate = pair .Remote
165
+ }
157
166
return addr
158
167
}
159
168
@@ -176,9 +185,15 @@ func (c *Conn) Close() (err error) {
176
185
177
186
c .negotiator .handleClose (c )
178
187
188
+ if c .reliable != nil {
189
+ err = c .reliable .Close ()
190
+ }
191
+ if c .unreliable != nil {
192
+ err = errors .Join (err , c .unreliable .Close ())
193
+ }
194
+
179
195
err = errors .Join (
180
- c .reliable .Close (),
181
- c .unreliable .Close (),
196
+ err ,
182
197
c .sctp .Stop (),
183
198
c .dtls .Stop (),
184
199
c .ice .Stop (),
@@ -254,7 +269,6 @@ func (c *Conn) handleSignal(signal *Signal) error {
254
269
Typ : webrtc .ICECandidateType (candidate .Type ()),
255
270
TCPType : candidate .TCPType ().String (),
256
271
}
257
-
258
272
if r := candidate .RelatedAddress (); r != nil {
259
273
i .RelatedAddress , i .RelatedPort = r .Address , uint16 (r .Port )
260
274
}
@@ -323,9 +337,9 @@ func parseDescription(d *sdp.SessionDescription) (*description, error) {
323
337
}
324
338
var role webrtc.DTLSRole
325
339
switch attr {
326
- case "active" :
340
+ case sdp . ConnectionRoleActive . String () :
327
341
role = webrtc .DTLSRoleClient
328
- case "actpass" :
342
+ case sdp . ConnectionRoleActpass . String () :
329
343
role = webrtc .DTLSRoleServer
330
344
default :
331
345
return nil , fmt .Errorf ("invalid setup attribute: %s" , attr )
@@ -360,14 +374,6 @@ func parseDescription(d *sdp.SessionDescription) (*description, error) {
360
374
}, nil
361
375
}
362
376
363
- // description contains parameters for calling the Start method of ICE, DTLS and SCTP transport.
364
- //
365
- // A description may be parsed by a negotiator (Listener or Dialer) using parseDescription
366
- // with a [sdp.SessionDescription] decoded from a Signal of SignalTypeOffer or SignalTypeAnswer.
367
- //
368
- // A description may be filled in by a negotiator (Listener or Dialer) to encode
369
- // a local description of a Conn.
370
-
371
377
// description contains parameters necessary for starting ICE, DTLS, and SCTP transport within a Conn.
372
378
//
373
379
// It may be created by parsing a [sdp.SessionDescription] signaled from a remote connection or filed
@@ -386,7 +392,7 @@ type description struct {
386
392
// parameters of each transport within a Conn.
387
393
func (desc description ) encode () ([]byte , error ) {
388
394
d := & sdp.SessionDescription {
389
- Version : 0x2 ,
395
+ Version : 0x0 ,
390
396
Origin : sdp.Origin {
391
397
Username : "-" ,
392
398
SessionID : rand .Uint64 (),
@@ -400,53 +406,50 @@ func (desc description) encode() ([]byte, error) {
400
406
{},
401
407
},
402
408
Attributes : []sdp.Attribute {
403
- {Key : "group" , Value : "BUNDLE 0" },
404
- { Key : "extmap-allow-mixed" , Value : "" } ,
405
- {Key : "msid-semantic" , Value : " WMS" },
409
+ {Key : sdp . AttrKeyGroup , Value : "BUNDLE 0" },
410
+ sdp . NewPropertyAttribute ( sdp . AttrKeyExtMapAllowMixed ) ,
411
+ {Key : sdp . AttrKeyMsidSemantic , Value : " WMS" },
406
412
},
407
- MediaDescriptions : []* sdp.MediaDescription {
408
- {
409
- MediaName : sdp.MediaName {
410
- Media : "application" ,
411
- Port : sdp.RangedPort {Value : 9 },
412
- Protos : []string {"UDP" , "DTLS" , "SCTP" },
413
- Formats : []string {"webrtc-datachannel" },
414
- },
415
- ConnectionInformation : & sdp.ConnectionInformation {
416
- NetworkType : "IN" ,
417
- AddressType : "IP4" ,
418
- Address : & sdp.Address {Address : "0.0.0.0" },
419
- },
420
- Attributes : []sdp.Attribute {
421
- {Key : "ice-ufrag" , Value : desc .ice .UsernameFragment },
422
- {Key : "ice-pwd" , Value : desc .ice .Password },
423
- {Key : "ice-options" , Value : "trickle" },
424
- {Key : "fingerprint" , Value : fmt .Sprintf ("%s %s" ,
425
- desc .dtls .Fingerprints [0 ].Algorithm ,
426
- desc .dtls .Fingerprints [0 ].Value ,
427
- )},
428
- desc .setupAttribute (),
429
- {Key : "mid" , Value : "0" },
430
- {Key : "sctp-port" , Value : "5000" },
431
- {Key : "max-message-size" , Value : strconv .FormatUint (uint64 (desc .sctp .MaxMessageSize ), 10 )},
432
- },
413
+ }
414
+
415
+ media := & sdp.MediaDescription {
416
+ MediaName : sdp.MediaName {
417
+ Media : "application" ,
418
+ Port : sdp.RangedPort {Value : 9 },
419
+ Protos : []string {"UDP" , "DTLS" , "SCTP" },
420
+ Formats : []string {"webrtc-datachannel" },
421
+ },
422
+ ConnectionInformation : & sdp.ConnectionInformation {
423
+ NetworkType : "IN" ,
424
+ AddressType : "IP4" ,
425
+ Address : & sdp.Address {
426
+ Address : "0.0.0.0" ,
433
427
},
434
428
},
435
429
}
436
- return d .Marshal ()
430
+ media .WithICECredentials (desc .ice .UsernameFragment , desc .ice .Password )
431
+ media .WithValueAttribute ("ice-options" , "trickle" )
432
+ for _ , fingerprint := range desc .dtls .Fingerprints {
433
+ media .WithFingerprint (fingerprint .Algorithm , fingerprint .Value )
434
+ }
435
+ media .WithValueAttribute (sdp .AttrKeyConnectionSetup , desc .connectionRole (desc .dtls .Role ).String ())
436
+ media .WithValueAttribute (sdp .AttrKeyMID , "0" )
437
+ media .WithValueAttribute ("sctp-port" , "5000" )
438
+ media .WithValueAttribute ("max-message-size" , strconv .FormatUint (uint64 (desc .sctp .MaxMessageSize ), 10 ))
439
+
440
+ return d .WithMedia (media ).Marshal ()
437
441
}
438
442
439
- // setupAttribute returns a [sdp.Attribute] with the key 'setup' indicating the local
440
- // DTLS role as either 'active' or 'actpass'. It is called by encode to include the role
441
- // in the media description of the local [sdp.SessionDescription] .
442
- func (desc description ) setupAttribute ( ) sdp.Attribute {
443
- attr := sdp. Attribute { Key : "setup" }
444
- if desc . dtls . Role == webrtc .DTLSRoleServer {
445
- attr . Value = "actpass"
446
- } else {
447
- attr . Value = "active"
443
+ // connectionRole returns a [sdp.ConnectionRole] indicating the local DTLS role. It is called
444
+ // by encode to include the role into the media description of local [sdp.SessionDescription]
445
+ // as a [sdp.Attribute] of 'setup' .
446
+ func (desc description ) connectionRole ( role webrtc. DTLSRole ) sdp.ConnectionRole {
447
+ switch role {
448
+ case webrtc .DTLSRoleServer :
449
+ return sdp . ConnectionRoleActpass
450
+ default :
451
+ return sdp . ConnectionRoleActive
448
452
}
449
- return attr
450
453
}
451
454
452
455
// newConn creates a Conn from the ICE, DTLS and SCTP transport associated with the IDs.
0 commit comments