murat-dogan / node-datachannel

WebRTC For Node.js and Electron. libdatachannel node bindings.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

onBufferedAmountLow() is not triggered if only one message is sent.

yuanzhanghu opened this issue · comments

Refer to below patch for reproducing the issue. just test client.js again after patch is applied.

diff --git a/examples/client-server/client.js b/examples/client-server/client.js
index 95a4841..894263e 100644                                                              
--- a/examples/client-server/client.js
+++ b/examples/client-server/client.js
@@ -5,6 +5,9 @@ import nodeDataChannel from '../../lib/index.js';
 // Init Logger     
 nodeDataChannel.initLogger('Error');
        
+// Constants                                                                              
+const BUFFER_SIZE = 0;
+                                          
 // PeerConnection Map                                                                                                                                                                 
 const pcMap = {};                                                                         
                                                                                           
@@ -42,7 +45,6 @@ ws.on('message', (msgStr) => {
         case 'candidate':                                                                 
             pcMap[msg.id].addRemoteCandidate(msg.candidate, msg.mid);
             break;                    
-                                                                                          
         default:
             break;                         
     }  
@@ -59,9 +61,12 @@ function readUserInput() { 
         if (peerId && peerId.length > 2) {
             console.log('Offering to ', peerId);
             createPeerConnection(peerId);
-
             console.log('Creating DataChannel with label "test"');
             let dc = pcMap[peerId].createDataChannel('test');
+
+            // Set Buffered Amount Low Threshold
+            dc.setBufferedAmountLowThreshold(BUFFER_SIZE);
+
             dc.onOpen(() => {
                 dc.sendMessage('Hello from ' + id);
             });
@@ -69,8 +74,12 @@ function readUserInput() { 
             dc.onMessage((msg) => {
                 console.log('Message from ' + peerId + ' received:', msg);
             });
-        }
  
+            dc.onBufferedAmountLow(() => {
+                dc.sendMessage('client message from onBufferedAmountLow');
+            });
+
+        }
         rl.close();
         readUserInput();
     });
@@ -93,9 +102,14 @@ function createPeerConnection(peerId) {
     });
     peerConnection.onDataChannel((dc) => {
         console.log('DataChannel from ' + peerId + ' received with label "', dc.getLabel() + '"');
+        // Set Buffered Amount Low Threshold 
+        dc.setBufferedAmountLowThreshold(BUFFER_SIZE);
         dc.onMessage((msg) => {
             console.log('Message from ' + peerId + ' received:', msg);
         });
+        dc.onBufferedAmountLow(() => {
+            dc.sendMessage('server Hello From ' + id);
+        });
         dc.sendMessage('Hello From ' + id);
     });

This is expected behavior: if a message can be sent immediately, it is not buffered, so the buffered amount stays at 0 and therefore onBufferedAmountLow is not triggered. The WebRTC implementation in browsers behaves similarly.

This is expected behavior: if a message can be sent immediately, it is not buffered, so the buffered amount stays at 0 and therefore onBufferedAmountLow is not triggered. The WebRTC implementation in browsers behaves similarly.

Then how can we trigger onBufferedAmountLow() steadily ? since If we send too fast, we got buffer full errors, if we send too slow, we cannot trigger onBufferedAmountLow(), thus we cannot fully use the bandwidth.

Simply check bufferedAmount(). While it is lower or equal to the threshold, you can send more messages, and when it gets higher than the threshold, you should stop sending and wait for onBufferedAmountLow().

But bufferedAmount() is not working well if we call it outside of onBufferedAmountLow().
And we got full screens buffer full logs:
2023-11-12 09:24:01.605 INFO [1877048] [rtc::impl::IceTransport::LogCallback@362] juice: Send failed, buffer is full

Please refer to below diff to reproducing the issue, note: we have to run client.js on different machine ( for example on 2 laptops within same WIFI network).
Just do this:
laptop1> node client.js signal-server-ip
laptop2> node client.js signal-server-ip

diff --git a/examples/client-server/client.js b/examples/client-server/client.js
index 95a4841..35db4b4 100644
--- a/examples/client-server/client.js
+++ b/examples/client-server/client.js
@@ -3,7 +3,10 @@ import readline from 'readline';
 import nodeDataChannel from '../../lib/index.js';
 
 // Init Logger
-nodeDataChannel.initLogger('Error');
+nodeDataChannel.initLogger('Info');
+
+// Constants
+const BUFFER_SIZE = 0;
 
 // PeerConnection Map
 const pcMap = {};
@@ -11,8 +14,14 @@ const pcMap = {};
 // Local ID
 const id = randomId(4);
 
-// Signaling Server
-const WS_URL = process.env.WS_URL || 'ws://localhost:8000';
+const defaultWsUrl = 'ws://localhost:8000';
+const cliArgWsUrl = `ws://${process.argv[2]}:8000`;
+let WS_URL = defaultWsUrl;
+if (process.argv[2]) {
+    WS_URL = cliArgWsUrl;
+}
+
+console.log(`websocket url: ${WS_URL}`);
 const ws = new WebSocket(WS_URL + '/' + id, {
     perMessageDeflate: false,
 });
@@ -42,7 +51,6 @@ ws.on('message', (msgStr) => {
         case 'candidate':
             pcMap[msg.id].addRemoteCandidate(msg.candidate, msg.mid);
             break;
-
         default:
             break;
     }
@@ -59,20 +67,33 @@ function readUserInput() {
         if (peerId && peerId.length > 2) {
             console.log('Offering to ', peerId);
             createPeerConnection(peerId);
-
             console.log('Creating DataChannel with label "test"');
             let dc = pcMap[peerId].createDataChannel('test');
+
+            // Set Buffered Amount Low Threshold
+            dc.setBufferedAmountLowThreshold(BUFFER_SIZE);
+
             dc.onOpen(() => {
-                dc.sendMessage('Hello from ' + id);
+                for (let i=0; i<10; i++) {
+                    dc.sendMessage('Hello from ' + id);
+                }
             });
 
             dc.onMessage((msg) => {
-                console.log('Message from ' + peerId + ' received:', msg);
+                // console.log('Message from ' + peerId + ' received:', msg);
+                while (dc.bufferedAmount() <= BUFFER_SIZE) {
+                    dc.sendMessage("Sending in onMessage");
+                }
+            });
+
+            dc.onBufferedAmountLow(() => {
+                while (dc.bufferedAmount() <= BUFFER_SIZE) {
+                    dc.sendMessage('client message from onBufferedAmountLow');
+                }
             });
-        }
 
+        }
         rl.close();
-        readUserInput();
     });
 }
 
@@ -93,8 +114,18 @@ function createPeerConnection(peerId) {
     });
     peerConnection.onDataChannel((dc) => {
         console.log('DataChannel from ' + peerId + ' received with label "', dc.getLabel() + '"');
+        // Set Buffered Amount Low Threshold
+        dc.setBufferedAmountLowThreshold(BUFFER_SIZE);
         dc.onMessage((msg) => {
-            console.log('Message from ' + peerId + ' received:', msg);
+            // console.log('Message from ' + peerId + ' received:', msg);
+            while (dc.bufferedAmount() <= BUFFER_SIZE) {
+                dc.sendMessage("server sending in onMessage");
+            }
+        });
+        dc.onBufferedAmountLow(() => {
+            while (dc.bufferedAmount() <= BUFFER_SIZE) {
+                dc.sendMessage("server sending in onBufferedAmountLow");
+            }
         });
         dc.sendMessage('Hello From ' + id);
     });

And we got full screens buffer full logs:
2023-11-12 09:24:01.605 INFO [1877048] [rtc::impl::IceTransport::LogCallback@362] juice: Send failed, buffer is full

This is not an error or warning and it might happen under normal operation (It could actually be debug level instead of info level). It means the UDP socket buffer is full, which is actually unrelated to the buffer of each DataChannel. It might happens for instance if you send fast enough between two peers on the same local WiFi network: in this case, the local network is the limiting link, therefore packets will queue immediately on the sender side, until packets can't be sent anymore, which will be interpreted as reaching maximum network capacity.

Got it. Thanks for explanations.