From 0a7291e90fa058cc1a7b9ee49bf38271676ed29a Mon Sep 17 00:00:00 2001 From: KokaKiwi Date: Sat, 9 Aug 2025 14:11:54 +0200 Subject: [PATCH] client,proxy: add a media channel --- client/lib/util.go | 11 ++++++++++ client/lib/webrtc.go | 46 ++++++++++++++++++++++++++++++++++++++++++ proxy/lib/snowflake.go | 13 ++++++++++++ 3 files changed, 70 insertions(+) diff --git a/client/lib/util.go b/client/lib/util.go index 536fa17..6dbbf2f 100644 --- a/client/lib/util.go +++ b/client/lib/util.go @@ -1,7 +1,9 @@ package snowflake_client import ( + "crypto/rand" "log" + "math/big" "time" ) @@ -69,3 +71,12 @@ func (b *bytesSyncLogger) addOutbound(amount int64) { func (b *bytesSyncLogger) addInbound(amount int64) { b.inboundChan <- amount } + +func randomInt(min, max int) int { + nBig, err := rand.Int(rand.Reader, big.NewInt(int64(max-min))) + if err != nil { + panic(err) + } + + return int(nBig.Int64()) + min +} diff --git a/client/lib/webrtc.go b/client/lib/webrtc.go index 397ba85..3c12a43 100644 --- a/client/lib/webrtc.go +++ b/client/lib/webrtc.go @@ -15,6 +15,7 @@ import ( "github.com/pion/transport/v3" "github.com/pion/transport/v3/stdnet" "github.com/pion/webrtc/v4" + "github.com/pion/webrtc/v4/pkg/media" "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/v2/common/event" "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/v2/common/proxy" @@ -296,6 +297,7 @@ func (c *WebRTCPeer) preparePeerConnection( log.Printf("NewPeerConnection ERROR: %s", err) return err } + ordered := true dataChannelOptions := &webrtc.DataChannelInit{ Ordered: &ordered, @@ -340,6 +342,8 @@ func (c *WebRTCPeer) preparePeerConnection( c.open = make(chan struct{}) log.Println("WebRTC: DataChannel created") + c.openMediaTrack() + offer, err := c.pc.CreateOffer(nil) // TODO: Potentially timeout and retry if ICE isn't working. if err != nil { @@ -365,6 +369,48 @@ func (c *WebRTCPeer) preparePeerConnection( return nil } +func (c *WebRTCPeer) openMediaTrack() { + videoTrack, err := webrtc.NewTrackLocalStaticSample( + webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeAV1}, "video", "pion", + ) + if err != nil { + log.Printf("webrtc.NewTrackLocalStaticSample ERROR: %s", err) + return + } + + rtpSender, err := c.pc.AddTrack(videoTrack) + if err != nil { + log.Printf("webrtc.AddTrack ERROR: %s", err) + return + } + + go func() { + rtcpBuf := make([]byte, 1500) + for { + if _, _, rtcpErr := rtpSender.Read(rtcpBuf); rtcpErr != nil { + return + } + } + }() + + go func() { + ticker := time.NewTicker(time.Second) + defer ticker.Stop() + + for ; true; <-ticker.C { + bufSize := randomInt(1000, 2500) + buf := make([]byte, bufSize) + + err := videoTrack.WriteSample(media.Sample{Data: buf, Duration: time.Second}) + if err != nil { + log.Printf("webrtc.WriteSample ERROR: %s", err) + } + } + }() + + log.Println("WebRTC: Media track opened") +} + // cleanup closes all channels and transports func (c *WebRTCPeer) cleanup() { // Close this side of the SOCKS pipe. diff --git a/proxy/lib/snowflake.go b/proxy/lib/snowflake.go index bcdfbda..4d6881c 100644 --- a/proxy/lib/snowflake.go +++ b/proxy/lib/snowflake.go @@ -451,6 +451,19 @@ func (sf *SnowflakeProxy) makePeerConnectionFromOffer( return nil, fmt.Errorf("accept: NewPeerConnection: %s", err) } + pc.OnTrack(func(remote *webrtc.TrackRemote, receiver *webrtc.RTPReceiver) { + log.Printf("Track has started streamId(%s) id(%s) rid(%s) \n", remote.StreamID(), remote.ID(), remote.RID()) + + for { + rtcpBuf := make([]byte, 1500) + for { + if _, _, err := receiver.Read(rtcpBuf); err != nil { + return + } + } + } + }) + pc.OnDataChannel(func(dc *webrtc.DataChannel) { log.Printf("New Data Channel %s-%d\n", dc.Label(), dc.ID()) close(dataChan)