- From: Jan-Ivar Bruaroey <jib@mozilla.com>
- Date: Sat, 20 Sep 2014 01:54:39 -0400
- To: "public-webrtc@w3.org" <public-webrtc@w3.org>
If you don't care for promises, their minimal impact is:
- navigator.getUserMedia(constraints, function(stream) {
+ mediaDevices.getUserMedia(constraints).then(function(stream) {
video.srcObject = stream;
video.play();
- }, function (err) {
+ }).catch(function (err) {
console.log(err.message);
});
But you'd be missing out by stopping there, as I believe they have a lot
more to offer WebRTC.
To illustrate, I've rewritten our local-loop replaceTrack demo-script to
use a promises polyfill that works in Firefox Nightly [1]. Here's a
cleaned-up excerpt:
function call(pc, signal) {
return mediaDevices.getUserMedia(myrequest)
.then(video => {
localvideo1.srcObject = video;
localvideo1.play();
video1.getTracks().forEach(track => pc.addTrack(track, video));
return pc.createOffer(offer_options);
})
.then(offer => pc.setLocalDescription(offer))
.then(() => signal.then(answer => pc.setRemoteDescription(answer)));
}
function pickup(pc, signal) {
return (oneway.checked? new Promise(resolve => resolve()) :
mediaDevices.getUserMedia(myrequest_reverse)
.then(video => {
localvideo2.srcObject = video;
localvideo2.play();
video.getTracks().forEach(track => pc.addTrack(track, video));
}))
.then(() => signal.then(offer => pc.setRemoteDescription(offer)))
.then(() => pc.createAnswer(answer_options))
.then(answer => pc.setLocalDescription(answer));
}
Promise.all([call(pc1, pc2.stable), pickup(pc2, pc1.haveLocalOffer)])
.then(() => log("HIP HIP HOORAY"))
.catch(failed); // 1-line error handling
This is a complete local-loop call. The two functions, call() and
pickup(), may be a bit contrived, but illustrate that unlike most
local-loop tests you've probably seen, each peer is set up
asynchronously and in parallel, with only a signal sent across, much
like in a remote call.
Several things are going on here - which I will explain - and promises
are used in three interesting ways:
First, there's the promise-chains: then().then().then(). We start two
chains in parallel and wait for both to complete with Promise.all. This
is pretty straightforward promise-stuff, but powerful.
Then, there's three new promises that I've added as read-only-attributes
(yes!) to the peerConnection polyfill that trigger on signalingstate:
pc.hasLocalOffer
pc.hasRemoteOffer
pc.stable
Turns out promises can be used to track simple states. E.g. to make
something happen when signalingstate changes to "has-local-offer", you
just do: pc.hasLocalOffer.then(function(offer) { ... }); To make it more
useful, I've made the fulfillment value be the offer (or answer
depending), which means I can use them as the carrier 'signal' argument
that gives the call() and pickup() functions the other peer's sdp when
it becomes available.
Lastly, my final use of promises was to fix an unfortunate race in
local-loop calls. With the two peers less tightly coupled, I started
seeing ICE failures. Turns out candidates were arriving before the other
peer could receive them, and addIceCandidate was failing, complaining
that it could not be called beforesetRemoteDescription. Is that by spec?
To solve this, I relied again on the signalingstate promises:
pc1.onicecandidate = obj => {
pc2.haveRemoteOffer.then(() => {
if (obj.candidate) {
pc2.addIceCandidate(obj.candidate).catch(failed);
}
});
};
pc2.onicecandidate = obj => {
pc1.stable.then(() => {
if (obj.candidate) {
pc1.addIceCandidate(obj.candidate).catch(failed);
}
});
};
Turns out promises can be used to queue function-calls. Calling then()
multiple times on the same promise queues functions up to be executed in
order later (or right away if the promise has already been resolved).
This made it easy to subjugate addIceCandidate's timing-needs.
So there you have it. Three uses of promises in the same API. I also
enjoy that there is one line of error-handling in the whole thing.
Feel free to have a look at the full test or take it for a spin:
Comments welcome.
[1] https://bug1033885.bugzilla.mozilla.org/attachment.cgi?id=8492552
.: Jan-Ivar :.
Received on Saturday, 20 September 2014 05:55:08 UTC