github.com/pion/webrtc/v3@v3.2.24/examples/data-channels-detach/main.go (about) 1 // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly> 2 // SPDX-License-Identifier: MIT 3 4 // data-channels-detach is an example that shows how you can detach a data channel. This allows direct access the the underlying [pion/datachannel](https://github.com/pion/datachannel). This allows you to interact with the data channel using a more idiomatic API based on the `io.ReadWriteCloser` interface. 5 package main 6 7 import ( 8 "fmt" 9 "io" 10 "os" 11 "time" 12 13 "github.com/pion/webrtc/v3" 14 "github.com/pion/webrtc/v3/examples/internal/signal" 15 ) 16 17 const messageSize = 15 18 19 func main() { 20 // Since this behavior diverges from the WebRTC API it has to be 21 // enabled using a settings engine. Mixing both detached and the 22 // OnMessage DataChannel API is not supported. 23 24 // Create a SettingEngine and enable Detach 25 s := webrtc.SettingEngine{} 26 s.DetachDataChannels() 27 28 // Create an API object with the engine 29 api := webrtc.NewAPI(webrtc.WithSettingEngine(s)) 30 31 // Everything below is the Pion WebRTC API! Thanks for using it ❤️. 32 33 // Prepare the configuration 34 config := webrtc.Configuration{ 35 ICEServers: []webrtc.ICEServer{ 36 { 37 URLs: []string{"stun:stun.l.google.com:19302"}, 38 }, 39 }, 40 } 41 42 // Create a new RTCPeerConnection using the API object 43 peerConnection, err := api.NewPeerConnection(config) 44 if err != nil { 45 panic(err) 46 } 47 defer func() { 48 if cErr := peerConnection.Close(); cErr != nil { 49 fmt.Printf("cannot close peerConnection: %v\n", cErr) 50 } 51 }() 52 53 // Set the handler for Peer connection state 54 // This will notify you when the peer has connected/disconnected 55 peerConnection.OnConnectionStateChange(func(s webrtc.PeerConnectionState) { 56 fmt.Printf("Peer Connection State has changed: %s\n", s.String()) 57 58 if s == webrtc.PeerConnectionStateFailed { 59 // Wait until PeerConnection has had no network activity for 30 seconds or another failure. It may be reconnected using an ICE Restart. 60 // Use webrtc.PeerConnectionStateDisconnected if you are interested in detecting faster timeout. 61 // Note that the PeerConnection may come back from PeerConnectionStateDisconnected. 62 fmt.Println("Peer Connection has gone to failed exiting") 63 os.Exit(0) 64 } 65 }) 66 67 // Register data channel creation handling 68 peerConnection.OnDataChannel(func(d *webrtc.DataChannel) { 69 fmt.Printf("New DataChannel %s %d\n", d.Label(), d.ID()) 70 71 // Register channel opening handling 72 d.OnOpen(func() { 73 fmt.Printf("Data channel '%s'-'%d' open.\n", d.Label(), d.ID()) 74 75 // Detach the data channel 76 raw, dErr := d.Detach() 77 if dErr != nil { 78 panic(dErr) 79 } 80 81 // Handle reading from the data channel 82 go ReadLoop(raw) 83 84 // Handle writing to the data channel 85 go WriteLoop(raw) 86 }) 87 }) 88 89 // Wait for the offer to be pasted 90 offer := webrtc.SessionDescription{} 91 signal.Decode(signal.MustReadStdin(), &offer) 92 93 // Set the remote SessionDescription 94 err = peerConnection.SetRemoteDescription(offer) 95 if err != nil { 96 panic(err) 97 } 98 99 // Create answer 100 answer, err := peerConnection.CreateAnswer(nil) 101 if err != nil { 102 panic(err) 103 } 104 105 // Create channel that is blocked until ICE Gathering is complete 106 gatherComplete := webrtc.GatheringCompletePromise(peerConnection) 107 108 // Sets the LocalDescription, and starts our UDP listeners 109 err = peerConnection.SetLocalDescription(answer) 110 if err != nil { 111 panic(err) 112 } 113 114 // Block until ICE Gathering is complete, disabling trickle ICE 115 // we do this because we only can exchange one signaling message 116 // in a production application you should exchange ICE Candidates via OnICECandidate 117 <-gatherComplete 118 119 // Output the answer in base64 so we can paste it in browser 120 fmt.Println(signal.Encode(*peerConnection.LocalDescription())) 121 122 // Block forever 123 select {} 124 } 125 126 // ReadLoop shows how to read from the datachannel directly 127 func ReadLoop(d io.Reader) { 128 for { 129 buffer := make([]byte, messageSize) 130 n, err := d.Read(buffer) 131 if err != nil { 132 fmt.Println("Datachannel closed; Exit the readloop:", err) 133 return 134 } 135 136 fmt.Printf("Message from DataChannel: %s\n", string(buffer[:n])) 137 } 138 } 139 140 // WriteLoop shows how to write to the datachannel directly 141 func WriteLoop(d io.Writer) { 142 for range time.NewTicker(5 * time.Second).C { 143 message := signal.RandSeq(messageSize) 144 fmt.Printf("Sending %s \n", message) 145 146 _, err := d.Write([]byte(message)) 147 if err != nil { 148 panic(err) 149 } 150 } 151 }