Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/media/webrtc/MediaTrackConstraints.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2
 * This Source Code Form is subject to the terms of the Mozilla Public
3
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
4
 * You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6
#include "MediaTrackConstraints.h"
7
8
#include <limits>
9
#include <algorithm>
10
#include <iterator>
11
12
#include "MediaEngineSource.h"
13
#include "nsIScriptError.h"
14
#include "mozilla/dom/MediaStreamTrackBinding.h"
15
#include "mozilla/MediaManager.h"
16
17
namespace mozilla {
18
19
using dom::ConstrainBooleanParameters;
20
using dom::OwningLongOrConstrainLongRange;
21
22
template<class ValueType>
23
template<class ConstrainRange>
24
void
25
NormalizedConstraintSet::Range<ValueType>::SetFrom(const ConstrainRange& aOther)
26
0
{
27
0
  if (aOther.mIdeal.WasPassed()) {
28
0
    mIdeal.emplace(aOther.mIdeal.Value());
29
0
  }
30
0
  if (aOther.mExact.WasPassed()) {
31
0
    mMin = aOther.mExact.Value();
32
0
    mMax = aOther.mExact.Value();
33
0
  } else {
34
0
    if (aOther.mMin.WasPassed()) {
35
0
      mMin = aOther.mMin.Value();
36
0
    }
37
0
    if (aOther.mMax.WasPassed()) {
38
0
      mMax = aOther.mMax.Value();
39
0
    }
40
0
  }
41
0
}
Unexecuted instantiation: void mozilla::NormalizedConstraintSet::Range<int>::SetFrom<mozilla::dom::ConstrainLongRange>(mozilla::dom::ConstrainLongRange const&)
Unexecuted instantiation: void mozilla::NormalizedConstraintSet::Range<double>::SetFrom<mozilla::dom::ConstrainDoubleRange>(mozilla::dom::ConstrainDoubleRange const&)
42
43
// The Range code works surprisingly well for bool, except when averaging ideals.
44
template<>
45
bool
46
0
NormalizedConstraintSet::Range<bool>::Merge(const Range& aOther) {
47
0
  if (!Intersects(aOther)) {
48
0
    return false;
49
0
  }
50
0
  Intersect(aOther);
51
0
52
0
  // To avoid "unsafe use of type 'bool'", we keep counter in mMergeDenominator
53
0
  uint32_t counter = mMergeDenominator >> 16;
54
0
  uint32_t denominator = mMergeDenominator & 0xffff;
55
0
56
0
  if (aOther.mIdeal.isSome()) {
57
0
    if (mIdeal.isNothing()) {
58
0
      mIdeal.emplace(aOther.Get(false));
59
0
      counter = aOther.Get(false);
60
0
      denominator = 1;
61
0
    } else {
62
0
      if (!denominator) {
63
0
        counter = Get(false);
64
0
        denominator = 1;
65
0
      }
66
0
      counter += aOther.Get(false);
67
0
      denominator++;
68
0
    }
69
0
  }
70
0
  mMergeDenominator = ((counter & 0xffff) << 16) + (denominator & 0xffff);
71
0
  return true;
72
0
}
73
74
template<>
75
void
76
NormalizedConstraintSet::Range<bool>::FinalizeMerge()
77
0
{
78
0
  if (mMergeDenominator) {
79
0
    uint32_t counter = mMergeDenominator >> 16;
80
0
    uint32_t denominator = mMergeDenominator & 0xffff;
81
0
82
0
    *mIdeal = !!(counter / denominator);
83
0
    mMergeDenominator = 0;
84
0
  }
85
0
}
86
87
NormalizedConstraintSet::LongRange::LongRange(
88
    LongPtrType aMemberPtr,
89
    const char* aName,
90
    const dom::OwningLongOrConstrainLongRange& aOther,
91
    bool advanced,
92
    nsTArray<MemberPtrType>* aList)
93
: Range<int32_t>((MemberPtrType)aMemberPtr, aName,
94
                 1 + INT32_MIN, INT32_MAX, // +1 avoids Windows compiler bug
95
                 aList)
96
0
{
97
0
  if (aOther.IsLong()) {
98
0
    if (advanced) {
99
0
      mMin = mMax = aOther.GetAsLong();
100
0
    } else {
101
0
      mIdeal.emplace(aOther.GetAsLong());
102
0
    }
103
0
  } else {
104
0
    SetFrom(aOther.GetAsConstrainLongRange());
105
0
  }
106
0
}
107
108
NormalizedConstraintSet::LongLongRange::LongLongRange(
109
    LongLongPtrType aMemberPtr,
110
    const char* aName,
111
    const long long& aOther,
112
    nsTArray<MemberPtrType>* aList)
113
: Range<int64_t>((MemberPtrType)aMemberPtr, aName,
114
                 1 + INT64_MIN, INT64_MAX, // +1 avoids Windows compiler bug
115
                 aList)
116
0
{
117
0
  mIdeal.emplace(aOther);
118
0
}
119
120
NormalizedConstraintSet::DoubleRange::DoubleRange(
121
    DoublePtrType aMemberPtr,
122
    const char* aName,
123
    const dom::OwningDoubleOrConstrainDoubleRange& aOther, bool advanced,
124
    nsTArray<MemberPtrType>* aList)
125
: Range<double>((MemberPtrType)aMemberPtr, aName,
126
                -std::numeric_limits<double>::infinity(),
127
                std::numeric_limits<double>::infinity(), aList)
128
0
{
129
0
  if (aOther.IsDouble()) {
130
0
    if (advanced) {
131
0
      mMin = mMax = aOther.GetAsDouble();
132
0
    } else {
133
0
      mIdeal.emplace(aOther.GetAsDouble());
134
0
    }
135
0
  } else {
136
0
    SetFrom(aOther.GetAsConstrainDoubleRange());
137
0
  }
138
0
}
139
140
NormalizedConstraintSet::BooleanRange::BooleanRange(
141
    BooleanPtrType aMemberPtr,
142
    const char* aName,
143
    const dom::OwningBooleanOrConstrainBooleanParameters& aOther,
144
    bool advanced,
145
    nsTArray<MemberPtrType>* aList)
146
: Range<bool>((MemberPtrType)aMemberPtr, aName, false, true, aList)
147
0
{
148
0
  if (aOther.IsBoolean()) {
149
0
    if (advanced) {
150
0
      mMin = mMax = aOther.GetAsBoolean();
151
0
    } else {
152
0
      mIdeal.emplace(aOther.GetAsBoolean());
153
0
    }
154
0
  } else {
155
0
    const dom::ConstrainBooleanParameters& r = aOther.GetAsConstrainBooleanParameters();
156
0
    if (r.mIdeal.WasPassed()) {
157
0
      mIdeal.emplace(r.mIdeal.Value());
158
0
    }
159
0
    if (r.mExact.WasPassed()) {
160
0
      mMin = r.mExact.Value();
161
0
      mMax = r.mExact.Value();
162
0
    }
163
0
  }
164
0
}
165
166
NormalizedConstraintSet::StringRange::StringRange(
167
    StringPtrType aMemberPtr,
168
    const char* aName,
169
    const dom::OwningStringOrStringSequenceOrConstrainDOMStringParameters& aOther,
170
    bool advanced,
171
    nsTArray<MemberPtrType>* aList)
172
  : BaseRange((MemberPtrType)aMemberPtr, aName, aList)
173
0
{
174
0
  if (aOther.IsString()) {
175
0
    if (advanced) {
176
0
      mExact.insert(aOther.GetAsString());
177
0
    } else {
178
0
      mIdeal.insert(aOther.GetAsString());
179
0
    }
180
0
  } else if (aOther.IsStringSequence()) {
181
0
    if (advanced) {
182
0
      mExact.clear();
183
0
      for (auto& str : aOther.GetAsStringSequence()) {
184
0
        mExact.insert(str);
185
0
      }
186
0
    } else {
187
0
      mIdeal.clear();
188
0
      for (auto& str : aOther.GetAsStringSequence()) {
189
0
        mIdeal.insert(str);
190
0
      }
191
0
    }
192
0
  } else {
193
0
    SetFrom(aOther.GetAsConstrainDOMStringParameters());
194
0
  }
195
0
}
196
197
void
198
NormalizedConstraintSet::StringRange::SetFrom(
199
    const dom::ConstrainDOMStringParameters& aOther)
200
0
{
201
0
  if (aOther.mIdeal.WasPassed()) {
202
0
    mIdeal.clear();
203
0
    if (aOther.mIdeal.Value().IsString()) {
204
0
      mIdeal.insert(aOther.mIdeal.Value().GetAsString());
205
0
    } else {
206
0
      for (auto& str : aOther.mIdeal.Value().GetAsStringSequence()) {
207
0
        mIdeal.insert(str);
208
0
      }
209
0
    }
210
0
  }
211
0
  if (aOther.mExact.WasPassed()) {
212
0
    mExact.clear();
213
0
    if (aOther.mExact.Value().IsString()) {
214
0
      mExact.insert(aOther.mExact.Value().GetAsString());
215
0
    } else {
216
0
      for (auto& str : aOther.mExact.Value().GetAsStringSequence()) {
217
0
        mIdeal.insert(str);
218
0
      }
219
0
    }
220
0
  }
221
0
}
222
223
auto
224
NormalizedConstraintSet::StringRange::Clamp(const ValueType& n) const -> ValueType
225
0
{
226
0
  if (mExact.empty()) {
227
0
    return n;
228
0
  }
229
0
  ValueType result;
230
0
  for (auto& entry : n) {
231
0
    if (mExact.find(entry) != mExact.end()) {
232
0
      result.insert(entry);
233
0
    }
234
0
  }
235
0
  return result;
236
0
}
237
238
bool
239
NormalizedConstraintSet::StringRange::Intersects(const StringRange& aOther) const
240
0
{
241
0
  if (mExact.empty() || aOther.mExact.empty()) {
242
0
    return true;
243
0
  }
244
0
245
0
  ValueType intersection;
246
0
  set_intersection(mExact.begin(), mExact.end(),
247
0
                   aOther.mExact.begin(), aOther.mExact.end(),
248
0
                   std::inserter(intersection, intersection.begin()));
249
0
  return !intersection.empty();
250
0
}
251
252
void
253
NormalizedConstraintSet::StringRange::Intersect(const StringRange& aOther)
254
0
{
255
0
  if (aOther.mExact.empty()) {
256
0
    return;
257
0
  }
258
0
259
0
  ValueType intersection;
260
0
  set_intersection(mExact.begin(), mExact.end(),
261
0
                   aOther.mExact.begin(), aOther.mExact.end(),
262
0
                   std::inserter(intersection, intersection.begin()));
263
0
  mExact = intersection;
264
0
}
265
266
bool
267
NormalizedConstraintSet::StringRange::Merge(const StringRange& aOther)
268
0
{
269
0
  if (!Intersects(aOther)) {
270
0
    return false;
271
0
  }
272
0
  Intersect(aOther);
273
0
274
0
  ValueType unioned;
275
0
  set_union(mIdeal.begin(), mIdeal.end(),
276
0
            aOther.mIdeal.begin(), aOther.mIdeal.end(),
277
0
            std::inserter(unioned, unioned.begin()));
278
0
  mIdeal = unioned;
279
0
  return true;
280
0
}
281
282
NormalizedConstraints::NormalizedConstraints(
283
    const dom::MediaTrackConstraints& aOther,
284
    nsTArray<MemberPtrType>* aList)
285
  : NormalizedConstraintSet(aOther, false, aList)
286
  , mBadConstraint(nullptr)
287
0
{
288
0
  if (aOther.mAdvanced.WasPassed()) {
289
0
    for (auto& entry : aOther.mAdvanced.Value()) {
290
0
      mAdvanced.push_back(NormalizedConstraintSet(entry, true));
291
0
    }
292
0
  }
293
0
}
294
295
// Merge constructor. Create net constraints out of merging a set of others.
296
// This is only used to resolve competing constraints from concurrent requests,
297
// something the spec doesn't cover.
298
299
NormalizedConstraints::NormalizedConstraints(
300
    const nsTArray<const NormalizedConstraints*>& aOthers)
301
  : NormalizedConstraintSet(*aOthers[0])
302
  , mBadConstraint(nullptr)
303
0
{
304
0
  for (auto& entry : aOthers[0]->mAdvanced) {
305
0
    mAdvanced.push_back(entry);
306
0
  }
307
0
308
0
  // Create a list of member pointers.
309
0
  nsTArray<MemberPtrType> list;
310
0
  NormalizedConstraints dummy(dom::MediaTrackConstraints(), &list);
311
0
312
0
  // Do intersection of all required constraints, and average of ideals,
313
0
314
0
  for (uint32_t i = 1; i < aOthers.Length(); i++) {
315
0
    auto& other = *aOthers[i];
316
0
317
0
    for (auto& memberPtr : list) {
318
0
      auto& member = this->*memberPtr;
319
0
      auto& otherMember = other.*memberPtr;
320
0
321
0
      if (!member.Merge(otherMember)) {
322
0
        mBadConstraint = member.mName;
323
0
        return;
324
0
      }
325
0
    }
326
0
327
0
    for (auto& entry : other.mAdvanced) {
328
0
      mAdvanced.push_back(entry);
329
0
    }
330
0
  }
331
0
  for (auto& memberPtr : list) {
332
0
    (this->*memberPtr).FinalizeMerge();
333
0
  }
334
0
335
0
  // ...except for resolution and frame rate where we take the highest ideal.
336
0
  // This is a bit of a hack based on the perception that people would be more
337
0
  // surprised if they were to get lower resolution than they ideally requested.
338
0
  //
339
0
  // The spec gives browsers leeway here, saying they "SHOULD use the one with
340
0
  // the smallest fitness distance", and also does not directly address the
341
0
  // problem of competing constraints at all. There is no real web interop issue
342
0
  // here since this is more about interop with other tabs on the same browser.
343
0
  //
344
0
  // We should revisit this logic once we support downscaling of resolutions and
345
0
  // decimating of frame rates, per track.
346
0
347
0
  for (auto& other : aOthers) {
348
0
    mWidth.TakeHighestIdeal(other->mWidth);
349
0
    mHeight.TakeHighestIdeal(other->mHeight);
350
0
351
0
    // Consider implicit 30 fps default in comparison of competing constraints.
352
0
    // Avoids 160x90x10 and 640x480 becoming 1024x768x10 (fitness distance flaw)
353
0
    // This pretty much locks in 30 fps or higher, except for single-tab use.
354
0
    auto frameRate = other->mFrameRate;
355
0
    if (frameRate.mIdeal.isNothing()) {
356
0
      frameRate.mIdeal.emplace(30);
357
0
    }
358
0
    mFrameRate.TakeHighestIdeal(frameRate);
359
0
  }
360
0
}
361
362
FlattenedConstraints::FlattenedConstraints(const NormalizedConstraints& aOther)
363
: NormalizedConstraintSet(aOther)
364
0
{
365
0
  for (auto& set : aOther.mAdvanced) {
366
0
    // Must only apply compatible i.e. inherently non-overconstraining sets
367
0
    // This rule is pretty much why this code is centralized here.
368
0
    if (mWidth.Intersects(set.mWidth) &&
369
0
        mHeight.Intersects(set.mHeight) &&
370
0
        mFrameRate.Intersects(set.mFrameRate)) {
371
0
      mWidth.Intersect(set.mWidth);
372
0
      mHeight.Intersect(set.mHeight);
373
0
      mFrameRate.Intersect(set.mFrameRate);
374
0
    }
375
0
    if (mEchoCancellation.Intersects(set.mEchoCancellation)) {
376
0
        mEchoCancellation.Intersect(set.mEchoCancellation);
377
0
    }
378
0
    if (mNoiseSuppression.Intersects(set.mNoiseSuppression)) {
379
0
        mNoiseSuppression.Intersect(set.mNoiseSuppression);
380
0
    }
381
0
    if (mAutoGainControl.Intersects(set.mAutoGainControl)) {
382
0
        mAutoGainControl.Intersect(set.mAutoGainControl);
383
0
    }
384
0
    if (mChannelCount.Intersects(set.mChannelCount)) {
385
0
        mChannelCount.Intersect(set.mChannelCount);
386
0
    }
387
0
  }
388
0
}
389
390
// MediaEngine helper
391
//
392
// The full algorithm for all devices. Sources that don't list capabilities
393
// need to fake it and hardcode some by populating mHardcodedCapabilities above.
394
//
395
// Fitness distance returned as integer math * 1000. Infinity = UINT32_MAX
396
397
// First, all devices have a minimum distance based on their deviceId.
398
// If you have no other constraints, use this one. Reused by all device types.
399
400
/* static */ bool
401
MediaConstraintsHelper::SomeSettingsFit(const NormalizedConstraints &aConstraints,
402
                                        const nsTArray<RefPtr<MediaDevice>>& aDevices)
403
0
{
404
0
  nsTArray<const NormalizedConstraintSet*> sets;
405
0
  sets.AppendElement(&aConstraints);
406
0
407
0
  MOZ_ASSERT(!aDevices.IsEmpty());
408
0
  for (auto& device : aDevices) {
409
0
    if (device->GetBestFitnessDistance(sets, false) != UINT32_MAX) {
410
0
      return true;
411
0
    }
412
0
  }
413
0
  return false;
414
0
}
415
416
/* static */ uint32_t
417
MediaConstraintsHelper::GetMinimumFitnessDistance(
418
    const NormalizedConstraintSet &aConstraints,
419
    const nsString& aDeviceId)
420
0
{
421
0
  return FitnessDistance(aDeviceId, aConstraints.mDeviceId);
422
0
}
423
424
template<class ValueType, class NormalizedRange>
425
/* static */ uint32_t
426
MediaConstraintsHelper::FitnessDistance(ValueType aN,
427
                                        const NormalizedRange& aRange)
428
0
{
429
0
  if (aRange.mMin > aN || aRange.mMax < aN) {
430
0
    return UINT32_MAX;
431
0
  }
432
0
  if (aN == aRange.mIdeal.valueOr(aN)) {
433
0
    return 0;
434
0
  }
435
0
  return uint32_t(ValueType((std::abs(aN - aRange.mIdeal.value()) * 1000) /
436
0
                            std::max(std::abs(aN), std::abs(aRange.mIdeal.value()))));
437
0
}
Unexecuted instantiation: unsigned int mozilla::MediaConstraintsHelper::FitnessDistance<int, mozilla::NormalizedConstraintSet::LongRange>(int, mozilla::NormalizedConstraintSet::LongRange const&)
Unexecuted instantiation: unsigned int mozilla::MediaConstraintsHelper::FitnessDistance<double, mozilla::NormalizedConstraintSet::DoubleRange>(double, mozilla::NormalizedConstraintSet::DoubleRange const&)
438
439
template<class ValueType, class NormalizedRange>
440
/* static */ uint32_t
441
MediaConstraintsHelper::FeasibilityDistance(ValueType aN,
442
                                            const NormalizedRange& aRange)
443
0
{
444
0
  if (aRange.mMin > aN) {
445
0
    return UINT32_MAX;
446
0
  }
447
0
  // We prefer larger resolution because now we support downscaling
448
0
  if (aN == aRange.mIdeal.valueOr(aN)) {
449
0
    return 0;
450
0
  }
451
0
452
0
  if (aN > aRange.mIdeal.value()) {
453
0
    return uint32_t(ValueType((std::abs(aN - aRange.mIdeal.value()) * 1000) /
454
0
      std::max(std::abs(aN), std::abs(aRange.mIdeal.value()))));
455
0
  }
456
0
457
0
  return 10000 + uint32_t(ValueType((std::abs(aN - aRange.mIdeal.value()) * 1000) /
458
0
    std::max(std::abs(aN), std::abs(aRange.mIdeal.value()))));
459
0
}
Unexecuted instantiation: unsigned int mozilla::MediaConstraintsHelper::FeasibilityDistance<int, mozilla::NormalizedConstraintSet::LongRange>(int, mozilla::NormalizedConstraintSet::LongRange const&)
Unexecuted instantiation: unsigned int mozilla::MediaConstraintsHelper::FeasibilityDistance<double, mozilla::NormalizedConstraintSet::DoubleRange>(double, mozilla::NormalizedConstraintSet::DoubleRange const&)
460
461
// Fitness distance returned as integer math * 1000. Infinity = UINT32_MAX
462
463
/* static */ uint32_t
464
MediaConstraintsHelper::FitnessDistance(
465
    nsString aN,
466
    const NormalizedConstraintSet::StringRange& aParams)
467
0
{
468
0
  if (!aParams.mExact.empty() && aParams.mExact.find(aN) == aParams.mExact.end()) {
469
0
    return UINT32_MAX;
470
0
  }
471
0
  if (!aParams.mIdeal.empty() && aParams.mIdeal.find(aN) == aParams.mIdeal.end()) {
472
0
    return 1000;
473
0
  }
474
0
  return 0;
475
0
}
476
477
/* static */ const char*
478
MediaConstraintsHelper::SelectSettings(
479
    const NormalizedConstraints& aConstraints,
480
    nsTArray<RefPtr<MediaDevice>>& aDevices,
481
    bool aIsChrome)
482
0
{
483
0
  auto& c = aConstraints;
484
0
485
0
  // First apply top-level constraints.
486
0
487
0
  // Stack constraintSets that pass, starting with the required one, because the
488
0
  // whole stack must be re-satisfied each time a capability-set is ruled out
489
0
  // (this avoids storing state or pushing algorithm into the lower-level code).
490
0
  nsTArray<RefPtr<MediaDevice>> unsatisfactory;
491
0
  nsTArray<const NormalizedConstraintSet*> aggregateConstraints;
492
0
  aggregateConstraints.AppendElement(&c);
493
0
494
0
  std::multimap<uint32_t, RefPtr<MediaDevice>> ordered;
495
0
496
0
  for (uint32_t i = 0; i < aDevices.Length();) {
497
0
    uint32_t distance =
498
0
      aDevices[i]->GetBestFitnessDistance(aggregateConstraints, aIsChrome);
499
0
    if (distance == UINT32_MAX) {
500
0
      unsatisfactory.AppendElement(std::move(aDevices[i]));
501
0
      aDevices.RemoveElementAt(i);
502
0
    } else {
503
0
      ordered.insert(std::make_pair(distance, aDevices[i]));
504
0
      ++i;
505
0
    }
506
0
  }
507
0
  if (aDevices.IsEmpty()) {
508
0
    return FindBadConstraint(c, unsatisfactory);
509
0
  }
510
0
511
0
  // Order devices by shortest distance
512
0
  for (auto& ordinal : ordered) {
513
0
    aDevices.RemoveElement(ordinal.second);
514
0
    aDevices.AppendElement(ordinal.second);
515
0
  }
516
0
517
0
  // Then apply advanced constraints.
518
0
519
0
  for (int i = 0; i < int(c.mAdvanced.size()); i++) {
520
0
    aggregateConstraints.AppendElement(&c.mAdvanced[i]);
521
0
    nsTArray<RefPtr<MediaDevice>> rejects;
522
0
    for (uint32_t j = 0; j < aDevices.Length();) {
523
0
      uint32_t distance = aDevices[j]->GetBestFitnessDistance(aggregateConstraints,
524
0
                                                              aIsChrome);
525
0
      if (distance == UINT32_MAX) {
526
0
        rejects.AppendElement(std::move(aDevices[j]));
527
0
        aDevices.RemoveElementAt(j);
528
0
      } else {
529
0
        ++j;
530
0
      }
531
0
    }
532
0
    if (aDevices.IsEmpty()) {
533
0
      aDevices.AppendElements(std::move(rejects));
534
0
      aggregateConstraints.RemoveLastElement();
535
0
    }
536
0
  }
537
0
  return nullptr;
538
0
}
539
540
/* static */ const char*
541
MediaConstraintsHelper::FindBadConstraint(
542
    const NormalizedConstraints& aConstraints,
543
    const nsTArray<RefPtr<MediaDevice>>& aDevices)
544
0
{
545
0
  // The spec says to report a constraint that satisfies NONE
546
0
  // of the sources. Unfortunately, this is a bit laborious to find out, and
547
0
  // requires updating as new constraints are added!
548
0
  auto& c = aConstraints;
549
0
  dom::MediaTrackConstraints empty;
550
0
551
0
  if (aDevices.IsEmpty() ||
552
0
      !SomeSettingsFit(NormalizedConstraints(empty), aDevices)) {
553
0
    return "";
554
0
  }
555
0
  {
556
0
    NormalizedConstraints fresh(empty);
557
0
    fresh.mDeviceId = c.mDeviceId;
558
0
    if (!SomeSettingsFit(fresh, aDevices)) {
559
0
      return "deviceId";
560
0
    }
561
0
  }
562
0
  {
563
0
    NormalizedConstraints fresh(empty);
564
0
    fresh.mWidth = c.mWidth;
565
0
    if (!SomeSettingsFit(fresh, aDevices)) {
566
0
      return "width";
567
0
    }
568
0
  }
569
0
  {
570
0
    NormalizedConstraints fresh(empty);
571
0
    fresh.mHeight = c.mHeight;
572
0
    if (!SomeSettingsFit(fresh, aDevices)) {
573
0
      return "height";
574
0
    }
575
0
  }
576
0
  {
577
0
    NormalizedConstraints fresh(empty);
578
0
    fresh.mFrameRate = c.mFrameRate;
579
0
    if (!SomeSettingsFit(fresh, aDevices)) {
580
0
      return "frameRate";
581
0
    }
582
0
  }
583
0
  {
584
0
    NormalizedConstraints fresh(empty);
585
0
    fresh.mFacingMode = c.mFacingMode;
586
0
    if (!SomeSettingsFit(fresh, aDevices)) {
587
0
      return "facingMode";
588
0
    }
589
0
  }
590
0
  return "";
591
0
}
592
593
/* static */ const char*
594
MediaConstraintsHelper::FindBadConstraint(
595
    const NormalizedConstraints& aConstraints,
596
    const RefPtr<MediaEngineSource>& aMediaEngineSource,
597
    const nsString& aDeviceId)
598
0
{
599
0
  AutoTArray<RefPtr<MediaDevice>, 1> devices;
600
0
  devices.AppendElement(MakeRefPtr<MediaDevice>(aMediaEngineSource,
601
0
                                                aMediaEngineSource->GetName(),
602
0
                                                aDeviceId));
603
0
  return FindBadConstraint(aConstraints, devices);
604
0
}
605
606
/* static */ void
607
MediaConstraintsHelper::ConvertOldWithWarning(
608
    const dom::OwningBooleanOrConstrainBooleanParameters& old,
609
    dom::OwningBooleanOrConstrainBooleanParameters& to,
610
    const char* aMessageName,
611
0
    nsPIDOMWindowInner* aWindow) {
612
0
  if ((old.IsBoolean() ||
613
0
       old.GetAsConstrainBooleanParameters().mExact.WasPassed() ||
614
0
       old.GetAsConstrainBooleanParameters().mIdeal.WasPassed()) &&
615
0
      !(to.IsBoolean() ||
616
0
        to.GetAsConstrainBooleanParameters().mExact.WasPassed() ||
617
0
        to.GetAsConstrainBooleanParameters().mIdeal.WasPassed())) {
618
0
    nsCOMPtr<nsIDocument> doc = aWindow->GetDoc();
619
0
    if (doc) {
620
0
      nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
621
0
                                      NS_LITERAL_CSTRING("DOM"), doc,
622
0
                                      nsContentUtils::eDOM_PROPERTIES,
623
0
                                      aMessageName);
624
0
    }
625
0
    if (old.IsBoolean()) {
626
0
      to.SetAsBoolean() = old.GetAsBoolean();
627
0
    } else {
628
0
      to.SetAsConstrainBooleanParameters() = old.GetAsConstrainBooleanParameters();
629
0
    }
630
0
  }
631
0
}
632
633
}