package main import ( "encoding/json" "fmt" "net" "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{} if err = m.RegisterDefaultCodecs(); err != nil { panic(err) } settingEngine := webrtc.SettingEngine{} // Enable support only for TCP ICE candidates. settingEngine.SetNetworkTypes([]webrtc.NetworkType{ webrtc.NetworkTypeTCP4, webrtc.NetworkTypeTCP6, }) var tcpListener net.Listener tcpListener, err = net.ListenTCP("tcp", &net.TCPAddr{ IP: net.IP{0, 0, 0, 0}, Port: 8443, }) if err != nil { panic(err) } fmt.Printf("Listening for ICE TCP at %s\n", tcpListener.Addr()) tcpMux := webrtc.NewICETCPMux(nil, tcpListener, 8) settingEngine.SetICETCPMux(tcpMux) 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)) }