Skip to content

Change Upstream Bitrate

Oliver Hargreaves Mar 14, 2024 9:39:33 AM

It’s 9 AM on a Monday morning, you have already gone for a run, cooked breakfast for the family, and have a fresh cup of coffee sitting on your desk as you log in for a company town hall. And that is when the first tragedy of the day strikes: Technical difficulties plague the leadership team and no one knows how to fix it. After 5 minutes, you get an email saying the event will be rescheduled pending a technical fix. What happened? 

As it turns out, the technical team who just finished your company’s custom meeting application opted to set everyone’s quality settings to maximum causing people’s devices to start freezing and the servers to be over-utilized. Now it is time to put out a patch, but how can this be fixed? 

After a quick meeting with their WebRTC vendor, the technical team realizes that they need to optimize the bitrates of the participants and only send high-quality feeds out for those that will be presenting, while the rest of the group can send a lower-quality feed since they are not the focal point of the meeting. Doing so will help reduce the server load and the amount of data that other end-user devices will need to process.

Let’s dive in and see how this can be accomplished using the LiveSwitch SDK.

In our example, we will show the sending bitrate and the bitrate we are receiving for our video stream. We will also show a select box that will allow us to change the target bitrate at which we will be sending.

In order to show the sending and receiving bitrates, we need to listen for a new event onStats on the upstream and downstream connections.

Let’s start with the bitrate we are sending to the media server.

senderUpstreamConnection.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));
            sendingBitrateSpan.innerText = bitrate.toLocaleString(); 
        }
        lastSenderStatsEventBytesSent = bytesSent;
        lastSenderStatsEventTimestamp = Date.now();
    }
});

Here, we start by pulling the sender information off the video stream from our stats object. Next, we calculate the bitrate based on the bytes sent since our last stats check. Finally, we write the bitrate out to our user interface.

For incoming downstream connections, the logic is almost the same, except this time, we pull the receiver data from the video stream on the stats object.

conn.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));
            receivingBitrateSpan.innerText = bitrate.toLocaleString();
        }
        lastReceiverStatsEventBytesReceived = bytesReceived;
        lastReceiverStatsEventTimestamp = Date.now();
    }
});

Now that we are showing the bitrate we are sending and receiving, we can add the controls to adjust the bitrates on the fly.

There are two times where we will set the bitrate. First is when we establish our upstream connection for the first time, and then set it again whenever we change the option in our dropdown menu.

async function openSfuUpstreamConnection() {

    let audioStream = new fm.liveswitch.AudioStream(localMedia);
    let videoStream = new fm.liveswitch.VideoStream(localMedia);
    videoStream.setMaxSendBitrate(
      upstreamBitrateSelector.value);
    senderUpstreamConnection = senderChannel.createSfuUpstreamConnection(audioStream, videoStream);
    …
}
function updateBitrate() {

    console.log("Setting new bitrate to " + upstreamBitrateSelector.value + " kbps.");
    senderUpstreamConnection.getVideoStream()
.setMaxSendBitrate(upstreamBitrateSelector.value);
}

Congratulations, you can now dynamically control the upstream bitrate each user is sending.

Using this technique, you can define users by roles and give your host and presenters a high maximum bitrate to ensure the best quality video and drop everyone else’s to the lowest acceptable bitrate to prevent servers and client devices from being overwhelmed in large calls.

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 here.

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!