github.com/pion/webrtc/v3@v3.2.24/examples/ortc/main.go (about)

     1  // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
     2  // SPDX-License-Identifier: MIT
     3  
     4  //go:build !js
     5  // +build !js
     6  
     7  // ortc demonstrates Pion WebRTC's ORTC capabilities.
     8  package main
     9  
    10  import (
    11  	"flag"
    12  	"fmt"
    13  	"time"
    14  
    15  	"github.com/pion/webrtc/v3"
    16  	"github.com/pion/webrtc/v3/examples/internal/signal"
    17  )
    18  
    19  func main() {
    20  	isOffer := flag.Bool("offer", false, "Act as the offerer if set")
    21  	flag.Parse()
    22  
    23  	// Everything below is the Pion WebRTC (ORTC) API! Thanks for using it ❤️.
    24  
    25  	// Prepare ICE gathering options
    26  	iceOptions := webrtc.ICEGatherOptions{
    27  		ICEServers: []webrtc.ICEServer{
    28  			{URLs: []string{"stun:stun.l.google.com:19302"}},
    29  		},
    30  	}
    31  
    32  	// Create an API object
    33  	api := webrtc.NewAPI()
    34  
    35  	// Create the ICE gatherer
    36  	gatherer, err := api.NewICEGatherer(iceOptions)
    37  	if err != nil {
    38  		panic(err)
    39  	}
    40  
    41  	// Construct the ICE transport
    42  	ice := api.NewICETransport(gatherer)
    43  
    44  	// Construct the DTLS transport
    45  	dtls, err := api.NewDTLSTransport(ice, nil)
    46  	if err != nil {
    47  		panic(err)
    48  	}
    49  
    50  	// Construct the SCTP transport
    51  	sctp := api.NewSCTPTransport(dtls)
    52  
    53  	// Handle incoming data channels
    54  	sctp.OnDataChannel(func(channel *webrtc.DataChannel) {
    55  		fmt.Printf("New DataChannel %s %d\n", channel.Label(), channel.ID())
    56  
    57  		// Register the handlers
    58  		channel.OnOpen(handleOnOpen(channel))
    59  		channel.OnMessage(func(msg webrtc.DataChannelMessage) {
    60  			fmt.Printf("Message from DataChannel '%s': '%s'\n", channel.Label(), string(msg.Data))
    61  		})
    62  	})
    63  
    64  	gatherFinished := make(chan struct{})
    65  	gatherer.OnLocalCandidate(func(i *webrtc.ICECandidate) {
    66  		if i == nil {
    67  			close(gatherFinished)
    68  		}
    69  	})
    70  
    71  	// Gather candidates
    72  	err = gatherer.Gather()
    73  	if err != nil {
    74  		panic(err)
    75  	}
    76  
    77  	<-gatherFinished
    78  
    79  	iceCandidates, err := gatherer.GetLocalCandidates()
    80  	if err != nil {
    81  		panic(err)
    82  	}
    83  
    84  	iceParams, err := gatherer.GetLocalParameters()
    85  	if err != nil {
    86  		panic(err)
    87  	}
    88  
    89  	dtlsParams, err := dtls.GetLocalParameters()
    90  	if err != nil {
    91  		panic(err)
    92  	}
    93  
    94  	sctpCapabilities := sctp.GetCapabilities()
    95  
    96  	s := Signal{
    97  		ICECandidates:    iceCandidates,
    98  		ICEParameters:    iceParams,
    99  		DTLSParameters:   dtlsParams,
   100  		SCTPCapabilities: sctpCapabilities,
   101  	}
   102  
   103  	// Exchange the information
   104  	fmt.Println(signal.Encode(s))
   105  	remoteSignal := Signal{}
   106  	signal.Decode(signal.MustReadStdin(), &remoteSignal)
   107  
   108  	iceRole := webrtc.ICERoleControlled
   109  	if *isOffer {
   110  		iceRole = webrtc.ICERoleControlling
   111  	}
   112  
   113  	err = ice.SetRemoteCandidates(remoteSignal.ICECandidates)
   114  	if err != nil {
   115  		panic(err)
   116  	}
   117  
   118  	// Start the ICE transport
   119  	err = ice.Start(nil, remoteSignal.ICEParameters, &iceRole)
   120  	if err != nil {
   121  		panic(err)
   122  	}
   123  
   124  	// Start the DTLS transport
   125  	err = dtls.Start(remoteSignal.DTLSParameters)
   126  	if err != nil {
   127  		panic(err)
   128  	}
   129  
   130  	// Start the SCTP transport
   131  	err = sctp.Start(remoteSignal.SCTPCapabilities)
   132  	if err != nil {
   133  		panic(err)
   134  	}
   135  
   136  	// Construct the data channel as the offerer
   137  	if *isOffer {
   138  		var id uint16 = 1
   139  
   140  		dcParams := &webrtc.DataChannelParameters{
   141  			Label: "Foo",
   142  			ID:    &id,
   143  		}
   144  		var channel *webrtc.DataChannel
   145  		channel, err = api.NewDataChannel(sctp, dcParams)
   146  		if err != nil {
   147  			panic(err)
   148  		}
   149  
   150  		// Register the handlers
   151  		// channel.OnOpen(handleOnOpen(channel)) // TODO: OnOpen on handle ChannelAck
   152  		go handleOnOpen(channel)() // Temporary alternative
   153  		channel.OnMessage(func(msg webrtc.DataChannelMessage) {
   154  			fmt.Printf("Message from DataChannel '%s': '%s'\n", channel.Label(), string(msg.Data))
   155  		})
   156  	}
   157  
   158  	select {}
   159  }
   160  
   161  // Signal is used to exchange signaling info.
   162  // This is not part of the ORTC spec. You are free
   163  // to exchange this information any way you want.
   164  type Signal struct {
   165  	ICECandidates    []webrtc.ICECandidate   `json:"iceCandidates"`
   166  	ICEParameters    webrtc.ICEParameters    `json:"iceParameters"`
   167  	DTLSParameters   webrtc.DTLSParameters   `json:"dtlsParameters"`
   168  	SCTPCapabilities webrtc.SCTPCapabilities `json:"sctpCapabilities"`
   169  }
   170  
   171  func handleOnOpen(channel *webrtc.DataChannel) func() {
   172  	return func() {
   173  		fmt.Printf("Data channel '%s'-'%d' open. Random messages will now be sent to any connected DataChannels every 5 seconds\n", channel.Label(), channel.ID())
   174  
   175  		for range time.NewTicker(5 * time.Second).C {
   176  			message := signal.RandSeq(15)
   177  			fmt.Printf("Sending '%s' \n", message)
   178  
   179  			err := channel.SendText(message)
   180  			if err != nil {
   181  				panic(err)
   182  			}
   183  		}
   184  	}
   185  }