- From: Jan-Ivar Bruaroey <jib@mozilla.com>
- Date: Wed, 19 Mar 2014 19:50:01 -0400
- To: "public-media-capture@w3.org" <public-media-capture@w3.org>
- Message-ID: <532A2D29.10001@mozilla.com>
We can change constraints to use WebIDL again while preserving baseline functionality. Basically, we fix the syntax without changing the semantics of constraints (much): Main proposal: require ====================== dictionary Constraints { sequence<DOMString> require; // names of required constraints, if any }; dictionary MediaConstraints : Constraints { ConstrainLong width; ConstrainLong height; ConstrainDouble aspectRatio; ConstrainDouble frameRate; ... }; typedef (long or ConstrainLongRange) ConstrainLong; dictionary ConstrainLongRange { long min; long max; }; Clients may list the names of individual constraints they require. For example: var constraints = { require: ["width", "height"], width: { min: 640, max: 1280 }, height: { min: 480, max: 768 }, aspectRatio: 16/9, frameRate: 60, }; navigator.getUserMedia(constraints, success, failure); GetUserMedia fails if the required constraints are unknown, missing or unsatisfied. Here it fails if none of the sources support a resolution within the range (640 to 1280) x (480 to 768) regardless of aspect or frame-rate. There is no order by default, instead sources are ranked by how many constraints they satisfy, with the UA breaking a tie for the default choice (which end-users may ultimately override). This is the core of the proposal. Two extensions are needed to reach functional parity, but add complexity: Extension #1: prefer ==================== dictionary Constraints { sequence<DOMString> require; // names of required constraints, if any sequence<DOMString> prefer; // names of preferred constraints, if any }; Clients who prefer an order to their constraints may specify one: var constraints = { require: ["width", "height"], prefer: ["aspectRatio", "frameRate"], width: { min: 640, max: 1280 }, height: { min: 480, max: 768 }, aspectRatio: 16/9, frameRate: 60, facingMode: "user", }; navigator.getUserMedia(constraints, success, failure); Sources are eliminated by required constraints first. The remaining sources are ranked by constraints in the preferred order (e.g. aspectRatio, then frameRate, then facingMode) using a familiar algorithm [1] Since prefer is specified, the above example will rank 16:9 60hz user-facing sources highest, followed by other 16:9 60hz sources, followed by other 16:9 sources, followed by everything else. GetUserMedia will not fail if preferred constraints are missing, unknown or unsatisfied. Extension #2: ideal =================== dictionary ConstrainLongRange { long min; long max; long ideal; }; dictionary ConstrainDoubleRange { double min; double max; double ideal; }; Ideal expresses a target value within an acceptable range, with values closer to the ideal more desirable. For example, clients may use this to express preference for higher values: var constraints = { aspectRatio: 16/9, frameRate: { min: 60, max: 300, ideal: 300 }, }; navigator.getUserMedia(constraints, success, failure); Only min and max need to be satisfied to satisfy a constraint, but sources satisfied by the same range are individually ranked by their proximity to the ideal. [2] This example ranks 16/9 sources with frame-rates closest to 300hz highest, followed by gradually lower frame-rate 16:9 ones down to 60hz, followed by all other aspects 300hz and down. That's it! ========== I'd be happy to work with the Editors to incorporate this proposal if the TF likes it. .: Jan-Ivar :. --- Apendix 1: Fine print (skip!) [1] Prefer algorithm: When a prefer array is specified, ranking is determined by a (familiar) for-each-constraint source-elimination algorithm that awards points for each round. This algorithm eliminates the "sub-set less than the entire set of remaining sources" that does not satisfy a constraint (i.e. if no sources satisfy the constraint, go to next constraint, else if one or more sources satisfy the constraint, reduce sources to those and go to next constraint). The net result is the "preferred set" (the ones with most points). If, after this, there are more constraints to process (e.g. facingMode), then sources in the preferred set are individually ranked (earn more points) by how many remaining constraints they satisfy. Names already in require or earlier in prefer are ignored. [2] Ideal algorithm: For example, if three sources satisfy the frameRate constraint above, the one with the lowest frame-rate among them gets 1/3 point, the middle one gets 2/3 points and the highest frame-rate one gets one point. Appendix 2: Full WebIDL ======================= - Everything is defined in standard WebIDL. - Audio and video constraints co-exist with non-constraints like peerIdentity. - Media-types (audio, video) are inferred from known type-specific constraints. - We re-absorb Constrainable for context needed to define things concretely. - getNativeSettings() is unneeded. "ideal" resolution etc. is in getCapabilities(). dictionary Constraints { sequence<DOMString> require; // names of required constraints, if any sequence<DOMString> prefer; // names of preferred constraints, if any }; dictionary MediaConstraints : Constraints { boolean video; boolean audio; DOMString peerIdentity; ConstrainLong width; ConstrainLong height; ConstrainDouble aspectRatio; ConstrainDouble frameRate; ConstrainVideoFacingMode facingMode; ConstrainDouble volume; ConstrainLong sampleRate; ConstrainLong sampleSize; boolean echoCancelation; ConstrainDOMString sourceId; // Dictionary may be extended through gUM-specific IANA registry. }; typedef (long or ConstrainLongRange) ConstrainLong; typedef (double or ConstrainDoubleRange) ConstraintDouble; typedef (VideoFacingModeEnum or sequence<VideoFacingModeEnum>) ConstrainVideoFacingMode; typedef (DOMString or sequence<DOMString>) ConstrainDOMString; dictionary ConstrainLongRange { long min; long max; long ideal; }; dictionary ConstrainDoubleRange { double min; double max; double ideal; }; interface MediaStreamTrack : EventTarget { MediaConstraints getCapabilities(); MediaConstraints getConstraints(); MediaConstraints getSettings(); void applyConstraints(MediaConstraints constraints, VoidFunction successCallback, ConstraintErrorCallback errorCallback); attribute EventHandler onoverconstrained; readonly attribute DOMString kind; readonly attribute DOMString id; readonly attribute DOMString label; attribute boolean enabled; readonly attribute boolean muted; attribute EventHandler onmute; attribute EventHandler onunmute; readonly attribute boolean _readonly; readonly attribute boolean remote; readonly attribute MediaStreamTrackState readyState; attribute EventHandler onstarted; attribute EventHandler onended; MediaStreamTrack clone(); void stop(); };
Received on Wednesday, 19 March 2014 23:50:30 UTC