I’m implementing a mechanism to detect when a producer’s network becomes weak, and I’m not sure if the approach I’m taking is the best practice.
Right now I’m relying on Mediasoup’s producer trace events, specifically when packetLost > 0, to consider the producer’s network unstable.
When this happens, I notify the other peers in the room.
Since packetlost traces can fire many times per second, I added a simple throttle so that a “weak network” notification is emitted only once every few seconds.
Below is the simplified version of the code:
Producer trace handler (peer.js)
producer.on("trace", (trace) => {
if (trace.type !== "rtp") return;
if (trace.info && trace.info.packetLost > 0) {
if (this.onProducerWeakNetwork) {
this.onProducerWeakNetwork(
this.userId,
producer.id,
this.id // socketId
);
}
}
});
Room-level throttling and broadcast (room.js)
// Map: producerId -> last notification timestamp
this._weakNetworkTs = new Map();
peer.onProducerWeakNetwork = (userId, producerId, socketId) => {
const now = Date.now();
const last = this._weakNetworkTs.get(producerId) || 0;
const THROTTLE_MS = 3000;
if (now - last < THROTTLE_MS) {
return; // avoid spamming
}
this._weakNetworkTs.set(producerId, now);
const data = {
userId,
producerId,
warning: "Producer network seems unstable"
};
// Notify all peers in the room
this.broadcast(socketId, "producerNetworkSlow", data);
};
My questions
Is using packetlost trace events a recommended way to detect weak networks for producers?
Is throttling this event (once per few seconds) the proper way to avoid overwhelming the system and clients?
Are there better or more accurate metrics to depend on (bitrate drop, NACK count, RTT spikes, producer score, etc.)?
Is there a more idiomatic or recommended Mediasoup method for detecting unstable network conditions?
Any insights would be greatly appreciated. Thanks! @ibc
I have a quick question about using producer.on("score").
Do I need to enable any specific log level or debugging option in order for the score events to be emitted?
And from your perspective, is relying on producer.on("score") recommended in a production environment?
I hope you don’t mind me adding a small thought here.
I recently found that slow-internet detection can also be done directly in the browser using WebRTC getStats(), and it appears to be quite lightweight. Since all the analysis (bandwidth, jitter, packet loss, RTT) is processed locally in the user’s browser, it doesn’t introduce any noticeable hardware cost on the server side.
The server only receives a tiny JSON report when the connection quality drops, so the impact is extremely low.
I’m not completely sure, but it seems like services such as Google Meet and Zoom also use this client-side approach.
I just wanted to share this in case it might be helpful
// Detect slow internet directly from the browser using WebRTC getStats().
// This is lightweight and does NOT increase server hardware costs.
// All network calculations run on the client side.
const pc = new RTCPeerConnection();
async function getNetworkStats() {
const stats = await pc.getStats();
let bytesSent = 0;
let bytesReceived = 0;
let packetsLost = 0;
let jitter = 0;
let rtt = 0;
stats.forEach(report => {
// Outbound RTP: video sent by the client
if (report.type === "outbound-rtp" && report.kind === "video") {
bytesSent += report.bytesSent || 0;
packetsLost += report.packetsLost || 0;
jitter += report.jitter || 0;
}
// Inbound RTP: video received by the client
if (report.type === "inbound-rtp" && report.kind === "video") {
bytesReceived += report.bytesReceived || 0;
packetsLost += report.packetsLost || 0;
jitter += report.jitter || 0;
rtt += report.roundTripTime || 0;
}
});
return {
bytesSent,
bytesReceived,
packetsLost,
jitter,
rtt
};
}
let lastStats = null;
// Check network status every 5 seconds
setInterval(async () => {
const stats = await getNetworkStats();
if (lastStats) {
const deltaTime = 5; // seconds
// Calculate upload and download speed in Mbps
const uploadMbps =
((stats.bytesSent - lastStats.bytesSent) * 8) /
(deltaTime * 1024 * 1024);
const downloadMbps =
((stats.bytesReceived - lastStats.bytesReceived) * 8) /
(deltaTime * 1024 * 1024);
console.log(
`Upload: ${uploadMbps.toFixed(2)} Mbps, Download: ${downloadMbps.toFixed(2)} Mbps`
);
console.log(
`Packets lost: ${stats.packetsLost}, Jitter: ${stats.jitter.toFixed(3)}, RTT: ${stats.rtt.toFixed(3)}s`
);
// Send lightweight report only if quality is poor
if (uploadMbps < 1 || downloadMbps < 1 || stats.packetsLost > 5) {
fetch("/api/internet-status", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({
uploadMbps,
downloadMbps,
packetsLost: stats.packetsLost,
jitter: stats.jitter,
rtt: stats.rtt,
timestamp: Date.now()
})
});
}
}
lastStats = stats;
}, 5000);