We live in a world surrounded by internet connectivity. From our computers, phones, and tablets to our thermostats, ovens, and refrigerators, almost every device can be connected to the internet. While this level of connectivity might lead you to believe that a simple video call should be accessible to everyone no matter where they are, the quality of this connection varies and can be fickle throughout the day in the same location.
Due to this inconsistency, it is important to add stabilization logic to your application to smooth out the peaks and valleys of connectivity and present your users with a smooth experience.
We recently covered how to address this from the sender side, but that is just a piece of the equation. In the event that the receiver is limited in the downstream bandwidth, you will need to signal to the sender that a reduced bitrate should be sent.
In this example, we will go over how to perform this signaling and use getStats() to validate that the sender is reacting appropriately to our requests.
Let's start by listening to the connection statistics to understand what is happening in our application.
receiverDownstreamConnection.addOnStats(stats => {
var receiverStats = stats.getVideoStream().getReceiver();
if (receiverStats != null) {
var bytesReceived = receiverStats.getBytesReceived();
if (lastReceiverStatsEventTimestamp) {
var millisecondsSinceLastStatsEvent = Date.now() - lastReceiverStatsEventTimestamp;
var bitrate = Math.floor((bytesReceived - lastReceiverStatsEventBytesReceived) * 8 / (millisecondsSinceLastStatsEvent));
// bitrate in kbps
receivingBitrateSpan.innerText = bitrate.toLocaleString();
}
lastReceiverStatsEventBytesReceived = bytesReceived;
lastReceiverStatsEventTimestamp = Date.now();
}
});
We will begin by looking at the downstream connection. When the statistics are updated, we will document the timestamp and the downstream bytes received and calculate the bitrate between statistic updates.
We will then do the same on the sending side for the purposes of our demonstration.
conn.addOnStats(stats => {
var senderStats = stats.getVideoStream().getSender();
if (senderStats != null) {
var bytesSent = senderStats.getBytesSent();
if (lastSenderStatsEventTimestamp) {
var millisecondsSinceLastStatsEvent = Date.now() - lastSenderStatsEventTimestamp;
var bitrate = Math.floor((bytesSent - lastSenderStatsEventBytesSent) * 8 / (millisecondsSinceLastStatsEvent));
// bitrate in kbps
sendingBitrateSpan.innerText = bitrate.toLocaleString();
}
lastSenderStatsEventBytesSent = bytesSent;
lastSenderStatsEventTimestamp = Date.now();
}
});
The last piece we need to complete this is the actual signal from the downstream connection to change the bitrate. To do this, we will get the individual downstream connection that is too high, pull out the video stream, and set the maximum bitrate we would like to receive on that specific feed.
receiverDownstreamConnection.getVideoStream().setMaxReceiveBitrate(downstreamBitrateSelector.value);
And that is all it takes! In this 1:1 call scenario, it is straightforward to update the single video track. However for use cases that have multiple users in a call, you will need to determine at which point to trigger this logic. In most cases, it is good to trigger this logic when the majority of downstream connections are struggling, but that is a decision for you to make based on what is most important for your customers.
If you want to see this in action, please check out the full application in this demo and check out the code for this example.
If you are interested in building this out further and exploring this with some of the other examples we have discussed in our blogs such as the chat example, please sign up for a free 30-day trial and build your own application!
Need assistance in architecting the perfect WebRTC application? Let our team help out! Get in touch with us today!