github.com/pion/webrtc/v4@v4.0.1/examples/trickle-ice/main.go (about) 1 // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly> 2 // SPDX-License-Identifier: MIT 3 4 // trickle-ice demonstrates Pion WebRTC's Trickle ICE APIs. ICE is the subsystem WebRTC uses to establish connectivity. 5 package main 6 7 import ( 8 "encoding/json" 9 "fmt" 10 "net/http" 11 "time" 12 13 "github.com/pion/webrtc/v4" 14 "golang.org/x/net/websocket" 15 ) 16 17 // websocketServer is called for every new inbound WebSocket 18 func websocketServer(ws *websocket.Conn) { // nolint:gocognit 19 // Create a new RTCPeerConnection 20 peerConnection, err := webrtc.NewPeerConnection(webrtc.Configuration{}) 21 if err != nil { 22 panic(err) 23 } 24 25 // When Pion gathers a new ICE Candidate send it to the client. This is how 26 // ice trickle is implemented. Everytime we have a new candidate available we send 27 // it as soon as it is ready. We don't wait to emit a Offer/Answer until they are 28 // all available 29 peerConnection.OnICECandidate(func(c *webrtc.ICECandidate) { 30 if c == nil { 31 return 32 } 33 34 outbound, marshalErr := json.Marshal(c.ToJSON()) 35 if marshalErr != nil { 36 panic(marshalErr) 37 } 38 39 if _, err = ws.Write(outbound); err != nil { 40 panic(err) 41 } 42 }) 43 44 // Set the handler for ICE connection state 45 // This will notify you when the peer has connected/disconnected 46 peerConnection.OnICEConnectionStateChange(func(connectionState webrtc.ICEConnectionState) { 47 fmt.Printf("ICE Connection State has changed: %s\n", connectionState.String()) 48 }) 49 50 // Send the current time via a DataChannel to the remote peer every 3 seconds 51 peerConnection.OnDataChannel(func(d *webrtc.DataChannel) { 52 d.OnOpen(func() { 53 for range time.Tick(time.Second * 3) { 54 if err = d.SendText(time.Now().String()); err != nil { 55 panic(err) 56 } 57 } 58 }) 59 }) 60 61 buf := make([]byte, 1500) 62 for { 63 // Read each inbound WebSocket Message 64 n, err := ws.Read(buf) 65 if err != nil { 66 panic(err) 67 } 68 69 // Unmarshal each inbound WebSocket message 70 var ( 71 candidate webrtc.ICECandidateInit 72 offer webrtc.SessionDescription 73 ) 74 75 switch { 76 // Attempt to unmarshal as a SessionDescription. If the SDP field is empty 77 // assume it is not one. 78 case json.Unmarshal(buf[:n], &offer) == nil && offer.SDP != "": 79 if err = peerConnection.SetRemoteDescription(offer); err != nil { 80 panic(err) 81 } 82 83 answer, answerErr := peerConnection.CreateAnswer(nil) 84 if answerErr != nil { 85 panic(answerErr) 86 } 87 88 if err = peerConnection.SetLocalDescription(answer); err != nil { 89 panic(err) 90 } 91 92 outbound, marshalErr := json.Marshal(answer) 93 if marshalErr != nil { 94 panic(marshalErr) 95 } 96 97 if _, err = ws.Write(outbound); err != nil { 98 panic(err) 99 } 100 // Attempt to unmarshal as a ICECandidateInit. If the candidate field is empty 101 // assume it is not one. 102 case json.Unmarshal(buf[:n], &candidate) == nil && candidate.Candidate != "": 103 if err = peerConnection.AddICECandidate(candidate); err != nil { 104 panic(err) 105 } 106 default: 107 panic("Unknown message") 108 } 109 } 110 } 111 112 func main() { 113 http.Handle("/", http.FileServer(http.Dir("."))) 114 http.Handle("/websocket", websocket.Handler(websocketServer)) 115 116 fmt.Println("Open http://localhost:8080 to access this demo") 117 // nolint: gosec 118 panic(http.ListenAndServe(":8080", nil)) 119 }