Should peers be able to connect via WebRTC while they are on the same network, but behind a router with symmetric NAT? In this case there is no need for the ICE server, so there should be no problem right?
I have two peers that are on the same machine trying to connect to each other and the connection fails, but it's my first time trying to do something with WebRTC so my implementation can be flawed :P
Offering Peer in Go:
package main
import (
"fmt"
"io"
"net/http"
"strconv"
"github.com/pion/webrtc/v4"
)
func main() {
answerC := HTTPSDPServer(8000) // feeds sdp into
// Create a new RTCPeerConnection
peerConnection, err := webrtc.NewPeerConnection(webrtc.Configuration{})
if err != nil {
panic(err)
}
defer func() {
if cErr := peerConnection.Close(); cErr != nil {
fmt.Printf("cannot close peerConnection: %v\n", cErr)
}
}()
peerConnection.OnConnectionStateChange(func(s webrtc.PeerConnectionState) {
fmt.Printf("Peer Connection State has changed: %s\n", s.String())
})
c, err := peerConnection.CreateDataChannel("channel", nil)
if err != nil {
panic(err)
}
c.OnOpen(func() {
fmt.Println("Data Channel OPEN")
})
c.OnClose(func() {
fmt.Println("Data Channel CLOSE")
})
offer, err := peerConnection.CreateOffer(nil)
if err != nil {
panic(err)
}
err = peerConnection.SetLocalDescription(offer)
if err != nil {
panic(err)
}
fmt.Println(strconv.Quote(offer.SDP)) // Copy this to frontend app
answerStr := <-answerC
answer := webrtc.SessionDescription{
Type: webrtc.SDPTypeAnswer,
SDP: answerStr,
}
err = peerConnection.SetRemoteDescription(answer)
if err != nil {
panic(err)
}
select {}
}
func HTTPSDPServer(port int) chan string {
sdpChan := make(chan string)
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
body, _ := io.ReadAll(r.Body)
fmt.Fprintf(w, "done")
sdpChan <- string(body)
})
go func() {
// nolint: gosec
err := http.ListenAndServe(":"+strconv.Itoa(port), nil)
if err != nil {
panic(err)
}
}()
return sdpChan
}
Vue frontend which runs this script on launch:
const remoteConnection = new RTCPeerConnection()
remoteConnection.onicecandidate = e => {
console.log(" NEW ice candidnat!! on localconnection reprinting SDP ")
console.log(JSON.stringify(remoteConnection.localDescription))
}
remoteConnection.ondatachannel = e => {
const receiveChannel = e.channel;
receiveChannel.onmessage = e => console.log("message: " + e.data)
receiveChannel.onopen = e => console.log("Data Channel OPEN");
receiveChannel.onclose = e => console.log("Data Channel CLOSED");
remoteConnection.channel = receiveChannel;
}
var sdp = "PASTE OFFER HERE" // Paste SDP copied from the offering peer
var offer = { "type": "offer", "sdp": sdp }
remoteConnection.setRemoteDescription(offer).then(a => console.log("done"))
//create answer
await remoteConnection.createAnswer().then(a => remoteConnection.setLocalDescription(a)).then(a =>
console.log(JSON.stringify(remoteConnection.localDescription)))
After the frontend app prints it's sdp it's sent in a request to offering peer's server to unblock it and proceed. There is no error, the connection just goes from "connecting" to "failed".
Turn's out I was handling offer creation wrong. I created an offer, set it as local description and then used it directly
offer, err := peerConnection.CreateOffer(nil)
if err != nil {
panic(err)
}
err = peerConnection.SetLocalDescription(offer)
if err != nil {
panic(err)
}
// then I referenced offer.SPD to get the SPD.
What I needed to do was to call webrtc.GatheringCompletePromise(peerConnection)
and wait until it finishes and then use peerConnection.LocalDescription().SPD
instead of offer.SPD
Here is a full example
offer, err := peerConnection.CreateOffer(nil)
if err != nil {
panic(err)
}
// Create channel that is blocked until ICE Gathering is complete
gatherComplete := webrtc.GatheringCompletePromise(peerConnection)
err = peerConnection.SetLocalDescription(offer)
if err != nil {
panic(err)
}
<-gatherComplete
// get SPD from peerConnection.LocalDescription().SPD