Last active
June 30, 2024 15:07
-
-
Save enobufs/7d8e2996022658b31c04019afac91393 to your computer and use it in GitHub Desktop.
Pion data channel example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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: | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
go.mod for the example code above to build:
pion/webrtc/[email protected]
Run