- From: Harald Alvestrand <harald@alvestrand.no>
- Date: Sat, 09 Nov 2013 22:34:18 +0100
- To: public-media-capture@w3.org
On 11/09/2013 03:55 PM, Stefan Håkansson LK wrote: > On 08/11/13 20:48, Martin Thomson wrote: >> I was asked to write this up and I've sat on this for a while, worried >> that the barrage of detail would destroy the message. There's a fair >> degree of nuance in the proposal, so I recommend reading through, >> maybe skipping the code for getUserMedia() and then we can discuss the >> various issues that you see. >> >> # Connecting Devices and Tracks >> >> The device enumeration function provided by getMediaDevices() is >> critical to this proposal. The object that is produced by >> getMediaDevices(), MediaDeviceInfo, is extended to include a way to >> open and use that source (we can entertain a name change later; it >> doesn't appear in the API explicitly, but it might be nice for a >> better handle): >> >> partial interface MediaDeviceInfo { >> MediaStreamTrack createTrack(Constraints? constraints); >> void connectTrack(MediaStreamTrack track); >> } >> >> For someone who was going to be using the sourceId constraint to >> select a source, this is really easy to use. >> >> var track = deviceInfo.createTrack({ ... constraints ... }); >> >> It gets a little harder when you don't want to choose, and for that >> purpose I'm going to propose that we retain getUserMedia >> (implementation below). >> >> The constructor of MediaStreamTrack becomes more critical to the >> process. The track that is acquired as a result of calling the >> constructor directly produces black or silence. You'll notice that >> this is intentionally synchronous; there are consequences for that, >> but I think that this is something that the browser will have to >> handle. >> >> Any user consent interactions are triggered when connectTrack() is >> called. Once an active (i.e., unmuted) device is attached to the >> track, the 'onunmuted' event is fired for that track. >> >> createTrack() is a shortcut for both creating a track and connecting it: >> >> MediaDeviceInfo.createTrack = function createTrack(constraints) { >> var track = new {Video,Audio}MediaStreamTrack(constraints); >> this.connectTrack(track); >> return track; >> }; > Let's see if I've understood correctly: > > * If you do createTrack, the UA will immediately create a track > connected to the source in question, but it will only produce > silence/blackness until the user approves its use, right? So it could be > used immediately for negotiation? > > Is that about right? > > * What is then the use of the MediaStreamTrack constructor? It has been > argued that if you just construct a track (with no info at all about an > eventual source) it can't be used for negotiation, and I can see no > other use for it? > > > * Is connectTrack supposed to give an error if the track you supply > already has a source, or is the plan to allow for changing source of a > track? > > I'm trying to understand what this proposal (which I like BTW, but if we > can get support the same functionality with fewer changes that feels > safer) buys us over the one Jan-Ivar did a long time ago [1]. Thanks Martin! I see this as a fleshed-out version of what Jan-Ivar proposed (the link you gave didn't have any actual spec language). The challenge I set Martin was to create something that did not change the syntax or semantics of getUserMedia, yet allowed getUserMedia to be implemented as a Javascript function. There are some missing code pieces (no "else" branch in the trackConnected callback, for instance), but overall, I think it's close. One property this has is that the sequence of entries in "devices" controls the selection of device; in the original constraint-based selection algorithm, the device that satisfied the longest list of optional constraints would "win". Perhaps we should think of adding a "rankOnConstraints" function to deviceInfo? > > > > [1] > http://lists.w3.org/Archives/Public/public-media-capture/2013Sep/0080.html > >> And that's it. >> >> The following code demonstrates how this can be used to replicate the >> behaviour of getUserMedia. It uses createTrack(). >> >> -- >> >> navigator.getUserMedia = function getUserMedia(constraints, >> successCb, failureCb) { >> // error checking omitted >> if (constraints.video) { >> getTrack("video", constraints.video, trackConnected, trackFailure); >> } >> if (constraints.audio) { >> getTrack("audio", constraints.audio, trackConnected, trackFailure); >> } >> >> var firstTrack; >> function trackConnected(track) { >> if (firstTrack || !constraints.video || !constraints.audio) { >> successCb(new MediaStream([firstTrack, track])); >> } >> } >> >> var failedAlready; >> function trackFailure(e) { >> if (!failedAlready) { >> failedAlready = true; >> failureCb(e); >> } >> } >> }; >> >> function getTrack(type, constraints, successCb, failureCb) { >> var devices = navigator.getMediaDevices().filter(ofType(type)); >> >> function stopMonitoring(track) { >> track.removeEventListener('unmute', connected); // overly cautious here >> track.removeEventListener('overconstrained', tryDevice); >> } >> >> function tryDevice(e) { >> if (e) { >> if (timeout) { >> window.clearTimeout(timeout); >> } >> stopMonitoring(e.target); >> e.target.stop(); >> } >> >> var dev = devices.shift(); // pick the next one >> if (!dev) { >> failureCb(new Error('overconstrained')); // use real thing >> } >> var track = dev.openTrack(typeof constraints === 'object' ? >> constraints : undefined); >> track.addEventListener('unmute', connected); >> track.addEventListener('overconstrained', tryDevice); >> >> var timeout = window.setTimeout(tryDevice, 1000); >> } >> >> function connected(e) { >> stopMonitoring(e.target); >> successCb(e.target); >> } >> } >> >> function ofType(t) { >> return function(x) { >> return x.type == "video"; >> }; >> } >> >> -- >> >> Please excuse the inevitable bugs and syntax errors; obviously I can't >> compile or run this and I didn't bother linting it. >> >> Obviously, this isn't going to be how a browser would really implement >> this. This results in the camera going on all cameras in turn, which >> is not ideal. It might also find a device that meets the provided >> contraints but is suboptimal. Another problem is that this requires a >> timeout in case a muted device is selected because we don't >> distinguish between muted and no user consent (intentionally). A >> browser can, of course, use the extra knowledge it has about sources >> in order to implement these functions. >> >> Names are, of course, negotiable, as is every other aspect of this. >> For instance, I was considering the use of an overload on >> "connectTrack", but the difference in method signatures seemed enough >> to justify two names. >> >> > -- Surveillance is pervasive. Go Dark.
Received on Saturday, 9 November 2013 21:34:50 UTC