← View all posts
October 19, 2016

Warm-up with dummy tracks and replaceTrack

Contributed by Jan-Ivar Bruaroey,

If you’ve looked at the WebRTC spec over the last year, you’ll find a gap between what it says and what browsers have implemented so far. The big difference is the spec talks about senders and receivers of tracks, whereas most browsers still operate with streams.

Firefox is the only browser so far to have pivoted to tracks, the stuff streams are made of. This opens up exciting possibilities like sender.replaceTrack(). It lets you switch out an already-sending track without needing to renegotiate, and still see the change reflected remotely. We’re not fully done with senders and receivers, and we have more to do (like transports), but replaceTrack works.

The spec, however, goes even further, defining transceivers, a pairing of a sender and a receiver. Even Firefox hasn’t implemented that yet. The spec shows an example of connection warm-up using transceivers to set up a connection before media is ready. This means you can send media the instant it becomes available. Quite neat, and a benefit of the spec moving to objects that can exist before media is added.

But it turns out we don’t have to wait for transceivers to do warm-up, which is what we’re going to show here!

You can already read my other blog on how to renegotiate quickly over datachannels, but that won’t cut it here. For parity with the spec’s warm-up example, we must be ready to send media without any additional negotiation at all.

We’re going to (surprise!) use replaceTrack for this: Basically, we’ll set up and negotiate a connection using dummy tracks, and replace them with real media later once available. To do this, we first need dummy tracks.

Dummy tracks

For all the bells and whistles of WebRTC, you’d think creating dummy audio and video tracks would be basic. Well, it’s not, but it’s doable. Without further ado, here’s what we have to do:

Click the “Result” tab above to see it working in both Firefox and Chrome.

Tada! Silly, right? Quite the effort for a black rectangle. What a dumb blog this is so far. The crucial part here though is that we now have a stream we didn’t have to ask permission for from the user. This will help later to connect immediately with usable media ports, on all browsers, even less permissive ones like Firefox, and we avoid asking users for permission twice.

Connect with dummies, then replaceTrack

Now that we have our dummies, we can connect with them, which hooks up all the ports needed for media. We have a button to add and switch in real media later. Switch to “Result” to see it in action:

And there you have it. If you run this in Firefox, you’ll see a connection being established immediately, with two video elements showing black: the original one on the left, and the “remote” one coming out the other end of the peer connection on the right (which may be blank in Chrome), and silence.

Once you click the “Add Media!” button, video from your camera should appear in both places, and sound should echo out of the remote end, without any additional negotiation having happened.

If you ran this in Chrome, you might be surprised to see it working there as well! This may be thanks to a polyfill I wrote special for this example, which means there’s an extra renegotiation for you, sorry! However, I wrote it such that once Chrome implements replaceTrack, you should be able to run the example without renegotiation. If you’re using Firefox, rest assured that the polyfill is unused.

Once we’ve implemented transceivers, we’ll no longer need to do warm-up this way. Still, this is just one of the many uses of replaceTrack. Hopefully you’ve seen how versatile replaceTrack can be, and you’ve gotten some insight into the kinds of things the spec envisions you doing with tracks in WebRTC.