mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1181896 - make gUM fail w/OverconstrainedError and candidate argument r=jesup
This commit is contained in:
parent
1fedf527e6
commit
6dccc3ae57
@ -949,10 +949,26 @@ GetSources(MediaEngine *engine, dom::MediaSourceEnum aSrcType,
|
||||
}
|
||||
}
|
||||
|
||||
template<class DeviceType>
|
||||
static bool
|
||||
AreUnfitSettings(const MediaTrackConstraints &aConstraints,
|
||||
nsTArray<nsRefPtr<DeviceType>>& aSources)
|
||||
{
|
||||
nsTArray<const MediaTrackConstraintSet*> aggregateConstraints;
|
||||
aggregateConstraints.AppendElement(&aConstraints);
|
||||
|
||||
for (auto& source : aSources) {
|
||||
if (source->GetBestFitnessDistance(aggregateConstraints) != UINT32_MAX) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Apply constrains to a supplied list of sources (removes items from the list)
|
||||
|
||||
template<class DeviceType>
|
||||
static void
|
||||
static const char*
|
||||
SelectSettings(const MediaTrackConstraints &aConstraints,
|
||||
nsTArray<nsRefPtr<DeviceType>>& aSources)
|
||||
{
|
||||
@ -963,6 +979,7 @@ SelectSettings(const MediaTrackConstraints &aConstraints,
|
||||
// Stack constraintSets that pass, starting with the required one, because the
|
||||
// whole stack must be re-satisfied each time a capability-set is ruled out
|
||||
// (this avoids storing state or pushing algorithm into the lower-level code).
|
||||
nsTArray<nsRefPtr<DeviceType>> unsatisfactory;
|
||||
nsTArray<const MediaTrackConstraintSet*> aggregateConstraints;
|
||||
aggregateConstraints.AppendElement(&c);
|
||||
|
||||
@ -971,6 +988,7 @@ SelectSettings(const MediaTrackConstraints &aConstraints,
|
||||
for (uint32_t i = 0; i < aSources.Length();) {
|
||||
uint32_t distance = aSources[i]->GetBestFitnessDistance(aggregateConstraints);
|
||||
if (distance == UINT32_MAX) {
|
||||
unsatisfactory.AppendElement(aSources[i]);
|
||||
aSources.RemoveElementAt(i);
|
||||
} else {
|
||||
ordered.insert(std::pair<uint32_t, nsRefPtr<DeviceType>>(distance,
|
||||
@ -978,6 +996,49 @@ SelectSettings(const MediaTrackConstraints &aConstraints,
|
||||
++i;
|
||||
}
|
||||
}
|
||||
if (!aSources.Length()) {
|
||||
// None selected. The spec says to report a constraint that satisfies NONE
|
||||
// of the sources. Unfortunately, this is a bit laborious to find out, and
|
||||
// requires updating as new constraints are added!
|
||||
|
||||
if (c.mDeviceId.IsConstrainDOMStringParameters()) {
|
||||
MediaTrackConstraints fresh;
|
||||
fresh.mDeviceId = c.mDeviceId;
|
||||
if (AreUnfitSettings(fresh, unsatisfactory)) {
|
||||
return "deviceId";
|
||||
}
|
||||
}
|
||||
if (c.mWidth.IsConstrainLongRange()) {
|
||||
MediaTrackConstraints fresh;
|
||||
fresh.mWidth = c.mWidth;
|
||||
if (AreUnfitSettings(fresh, unsatisfactory)) {
|
||||
return "width";
|
||||
}
|
||||
}
|
||||
if (c.mHeight.IsConstrainLongRange()) {
|
||||
MediaTrackConstraints fresh;
|
||||
fresh.mHeight = c.mHeight;
|
||||
if (AreUnfitSettings(fresh, unsatisfactory)) {
|
||||
return "height";
|
||||
}
|
||||
}
|
||||
if (c.mFrameRate.IsConstrainDoubleRange()) {
|
||||
MediaTrackConstraints fresh;
|
||||
fresh.mFrameRate = c.mFrameRate;
|
||||
if (AreUnfitSettings(fresh, unsatisfactory)) {
|
||||
return "frameRate";
|
||||
}
|
||||
}
|
||||
if (c.mFacingMode.IsConstrainDOMStringParameters()) {
|
||||
MediaTrackConstraints fresh;
|
||||
fresh.mFacingMode = c.mFacingMode;
|
||||
if (AreUnfitSettings(fresh, unsatisfactory)) {
|
||||
return "facingMode";
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
// Order devices by shortest distance
|
||||
for (auto& ordinal : ordered) {
|
||||
aSources.RemoveElement(ordinal.second);
|
||||
@ -1006,9 +1067,10 @@ SelectSettings(const MediaTrackConstraints &aConstraints,
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bool
|
||||
static const char*
|
||||
SelectSettings(MediaStreamConstraints &aConstraints,
|
||||
nsTArray<nsRefPtr<MediaDevice>>& aSources)
|
||||
{
|
||||
@ -1016,7 +1078,6 @@ SelectSettings(MediaStreamConstraints &aConstraints,
|
||||
// a candidate set is overconstrained (zero members), we must split up the
|
||||
// list into videos and audios, and put it back together again at the end.
|
||||
|
||||
bool overconstrained = false;
|
||||
nsTArray<nsRefPtr<VideoDevice>> videos;
|
||||
nsTArray<nsRefPtr<AudioDevice>> audios;
|
||||
|
||||
@ -1032,25 +1093,21 @@ SelectSettings(MediaStreamConstraints &aConstraints,
|
||||
aSources.Clear();
|
||||
MOZ_ASSERT(!aSources.Length());
|
||||
|
||||
const char* badConstraint = nullptr;
|
||||
|
||||
if (IsOn(aConstraints.mVideo)) {
|
||||
SelectSettings(GetInvariant(aConstraints.mVideo), videos);
|
||||
if (!videos.Length()) {
|
||||
overconstrained = true;
|
||||
}
|
||||
badConstraint = SelectSettings(GetInvariant(aConstraints.mVideo), videos);
|
||||
for (auto& video : videos) {
|
||||
aSources.AppendElement(video);
|
||||
}
|
||||
}
|
||||
if (IsOn(aConstraints.mAudio)) {
|
||||
SelectSettings(GetInvariant(aConstraints.mAudio), audios);
|
||||
if (!audios.Length()) {
|
||||
overconstrained = true;
|
||||
}
|
||||
if (audios.Length() && IsOn(aConstraints.mAudio)) {
|
||||
badConstraint = SelectSettings(GetInvariant(aConstraints.mAudio), audios);
|
||||
for (auto& audio : audios) {
|
||||
aSources.AppendElement(audio);
|
||||
}
|
||||
}
|
||||
return !overconstrained;
|
||||
return badConstraint;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1697,7 +1754,7 @@ MediaManager::GetUserMedia(nsPIDOMWindow* aWindow,
|
||||
auto& vc = c.mVideo.GetAsMediaTrackConstraints();
|
||||
videoType = StringToEnum(dom::MediaSourceEnumValues::strings,
|
||||
vc.mMediaSource,
|
||||
videoType);
|
||||
dom::MediaSourceEnum::Other);
|
||||
switch (videoType) {
|
||||
case dom::MediaSourceEnum::Camera:
|
||||
break;
|
||||
@ -1740,7 +1797,10 @@ MediaManager::GetUserMedia(nsPIDOMWindow* aWindow,
|
||||
case dom::MediaSourceEnum::Other:
|
||||
default: {
|
||||
nsRefPtr<MediaStreamError> error =
|
||||
new MediaStreamError(aWindow, NS_LITERAL_STRING("NotFoundError"));
|
||||
new MediaStreamError(aWindow,
|
||||
NS_LITERAL_STRING("OverconstrainedError"),
|
||||
NS_LITERAL_STRING(""),
|
||||
NS_LITERAL_STRING("mediaSource"));
|
||||
onFailure->OnError(error);
|
||||
return NS_OK;
|
||||
}
|
||||
@ -1785,7 +1845,7 @@ MediaManager::GetUserMedia(nsPIDOMWindow* aWindow,
|
||||
auto& ac = c.mAudio.GetAsMediaTrackConstraints();
|
||||
audioType = StringToEnum(dom::MediaSourceEnumValues::strings,
|
||||
ac.mMediaSource,
|
||||
audioType);
|
||||
dom::MediaSourceEnum::Other);
|
||||
// Work around WebIDL default since spec uses same dictionary w/audio & video.
|
||||
if (audioType == dom::MediaSourceEnum::Camera) {
|
||||
audioType = dom::MediaSourceEnum::Microphone;
|
||||
@ -1812,7 +1872,10 @@ MediaManager::GetUserMedia(nsPIDOMWindow* aWindow,
|
||||
case dom::MediaSourceEnum::Other:
|
||||
default: {
|
||||
nsRefPtr<MediaStreamError> error =
|
||||
new MediaStreamError(aWindow, NS_LITERAL_STRING("NotFoundError"));
|
||||
new MediaStreamError(aWindow,
|
||||
NS_LITERAL_STRING("OverconstrainedError"),
|
||||
NS_LITERAL_STRING(""),
|
||||
NS_LITERAL_STRING("mediaSource"));
|
||||
onFailure->OnError(error);
|
||||
return NS_OK;
|
||||
}
|
||||
@ -1905,8 +1968,19 @@ MediaManager::GetUserMedia(nsPIDOMWindow* aWindow,
|
||||
}
|
||||
|
||||
// Apply any constraints. This modifies the list.
|
||||
|
||||
if (!SelectSettings(c, *devices)) {
|
||||
const char* badConstraint = SelectSettings(c, *devices);
|
||||
if (badConstraint) {
|
||||
nsString constraint;
|
||||
constraint.AssignASCII(badConstraint);
|
||||
nsRefPtr<MediaStreamError> error =
|
||||
new MediaStreamError(window,
|
||||
NS_LITERAL_STRING("OverconstrainedError"),
|
||||
NS_LITERAL_STRING(""),
|
||||
constraint);
|
||||
onFailure->OnError(error);
|
||||
return;
|
||||
}
|
||||
if (!devices->Length()) {
|
||||
nsRefPtr<MediaStreamError> error =
|
||||
new MediaStreamError(window, NS_LITERAL_STRING("NotFoundError"));
|
||||
onFailure->OnError(error);
|
||||
|
@ -28,8 +28,9 @@ BaseMediaMgrError::BaseMediaMgrError(const nsAString& aName,
|
||||
} else if (mName.EqualsLiteral("InternalError")) {
|
||||
mMessage.AssignLiteral("Internal error.");
|
||||
} else if (mName.EqualsLiteral("NotSupportedError")) {
|
||||
mMessage.AssignLiteral("Constraints with no audio or video in it are not "
|
||||
"supported");
|
||||
mMessage.AssignLiteral("The operation is not supported.");
|
||||
} else if (mName.EqualsLiteral("OverconstrainedError")) {
|
||||
mMessage.AssignLiteral("Constraints could be not satisfied.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,9 +16,13 @@ function mustSucceed(msg, f) {
|
||||
e => is(e.name, null, msg + " must succeed: " + e.message));
|
||||
}
|
||||
|
||||
function mustFailWith(msg, reason, f) {
|
||||
return f().then(() => ok(false, msg + " must fail"),
|
||||
e => is(e.name, reason, msg + " must fail: " + e.message));
|
||||
function mustFailWith(msg, reason, constraint, f) {
|
||||
return f().then(() => ok(false, msg + " must fail"), e => {
|
||||
is(e.name, reason, msg + " must fail: " + e.message);
|
||||
if (constraint) {
|
||||
is(e.constraint, constraint, msg + " must fail w/correct constraint.");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var pushPrefs = (...p) => new Promise(r => SpecialPowers.pushPrefEnv({set: p}, r));
|
||||
@ -49,13 +53,15 @@ runTest(() =>
|
||||
audio: { deviceId: "unknown9qHr8B0JIbcHlbl9xR+jMbZZ8WyoPfpCXPfc=" },
|
||||
fake: true,
|
||||
})))
|
||||
.then(() => mustFailWith("unknown exact deviceId on video", "NotFoundError",
|
||||
() => navigator.mediaDevices.getUserMedia({
|
||||
.then(() => mustFailWith("unknown exact deviceId on video",
|
||||
"OverconstrainedError", "deviceId",
|
||||
() => navigator.mediaDevices.getUserMedia({
|
||||
video: { deviceId: { exact: "unknown9qHr8B0JIbcHlbl9xR+jMbZZ8WyoPfpCXPfc=" } },
|
||||
fake: true,
|
||||
})))
|
||||
.then(() => mustFailWith("unknown exact deviceId on audio", "NotFoundError",
|
||||
() => navigator.mediaDevices.getUserMedia({
|
||||
.then(() => mustFailWith("unknown exact deviceId on audio",
|
||||
"OverconstrainedError", "deviceId",
|
||||
() => navigator.mediaDevices.getUserMedia({
|
||||
audio: { deviceId: { exact: "unknown9qHr8B0JIbcHlbl9xR+jMbZZ8WyoPfpCXPfc=" } },
|
||||
fake: true,
|
||||
})))
|
||||
|
@ -39,9 +39,14 @@ var tests = [
|
||||
{ message: "browser screensharing requires permission",
|
||||
constraints: { video: { mediaSource: 'browser' } },
|
||||
error: "PermissionDeniedError" },
|
||||
{ message: "unknown mediaSource fails",
|
||||
{ message: "unknown mediaSource in video fails",
|
||||
constraints: { video: { mediaSource: 'uncle' } },
|
||||
error: "NotFoundError" },
|
||||
error: "OverconstrainedError",
|
||||
constraint: "mediaSource" },
|
||||
{ message: "unknown mediaSource in audio fails",
|
||||
constraints: { audio: { mediaSource: 'uncle' } },
|
||||
error: "OverconstrainedError",
|
||||
constraint: "mediaSource" },
|
||||
{ message: "emtpy constraint fails",
|
||||
constraints: { },
|
||||
error: "NotSupportedError" },
|
||||
@ -106,8 +111,13 @@ runTest(function() {
|
||||
|
||||
return tests.reduce((p, test) =>
|
||||
p.then(() => navigator.mediaDevices.getUserMedia(test.constraints))
|
||||
.then(() => is(null, test.error, test.message),
|
||||
e => is(e.name, test.error, test.message + ": " + e.message)), p);
|
||||
.then(() => is(null, test.error, test.message), e => {
|
||||
is(e.name, test.error, test.message + ": " + e.message);
|
||||
if (test.constraint) {
|
||||
is(e.constraint, test.constraint,
|
||||
test.message + " w/correct constraint.");
|
||||
}
|
||||
}), p);
|
||||
});
|
||||
|
||||
</script>
|
||||
|
Loading…
Reference in New Issue
Block a user