mirror of
https://github.com/harshabose/datachannel.git
synced 2025-09-27 06:22:08 +08:00
first commit
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/third_party
|
||||
.idea
|
27
go.mod
Normal file
27
go.mod
Normal file
@@ -0,0 +1,27 @@
|
||||
module datachannel
|
||||
|
||||
go 1.23
|
||||
|
||||
require (
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/pion/datachannel v1.5.10 // indirect
|
||||
github.com/pion/dtls/v3 v3.0.4 // indirect
|
||||
github.com/pion/ice/v4 v4.0.6 // indirect
|
||||
github.com/pion/interceptor v0.1.37 // indirect
|
||||
github.com/pion/logging v0.2.3 // indirect
|
||||
github.com/pion/mdns/v2 v2.0.7 // indirect
|
||||
github.com/pion/randutil v0.1.0 // indirect
|
||||
github.com/pion/rtcp v1.2.15 // indirect
|
||||
github.com/pion/rtp v1.8.11 // indirect
|
||||
github.com/pion/sctp v1.8.35 // indirect
|
||||
github.com/pion/sdp/v3 v3.0.10 // indirect
|
||||
github.com/pion/srtp/v3 v3.0.4 // indirect
|
||||
github.com/pion/stun/v3 v3.0.0 // indirect
|
||||
github.com/pion/transport/v3 v3.0.7 // indirect
|
||||
github.com/pion/turn/v4 v4.0.0 // indirect
|
||||
github.com/pion/webrtc/v4 v4.0.10 // indirect
|
||||
github.com/wlynxg/anet v0.0.5 // indirect
|
||||
golang.org/x/crypto v0.32.0 // indirect
|
||||
golang.org/x/net v0.34.0 // indirect
|
||||
golang.org/x/sys v0.29.0 // indirect
|
||||
)
|
42
go.sum
Normal file
42
go.sum
Normal file
@@ -0,0 +1,42 @@
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/pion/datachannel v1.5.10 h1:ly0Q26K1i6ZkGf42W7D4hQYR90pZwzFOjTq5AuCKk4o=
|
||||
github.com/pion/datachannel v1.5.10/go.mod h1:p/jJfC9arb29W7WrxyKbepTU20CFgyx5oLo8Rs4Py/M=
|
||||
github.com/pion/dtls/v3 v3.0.4 h1:44CZekewMzfrn9pmGrj5BNnTMDCFwr+6sLH+cCuLM7U=
|
||||
github.com/pion/dtls/v3 v3.0.4/go.mod h1:R373CsjxWqNPf6MEkfdy3aSe9niZvL/JaKlGeFphtMg=
|
||||
github.com/pion/ice/v4 v4.0.6 h1:jmM9HwI9lfetQV/39uD0nY4y++XZNPhvzIPCb8EwxUM=
|
||||
github.com/pion/ice/v4 v4.0.6/go.mod h1:y3M18aPhIxLlcO/4dn9X8LzLLSma84cx6emMSu14FGw=
|
||||
github.com/pion/interceptor v0.1.37 h1:aRA8Zpab/wE7/c0O3fh1PqY0AJI3fCSEM5lRWJVorwI=
|
||||
github.com/pion/interceptor v0.1.37/go.mod h1:JzxbJ4umVTlZAf+/utHzNesY8tmRkM2lVmkS82TTj8Y=
|
||||
github.com/pion/logging v0.2.3 h1:gHuf0zpoh1GW67Nr6Gj4cv5Z9ZscU7g/EaoC/Ke/igI=
|
||||
github.com/pion/logging v0.2.3/go.mod h1:z8YfknkquMe1csOrxK5kc+5/ZPAzMxbKLX5aXpbpC90=
|
||||
github.com/pion/mdns/v2 v2.0.7 h1:c9kM8ewCgjslaAmicYMFQIde2H9/lrZpjBkN8VwoVtM=
|
||||
github.com/pion/mdns/v2 v2.0.7/go.mod h1:vAdSYNAT0Jy3Ru0zl2YiW3Rm/fJCwIeM0nToenfOJKA=
|
||||
github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
|
||||
github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
|
||||
github.com/pion/rtcp v1.2.15 h1:LZQi2JbdipLOj4eBjK4wlVoQWfrZbh3Q6eHtWtJBZBo=
|
||||
github.com/pion/rtcp v1.2.15/go.mod h1:jlGuAjHMEXwMUHK78RgX0UmEJFV4zUKOFHR7OP+D3D0=
|
||||
github.com/pion/rtp v1.8.11 h1:17xjnY5WO5hgO6SD3/NTIUPvSFw/PbLsIJyz1r1yNIk=
|
||||
github.com/pion/rtp v1.8.11/go.mod h1:8uMBJj32Pa1wwx8Fuv/AsFhn8jsgw+3rUC2PfoBZ8p4=
|
||||
github.com/pion/sctp v1.8.35 h1:qwtKvNK1Wc5tHMIYgTDJhfZk7vATGVHhXbUDfHbYwzA=
|
||||
github.com/pion/sctp v1.8.35/go.mod h1:EcXP8zCYVTRy3W9xtOF7wJm1L1aXfKRQzaM33SjQlzg=
|
||||
github.com/pion/sdp/v3 v3.0.10 h1:6MChLE/1xYB+CjumMw+gZ9ufp2DPApuVSnDT8t5MIgA=
|
||||
github.com/pion/sdp/v3 v3.0.10/go.mod h1:88GMahN5xnScv1hIMTqLdu/cOcUkj6a9ytbncwMCq2E=
|
||||
github.com/pion/srtp/v3 v3.0.4 h1:2Z6vDVxzrX3UHEgrUyIGM4rRouoC7v+NiF1IHtp9B5M=
|
||||
github.com/pion/srtp/v3 v3.0.4/go.mod h1:1Jx3FwDoxpRaTh1oRV8A/6G1BnFL+QI82eK4ms8EEJQ=
|
||||
github.com/pion/stun/v3 v3.0.0 h1:4h1gwhWLWuZWOJIJR9s2ferRO+W3zA/b6ijOI6mKzUw=
|
||||
github.com/pion/stun/v3 v3.0.0/go.mod h1:HvCN8txt8mwi4FBvS3EmDghW6aQJ24T+y+1TKjB5jyU=
|
||||
github.com/pion/transport/v3 v3.0.7 h1:iRbMH05BzSNwhILHoBoAPxoB9xQgOaJk+591KC9P1o0=
|
||||
github.com/pion/transport/v3 v3.0.7/go.mod h1:YleKiTZ4vqNxVwh77Z0zytYi7rXHl7j6uPLGhhz9rwo=
|
||||
github.com/pion/turn/v4 v4.0.0 h1:qxplo3Rxa9Yg1xXDxxH8xaqcyGUtbHYw4QSCvmFWvhM=
|
||||
github.com/pion/turn/v4 v4.0.0/go.mod h1:MuPDkm15nYSklKpN8vWJ9W2M0PlyQZqYt1McGuxG7mA=
|
||||
github.com/pion/webrtc/v4 v4.0.10 h1:Hq/JLjhqLxi+NmCtE8lnRPDr8H4LcNvwg8OxVcdv56Q=
|
||||
github.com/pion/webrtc/v4 v4.0.10/go.mod h1:ViHLVaNpiuvaH8pdiuQxuA9awuE6KVzAXx3vVWilOck=
|
||||
github.com/wlynxg/anet v0.0.5 h1:J3VJGi1gvo0JwZ/P1/Yc/8p63SoW98B5dHkYDmpgvvU=
|
||||
github.com/wlynxg/anet v0.0.5/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA=
|
||||
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
|
||||
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
|
||||
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
|
||||
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
|
||||
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
21
main.go
Normal file
21
main.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// TIP <p>To run your code, right-click the code and select <b>Run</b>.</p> <p>Alternatively, click
|
||||
// the <icon src="AllIcons.Actions.Execute"/> icon in the gutter and select the <b>Run</b> menu item from here.</p>
|
||||
|
||||
func main() {
|
||||
// TIP <p>Press <shortcut actionId="ShowIntentionActions"/> when your caret is at the underlined text
|
||||
// to see how GoLand suggests fixing the warning.</p><p>Alternatively, if available, click the lightbulb to view possible fixes.</p>
|
||||
s := "gopher"
|
||||
fmt.Printf("Hello and welcome, %s!\n", s)
|
||||
|
||||
for i := 1; i <= 5; i++ {
|
||||
// TIP <p>To start your debugging session, right-click your code in the editor and select the Debug option.</p> <p>We have set one <icon src="AllIcons.Debugger.Db_set_breakpoint"/> breakpoint
|
||||
// for you, but you can always add more by pressing <shortcut actionId="ToggleLineBreakpoint"/>.</p>
|
||||
fmt.Println("i =", 100/i)
|
||||
}
|
||||
}
|
6
pkg/constants.go
Normal file
6
pkg/constants.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package pkg
|
||||
|
||||
const (
|
||||
DefaultBindPort = 14551
|
||||
DefaultLoopBackPort = 14550
|
||||
)
|
85
pkg/datachannel.go
Normal file
85
pkg/datachannel.go
Normal file
@@ -0,0 +1,85 @@
|
||||
package pkg
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/pion/webrtc/v4"
|
||||
)
|
||||
|
||||
type DataChannels map[string]*DataChannel
|
||||
|
||||
type DataChannel struct {
|
||||
datachannel *webrtc.DataChannel
|
||||
loopback *LoopBack
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
func CreateDataChannel(ctx context.Context, label string, peerConnection *webrtc.PeerConnection, loopback *LoopBack) (*DataChannel, error) {
|
||||
var (
|
||||
datachannel *webrtc.DataChannel
|
||||
dataChannelNegotiated = true
|
||||
dataChannelProtocol = "binary"
|
||||
dataChannelOrdered = true
|
||||
dataChannelID = uint16(1) // Add explicit ID
|
||||
dataChannelInit = webrtc.DataChannelInit{
|
||||
Negotiated: &dataChannelNegotiated,
|
||||
Protocol: &dataChannelProtocol,
|
||||
Ordered: &dataChannelOrdered,
|
||||
ID: &dataChannelID,
|
||||
}
|
||||
err error
|
||||
)
|
||||
|
||||
if datachannel, err = peerConnection.CreateDataChannel(label, &dataChannelInit); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = loopback.AttachDataChannel(datachannel); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &DataChannel{
|
||||
datachannel: datachannel,
|
||||
loopback: loopback,
|
||||
ctx: ctx,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (dataChannel *DataChannel) Label() string {
|
||||
return dataChannel.datachannel.Label()
|
||||
}
|
||||
|
||||
func (dataChannel *DataChannel) Send(message []byte) error {
|
||||
return dataChannel.datachannel.Send(message)
|
||||
}
|
||||
|
||||
func (dataChannel *DataChannel) Close() (err error) {
|
||||
if err = dataChannel.datachannel.Close(); err == nil {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (dataChannel *DataChannel) onOpen() *DataChannel {
|
||||
dataChannel.datachannel.OnOpen(func() {
|
||||
fmt.Printf("dataChannel Open with Label: %s\n", dataChannel.datachannel.Label())
|
||||
})
|
||||
return dataChannel
|
||||
}
|
||||
|
||||
func (dataChannel *DataChannel) onClose() *DataChannel {
|
||||
dataChannel.datachannel.OnClose(func() {
|
||||
fmt.Printf("dataChannel Closed with Label: %s\n", dataChannel.datachannel.Label())
|
||||
})
|
||||
return dataChannel
|
||||
}
|
||||
|
||||
func (dataChannel *DataChannel) onMessage() *DataChannel {
|
||||
dataChannel.datachannel.OnMessage(func(message webrtc.DataChannelMessage) {
|
||||
if err := dataChannel.loopback.Send(message.Data); err != nil {
|
||||
fmt.Println("Error sending data: " + err.Error())
|
||||
}
|
||||
})
|
||||
return dataChannel
|
||||
}
|
137
pkg/loopback.go
Normal file
137
pkg/loopback.go
Normal file
@@ -0,0 +1,137 @@
|
||||
package pkg
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/pion/webrtc/v4"
|
||||
)
|
||||
|
||||
type LoopBack struct {
|
||||
dataChannel *webrtc.DataChannel
|
||||
udpListener *net.UDPConn
|
||||
loopBackPort *net.UDPAddr
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
func CreateLoopBack(ctx context.Context, options ...LoopBackOption) (*LoopBack, error) {
|
||||
loopBack := &LoopBack{
|
||||
ctx: ctx,
|
||||
}
|
||||
|
||||
for _, option := range options {
|
||||
if err := option(loopBack); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return loopBack, nil
|
||||
}
|
||||
|
||||
func (loopback *LoopBack) AttachDataChannel(datachannel *webrtc.DataChannel) error {
|
||||
if loopback.dataChannel == nil {
|
||||
loopback.dataChannel = datachannel
|
||||
return nil
|
||||
}
|
||||
return errors.New("datachannel already attached")
|
||||
}
|
||||
|
||||
func (loopback *LoopBack) Start() {
|
||||
go loopback.loop()
|
||||
}
|
||||
|
||||
func (loopback *LoopBack) loop() {
|
||||
var (
|
||||
buffer []byte
|
||||
nRead = 0
|
||||
)
|
||||
|
||||
defer loopback.Close()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-loopback.ctx.Done():
|
||||
return
|
||||
default:
|
||||
|
||||
if loopback.udpListener == nil {
|
||||
fmt.Println("Bind port not yet detected. Sleeping for 0.1 second...")
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
continue
|
||||
}
|
||||
|
||||
if buffer, nRead = loopback.readMessageFromUDPPort(); nRead > 0 && nRead < 1025 {
|
||||
loopback.sendMessageThroughDataChannel(buffer[:nRead])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (loopback *LoopBack) Close() {
|
||||
if loopback.udpListener != nil {
|
||||
loopback.udpListener.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func (loopback *LoopBack) Send(message []byte) error {
|
||||
var (
|
||||
bytesWritten = 0
|
||||
err error = nil
|
||||
)
|
||||
|
||||
if loopback.udpListener == nil {
|
||||
return fmt.Errorf("bind port not yet set. Skipping message")
|
||||
}
|
||||
if loopback.loopBackPort == nil {
|
||||
return fmt.Errorf("loopback port not yet discovered. Skipping message")
|
||||
}
|
||||
if bytesWritten, err = loopback.udpListener.WriteToUDP(message, loopback.loopBackPort); err == nil {
|
||||
if bytesWritten != len(message) {
|
||||
err = fmt.Errorf("written bytes (%d) != message length (%d)", bytesWritten, len(message))
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (loopback *LoopBack) readMessageFromUDPPort() ([]byte, int) {
|
||||
var (
|
||||
buffer []byte = make([]byte, 1024)
|
||||
nRead = 0
|
||||
senderAddr *net.UDPAddr = nil
|
||||
err error = nil
|
||||
)
|
||||
|
||||
if nRead, senderAddr, err = loopback.udpListener.ReadFromUDP(buffer); err != nil {
|
||||
fmt.Println("Error while reading message from bind port" + err.Error())
|
||||
return nil, 0
|
||||
}
|
||||
|
||||
if loopback.loopBackPort == nil {
|
||||
loopback.loopBackPort = &net.UDPAddr{IP: senderAddr.IP, Port: senderAddr.Port}
|
||||
fmt.Println("Found sender port to bind port")
|
||||
}
|
||||
|
||||
if senderAddr != nil && senderAddr.Port != loopback.loopBackPort.Port {
|
||||
fmt.Println(fmt.Sprintf("expected port %d but got %d", loopback.loopBackPort.Port, senderAddr.Port))
|
||||
}
|
||||
|
||||
return buffer, nRead
|
||||
}
|
||||
|
||||
func (loopback *LoopBack) sendMessageThroughDataChannel(message []byte) {
|
||||
var err error = nil
|
||||
|
||||
if loopback.dataChannel == nil {
|
||||
fmt.Println("datachannel not yet set")
|
||||
return
|
||||
}
|
||||
if loopback.dataChannel.ReadyState() == webrtc.DataChannelStateOpen {
|
||||
if err = loopback.dataChannel.Send(message); err != nil {
|
||||
fmt.Println("failed to send data: " + err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
22
pkg/loopback_option.go
Normal file
22
pkg/loopback_option.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package pkg
|
||||
|
||||
import "net"
|
||||
|
||||
type LoopBackOption = func(*LoopBack) error
|
||||
|
||||
func WithBindPort(loopback *LoopBack) error {
|
||||
var err error
|
||||
if loopback.udpListener, err = net.ListenUDP("udp4", &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: DefaultBindPort}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func WithLoopBackPort(loopback *LoopBack) error {
|
||||
loopback.loopBackPort = &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: DefaultLoopBackPort}
|
||||
return nil
|
||||
}
|
||||
|
||||
func WithMAVP2P(loopback *LoopBack) error {
|
||||
return nil
|
||||
}
|
Reference in New Issue
Block a user