ORTC support in Edge has been announced today. A while back, we saw this on twitter:
Windows Insider Preview build 10525 is now available for PCs: http://t.co/zeXQJocgLs This release lays groundwork for ORTC in Microsoft Edge
— Microsoft Edge Dev (@MSEdgeDev) August 18, 2015
“This release [build 10525] lays the groundwork for ORTC” was quite an understatement. It was considered experimental and while the implementation still differs from the specification (which is still work in progress) slightly, it already worked and as a developer you can get familiar with how ORTC works and how it is different from the RTCPeerConnection API.
If you want to test this, please use builds newer than 10547. Join the Windows Insider Program to get them and make sure you’re on the fast ring.
The approach taken differs from the RTCPeerConnection way of giving you a blob that you exchange as this WebRTC PC1 sample shows quite well. It’s more about giving you the building blocks.
In ORTC, you have to incrementally build up things. Let’s walk through the code (available on github):
Setting up a Peer to Peer connection
1 2 3 |
var gatherer1 = new RTCIceGatherer(iceOptions); var transport1 = new RTCIceTransport(gatherer1); var dtls1 = new RTCDtlsTransport(transport1); |
There are three elements on the transport side:
- RTCIceGatherer – gathers ICE candidates to be sent to the peer
- RTCIceTransport – where you add the candidates from the peer
- DtlsTransport – sits on top of the ICE transport and deals with encryption.
As in the peerConnection API, you exchange the candidates:
1 2 3 4 5 6 7 8 9 |
// Exchange ICE candidates. gatherer1.onlocalcandidate = function (evt) { console.log('1 -> 2', evt.candidate); transport2.addRemoteCandidate(evt.candidate); }; gatherer2.onlocalcandidate = function (evt) { console.log('2 -> 1', evt.candidate); transport1.addRemoteCandidate(evt.candidate); }; |
Also, you need to exchange the ICE parameters (usernameFragment and password) and start the ICE transport:
1 2 3 4 |
transport1.start(gatherer1, gatherer2.getLocalParameters(), 'controlling'); transport1.onicestatechange = function() { console.log('ICE transport 1 state change', transport1.state); }; |
This is done with SDP in the PeerConnection API. One side needs to be controlling, the other is controlled.
You also need to start the DTLS transport with the remote fingerprint and hash algorithm:
1 2 3 4 |
dtls1.start(dtls2.getLocalParameters()); dtls1.ondtlsstatechange = function() { console.log('DTLS transport 1 state change', dtls1.state); }; |
Once this is done, you can see the candidates being exchanged and the ICE and DTLS state changes on both sides.
Cool. Now what?
Sending a MediaStream track over the connection
Let’s send a MediaStream track. First, we acquire it using the promise-based navigator.mediaDevices.getUserMedia API and attach it to the local video element.
1 2 3 4 |
// call getUserMedia to get a MediaStream. navigator.mediaDevices.getUserMedia({video: true}) .then(function(stream) { document.getElementById('localVideo').srcObject = stream; |
Next, we determine the send and receive parameters. This is where the PeerConnection API does the “offer/answer” magic.
Since our sending capabilities match the receiving capabilities, there is little we need to do here.
Some black magic is still involved, check the specification for the gory details.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
// Determine RtpCodecParameters. Consider this black magic. var params = RTCRtpReceiver.getCapabilities('video'); params.muxId = 1001; params.encodings = [{ ssrc: 1001, codecPayloadType: 0, fec: 0, rtx: 0, priority: 1.0, maxBitrate: 2000000.0, minQuality: 0, framerateBias: 0.5, resolutionScale: 1.0, framerateScale: 1.0, active: true, dependencyEncodingId: undefined, encodingId: undefined }]; // We need to transform the codec capability into a codec. params.codecs.forEach(function (codec) { codec.payloadType = codec.preferredPayloadType; }); params.rtcp = { cname: "", reducedSize: false, ssrc: 0, mux: true }; console.log(params); |
Then, we start the RtpReceiver with those parameters:
1 2 3 4 5 6 |
// Start the RtpReceiver to receive the track. receiver = new RTCRtpReceiver(dtls2, 'video'); receiver.receive(params); var remoteStream = new MediaStream(); remoteStream.addTrack(receiver.track); document.getElementById('remoteVideo').srcObject = remoteStream; |
Note that the Edge implementation is slightly different from the current ORTC specification here since you need to specify the media type as second argument when creating the RtpReceiver.
We create a stream to contain the track and attach it to the remote video element.
Last but not least, let’s send the video track we got:
1 2 |
sender = new RTCRtpSender(stream.getVideoTracks()[0], dtls1); sender.send(params); |
That’s it. It gets slightly more complicated when you have to deal with multiple tracks, and have to actually negotiate capabilities in order to interop between Chrome and Edge. But that’s a longer story…
{“author”: “Philipp Hancke“}
Leave a Reply