Skip to content

Instantly share code, notes, and snippets.

@enobufs
Last active June 2, 2023 03:54
Show Gist options
  • Save enobufs/7d8e2996022658b31c04019afac91393 to your computer and use it in GitHub Desktop.
Save enobufs/7d8e2996022658b31c04019afac91393 to your computer and use it in GitHub Desktop.
Pion data channel example
package main
import (
"encoding/json"
"log"
"time"
"github.com/pion/webrtc/v2"
)
func check(err error) {
if err != nil {
panic(err)
}
}
// EndpointListener ...
type EndpointListener struct {
OnDescription chan string
OnBye chan bool
}
// Endpoint ...
type Endpoint struct {
PC *webrtc.PeerConnection
Listener *EndpointListener
IsInitiator bool
dataChs map[string]*webrtc.DataChannel
}
// NewEndpoint ...
func NewEndpoint() *Endpoint {
// Prepare the configuration
config := webrtc.Configuration{
ICEServers: []webrtc.ICEServer{},
}
// Create a new PeerConnection
pc, err := webrtc.NewPeerConnection(config)
check(err)
return &Endpoint{
PC: pc,
Listener: &EndpointListener{
OnDescription: make(chan string),
OnBye: make(chan bool),
},
IsInitiator: false,
dataChs: map[string]*webrtc.DataChannel{},
}
}
// Start assigns this epoint as an initiator and triggers sendding an offer.
func (ep *Endpoint) Start() {
var msgID = 0
buf := make([]byte, 1000)
ep.IsInitiator = true
ordered := false
maxRetransmits := uint16(0)
options := &webrtc.DataChannelInit{
Ordered: &ordered,
MaxRetransmits: &maxRetransmits,
}
// Create a datachannel with label 'data'
dc, err := ep.PC.CreateDataChannel("data", options)
check(err)
// Register channel opening handling
dc.OnOpen(func() {
log.Printf("OnOpen: %s-%d. Random messages will now be sent to any connected DataChannels every second\n", dc.Label(), dc.ID())
for range time.NewTicker(1000 * time.Millisecond).C {
log.Printf("Sending (%d) msg with len %d \n", msgID, len(buf))
msgID++
err := dc.Send(buf)
check(err)
}
})
// Register the OnMessage to handle incoming messages
dc.OnMessage(func(dcMsg webrtc.DataChannelMessage) {
if dcMsg.IsString {
log.Printf("Message (string) from DataChannel '%s' payload '%s'\n", dc.Label(), string(dcMsg.Data))
} else {
log.Printf("Message ([]byte) from DataChannel '%s' with length %d\n", dc.Label(), len(dcMsg.Data))
}
})
ep.dataChs[dc.Label()] = dc
// Now, create an offer
offer, err := ep.PC.CreateOffer(nil)
check(err)
ep.PC.SetLocalDescription(offer)
desc, err := json.Marshal(offer)
check(err)
go func() {
ep.Listener.OnDescription <- string(desc)
}()
}
// OnRemoteDescription ...
func (ep *Endpoint) OnRemoteDescription(sdp string) {
var desc webrtc.SessionDescription
bytes := []byte(sdp)
err := json.Unmarshal(bytes, &desc)
check(err)
// Apply the desc as the remote description
err = ep.PC.SetRemoteDescription(desc)
check(err)
if ep.IsInitiator {
return
}
// Set callback for new data channels
ep.PC.OnDataChannel(func(dc *webrtc.DataChannel) {
// Register channel opening handling
dc.OnOpen(func() {
log.Printf("OnOpen: %s-%d. Random messages will now be sent to any connected DataChannels every second\n", dc.Label(), dc.ID())
})
// Register the OnMessage to handle incoming messages
dc.OnMessage(func(dcMsg webrtc.DataChannelMessage) {
if dcMsg.IsString {
log.Printf("Message (string) from DataChannel '%s' payload '%s'\n", dc.Label(), string(dcMsg.Data))
} else {
log.Printf("Message ([]byte) from DataChannel '%s' with length %d\n", dc.Label(), len(dcMsg.Data))
}
})
ep.dataChs[dc.Label()] = dc
})
answer, err := ep.PC.CreateAnswer(nil)
check(err)
ep.PC.SetLocalDescription(answer)
desc2, err := json.Marshal(answer)
check(err)
go func() {
ep.Listener.OnDescription <- string(desc2)
}()
}
func main() {
ep1 := NewEndpoint()
ep2 := NewEndpoint()
ep1.Start()
for {
// Block forever
select {
case sig := <-ep1.Listener.OnDescription:
log.Printf("EP1 => EP2:\n%s\n", sig)
ep2.OnRemoteDescription(sig)
case <-ep1.Listener.OnBye:
case sig := <-ep2.Listener.OnDescription:
log.Printf("EP2 => EP1:\n%s\n", sig)
ep1.OnRemoteDescription(sig)
case <-ep1.Listener.OnBye:
}
}
}
@enobufs
Copy link
Author

enobufs commented Feb 11, 2019

go.mod for the example code above to build:

pion/webrtc/v2@v2.0.27

module github.com/enobufs/pion-examples/simple-dc

go 1.12

require (
	github.com/golang/mock v1.3.1 // indirect
	github.com/golang/protobuf v1.3.2 // indirect
	github.com/kr/pretty v0.1.0 // indirect
	github.com/lucas-clemente/quic-go v0.11.2 // indirect
	github.com/marten-seemann/qtls v0.3.2 // indirect
	github.com/onsi/ginkgo v1.8.0 // indirect
	github.com/onsi/gomega v1.5.0 // indirect
	github.com/pion/webrtc/v2 v2.0.27
	golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 // indirect
	golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 // indirect
	golang.org/x/sys v0.0.0-20190730183949-1393eb018365 // indirect
	golang.org/x/text v0.3.2 // indirect
	gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
	gopkg.in/yaml.v2 v2.2.2 // indirect
)

Run

go run main.go

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment