mirror of
https://github.com/pion/webrtc.git
synced 2025-10-06 07:37:10 +08:00
Add experimental support for ICE TCP
See pion/ice issue and PR: - https://github.com/pion/ice/tree/issue-196 - https://github.com/pion/ice/pull/226
This commit is contained in:
22
examples/ice-tcp/README.md
Normal file
22
examples/ice-tcp/README.md
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# ice-tcp
|
||||||
|
ice-tcp demonstrates Pion WebRTC's ICE TCP abilities.
|
||||||
|
|
||||||
|
## Instructions
|
||||||
|
|
||||||
|
### Download ice-tcp
|
||||||
|
This example requires you to clone the repo since it is serving static HTML.
|
||||||
|
|
||||||
|
```
|
||||||
|
mkdir -p $GOPATH/src/github.com/pion
|
||||||
|
cd $GOPATH/src/github.com/pion
|
||||||
|
git clone https://github.com/pion/webrtc.git
|
||||||
|
cd webrtc/examples/ice-tcp
|
||||||
|
```
|
||||||
|
|
||||||
|
### Run ice-tcp
|
||||||
|
Execute `go run *.go`
|
||||||
|
|
||||||
|
### Open the Web UI
|
||||||
|
Open [http://localhost:8080](http://localhost:8080). This will automatically start a PeerConnection. This page will now prints stats about the PeerConnection. The UDP candidates will be filtered out from the SDP.
|
||||||
|
|
||||||
|
Congrats, you have used Pion WebRTC! Now start building something cool
|
54
examples/ice-tcp/index.html
Normal file
54
examples/ice-tcp/index.html
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>ice-tcp</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<button onclick="window.doSignaling(true)"> ICE TCP </button><br />
|
||||||
|
|
||||||
|
|
||||||
|
<h3> ICE Connection States </h3>
|
||||||
|
<div id="iceConnectionStates"></div> <br />
|
||||||
|
|
||||||
|
<h3> Inbound DataChannel Messages </h3>
|
||||||
|
<div id="inboundDataChannelMessages"></div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
let pc = new RTCPeerConnection()
|
||||||
|
let dc = pc.createDataChannel('data')
|
||||||
|
|
||||||
|
dc.onmessage = event => {
|
||||||
|
let el = document.createElement('p')
|
||||||
|
el.appendChild(document.createTextNode(event.data))
|
||||||
|
|
||||||
|
document.getElementById('inboundDataChannelMessages').appendChild(el);
|
||||||
|
}
|
||||||
|
|
||||||
|
pc.oniceconnectionstatechange = () => {
|
||||||
|
let el = document.createElement('p')
|
||||||
|
el.appendChild(document.createTextNode(pc.iceConnectionState))
|
||||||
|
|
||||||
|
document.getElementById('iceConnectionStates').appendChild(el);
|
||||||
|
}
|
||||||
|
|
||||||
|
pc.createOffer()
|
||||||
|
.then(offer => {
|
||||||
|
pc.setLocalDescription(offer)
|
||||||
|
|
||||||
|
return fetch(`/doSignaling`, {
|
||||||
|
method: 'post',
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json, text/plain, */*',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify(offer)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.then(res => res.json())
|
||||||
|
.then(res => {
|
||||||
|
pc.setRemoteDescription(res)
|
||||||
|
})
|
||||||
|
.catch(alert)
|
||||||
|
</script>
|
||||||
|
</html>
|
97
examples/ice-tcp/main.go
Normal file
97
examples/ice-tcp/main.go
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/pion/webrtc/v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
var peerConnection *webrtc.PeerConnection //nolint
|
||||||
|
|
||||||
|
func doSignaling(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if peerConnection == nil {
|
||||||
|
m := webrtc.MediaEngine{}
|
||||||
|
m.RegisterDefaultCodecs()
|
||||||
|
|
||||||
|
settingEngine := webrtc.SettingEngine{}
|
||||||
|
|
||||||
|
// Enable support only for TCP ICE candidates.
|
||||||
|
settingEngine.SetNetworkTypes([]webrtc.NetworkType{
|
||||||
|
webrtc.NetworkTypeTCP4,
|
||||||
|
webrtc.NetworkTypeTCP6,
|
||||||
|
})
|
||||||
|
settingEngine.SetICETCPPort(8443)
|
||||||
|
|
||||||
|
api := webrtc.NewAPI(
|
||||||
|
webrtc.WithMediaEngine(m),
|
||||||
|
webrtc.WithSettingEngine(settingEngine),
|
||||||
|
)
|
||||||
|
if peerConnection, err = api.NewPeerConnection(webrtc.Configuration{}); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the handler for ICE connection state
|
||||||
|
// This will notify you when the peer has connected/disconnected
|
||||||
|
peerConnection.OnICEConnectionStateChange(func(connectionState webrtc.ICEConnectionState) {
|
||||||
|
fmt.Printf("ICE Connection State has changed: %s\n", connectionState.String())
|
||||||
|
})
|
||||||
|
|
||||||
|
// Send the current time via a DataChannel to the remote peer every 3 seconds
|
||||||
|
peerConnection.OnDataChannel(func(d *webrtc.DataChannel) {
|
||||||
|
d.OnOpen(func() {
|
||||||
|
for range time.Tick(time.Second * 3) {
|
||||||
|
if err = d.SendText(time.Now().String()); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var offer webrtc.SessionDescription
|
||||||
|
if err = json.NewDecoder(r.Body).Decode(&offer); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = peerConnection.SetRemoteDescription(offer); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create channel that is blocked until ICE Gathering is complete
|
||||||
|
gatherComplete := webrtc.GatheringCompletePromise(peerConnection)
|
||||||
|
|
||||||
|
answer, err := peerConnection.CreateAnswer(nil)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
} else if err = peerConnection.SetLocalDescription(answer); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Block until ICE Gathering is complete, disabling trickle ICE
|
||||||
|
// we do this because we only can exchange one signaling message
|
||||||
|
// in a production application you should exchange ICE Candidates via OnICECandidate
|
||||||
|
<-gatherComplete
|
||||||
|
|
||||||
|
response, err := json.Marshal(*peerConnection.LocalDescription())
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
if _, err := w.Write(response); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
http.Handle("/", http.FileServer(http.Dir(".")))
|
||||||
|
http.HandleFunc("/doSignaling", doSignaling)
|
||||||
|
|
||||||
|
fmt.Println("Open http://localhost:8080 to access this demo")
|
||||||
|
panic(http.ListenAndServe(":8080", nil))
|
||||||
|
}
|
2
go.mod
2
go.mod
@@ -5,7 +5,7 @@ go 1.12
|
|||||||
require (
|
require (
|
||||||
github.com/pion/datachannel v1.4.17
|
github.com/pion/datachannel v1.4.17
|
||||||
github.com/pion/dtls/v2 v2.0.1
|
github.com/pion/dtls/v2 v2.0.1
|
||||||
github.com/pion/ice/v2 v2.0.0-rc.5
|
github.com/pion/ice/v2 v2.0.0-rc.6
|
||||||
github.com/pion/logging v0.2.2
|
github.com/pion/logging v0.2.2
|
||||||
github.com/pion/quic v0.1.1
|
github.com/pion/quic v0.1.1
|
||||||
github.com/pion/randutil v0.1.0
|
github.com/pion/randutil v0.1.0
|
||||||
|
16
go.sum
16
go.sum
@@ -31,20 +31,22 @@ github.com/pion/datachannel v1.4.17 h1:8CChK5VrJoGrwKCysoTscoWvshCAFpUkgY11Tqgz5
|
|||||||
github.com/pion/datachannel v1.4.17/go.mod h1:+vPQfypU9vSsyPXogYj1hBThWQ6MNXEQoQAzxoPvjYM=
|
github.com/pion/datachannel v1.4.17/go.mod h1:+vPQfypU9vSsyPXogYj1hBThWQ6MNXEQoQAzxoPvjYM=
|
||||||
github.com/pion/dtls/v2 v2.0.1 h1:ddE7+V0faYRbyh4uPsRZ2vLdRrjVZn+wmCfI7jlBfaA=
|
github.com/pion/dtls/v2 v2.0.1 h1:ddE7+V0faYRbyh4uPsRZ2vLdRrjVZn+wmCfI7jlBfaA=
|
||||||
github.com/pion/dtls/v2 v2.0.1/go.mod h1:uMQkz2W0cSqY00xav7WByQ4Hb+18xeQh2oH2fRezr5U=
|
github.com/pion/dtls/v2 v2.0.1/go.mod h1:uMQkz2W0cSqY00xav7WByQ4Hb+18xeQh2oH2fRezr5U=
|
||||||
github.com/pion/ice/v2 v2.0.0-rc.5 h1:HSSnTn3QEBgRgxwGj/kiI4iBgseNWpTQpb9GZZfLBcY=
|
github.com/pion/ice/v2 v2.0.0-rc.3 h1:GvQ6nMGIGz7GltCUC9EU0m9JyQMan2vbifO4i8Y6T6A=
|
||||||
github.com/pion/ice/v2 v2.0.0-rc.5/go.mod h1:qfkp2BfgVTocUA3C9W559kFzW3IeCZxGplCIHAMyBZs=
|
github.com/pion/ice/v2 v2.0.0-rc.3/go.mod h1:5sP3yQ8Kd/azvPS4UrVTSgs/p5jfXMy3Ft2dQZBWyI8=
|
||||||
|
github.com/pion/ice/v2 v2.0.0-rc.6 h1:Jz88W1iXzHBYJG6I5QbRTm+xuKD1vbgUW+NP1MtUPAg=
|
||||||
|
github.com/pion/ice/v2 v2.0.0-rc.6/go.mod h1:VvpoDXwdierv9sPB8LAV3+T33ncCt0IG2NeI+CZYmTg=
|
||||||
github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
|
github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
|
||||||
github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
|
github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
|
||||||
github.com/pion/mdns v0.0.4 h1:O4vvVqr4DGX63vzmO6Fw9vpy3lfztVWHGCQfyw0ZLSY=
|
github.com/pion/mdns v0.0.4 h1:O4vvVqr4DGX63vzmO6Fw9vpy3lfztVWHGCQfyw0ZLSY=
|
||||||
github.com/pion/mdns v0.0.4/go.mod h1:R1sL0p50l42S5lJs91oNdUL58nm0QHrhxnSegr++qC0=
|
github.com/pion/mdns v0.0.4/go.mod h1:R1sL0p50l42S5lJs91oNdUL58nm0QHrhxnSegr++qC0=
|
||||||
github.com/pion/quic v0.1.1 h1:D951FV+TOqI9A0rTF7tHx0Loooqz+nyzjEyj8o3PuMA=
|
github.com/pion/quic v0.1.1 h1:D951FV+TOqI9A0rTF7tHx0Loooqz+nyzjEyj8o3PuMA=
|
||||||
github.com/pion/quic v0.1.1/go.mod h1:zEU51v7ru8Mp4AUBJvj6psrSth5eEFNnVQK5K48oV3k=
|
github.com/pion/quic v0.1.1/go.mod h1:zEU51v7ru8Mp4AUBJvj6psrSth5eEFNnVQK5K48oV3k=
|
||||||
github.com/pion/randutil v0.0.0 h1:aLWLVhTG2jzoD25F0OlW6nXvXrjoGwiXq2Sz7j7NzL0=
|
|
||||||
github.com/pion/randutil v0.0.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
|
github.com/pion/randutil v0.0.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
|
||||||
github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
|
github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
|
||||||
github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
|
github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
|
||||||
github.com/pion/rtcp v1.2.3 h1:2wrhKnqgSz91Q5nzYTO07mQXztYPtxL8a0XOss4rJqA=
|
github.com/pion/rtcp v1.2.3 h1:2wrhKnqgSz91Q5nzYTO07mQXztYPtxL8a0XOss4rJqA=
|
||||||
github.com/pion/rtcp v1.2.3/go.mod h1:zGhIv0RPRF0Z1Wiij22pUt5W/c9fevqSzT4jje/oK7I=
|
github.com/pion/rtcp v1.2.3/go.mod h1:zGhIv0RPRF0Z1Wiij22pUt5W/c9fevqSzT4jje/oK7I=
|
||||||
|
github.com/pion/rtp v1.5.4/go.mod h1:bg60AL5GotNOlYZsqycbhDtEV3TkfbpXG0KBiUq29Mg=
|
||||||
github.com/pion/rtp v1.5.5 h1:WTqWdmBuIj+luh8Wg6XVX+w7OytZHAIgtC7uSvgEl9Y=
|
github.com/pion/rtp v1.5.5 h1:WTqWdmBuIj+luh8Wg6XVX+w7OytZHAIgtC7uSvgEl9Y=
|
||||||
github.com/pion/rtp v1.5.5/go.mod h1:bg60AL5GotNOlYZsqycbhDtEV3TkfbpXG0KBiUq29Mg=
|
github.com/pion/rtp v1.5.5/go.mod h1:bg60AL5GotNOlYZsqycbhDtEV3TkfbpXG0KBiUq29Mg=
|
||||||
github.com/pion/rtp v1.6.0 h1:4Ssnl/T5W2LzxHj9ssYpGVEQh3YYhQFNVmSWO88MMwk=
|
github.com/pion/rtp v1.6.0 h1:4Ssnl/T5W2LzxHj9ssYpGVEQh3YYhQFNVmSWO88MMwk=
|
||||||
@@ -53,10 +55,15 @@ github.com/pion/sctp v1.7.6 h1:8qZTdJtbKfAns/Hv5L0PAj8FyXcsKhMH1pKUCGisQg4=
|
|||||||
github.com/pion/sctp v1.7.6/go.mod h1:ichkYQ5tlgCQwEwvgfdcAolqx1nHbYCxo4D7zK/K0X8=
|
github.com/pion/sctp v1.7.6/go.mod h1:ichkYQ5tlgCQwEwvgfdcAolqx1nHbYCxo4D7zK/K0X8=
|
||||||
github.com/pion/sctp v1.7.7 h1:6KVHBstRFV9+2si2B8H39CUpNn03oQ9yk/3dJ1TnkOs=
|
github.com/pion/sctp v1.7.7 h1:6KVHBstRFV9+2si2B8H39CUpNn03oQ9yk/3dJ1TnkOs=
|
||||||
github.com/pion/sctp v1.7.7/go.mod h1:E0K0acHLowZ2Ua21lHlQe4pHJoRzMU0HXqZVQEk061k=
|
github.com/pion/sctp v1.7.7/go.mod h1:E0K0acHLowZ2Ua21lHlQe4pHJoRzMU0HXqZVQEk061k=
|
||||||
|
github.com/pion/sdp/v2 v2.3.9 h1:KQMzypCMOcbHnx20t2r/Kuh9rKqWBa7RVy2tZ8Zk2MA=
|
||||||
|
github.com/pion/sdp/v2 v2.3.9/go.mod h1:sbxACjjlmwAgXMk0Qqw9uzFaazLIdPv4m0mIreLzPVk=
|
||||||
github.com/pion/sdp/v2 v2.4.0 h1:luUtaETR5x2KNNpvEMv/r4Y+/kzImzbz4Lm1z8eQNQI=
|
github.com/pion/sdp/v2 v2.4.0 h1:luUtaETR5x2KNNpvEMv/r4Y+/kzImzbz4Lm1z8eQNQI=
|
||||||
github.com/pion/sdp/v2 v2.4.0/go.mod h1:L2LxrOpSTJbAns244vfPChbciR/ReU1KWfG04OpkR7E=
|
github.com/pion/sdp/v2 v2.4.0/go.mod h1:L2LxrOpSTJbAns244vfPChbciR/ReU1KWfG04OpkR7E=
|
||||||
|
github.com/pion/srtp v1.3.4 h1:idh+9/W7tLOsHjcYYketIPSShb9k2Dz+RVrqyCm2LQE=
|
||||||
|
github.com/pion/srtp v1.3.4/go.mod h1:M3+LQiqLfVcV/Jo46KYJ3z9PP8DjmGPW8fUOQrF6q/M=
|
||||||
github.com/pion/srtp v1.4.0 h1:Qg/RYeCOY59fpjaHgAaybj+Wdu7EBSmrqWqlb0hjrdE=
|
github.com/pion/srtp v1.4.0 h1:Qg/RYeCOY59fpjaHgAaybj+Wdu7EBSmrqWqlb0hjrdE=
|
||||||
github.com/pion/srtp v1.4.0/go.mod h1:LSHkbwXr484DujfzX9bY1PsoQbAqDO+WMKd1KBq5yW0=
|
github.com/pion/srtp v1.4.0/go.mod h1:LSHkbwXr484DujfzX9bY1PsoQbAqDO+WMKd1KBq5yW0=
|
||||||
|
github.com/pion/stun v0.3.3/go.mod h1:xrCld6XM+6GWDZdvjPlLMsTU21rNxnO6UO8XsAvHr/M=
|
||||||
github.com/pion/stun v0.3.5 h1:uLUCBCkQby4S1cf6CGuR9QrVOKcvUwFeemaC865QHDg=
|
github.com/pion/stun v0.3.5 h1:uLUCBCkQby4S1cf6CGuR9QrVOKcvUwFeemaC865QHDg=
|
||||||
github.com/pion/stun v0.3.5/go.mod h1:gDMim+47EeEtfWogA37n6qXZS88L5V6LqFcf+DZA2UA=
|
github.com/pion/stun v0.3.5/go.mod h1:gDMim+47EeEtfWogA37n6qXZS88L5V6LqFcf+DZA2UA=
|
||||||
github.com/pion/transport v0.6.0/go.mod h1:iWZ07doqOosSLMhZ+FXUTq+TamDoXSllxpbGcfkCmbE=
|
github.com/pion/transport v0.6.0/go.mod h1:iWZ07doqOosSLMhZ+FXUTq+TamDoXSllxpbGcfkCmbE=
|
||||||
@@ -65,8 +72,11 @@ github.com/pion/transport v0.10.0 h1:9M12BSneJm6ggGhJyWpDveFOstJsTiQjkLf4M44rm80
|
|||||||
github.com/pion/transport v0.10.0/go.mod h1:BnHnUipd0rZQyTVB2SBGojFHT9CBt5C5TcsJSQGkvSE=
|
github.com/pion/transport v0.10.0/go.mod h1:BnHnUipd0rZQyTVB2SBGojFHT9CBt5C5TcsJSQGkvSE=
|
||||||
github.com/pion/transport v0.10.1 h1:2W+yJT+0mOQ160ThZYUx5Zp2skzshiNgxrNE9GUfhJM=
|
github.com/pion/transport v0.10.1 h1:2W+yJT+0mOQ160ThZYUx5Zp2skzshiNgxrNE9GUfhJM=
|
||||||
github.com/pion/transport v0.10.1/go.mod h1:PBis1stIILMiis0PewDw91WJeLJkyIMcEk+DwKOzf4A=
|
github.com/pion/transport v0.10.1/go.mod h1:PBis1stIILMiis0PewDw91WJeLJkyIMcEk+DwKOzf4A=
|
||||||
|
github.com/pion/turn/v2 v2.0.3 h1:SJUUIbcPoehlyZgMyIUbBBDhI03sBx32x3JuSIBKBWA=
|
||||||
|
github.com/pion/turn/v2 v2.0.3/go.mod h1:kl1hmT3NxcLynpXVnwJgObL8C9NaCyPTeqI2DcCpSZs=
|
||||||
github.com/pion/turn/v2 v2.0.4 h1:oDguhEv2L/4rxwbL9clGLgtzQPjtuZwCdoM7Te8vQVk=
|
github.com/pion/turn/v2 v2.0.4 h1:oDguhEv2L/4rxwbL9clGLgtzQPjtuZwCdoM7Te8vQVk=
|
||||||
github.com/pion/turn/v2 v2.0.4/go.mod h1:1812p4DcGVbYVBTiraUmP50XoKye++AMkbfp+N27mog=
|
github.com/pion/turn/v2 v2.0.4/go.mod h1:1812p4DcGVbYVBTiraUmP50XoKye++AMkbfp+N27mog=
|
||||||
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
@@ -19,6 +19,7 @@ type ICECandidate struct {
|
|||||||
Component uint16 `json:"component"`
|
Component uint16 `json:"component"`
|
||||||
RelatedAddress string `json:"relatedAddress"`
|
RelatedAddress string `json:"relatedAddress"`
|
||||||
RelatedPort uint16 `json:"relatedPort"`
|
RelatedPort uint16 `json:"relatedPort"`
|
||||||
|
TCPType string `json:"tcpType"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Conversion for package ice
|
// Conversion for package ice
|
||||||
@@ -56,6 +57,7 @@ func newICECandidateFromICE(i ice.Candidate) (ICECandidate, error) {
|
|||||||
Port: uint16(i.Port()),
|
Port: uint16(i.Port()),
|
||||||
Component: i.Component(),
|
Component: i.Component(),
|
||||||
Typ: typ,
|
Typ: typ,
|
||||||
|
TCPType: i.TCPType().String(),
|
||||||
}
|
}
|
||||||
|
|
||||||
if i.RelatedAddress() != nil {
|
if i.RelatedAddress() != nil {
|
||||||
@@ -76,6 +78,7 @@ func (c ICECandidate) toICE() (ice.Candidate, error) {
|
|||||||
Address: c.Address,
|
Address: c.Address,
|
||||||
Port: int(c.Port),
|
Port: int(c.Port),
|
||||||
Component: c.Component,
|
Component: c.Component,
|
||||||
|
TCPType: ice.NewTCPType(c.TCPType),
|
||||||
}
|
}
|
||||||
return ice.NewCandidateHost(&config)
|
return ice.NewCandidateHost(&config)
|
||||||
case ICECandidateTypeSrflx:
|
case ICECandidateTypeSrflx:
|
||||||
@@ -140,6 +143,15 @@ func (c ICECandidate) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func iceCandidateToSDP(c ICECandidate) sdp.ICECandidate {
|
func iceCandidateToSDP(c ICECandidate) sdp.ICECandidate {
|
||||||
|
var extensions []sdp.ICECandidateAttribute
|
||||||
|
|
||||||
|
if c.Protocol == ICEProtocolTCP && c.TCPType != "" {
|
||||||
|
extensions = append(extensions, sdp.ICECandidateAttribute{
|
||||||
|
Key: "tcptype",
|
||||||
|
Value: c.TCPType,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return sdp.ICECandidate{
|
return sdp.ICECandidate{
|
||||||
Foundation: c.Foundation,
|
Foundation: c.Foundation,
|
||||||
Priority: c.Priority,
|
Priority: c.Priority,
|
||||||
@@ -150,6 +162,7 @@ func iceCandidateToSDP(c ICECandidate) sdp.ICECandidate {
|
|||||||
Typ: c.Typ.String(),
|
Typ: c.Typ.String(),
|
||||||
RelatedAddress: c.RelatedAddress,
|
RelatedAddress: c.RelatedAddress,
|
||||||
RelatedPort: c.RelatedPort,
|
RelatedPort: c.RelatedPort,
|
||||||
|
ExtensionAttributes: extensions,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,6 +175,17 @@ func newICECandidateFromSDP(c sdp.ICECandidate) (ICECandidate, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return ICECandidate{}, err
|
return ICECandidate{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var tcpType string
|
||||||
|
if protocol == ICEProtocolTCP {
|
||||||
|
for _, attr := range c.ExtensionAttributes {
|
||||||
|
if attr.Key == "tcptype" {
|
||||||
|
tcpType = attr.Value
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ICECandidate{
|
return ICECandidate{
|
||||||
Foundation: c.Foundation,
|
Foundation: c.Foundation,
|
||||||
Priority: c.Priority,
|
Priority: c.Priority,
|
||||||
@@ -172,6 +196,7 @@ func newICECandidateFromSDP(c sdp.ICECandidate) (ICECandidate, error) {
|
|||||||
Typ: typ,
|
Typ: typ,
|
||||||
RelatedAddress: c.RelatedAddress,
|
RelatedAddress: c.RelatedAddress,
|
||||||
RelatedPort: c.RelatedPort,
|
RelatedPort: c.RelatedPort,
|
||||||
|
TCPType: tcpType,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -4,7 +4,9 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/pion/ice/v2"
|
"github.com/pion/ice/v2"
|
||||||
|
"github.com/pion/sdp/v2"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestICECandidate_Convert(t *testing.T) {
|
func TestICECandidate_Convert(t *testing.T) {
|
||||||
@@ -129,6 +131,47 @@ func TestICECandidate_Convert(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestICECandidate_ConvertTCP(t *testing.T) {
|
||||||
|
candidate := ICECandidate{
|
||||||
|
Foundation: "foundation",
|
||||||
|
Priority: 128,
|
||||||
|
Address: "1.0.0.1",
|
||||||
|
Protocol: ICEProtocolTCP,
|
||||||
|
Port: 1234,
|
||||||
|
Typ: ICECandidateTypeHost,
|
||||||
|
Component: 1,
|
||||||
|
TCPType: "passive",
|
||||||
|
}
|
||||||
|
|
||||||
|
got, err := candidate.toICE()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
want, err := ice.NewCandidateHost(&ice.CandidateHostConfig{
|
||||||
|
CandidateID: got.ID(),
|
||||||
|
Address: "1.0.0.1",
|
||||||
|
Component: 1,
|
||||||
|
Network: "tcp",
|
||||||
|
Port: 1234,
|
||||||
|
TCPType: ice.TCPTypePassive,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, want, got)
|
||||||
|
|
||||||
|
sdpCandidate := iceCandidateToSDP(candidate)
|
||||||
|
assert.Equal(t, []sdp.ICECandidateAttribute{
|
||||||
|
{
|
||||||
|
Key: "tcptype",
|
||||||
|
Value: "passive",
|
||||||
|
},
|
||||||
|
}, sdpCandidate.ExtensionAttributes)
|
||||||
|
|
||||||
|
candidate2, err := newICECandidateFromSDP(sdpCandidate)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, candidate, candidate2)
|
||||||
|
}
|
||||||
|
|
||||||
func TestConvertTypeFromICE(t *testing.T) {
|
func TestConvertTypeFromICE(t *testing.T) {
|
||||||
t.Run("host", func(t *testing.T) {
|
t.Run("host", func(t *testing.T) {
|
||||||
ct, err := convertTypeFromICE(ice.CandidateTypeHost)
|
ct, err := convertTypeFromICE(ice.CandidateTypeHost)
|
||||||
|
@@ -109,6 +109,7 @@ func (g *ICEGatherer) createAgent() error {
|
|||||||
MulticastDNSHostName: g.api.settingEngine.candidates.MulticastDNSHostName,
|
MulticastDNSHostName: g.api.settingEngine.candidates.MulticastDNSHostName,
|
||||||
LocalUfrag: g.api.settingEngine.candidates.UsernameFragment,
|
LocalUfrag: g.api.settingEngine.candidates.UsernameFragment,
|
||||||
LocalPwd: g.api.settingEngine.candidates.Password,
|
LocalPwd: g.api.settingEngine.candidates.Password,
|
||||||
|
TCPListenPort: g.api.settingEngine.iceTCPPort,
|
||||||
}
|
}
|
||||||
|
|
||||||
requestedNetworkTypes := g.api.settingEngine.candidates.ICENetworkTypes
|
requestedNetworkTypes := g.api.settingEngine.candidates.ICENetworkTypes
|
||||||
|
@@ -56,6 +56,7 @@ type SettingEngine struct {
|
|||||||
disableSRTCPReplayProtection bool
|
disableSRTCPReplayProtection bool
|
||||||
vnet *vnet.Net
|
vnet *vnet.Net
|
||||||
LoggerFactory logging.LoggerFactory
|
LoggerFactory logging.LoggerFactory
|
||||||
|
iceTCPPort int
|
||||||
}
|
}
|
||||||
|
|
||||||
// DetachDataChannels enables detaching data channels. When enabled
|
// DetachDataChannels enables detaching data channels. When enabled
|
||||||
@@ -242,6 +243,12 @@ func (e *SettingEngine) SetSDPMediaLevelFingerprints(sdpMediaLevelFingerprints b
|
|||||||
e.sdpMediaLevelFingerprints = sdpMediaLevelFingerprints
|
e.sdpMediaLevelFingerprints = sdpMediaLevelFingerprints
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetICETCPPort to a non-zero value enables ICE-TCP listener. This API is experimental and
|
||||||
|
// is likely to change in the future.
|
||||||
|
func (e *SettingEngine) SetICETCPPort(port int) {
|
||||||
|
e.iceTCPPort = port
|
||||||
|
}
|
||||||
|
|
||||||
// AddSDPExtensions adds available and offered extensions for media type.
|
// AddSDPExtensions adds available and offered extensions for media type.
|
||||||
//
|
//
|
||||||
// Ext IDs are optional and generated if you do not provide them
|
// Ext IDs are optional and generated if you do not provide them
|
||||||
|
Reference in New Issue
Block a user