snapshot of https://github.com/pion/webrtc.git (main, 2026-09-15; blobs > 131072B omitted)
Some checks failed
REUSE Compliance Check / lint (push) Failing after 0s
Browser E2E / Test (push) Failing after 3s
Test / test (1.24) (push) Failing after 0s
Test / test-i386 (1.25) (push) Failing after 0s
Test / test-i386 (1.24) (push) Failing after 0s
Test / test-windows (1.25) (push) Failing after 0s
Test / test-windows (1.24) (push) Failing after 0s
Test / test (1.25) (push) Failing after 0s
Examples Tests / Test (push) Failing after 3s
Test / test-macos (1.25) (push) Failing after 0s
Test / test-macos (1.24) (push) Failing after 0s
Go mod tidy / tidy (push) Failing after 0s
Test / test-wasm (push) Failing after 0s
CodeQL / analyze (push) Failing after 1s
Fuzz / fuzz (push) Failing after 0s
Some checks failed
REUSE Compliance Check / lint (push) Failing after 0s
Browser E2E / Test (push) Failing after 3s
Test / test (1.24) (push) Failing after 0s
Test / test-i386 (1.25) (push) Failing after 0s
Test / test-i386 (1.24) (push) Failing after 0s
Test / test-windows (1.25) (push) Failing after 0s
Test / test-windows (1.24) (push) Failing after 0s
Test / test (1.25) (push) Failing after 0s
Examples Tests / Test (push) Failing after 3s
Test / test-macos (1.25) (push) Failing after 0s
Test / test-macos (1.24) (push) Failing after 0s
Go mod tidy / tidy (push) Failing after 0s
Test / test-wasm (push) Failing after 0s
CodeQL / analyze (push) Failing after 1s
Fuzz / fuzz (push) Failing after 0s
This commit is contained in:
63
examples/data-channels-flow-control/README.md
Normal file
63
examples/data-channels-flow-control/README.md
Normal file
@@ -0,0 +1,63 @@
|
||||
# data-channels-flow-control
|
||||
This example demonstrates how to use the following property / methods.
|
||||
|
||||
* func (d *DataChannel) BufferedAmount() uint64
|
||||
* func (d *DataChannel) SetBufferedAmountLowThreshold(th uint64)
|
||||
* func (d *DataChannel) BufferedAmountLowThreshold() uint64
|
||||
* func (d *DataChannel) OnBufferedAmountLow(f func())
|
||||
|
||||
These methods are equivalent to that of JavaScript WebRTC API.
|
||||
See https://developer.mozilla.org/en-US/docs/Web/API/RTCDataChannel for more details.
|
||||
|
||||
## When do we need it?
|
||||
Send or SendText methods are called on DataChannel to send data to the connected peer.
|
||||
The methods return immediately, but it does not mean the data was actually sent onto
|
||||
the wire. Instead, it is queued in a buffer until it actually gets sent out to the wire.
|
||||
|
||||
When you have a large amount of data to send, it is an application's responsibility to
|
||||
control the buffered amount in order not to indefinitely grow the buffer size to eventually
|
||||
exhaust the memory.
|
||||
|
||||
The rate you wish to send data might be much higher than the rate the data channel can
|
||||
actually send to the peer over the Internet. The above properties/methods help your
|
||||
application to pace the amount of data to be pushed into the data channel.
|
||||
|
||||
|
||||
## How to run the example code
|
||||
|
||||
The demo code (main.go) implements two endpoints (offerPC and answerPC) in it.
|
||||
|
||||
```
|
||||
signaling messages
|
||||
+----------------------------------------+
|
||||
| |
|
||||
v v
|
||||
+---------------+ +---------------+
|
||||
| | data | |
|
||||
| offerPC |----------------------->| answerPC |
|
||||
|:PeerConnection| |:PeerConnection|
|
||||
+---------------+ +---------------+
|
||||
```
|
||||
|
||||
First offerPC and answerPC will exchange signaling message to establish a peer-to-peer
|
||||
connection, and data channel (label: "data").
|
||||
|
||||
Once the data channel is successfully opened, offerPC will start sending a series of
|
||||
1024-byte packets to answerPC as fast as it can, until you kill the process by Ctrl-c.
|
||||
|
||||
|
||||
Here's how to run the code.
|
||||
|
||||
At the root of the example, `pion/webrtc/examples/data-channels-flow-control/`:
|
||||
```
|
||||
$ go run main.go
|
||||
2019/08/31 14:56:41 OnOpen: data-824635025728. Start sending a series of 1024-byte packets as fast as it can
|
||||
2019/08/31 14:56:41 OnOpen: data-824637171120. Start receiving data
|
||||
2019/08/31 14:56:42 Throughput: 179.118 Mbps
|
||||
2019/08/31 14:56:43 Throughput: 203.545 Mbps
|
||||
2019/08/31 14:56:44 Throughput: 211.516 Mbps
|
||||
2019/08/31 14:56:45 Throughput: 216.292 Mbps
|
||||
2019/08/31 14:56:46 Throughput: 217.961 Mbps
|
||||
2019/08/31 14:56:47 Throughput: 218.342 Mbps
|
||||
:
|
||||
```
|
||||
227
examples/data-channels-flow-control/main.go
Normal file
227
examples/data-channels-flow-control/main.go
Normal file
@@ -0,0 +1,227 @@
|
||||
// SPDX-FileCopyrightText: 2026 The Pion community <https://pion.ly>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
// data-channels-flow-control demonstrates how to use the DataChannel congestion control APIs
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/pion/webrtc/v4"
|
||||
)
|
||||
|
||||
const (
|
||||
bufferedAmountLowThreshold uint64 = 512 * 1024 // 512 KB
|
||||
maxBufferedAmount uint64 = 1024 * 1024 // 1 MB
|
||||
)
|
||||
|
||||
func check(err error) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func setRemoteDescription(pc *webrtc.PeerConnection, sdp []byte) {
|
||||
var desc webrtc.SessionDescription
|
||||
err := json.Unmarshal(sdp, &desc)
|
||||
check(err)
|
||||
|
||||
// Apply the desc as the remote description
|
||||
err = pc.SetRemoteDescription(desc)
|
||||
check(err)
|
||||
}
|
||||
|
||||
func createOfferer() *webrtc.PeerConnection {
|
||||
// Prepare the configuration
|
||||
config := webrtc.Configuration{
|
||||
ICEServers: []webrtc.ICEServer{},
|
||||
}
|
||||
|
||||
// Create a new PeerConnection
|
||||
pc, err := webrtc.NewPeerConnection(config)
|
||||
check(err)
|
||||
|
||||
buf := make([]byte, 1024)
|
||||
|
||||
ordered := false
|
||||
maxRetransmits := uint16(0)
|
||||
|
||||
options := &webrtc.DataChannelInit{
|
||||
Ordered: &ordered,
|
||||
MaxRetransmits: &maxRetransmits,
|
||||
}
|
||||
|
||||
sendMoreCh := make(chan struct{}, 1)
|
||||
|
||||
// Create a datachannel with label 'data'
|
||||
dataChannel, err := pc.CreateDataChannel("data", options)
|
||||
check(err)
|
||||
|
||||
// Register channel opening handling
|
||||
dataChannel.OnOpen(func() {
|
||||
log.Printf(
|
||||
"OnOpen: %s-%d. Start sending a series of 1024-byte packets as fast as it can\n",
|
||||
dataChannel.Label(), dataChannel.ID(),
|
||||
)
|
||||
|
||||
for {
|
||||
err2 := dataChannel.Send(buf)
|
||||
check(err2)
|
||||
|
||||
if dataChannel.BufferedAmount() > maxBufferedAmount {
|
||||
// Wait until the bufferedAmount becomes lower than the threshold
|
||||
<-sendMoreCh
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Set bufferedAmountLowThreshold so that we can get notified when
|
||||
// we can send more
|
||||
dataChannel.SetBufferedAmountLowThreshold(bufferedAmountLowThreshold)
|
||||
|
||||
// This callback is made when the current bufferedAmount becomes lower than the threshold
|
||||
dataChannel.OnBufferedAmountLow(func() {
|
||||
select {
|
||||
case sendMoreCh <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
})
|
||||
|
||||
return pc
|
||||
}
|
||||
|
||||
func createAnswerer() *webrtc.PeerConnection {
|
||||
// Prepare the configuration
|
||||
config := webrtc.Configuration{
|
||||
ICEServers: []webrtc.ICEServer{},
|
||||
}
|
||||
|
||||
// Create a new PeerConnection
|
||||
pc, err := webrtc.NewPeerConnection(config)
|
||||
check(err)
|
||||
|
||||
pc.OnDataChannel(func(dataChannel *webrtc.DataChannel) {
|
||||
var totalBytesReceived uint64
|
||||
|
||||
// Register channel opening handling
|
||||
dataChannel.OnOpen(func() {
|
||||
log.Printf("OnOpen: %s-%d. Start receiving data", dataChannel.Label(), dataChannel.ID())
|
||||
since := time.Now()
|
||||
|
||||
// Start printing out the observed throughput
|
||||
ticker := time.NewTicker(1000 * time.Millisecond)
|
||||
defer ticker.Stop()
|
||||
for range ticker.C {
|
||||
bps := float64(atomic.LoadUint64(&totalBytesReceived)*8) / time.Since(since).Seconds()
|
||||
log.Printf("Throughput: %.03f Mbps", bps/1024/1024)
|
||||
}
|
||||
})
|
||||
|
||||
// Register the OnMessage to handle incoming messages
|
||||
dataChannel.OnMessage(func(dcMsg webrtc.DataChannelMessage) {
|
||||
n := len(dcMsg.Data)
|
||||
atomic.AddUint64(&totalBytesReceived, uint64(n))
|
||||
})
|
||||
})
|
||||
|
||||
return pc
|
||||
}
|
||||
|
||||
func main() {
|
||||
offerPC := createOfferer()
|
||||
defer func() {
|
||||
if err := offerPC.Close(); err != nil {
|
||||
fmt.Printf("cannot close offerPC: %v\n", err)
|
||||
}
|
||||
}()
|
||||
|
||||
answerPC := createAnswerer()
|
||||
defer func() {
|
||||
if err := answerPC.Close(); err != nil {
|
||||
fmt.Printf("cannot close answerPC: %v\n", err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Set ICE Candidate handler. As soon as a PeerConnection has gathered a candidate
|
||||
// send it to the other peer
|
||||
answerPC.OnICECandidate(func(candidate *webrtc.ICECandidate) {
|
||||
if candidate != nil {
|
||||
check(offerPC.AddICECandidate(candidate.ToJSON()))
|
||||
}
|
||||
})
|
||||
|
||||
// Set ICE Candidate handler. As soon as a PeerConnection has gathered a candidate
|
||||
// send it to the other peer
|
||||
offerPC.OnICECandidate(func(candidate *webrtc.ICECandidate) {
|
||||
if candidate != nil {
|
||||
check(answerPC.AddICECandidate(candidate.ToJSON()))
|
||||
}
|
||||
})
|
||||
|
||||
// Set the handler for Peer connection state
|
||||
// This will notify you when the peer has connected/disconnected
|
||||
offerPC.OnConnectionStateChange(func(state webrtc.PeerConnectionState) {
|
||||
fmt.Printf("Peer Connection State has changed: %s (offerer)\n", state.String())
|
||||
|
||||
if state == webrtc.PeerConnectionStateFailed {
|
||||
// Wait until PeerConnection has had no network activity for 30 seconds or another failure.
|
||||
// It may be reconnected using an ICE Restart.
|
||||
// Use webrtc.PeerConnectionStateDisconnected if you are interested in detecting faster timeout.
|
||||
// Note that the PeerConnection may come back from PeerConnectionStateDisconnected.
|
||||
fmt.Println("Peer Connection has gone to failed exiting")
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
if state == webrtc.PeerConnectionStateClosed {
|
||||
// PeerConnection was explicitly closed. This usually happens from a DTLS CloseNotify
|
||||
fmt.Println("Peer Connection has gone to closed exiting")
|
||||
os.Exit(0)
|
||||
}
|
||||
})
|
||||
|
||||
// Set the handler for Peer connection state
|
||||
// This will notify you when the peer has connected/disconnected
|
||||
answerPC.OnConnectionStateChange(func(state webrtc.PeerConnectionState) {
|
||||
fmt.Printf("Peer Connection State has changed: %s (answerer)\n", state.String())
|
||||
|
||||
if state == webrtc.PeerConnectionStateFailed {
|
||||
// Wait until PeerConnection has had no network activity for 30 seconds or another failure.
|
||||
// It may be reconnected using an ICE Restart.
|
||||
// Use webrtc.PeerConnectionStateDisconnected if you are interested in detecting faster timeout.
|
||||
// Note that the PeerConnection may come back from PeerConnectionStateDisconnected.
|
||||
fmt.Println("Peer Connection has gone to failed exiting")
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
if state == webrtc.PeerConnectionStateClosed {
|
||||
// PeerConnection was explicitly closed. This usually happens from a DTLS CloseNotify
|
||||
fmt.Println("Peer Connection has gone to closed exiting")
|
||||
os.Exit(0)
|
||||
}
|
||||
})
|
||||
|
||||
// Now, create an offer
|
||||
offer, err := offerPC.CreateOffer(nil)
|
||||
check(err)
|
||||
check(offerPC.SetLocalDescription(offer))
|
||||
desc, err := json.Marshal(offer)
|
||||
check(err)
|
||||
|
||||
setRemoteDescription(answerPC, desc)
|
||||
|
||||
answer, err := answerPC.CreateAnswer(nil)
|
||||
check(err)
|
||||
check(answerPC.SetLocalDescription(answer))
|
||||
desc2, err := json.Marshal(answer)
|
||||
check(err)
|
||||
|
||||
setRemoteDescription(offerPC, desc2)
|
||||
|
||||
// Block forever
|
||||
select {}
|
||||
}
|
||||
Reference in New Issue
Block a user