Bug 917328 - Part 1: Update PeerConnection's constraints to webidl. r=bz, r=jesup

This commit is contained in:
Jan-Ivar Bruaroey 2013-10-03 15:48:42 -04:00
parent 4e0254eb70
commit 9bcff2f410
3 changed files with 59 additions and 65 deletions

View File

@ -324,75 +324,44 @@ RTCPeerConnection.prototype = {
},
/**
* Constraints look like this:
* MediaConstraints look like this:
*
* {
* mandatory: {"OfferToReceiveAudio": true, "OfferToReceiveVideo": true },
* optional: [{"VoiceActivityDetection": true}, {"FooBar": 10}]
* }
*
* We check for basic structure of constraints and the validity of
* mandatory constraints against those we support (fail if we don't).
* Unknown optional constraints may be of any type.
* WebIDL normalizes the top structure for us, but the mandatory constraints
* member comes in as a raw object so we can detect unknown constraints.
* We compare its members against ones we support, and fail if not found.
*/
_mustValidateConstraints: function(constraints, errorMsg) {
function isObject(obj) {
return obj && (typeof obj === "object");
}
function isArraylike(obj) {
return isObject(obj) && ("length" in obj);
}
const SUPPORTED_CONSTRAINTS = {
OfferToReceiveAudio:1,
OfferToReceiveVideo:1,
MozDontOfferDataChannel:1
};
const OTHER_KNOWN_CONSTRAINTS = {
VoiceActivityDetection:1,
IceTransports:1,
RequestIdentity:1
};
// Parse-aid: Testing for pilot error of missing outer block avoids
// otherwise silent no-op since both mandatory and optional are optional
if (!isObject(constraints) || Array.isArray(constraints)) {
throw new this._win.DOMError("", errorMsg);
}
if (constraints.mandatory) {
// Testing for pilot error of using [] on mandatory here throws nicer msg
// (arrays would throw in loop below regardless but with more cryptic msg)
if (!isObject(constraints.mandatory) || Array.isArray(constraints.mandatory)) {
throw new this._win.DOMError("",
errorMsg + " - malformed mandatory constraints");
let supported;
try {
// Passing the raw constraints.mandatory here validates its structure
supported = this._observer.getSupportedConstraints(constraints.mandatory);
} catch (e) {
throw new this._win.DOMError("", errorMsg + " - " + e.message);
}
for (let constraint in constraints.mandatory) {
if (!(constraint in SUPPORTED_CONSTRAINTS) &&
constraints.mandatory.hasOwnProperty(constraint)) {
throw new this._win.DOMError("", errorMsg + " - " +
((constraint in OTHER_KNOWN_CONSTRAINTS)? "unsupported" : "unknown") +
" mandatory constraint: " + constraint);
for (let constraint of Object.keys(constraints.mandatory)) {
if (!(constraint in supported)) {
throw new this._win.DOMError("",
errorMsg + " - unsupported mandatory constraint: " + constraint);
}
}
}
if (constraints.optional) {
if (!isArraylike(constraints.optional)) {
throw new this._win.DOMError("",
errorMsg + " - malformed optional constraint array");
}
let len = constraints.optional.length;
for (let i = 0; i < len; i += 1) {
if (!isObject(constraints.optional[i])) {
throw new this._win.DOMError("", errorMsg +
" - malformed optional constraint: " + constraints.optional[i]);
}
for (let i = 0; i < len; i++) {
let constraints_per_entry = 0;
for (let constraint in constraints.optional[i]) {
if (constraints.optional[i].hasOwnProperty(constraint)) {
if (constraints_per_entry) {
throw new this._win.DOMError("", errorMsg +
" - optional constraint must be single key/value pair");
}
constraints_per_entry += 1;
for (let constraint in Object.keys(constraints.optional[i])) {
if (constraints_per_entry) {
throw new this._win.DOMError("", errorMsg +
" - optional constraint must be single key/value pair");
}
constraints_per_entry += 1;
}
}
}
@ -1106,6 +1075,14 @@ PeerConnectionObserver.prototype = {
notifyClosedConnection: function() {
this.dispatchEvent(new this._dompc._win.Event("closedconnection"));
},
getSupportedConstraints: function(dict) {
// TODO: Once Bug 917328 makes this a webidl object, we just return our arg
// return dict;
return { "OfferToReceiveAudio":true,
"OfferToReceiveVideo":true,
"MozDontOfferDataChannel":true };
}
};

View File

@ -27,15 +27,9 @@
try { pconnect.createOffer(step1, failed, 1); } catch (e) { exception = e; }
ok(exception, "createOffer(step1, failed, 1) throws");
exception = null;
try { pconnect.createOffer(step1, failed, []); } catch (e) { exception = e; }
ok(exception, "createOffer(step1, failed, []) throws");
exception = null;
try { pconnects.createOffer(step1, failed, {}); } catch (e) { exception = e; }
ok(!exception, "createOffer(step1, failed, {}) succeeds");
exception = null;
try { pconnect.createOffer(step1, failed, { mandatory: [] }); } catch (e) { exception = e; }
ok(exception, "createOffer(step1, failed, { mandatory: [] }) throws");
exception = null;
try {
pconnect.createOffer(step1, failed, { mandatory: { FooBar: true } });
} catch (e) {
@ -44,9 +38,6 @@
}
ok(exception, "createOffer(step1, failed, { mandatory: { FooBar: true } }) throws");
exception = null;
try { pconnect.createOffer(step1, failed, { optional: {} }); } catch (e) { exception = e; }
ok(exception, "createOffer(step1, failed, { optional: {} }) throws");
exception = null;
try { pconnects.createOffer(step1, failed, { optional: [] }); } catch (e) { exception = e; }
ok(!exception, "createOffer(step1, failed, { optional: [] }) succeeds");
exception = null;

View File

@ -51,6 +51,32 @@ dictionary RTCDataChannelInit {
unsigned short stream; // now id
};
// Misnomer dictionaries housing PeerConnection-specific constraints.
//
// Important! Do not ever add members that might need tracing (e.g. object)
// to MediaConstraintSet or any dictionary marked XxxInternal here
dictionary MediaConstraintSet {
boolean OfferToReceiveAudio;
boolean OfferToReceiveVideo;
boolean MozDontOfferDataChannel;
};
// MediaConstraint = single-property-subset of MediaConstraintSet
// Implemented as full set. Test Object.keys(pair).length == 1
// typedef MediaConstraintSet MediaConstraint; // TODO: Bug 913053
dictionary MediaConstraints {
object mandatory; // so we can see unknown + unsupported constraints
sequence<MediaConstraintSet> _optional; // a.k.a. MediaConstraint
};
dictionary MediaConstraintsInternal {
MediaConstraintSet mandatory; // holds only supported constraints
sequence<MediaConstraintSet> _optional; // a.k.a. MediaConstraint
};
interface RTCDataChannel;
[Pref="media.peerconnection.enabled",
@ -61,10 +87,10 @@ interface RTCDataChannel;
interface mozRTCPeerConnection : EventTarget {
void createOffer (RTCSessionDescriptionCallback successCallback,
RTCPeerConnectionErrorCallback? failureCallback, // for apprtc
optional object? constraints);
optional MediaConstraints constraints);
void createAnswer (RTCSessionDescriptionCallback successCallback,
RTCPeerConnectionErrorCallback? failureCallback, // for apprtc
optional object? constraints);
optional MediaConstraints constraints);
void setLocalDescription (mozRTCSessionDescription description,
optional VoidFunction successCallback,
optional RTCPeerConnectionErrorCallback failureCallback);
@ -75,7 +101,7 @@ interface mozRTCPeerConnection : EventTarget {
readonly attribute mozRTCSessionDescription? remoteDescription;
readonly attribute RTCSignalingState signalingState;
void updateIce (optional RTCConfiguration configuration,
optional object? constraints);
optional MediaConstraints constraints);
void addIceCandidate (mozRTCIceCandidate candidate,
optional VoidFunction successCallback,
optional RTCPeerConnectionErrorCallback failureCallback);
@ -84,7 +110,7 @@ interface mozRTCPeerConnection : EventTarget {
sequence<MediaStream> getLocalStreams ();
sequence<MediaStream> getRemoteStreams ();
MediaStream? getStreamById (DOMString streamId);
void addStream (MediaStream stream, optional object? constraints);
void addStream (MediaStream stream, optional MediaConstraints constraints);
void removeStream (MediaStream stream);
void close ();
attribute EventHandler onnegotiationneeded;