Changeset 205574 in webkit
- Timestamp:
- Sep 7, 2016 5:01:29 PM (8 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r205572 r205574 1 2016-09-07 Eric Carlson <eric.carlson@apple.com> 2 3 [MediaStream] applyConstraints pt. 2 - advanced constraints 4 https://bugs.webkit.org/show_bug.cgi?id=161715 5 <rdar://problem/28195461> 6 7 Reviewed by Dean Jackson. 8 9 * fast/mediastream/apply-constraints-advanced-expected.txt: Added. 10 * fast/mediastream/apply-constraints-advanced.html: Added. 11 1 12 2016-09-06 Dean Jackson <dino@apple.com> 2 13 -
trunk/Source/WebCore/ChangeLog
r205569 r205574 1 2016-09-07 Eric Carlson <eric.carlson@apple.com> 2 3 [MediaStream] applyConstraints pt. 2 - advanced constraints 4 https://bugs.webkit.org/show_bug.cgi?id=161715 5 <rdar://problem/28195461> 6 7 Reviewed by Dean Jackson. 8 9 Test: fast/mediastream/apply-constraints-advanced.html 10 11 * platform/mediastream/MediaConstraints.cpp: 12 (WebCore::MediaConstraint::create): Return Ref<>, not RefPtr<>. 13 (WebCore::MediaConstraint::copy): New 14 (WebCore::IntConstraint::copy): Ditto. 15 (WebCore::DoubleConstraint::copy): Ditto. 16 (WebCore::BooleanConstraint::copy): Ditto. 17 (WebCore::StringConstraint::copy): Ditto. 18 (WebCore::StringConstraint::fitnessDistance): New, compute the fitness distance between the 19 constraint and the specified value. 20 (WebCore::StringConstraint::merge): New, merge value into constraint. 21 (WebCore::FlattenedConstraint::set): New, add or replace a constraint. 22 (WebCore::FlattenedConstraint::merge): New, merge or add a constraint. 23 * platform/mediastream/MediaConstraints.h: 24 (WebCore::MediaConstraint::fitnessDistance): 25 (WebCore::MediaConstraint::merge): 26 (WebCore::NumericConstraint::nearlyEqual): 27 (WebCore::FlattenedConstraint::isEmpty): 28 (WebCore::FlattenedConstraint::begin): 29 (WebCore::FlattenedConstraint::end): 30 (WebCore::MediaConstraint::~MediaConstraint): Deleted. 31 (WebCore::MediaConstraint::find): Deleted. 32 (WebCore::MediaConstraint::getIdeal): Deleted. 33 34 * platform/mediastream/RealtimeMediaSource.cpp: 35 (WebCore::RealtimeMediaSource::fitnessDistance): Return the fitness distance between the source 36 capabilities and a constraint. 37 (WebCore::applyNumericConstraint): New, apply a numeric constraint. 38 (WebCore::RealtimeMediaSource::applyConstraint): Use applyNumericConstraint. 39 (WebCore::RealtimeMediaSource::selectSettings): New, implement the SelectSettings algorithm 40 (WebCore::RealtimeMediaSource::applyConstraints): 41 (WebCore::RealtimeMediaSource::supportsConstraint): Deleted. 42 (WebCore::value): Deleted. 43 * platform/mediastream/RealtimeMediaSource.h: 44 1 45 2016-09-07 Mark Lam <mark.lam@apple.com> 2 46 -
trunk/Source/WebCore/platform/mediastream/MediaConstraints.cpp
r205348 r205574 38 38 namespace WebCore { 39 39 40 Ref Ptr<MediaConstraint> MediaConstraint::create(const String& name)40 Ref<MediaConstraint> MediaConstraint::create(const String& name) 41 41 { 42 42 MediaConstraintType constraintType = RealtimeMediaSourceSupportedConstraints::constraintFromName(name); … … 63 63 } 64 64 65 Ref<MediaConstraint> MediaConstraint::copy() const 66 { 67 return MediaConstraint::create(name()); 68 } 69 70 Ref<MediaConstraint> IntConstraint::copy() const 71 { 72 auto copy = IntConstraint::create(name(), type()); 73 copy->m_min = m_min; 74 copy->m_max = m_max; 75 copy->m_exact = m_exact; 76 copy->m_ideal = m_ideal; 77 78 return copy.leakRef(); 79 } 80 81 Ref<MediaConstraint> DoubleConstraint::copy() const 82 { 83 auto copy = DoubleConstraint::create(name(), type()); 84 copy->m_min = m_min; 85 copy->m_max = m_max; 86 copy->m_exact = m_exact; 87 copy->m_ideal = m_ideal; 88 89 return copy.leakRef(); 90 } 91 92 Ref<MediaConstraint> BooleanConstraint::copy() const 93 { 94 auto copy = BooleanConstraint::create(name(), type()); 95 copy->m_exact = m_exact; 96 copy->m_ideal = m_ideal; 97 98 return copy.leakRef(); 99 } 100 101 Ref<MediaConstraint> StringConstraint::copy() const 102 { 103 auto copy = StringConstraint::create(name(), type()); 104 copy->m_exact = m_exact; 105 copy->m_ideal = m_ideal; 106 107 return copy.leakRef(); 108 } 109 65 110 bool BooleanConstraint::getExact(bool& exact) const 66 111 { … … 137 182 } 138 183 184 double StringConstraint::fitnessDistance(const String& value) const 185 { 186 // https://w3c.github.io/mediacapture-main/#dfn-applyconstraints 187 188 // 1. If the constraint is not supported by the browser, the fitness distance is 0. 189 if (isEmpty()) 190 return 0; 191 192 // 2. If the constraint is required ('min', 'max', or 'exact'), and the settings 193 // dictionary's value for the constraint does not satisfy the constraint, the 194 // fitness distance is positive infinity. 195 if (!m_exact.isEmpty() && m_exact.find(value) == notFound) 196 return std::numeric_limits<double>::infinity(); 197 198 // 3. If no ideal value is specified, the fitness distance is 0. 199 if (m_exact.isEmpty()) 200 return 0; 201 202 // 5. For all string and enum non-required constraints (deviceId, groupId, facingMode, 203 // echoCancellation), the fitness distance is the result of the formula 204 // (actual == ideal) ? 0 : 1 205 return m_ideal.find(value) != notFound ? 0 : 1; 206 } 207 208 double StringConstraint::fitnessDistance(const Vector<String>& values) const 209 { 210 if (isEmpty()) 211 return 0; 212 213 double minimumDistance = std::numeric_limits<double>::infinity(); 214 for (auto& value : values) 215 minimumDistance = std::min(minimumDistance, fitnessDistance(value)); 216 217 return minimumDistance; 218 } 219 220 void StringConstraint::merge(const MediaConstraint& other) 221 { 222 if (other.isEmpty()) 223 return; 224 225 Vector<String> values; 226 if (other.getExact(values)) { 227 if (m_exact.isEmpty()) 228 m_exact = values; 229 else { 230 for (auto& value : values) { 231 if (m_exact.find(value) == notFound) 232 m_exact.append(value); 233 } 234 } 235 } 236 237 if (other.getIdeal(values)) { 238 if (m_ideal.isEmpty()) 239 m_ideal = values; 240 else { 241 for (auto& value : values) { 242 if (m_ideal.find(value) == notFound) 243 m_ideal.append(value); 244 } 245 } 246 } 247 } 248 249 void FlattenedConstraint::set(const MediaConstraint& constraint) 250 { 251 for (auto existingConstraint : m_constraints) { 252 if (existingConstraint->type() == constraint.type()) { 253 existingConstraint = constraint.copy(); 254 return; 255 } 256 } 257 258 m_constraints.append(constraint.copy()); 259 } 260 261 void FlattenedConstraint::merge(const MediaConstraint& constraint) 262 { 263 for (auto existingConstraint : m_constraints) { 264 if (existingConstraint->type() == constraint.type()) { 265 existingConstraint->merge(constraint); 266 return; 267 } 268 } 269 270 m_constraints.append(constraint.copy()); 271 } 272 139 273 } 140 274 -
trunk/Source/WebCore/platform/mediastream/MediaConstraints.h
r205348 r205574 36 36 37 37 #include "RealtimeMediaSourceSupportedConstraints.h" 38 #include <cstdlib> 38 39 #include <wtf/HashMap.h> 39 40 #include <wtf/RefCounted.h> 41 #include <wtf/text/StringHash.h> 40 42 #include <wtf/text/WTFString.h> 41 43 … … 44 46 class MediaConstraint : public RefCounted<MediaConstraint> { 45 47 public: 46 static Ref Ptr<MediaConstraint> create(const String& name);48 static Ref<MediaConstraint> create(const String&); 47 49 48 50 enum class ConstraintType { ExactConstraint, IdealConstraint, MinConstraint, MaxConstraint }; 49 51 50 52 virtual ~MediaConstraint() { }; 53 54 virtual Ref<MediaConstraint> copy() const; 51 55 virtual bool isEmpty() const = 0; 52 56 virtual bool isMandatory() const = 0; … … 58 62 virtual bool validForRange(int, int) const { ASSERT_NOT_REACHED(); return false; } 59 63 virtual int find(std::function<bool(ConstraintType, int)>) const { ASSERT_NOT_REACHED(); return 0; } 64 virtual double fitnessDistance(int, int) const { ASSERT_NOT_REACHED(); return 0; } 60 65 61 66 virtual bool getMin(double&) const { ASSERT_NOT_REACHED(); return false; } … … 65 70 virtual bool validForRange(double, double) const { ASSERT_NOT_REACHED(); return false; } 66 71 virtual double find(std::function<bool(ConstraintType, double)>) const { ASSERT_NOT_REACHED(); return 0; } 72 virtual double fitnessDistance(double, double) const { ASSERT_NOT_REACHED(); return 0; } 67 73 68 74 virtual bool getMin(bool&) const { ASSERT_NOT_REACHED(); return false; } … … 70 76 virtual bool getExact(bool&) const { ASSERT_NOT_REACHED(); return false; } 71 77 virtual bool getIdeal(bool&) const { ASSERT_NOT_REACHED(); return false; } 78 virtual double fitnessDistance(bool) const { ASSERT_NOT_REACHED(); return 0; } 72 79 73 80 virtual bool getMin(Vector<String>&) const { ASSERT_NOT_REACHED(); return false; } … … 77 84 virtual const String& find(std::function<bool(ConstraintType, const String&)>) const { ASSERT_NOT_REACHED(); return emptyString(); } 78 85 86 virtual double fitnessDistance(const String&) const { ASSERT_NOT_REACHED(); return 0; } 87 virtual double fitnessDistance(const Vector<String>&) const { ASSERT_NOT_REACHED(); return 0; } 88 89 virtual void merge(const MediaConstraint&) { ASSERT_NOT_REACHED(); } 90 79 91 MediaConstraintType type() const { return m_type; } 80 92 const String& name() const { return m_name; } … … 135 147 } 136 148 149 bool nearlyEqual(double a, double b) const 150 { 151 // Don't require strict equality when comparing constraints, or many floating point constraint values, 152 // e.g. "aspectRatio: 1.333", will never match. 153 const double epsilon = 0.00001; 154 return std::abs(a - b) <= epsilon; 155 } 156 157 double fitnessDistance(ValueType rangeMin, ValueType rangeMax) const final { 158 // https://w3c.github.io/mediacapture-main/#dfn-applyconstraints 159 // 1. If the constraint is not supported by the browser, the fitness distance is 0. 160 if (isEmpty()) 161 return 0; 162 163 // 2. If the constraint is required ('min', 'max', or 'exact'), and the settings 164 // dictionary's value for the constraint does not satisfy the constraint, the 165 // fitness distance is positive infinity. 166 bool valid = validForRange(rangeMin, rangeMax); 167 if (m_exact && !valid) 168 return std::numeric_limits<double>::infinity(); 169 170 if (m_min && !valid) 171 return std::numeric_limits<double>::infinity(); 172 173 if (m_max && !valid) 174 return std::numeric_limits<double>::infinity(); 175 176 // 3. If no ideal value is specified, the fitness distance is 0. 177 if (!m_ideal) 178 return 0; 179 180 // 4. For all positive numeric non-required constraints (such as height, width, frameRate, 181 // aspectRatio, sampleRate and sampleSize), the fitness distance is the result of the formula 182 // 183 // (actual == ideal) ? 0 : |actual - ideal| / max(|actual|,|ideal|) 184 ValueType ideal = m_ideal.value(); 185 if (ideal >= rangeMin && ideal <= rangeMax) 186 return 0; 187 188 ideal = ideal > std::max(rangeMin, rangeMax) ? rangeMax : rangeMin; 189 return static_cast<double>(std::abs(ideal - m_ideal.value())) / std::max(std::abs(ideal), std::abs(m_ideal.value())); 190 } 191 192 void merge(const MediaConstraint& other) final { 193 if (other.isEmpty()) 194 return; 195 196 ValueType value; 197 if (other.getExact(value)) 198 m_exact = value; 199 200 if (other.getMin(value)) 201 m_min = value; 202 203 if (other.getMax(value)) 204 m_max = value; 205 206 // https://w3c.github.io/mediacapture-main/#constrainable-interface 207 // When processing advanced constraints: 208 // ... the User Agent must attempt to apply, individually, any 'ideal' constraints or 209 // a constraint given as a bare value for the property. Of these properties, it must 210 // satisfy the largest number that it can, in any order. 211 if (other.getIdeal(value)) { 212 if (!m_ideal || value > m_ideal.value()) 213 m_ideal = value; 214 } 215 } 216 137 217 bool validForRange(ValueType rangeMin, ValueType rangeMax) const final { 138 218 if (isEmpty()) 139 219 return false; 140 220 141 if (m_exact && (m_exact.value() < rangeMin || m_exact.value() > rangeMax)) 142 return false; 143 144 if (m_min && m_min.value() > rangeMax) 145 return false; 146 147 if (m_max && m_max.value() < rangeMin) 148 return false; 221 if (m_exact) { 222 const ValueType exact = m_exact.value(); 223 if (exact < rangeMin && !nearlyEqual(exact, rangeMin)) 224 return false; 225 if (exact > rangeMax && !nearlyEqual(exact, rangeMax)) 226 return false; 227 } 228 229 if (m_min) { 230 const ValueType constraintMin = m_min.value(); 231 if (constraintMin > rangeMax && !nearlyEqual(constraintMin, rangeMax)) 232 return false; 233 } 234 235 236 if (m_max) { 237 const ValueType constraintMax = m_max.value(); 238 if (constraintMax < rangeMin && !nearlyEqual(constraintMax, rangeMin)) 239 return false; 240 } 149 241 150 242 return true; … … 174 266 } 175 267 176 private:177 268 Optional<ValueType> m_min; 178 269 Optional<ValueType> m_max; … … 185 276 static Ref<IntConstraint> create(const String& name, MediaConstraintType type) { return adoptRef(*new IntConstraint(name, type)); } 186 277 278 Ref<MediaConstraint> copy() const final; 279 187 280 private: 188 281 explicit IntConstraint(const String& name, MediaConstraintType type) … … 196 289 static Ref<DoubleConstraint> create(const String& name, MediaConstraintType type) { return adoptRef(*new DoubleConstraint(name, type)); } 197 290 291 Ref<MediaConstraint> copy() const final; 292 198 293 private: 199 294 explicit DoubleConstraint(const String& name, MediaConstraintType type) … … 207 302 static Ref<BooleanConstraint> create(const String& name, MediaConstraintType type) { return adoptRef(*new BooleanConstraint(name, type)); } 208 303 304 Ref<MediaConstraint> copy() const final; 305 209 306 void setExact(bool value) { m_exact = value; } 210 307 void setIdeal(bool value) { m_ideal = value; } … … 216 313 bool isMandatory() const final { return bool(m_exact); } 217 314 315 double fitnessDistance(bool value) const final { 316 // https://w3c.github.io/mediacapture-main/#dfn-applyconstraints 317 // 1. If the constraint is not supported by the browser, the fitness distance is 0. 318 if (isEmpty()) 319 return 0; 320 321 // 2. If the constraint is required ('min', 'max', or 'exact'), and the settings 322 // dictionary's value for the constraint does not satisfy the constraint, the 323 // fitness distance is positive infinity. 324 if (m_exact && value != m_exact.value()) 325 return std::numeric_limits<double>::infinity(); 326 327 // 3. If no ideal value is specified, the fitness distance is 0. 328 if (!m_ideal || m_ideal.value() == value) 329 return 0; 330 331 // 5. For all string and enum non-required constraints (deviceId, groupId, facingMode, 332 // echoCancellation), the fitness distance is the result of the formula 333 // (actual == ideal) ? 0 : 1 334 return 1; 335 } 336 337 void merge(const MediaConstraint& other) final { 338 if (other.isEmpty()) 339 return; 340 341 bool value; 342 if (other.getExact(value)) 343 m_exact = value; 344 345 if (other.getIdeal(value)) { 346 if (!m_ideal || (value && !m_ideal.value())) 347 m_ideal = value; 348 } 349 } 350 218 351 private: 219 352 explicit BooleanConstraint(const String& name, MediaConstraintType type) … … 229 362 public: 230 363 static Ref<StringConstraint> create(const String& name, MediaConstraintType type) { return adoptRef(*new StringConstraint(name, type)); } 364 365 Ref<MediaConstraint> copy() const final; 231 366 232 367 void setExact(const String&); … … 241 376 bool isMandatory() const final { return !m_exact.isEmpty(); } 242 377 243 const String& find(std::function<bool(ConstraintType, const String&)>) const override; 378 double fitnessDistance(const String&) const final; 379 double fitnessDistance(const Vector<String>&) const final; 380 381 const String& find(std::function<bool(ConstraintType, const String&)>) const final; 382 void merge(const MediaConstraint&) final; 244 383 245 384 private: … … 268 407 269 408 using MediaTrackConstraintSetMap = HashMap<String, RefPtr<MediaConstraint>>; 409 410 class FlattenedConstraint { 411 public: 412 typedef Vector<RefPtr<MediaConstraint>>::const_iterator const_iterator; 413 414 void set(const MediaConstraint&); 415 void merge(const MediaConstraint&); 416 bool isEmpty() const { return m_constraints.isEmpty(); } 417 418 const_iterator begin() const { return m_constraints.begin(); } 419 const_iterator end() const { return m_constraints.end(); } 420 421 private: 422 423 Vector<RefPtr<MediaConstraint>> m_constraints; 424 }; 270 425 271 426 class MediaConstraints : public RefCounted<MediaConstraints> { -
trunk/Source/WebCore/platform/mediastream/RealtimeMediaSource.cpp
r205348 r205574 151 151 } 152 152 153 RealtimeMediaSource::ConstraintSupport RealtimeMediaSource::supportsConstraint(const MediaConstraint& constraint)153 double RealtimeMediaSource::fitnessDistance(const MediaConstraint& constraint) 154 154 { 155 155 RealtimeMediaSourceCapabilities& capabilities = *this->capabilities(); … … 158 158 case MediaConstraintType::Width: { 159 159 if (!capabilities.supportsWidth()) 160 return ConstraintSupport::Ignored;161 162 auto widthRange = capabilities.width();163 return constraint. validForRange(widthRange.rangeMin().asInt, widthRange.rangeMax().asInt) ? ConstraintSupport::Supported : ConstraintSupport::Unsupported;160 return 0; 161 162 auto range = capabilities.width(); 163 return constraint.fitnessDistance(range.rangeMin().asInt, range.rangeMax().asInt); 164 164 break; 165 165 } … … 167 167 case MediaConstraintType::Height: { 168 168 if (!capabilities.supportsHeight()) 169 return ConstraintSupport::Ignored;170 171 auto heightRange = capabilities.height();172 return constraint. validForRange(heightRange.rangeMin().asInt, heightRange.rangeMax().asInt) ? ConstraintSupport::Supported : ConstraintSupport::Unsupported;169 return 0; 170 171 auto range = capabilities.height(); 172 return constraint.fitnessDistance(range.rangeMin().asInt, range.rangeMax().asInt); 173 173 break; 174 174 } … … 176 176 case MediaConstraintType::FrameRate: { 177 177 if (!capabilities.supportsFrameRate()) 178 return ConstraintSupport::Ignored;179 180 auto ra teRange = capabilities.frameRate();181 return constraint. validForRange(rateRange.rangeMin().asDouble, rateRange.rangeMax().asDouble) ? ConstraintSupport::Supported : ConstraintSupport::Unsupported;178 return 0; 179 180 auto range = capabilities.frameRate(); 181 return constraint.fitnessDistance(range.rangeMin().asDouble, range.rangeMax().asDouble); 182 182 break; 183 183 } … … 185 185 case MediaConstraintType::AspectRatio: { 186 186 if (!capabilities.supportsAspectRatio()) 187 return ConstraintSupport::Ignored;187 return 0; 188 188 189 189 auto range = capabilities.aspectRatio(); 190 return constraint. validForRange(range.rangeMin().asDouble, range.rangeMax().asDouble) ? ConstraintSupport::Supported : ConstraintSupport::Unsupported;190 return constraint.fitnessDistance(range.rangeMin().asDouble, range.rangeMax().asDouble); 191 191 break; 192 192 } … … 194 194 case MediaConstraintType::Volume: { 195 195 if (!capabilities.supportsVolume()) 196 return ConstraintSupport::Ignored;196 return 0; 197 197 198 198 auto range = capabilities.volume(); 199 return constraint. validForRange(range.rangeMin().asDouble, range.rangeMax().asDouble) ? ConstraintSupport::Supported : ConstraintSupport::Unsupported;199 return constraint.fitnessDistance(range.rangeMin().asDouble, range.rangeMax().asDouble); 200 200 break; 201 201 } … … 203 203 case MediaConstraintType::SampleRate: { 204 204 if (!capabilities.supportsSampleRate()) 205 return ConstraintSupport::Ignored;205 return 0; 206 206 207 207 auto range = capabilities.sampleRate(); 208 return constraint. validForRange(range.rangeMin().asDouble, range.rangeMax().asDouble) ? ConstraintSupport::Supported : ConstraintSupport::Unsupported;208 return constraint.fitnessDistance(range.rangeMin().asDouble, range.rangeMax().asDouble); 209 209 break; 210 210 } … … 212 212 case MediaConstraintType::SampleSize: { 213 213 if (!capabilities.supportsSampleSize()) 214 return ConstraintSupport::Ignored;214 return 0; 215 215 216 216 auto range = capabilities.sampleSize(); 217 return constraint. validForRange(range.rangeMin().asDouble, range.rangeMax().asDouble) ? ConstraintSupport::Supported : ConstraintSupport::Unsupported;217 return constraint.fitnessDistance(range.rangeMin().asDouble, range.rangeMax().asDouble); 218 218 break; 219 219 } … … 221 221 case MediaConstraintType::FacingMode: { 222 222 if (!capabilities.supportsFacingMode()) 223 return ConstraintSupport::Ignored; 224 225 ConstraintSupport support = ConstraintSupport::Ignored; 226 auto& supportedModes = capabilities.facingMode(); 227 std::function<bool(MediaConstraint::ConstraintType, const String&)> filter = [supportedModes, &support](MediaConstraint::ConstraintType type, const String& modeString) { 228 if (type == MediaConstraint::ConstraintType::ExactConstraint) 229 support = ConstraintSupport::Unsupported; 230 231 auto mode = RealtimeMediaSourceSettings::videoFacingModeEnum(modeString); 232 for (auto& supportedMode : supportedModes) { 233 if (supportedMode == mode) { 234 support = ConstraintSupport::Supported; 235 break; 236 } 237 } 238 239 return type == MediaConstraint::ConstraintType::ExactConstraint ? true : false; 240 }; 241 242 constraint.find(filter); 243 return support; 244 break; 245 } 246 247 case MediaConstraintType::EchoCancellation: 223 return 0; 224 225 auto& modes = capabilities.facingMode(); 226 Vector<String> supportedModes; 227 supportedModes.reserveInitialCapacity(modes.size()); 228 for (auto& mode : modes) 229 supportedModes.append(RealtimeMediaSourceSettings::facingMode(mode)); 230 return constraint.fitnessDistance(supportedModes); 231 break; 232 } 233 234 case MediaConstraintType::EchoCancellation: { 248 235 if (!capabilities.supportsEchoCancellation()) 249 return ConstraintSupport::Ignored; 250 251 if (capabilities.echoCancellation() == RealtimeMediaSourceCapabilities::EchoCancellation::ReadOnly) 252 return constraint.isMandatory() ? ConstraintSupport::Unsupported : ConstraintSupport::Ignored; 253 254 return ConstraintSupport::Supported; 255 break; 236 return 0; 237 238 bool echoCancellationReadWrite = capabilities.echoCancellation() == RealtimeMediaSourceCapabilities::EchoCancellation::ReadWrite; 239 return constraint.fitnessDistance(echoCancellationReadWrite); 240 break; 241 } 256 242 257 243 case MediaConstraintType::DeviceId: { 258 244 if (!capabilities.supportsDeviceId()) 259 return ConstraintSupport::Ignored; 260 261 ConstraintSupport support = ConstraintSupport::Ignored; 262 std::function<bool(MediaConstraint::ConstraintType, const String&)> filter = [this, &support](MediaConstraint::ConstraintType type, const String& idString) { 263 if (type != MediaConstraint::ConstraintType::ExactConstraint) 264 return false; // Keep looking. 265 266 support = idString == m_id ? ConstraintSupport::Supported : ConstraintSupport::Unsupported; 267 return false; 268 }; 269 270 constraint.find(filter); 271 return support; 245 return 0; 246 247 return constraint.fitnessDistance(m_id); 272 248 break; 273 249 } … … 275 251 case MediaConstraintType::GroupId: { 276 252 if (!capabilities.supportsDeviceId()) 277 return ConstraintSupport::Ignored; 278 279 ConstraintSupport support = ConstraintSupport::Ignored; 280 String groupId = settings().groupId(); 281 std::function<bool(MediaConstraint::ConstraintType, const String&)> filter = [groupId, &support](MediaConstraint::ConstraintType type, const String& idString) { 282 if (type != MediaConstraint::ConstraintType::ExactConstraint) 283 return false; // Keep looking. 284 285 support = idString == groupId ? ConstraintSupport::Supported : ConstraintSupport::Unsupported; 286 return false; 287 }; 288 289 constraint.find(filter); 290 return support; 253 return 0; 254 255 return constraint.fitnessDistance(settings().groupId()); 291 256 break; 292 257 } … … 297 262 } 298 263 299 return ConstraintSupport::Ignored; 300 } 301 302 303 template <typename T> 304 T value(const MediaConstraint& constraint, T rangeMin, T rangeMax) 305 { 306 T result; 307 308 if (constraint.getExact(result)) { 309 ASSERT(result >= rangeMin && result <= rangeMax); 310 return result; 311 } 312 313 if (constraint.getIdeal(result)) { 314 if (result < rangeMin) 315 result = rangeMin; 316 else if (result > rangeMax) 317 result = rangeMax; 318 319 return result; 320 } 321 322 if (constraint.getMin(result) && result > rangeMax) 323 return false; 324 325 if (constraint.getMax(result) && result < rangeMin) 326 return false; 327 328 return result; 329 } 330 264 return 0; 265 } 266 267 template <typename ValueType> 268 static void applyNumericConstraint(const MediaConstraint& constraint, ValueType current, ValueType capabilityMin, ValueType capabilityMax, RealtimeMediaSource* source, void (RealtimeMediaSource::*function)(ValueType)) 269 { 270 ValueType value; 271 ValueType min = capabilityMin; 272 ValueType max = capabilityMax; 273 274 if (constraint.getExact(value)) { 275 ASSERT(constraint.validForRange(capabilityMin, capabilityMax)); 276 (source->*function)(value); 277 return; 278 } 279 280 if (constraint.getMin(value)) { 281 ASSERT(constraint.validForRange(value, capabilityMax)); 282 if (value > min) 283 min = value; 284 285 // If there is no ideal, don't change if minimum is smaller than current. 286 ValueType ideal; 287 if (!constraint.getIdeal(ideal) && value < current) 288 value = current; 289 } 290 291 if (constraint.getMax(value)) { 292 ASSERT(constraint.validForRange(capabilityMin, value)); 293 if (value < max) 294 max = value; 295 } 296 297 if (constraint.getIdeal(value)) { 298 if (value < min) 299 value = min; 300 if (value > max) 301 value = max; 302 } 303 304 if (value != current) 305 (source->*function)(value); 306 } 331 307 332 308 void RealtimeMediaSource::applyConstraint(const MediaConstraint& constraint) … … 338 314 return; 339 315 340 auto widthRange = capabilities.width();341 setWidth(value(constraint, widthRange.rangeMin().asInt, widthRange.rangeMax().asInt));316 auto range = capabilities.width(); 317 applyNumericConstraint(constraint, size().width(), range.rangeMin().asInt, range.rangeMax().asInt, this, &RealtimeMediaSource::setWidth); 342 318 break; 343 319 } … … 347 323 return; 348 324 349 auto heightRange = capabilities.height();350 setHeight(value(constraint, heightRange.rangeMin().asInt, heightRange.rangeMax().asInt));325 auto range = capabilities.height(); 326 applyNumericConstraint(constraint, size().height(), range.rangeMin().asInt, range.rangeMax().asInt, this, &RealtimeMediaSource::setHeight); 351 327 break; 352 328 } … … 356 332 return; 357 333 358 auto ra teRange = capabilities.frameRate();359 setFrameRate(value(constraint, rateRange.rangeMin().asDouble, rateRange.rangeMax().asDouble));334 auto range = capabilities.frameRate(); 335 applyNumericConstraint(constraint, frameRate(), range.rangeMin().asDouble, range.rangeMax().asDouble, this, &RealtimeMediaSource::setFrameRate); 360 336 break; 361 337 } … … 366 342 367 343 auto range = capabilities.aspectRatio(); 368 setAspectRatio(value(constraint, range.rangeMin().asDouble, range.rangeMax().asDouble));344 applyNumericConstraint(constraint, aspectRatio(), range.rangeMin().asDouble, range.rangeMax().asDouble, this, &RealtimeMediaSource::setAspectRatio); 369 345 break; 370 346 } … … 375 351 376 352 auto range = capabilities.volume(); 377 // std::pair<T, T> valuesForRange(constraint, range.rangeMin().asDouble, range.rangeMax().asDouble) 378 setVolume(value(constraint, range.rangeMin().asDouble, range.rangeMax().asDouble)); 353 applyNumericConstraint(constraint, volume(), range.rangeMin().asDouble, range.rangeMax().asDouble, this, &RealtimeMediaSource::setVolume); 379 354 break; 380 355 } … … 385 360 386 361 auto range = capabilities.sampleRate(); 387 setSampleRate(value(constraint, range.rangeMin().asDouble, range.rangeMax().asDouble));362 applyNumericConstraint(constraint, sampleRate(), range.rangeMin().asDouble, range.rangeMax().asDouble, this, &RealtimeMediaSource::setSampleRate); 388 363 break; 389 364 } … … 394 369 395 370 auto range = capabilities.sampleSize(); 396 setSampleSize(value(constraint, range.rangeMin().asDouble, range.rangeMax().asDouble));371 applyNumericConstraint(constraint, sampleSize(), range.rangeMin().asDouble, range.rangeMax().asDouble, this, &RealtimeMediaSource::setSampleSize); 397 372 break; 398 373 } … … 437 412 } 438 413 439 void RealtimeMediaSource::applyConstraints(const MediaConstraints& constraints, SuccessHandler successHandler, FailureHandler failureHandler) 440 { 441 ASSERT(constraints.isValid()); 442 414 bool RealtimeMediaSource::selectSettings(const MediaConstraints& constraints, FlattenedConstraint& candidates, String& failedConstraint) 415 { 416 // https://w3c.github.io/mediacapture-main/#dfn-selectsettings 417 // 418 // 1. Each constraint specifies one or more values (or a range of values) for its property. 419 // A property may appear more than once in the list of 'advanced' ConstraintSets. If an 420 // empty object or list has been given as the value for a constraint, it must be interpreted 421 // as if the constraint were not specified (in other words, an empty constraint == no constraint). 422 // 423 // Note that unknown properties are discarded by WebIDL, which means that unknown/unsupported required 424 // constraints will silently disappear. To avoid this being a surprise, application authors are 425 // expected to first use the getSupportedConstraints() method as shown in the Examples below. 426 427 // 2. Let object be the ConstrainablePattern object on which this algorithm is applied. Let copy be an 428 // unconstrained copy of object (i.e., copy should behave as if it were object with all ConstraintSets 429 // removed.) 430 431 // 3. For every possible settings dictionary of copy compute its fitness distance, treating bare values of 432 // properties as ideal values. Let candidates be the set of settings dictionaries for which the fitness 433 // distance is finite. 443 434 auto& mandatoryConstraints = constraints.mandatoryConstraints(); 444 435 for (auto& nameConstraintPair : mandatoryConstraints) { 445 auto& constraint = *nameConstraintPair.value;446 if ( supportsConstraint(constraint) == ConstraintSupport::Unsupported) {447 fail ureHandler(constraint.name(), "Constraint not supported");448 return ;436 const auto& constraint = nameConstraintPair.value; 437 if (fitnessDistance(*constraint) == std::numeric_limits<double>::infinity()) { 438 failedConstraint = constraint->name(); 439 return false; 449 440 } 450 } 451 452 for (auto& nameConstraintPair : mandatoryConstraints) 453 applyConstraint(*nameConstraintPair.value); 441 442 candidates.set(*constraint); 443 } 444 445 // 4. If candidates is empty, return undefined as the result of the SelectSettings() algorithm. 446 if (candidates.isEmpty()) 447 return true; 448 449 // 5. Iterate over the 'advanced' ConstraintSets in newConstraints in the order in which they were specified. 450 // For each ConstraintSet: 451 452 // 5.1 compute the fitness distance between it and each settings dictionary in candidates, treating bare 453 // values of properties as exact. 454 Vector<std::pair<double, MediaTrackConstraintSetMap>> supportedConstraints; 455 double minimumDistance = std::numeric_limits<double>::infinity(); 456 for (const auto& advancedConstraint : constraints.advancedConstraints()) { 457 double constraintDistance = 0; 458 bool supported = false; 459 for (auto& nameConstraintPair : advancedConstraint) { 460 double distance = fitnessDistance(*nameConstraintPair.value); 461 constraintDistance += distance; 462 if (distance != std::numeric_limits<double>::infinity()) 463 supported = true; 464 } 465 466 if (constraintDistance < minimumDistance) 467 minimumDistance = constraintDistance; 468 469 // 5.2 If the fitness distance is finite for one or more settings dictionaries in candidates, keep those 470 // settings dictionaries in candidates, discarding others. 471 // If the fitness distance is infinite for all settings dictionaries in candidates, ignore this ConstraintSet. 472 if (supported) 473 supportedConstraints.append({constraintDistance, advancedConstraint}); 474 } 475 476 // 6. Select one settings dictionary from candidates, and return it as the result of the SelectSettings() algorithm. 477 // The UA should use the one with the smallest fitness distance, as calculated in step 3. 478 if (minimumDistance != std::numeric_limits<double>::infinity()) { 479 supportedConstraints.removeAllMatching( [&] (std::pair<double, MediaTrackConstraintSetMap> pair) -> bool { 480 return pair.first > minimumDistance; 481 }); 482 483 if (!supportedConstraints.isEmpty()) { 484 auto& advancedConstraint = supportedConstraints[0].second; 485 for (auto& nameConstraintPair : advancedConstraint) 486 candidates.merge(*nameConstraintPair.value); 487 } 488 } 489 490 return true; 491 } 492 493 494 void RealtimeMediaSource::applyConstraints(const MediaConstraints& constraints, SuccessHandler successHandler, FailureHandler failureHandler) 495 { 496 ASSERT(constraints.isValid()); 497 498 FlattenedConstraint candidates; 499 500 String failedConstraint; 501 if (!selectSettings(constraints, candidates, failedConstraint)) { 502 failureHandler(failedConstraint, "Constraint not supported"); 503 return; 504 } 505 506 for (auto constraint : candidates) 507 applyConstraint(*constraint); 454 508 455 509 successHandler(); -
trunk/Source/WebCore/platform/mediastream/RealtimeMediaSource.h
r205348 r205574 43 43 #include "PlatformLayer.h" 44 44 #include "RealtimeMediaSourceCapabilities.h" 45 #include <wtf/Lock.h>46 45 #include <wtf/RefCounted.h> 47 46 #include <wtf/Vector.h> … … 172 171 WeakPtr<RealtimeMediaSource> createWeakPtr() { return m_weakPtrFactory.createWeakPtr(); } 173 172 174 enum ConstraintSupport { Ignored, Supported, Unsupported }; 175 ConstraintSupport supportsConstraint(const MediaConstraint&); 173 bool supportsConstraints(const MediaTrackConstraintSetMap&); 174 bool selectSettings(const MediaConstraints&, FlattenedConstraint&, String&); 175 double fitnessDistance(const MediaConstraint&); 176 176 void applyConstraint(const MediaConstraint&); 177 177 178 178 WeakPtrFactory<RealtimeMediaSource> m_weakPtrFactory; 179 Lock m_lock;180 181 179 String m_id; 182 180 String m_persistentID;
Note: See TracChangeset
for help on using the changeset viewer.