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  }