8 "github.com/pion/datachannel"
10 "github.com/pion/webrtc/v2"
13 type Transport struct {
14 pc *webrtc.PeerConnection
15 dc *webrtc.DataChannel
20 // NewTransport creates a transport and returns a WebRTC offer
22 func NewTransport() (*Transport, webrtc.SessionDescription, error) {
23 // Enable the detach API (since it's non-standard but more idiomatic)
24 // (This should be done once globally)
25 s := webrtc.SettingEngine{}
26 s.DetachDataChannels()
27 api := webrtc.NewAPI(webrtc.WithSettingEngine(s))
29 config := webrtc.Configuration{ICEServers: []webrtc.ICEServer{{URLs: []string{"stun:stun.l.google.com:19302"}}}}
30 peerConnection, err := api.NewPeerConnection(config)
32 return nil, webrtc.SessionDescription{}, fmt.Errorf("failed to peer connection: %v\n", err)
34 dataChannel, err := peerConnection.CreateDataChannel("webrtc-datachannel", nil)
36 return nil, webrtc.SessionDescription{}, fmt.Errorf("failed to data channel: %v\n", err)
38 peerConnection.OnICEConnectionStateChange(func(connectionState webrtc.ICEConnectionState) {
39 fmt.Printf("ICE Connection State has changed: %s\n", connectionState.String())
42 dataChannel.OnMessage(func(msg webrtc.DataChannelMessage) {
43 fmt.Printf("Message from DataChannel '%s': '%s'\n", dataChannel.Label(), string(msg.Data))
45 offer, err := peerConnection.CreateOffer(nil)
47 return nil, webrtc.SessionDescription{}, fmt.Errorf("failed to create offer: %v\n", err)
49 err = peerConnection.SetLocalDescription(offer)
51 return nil, webrtc.SessionDescription{}, fmt.Errorf("failed to set local description: %v\n", err)
54 t := &Transport{pc: peerConnection, dc: dataChannel, lock: &sync.Mutex{}}
58 // NewTransportFromOffer creates a transport from a WebRTC offer and
59 // and returns a WebRTC answer to be announced
60 func NewTransportFromOffer(offer webrtc.SessionDescription, onOpen func(datachannel.ReadWriteCloser)) (*Transport, webrtc.SessionDescription, error) {
61 // Enable the detach API (since it's non-standard but more idiomatic)
62 // (This should be done once globally)
63 s := webrtc.SettingEngine{}
64 s.DetachDataChannels()
65 api := webrtc.NewAPI(webrtc.WithSettingEngine(s))
67 config := webrtc.Configuration{ICEServers: []webrtc.ICEServer{{URLs: []string{"stun:stun.l.google.com:19302"}}}}
68 peerConnection, err := api.NewPeerConnection(config)
70 return nil, webrtc.SessionDescription{}, fmt.Errorf("failed to peer connection: %v", err)
72 peerConnection.OnICEConnectionStateChange(func(connectionState webrtc.ICEConnectionState) {
73 fmt.Printf("ICE Connection State has changed: %s\n", connectionState.String())
76 t := &Transport{pc: peerConnection, lock: &sync.Mutex{}}
77 peerConnection.OnDataChannel(func(d *webrtc.DataChannel) {
78 fmt.Printf("New DataChannel %s %d\n", d.Label(), d.ID())
85 err = peerConnection.SetRemoteDescription(offer)
87 return nil, webrtc.SessionDescription{}, fmt.Errorf("%v", err)
89 answer, err := peerConnection.CreateAnswer(nil)
91 return nil, webrtc.SessionDescription{}, fmt.Errorf("%v", err)
93 err = peerConnection.SetLocalDescription(answer)
95 return nil, webrtc.SessionDescription{}, fmt.Errorf("%v", err)
101 // SetAnswer sets the WebRTC answer
102 func (t *Transport) SetAnswer(answer webrtc.SessionDescription, onOpen func(datachannel.ReadWriteCloser)) error {
105 err := t.pc.SetRemoteDescription(answer)
112 func (t *Transport) handleOpen(onOpen func(datachannel.ReadWriteCloser)) {
117 fmt.Printf("Data channel '%s'-'%d' open.\n", dc.Label(), dc.ID())
119 // Detach the data channel
120 raw, err := dc.Detach()
122 log.Fatalf("failed to detach: %v", err) // TODO: Error handling