1 use std::iter::FromIterator;
2 
3 use lazy_static::lazy_static;
4 
5 use crate::{
6     algorithms::{select_settings_candidates, SelectSettingsError},
7     errors::OverconstrainedError,
8     property::all::{name::*, names as all_properties},
9     AdvancedMediaTrackConstraints, FacingMode, MandatoryMediaTrackConstraints,
10     MediaTrackConstraints, MediaTrackSettings, MediaTrackSupportedConstraints, ResizeMode,
11     ResolvedAdvancedMediaTrackConstraints, ResolvedMandatoryMediaTrackConstraints,
12     ResolvedMediaTrackConstraint, ResolvedMediaTrackConstraints, ResolvedValueConstraint,
13     ResolvedValueRangeConstraint, ResolvedValueSequenceConstraint, SanitizedMediaTrackConstraints,
14 };
15 
16 use super::DeviceInformationExposureMode;
17 
18 lazy_static! {
19     static ref VIDEO_IDEAL: MediaTrackSettings = MediaTrackSettings::from_iter([
20         (&ASPECT_RATIO, 0.5625.into()),
21         (&FACING_MODE, FacingMode::user().into()),
22         (&FRAME_RATE, 60.0.into()),
23         (&WIDTH, 1920.into()),
24         (&HEIGHT, 1080.into()),
25         (&RESIZE_MODE, ResizeMode::none().into()),
26     ]);
27     static ref VIDEO_480P: MediaTrackSettings = MediaTrackSettings::from_iter([
28         (&DEVICE_ID, "480p".into()),
29         (&ASPECT_RATIO, 0.5625.into()),
30         (&FACING_MODE, FacingMode::user().into()),
31         (&FRAME_RATE, 240.into()),
32         (&WIDTH, 720.into()),
33         (&HEIGHT, 480.into()),
34         (&RESIZE_MODE, ResizeMode::crop_and_scale().into()),
35     ]);
36     static ref VIDEO_720P: MediaTrackSettings = MediaTrackSettings::from_iter([
37         (&DEVICE_ID, "720p".into()),
38         (&ASPECT_RATIO, 0.5625.into()),
39         (&FACING_MODE, FacingMode::user().into()),
40         (&FRAME_RATE, 120.into()),
41         (&WIDTH, 1280.into()),
42         (&HEIGHT, 720.into()),
43         (&RESIZE_MODE, ResizeMode::crop_and_scale().into()),
44     ]);
45     static ref VIDEO_1080P: MediaTrackSettings = MediaTrackSettings::from_iter([
46         (&DEVICE_ID, "1080p".into()),
47         (&ASPECT_RATIO, 0.5625.into()),
48         (&FACING_MODE, FacingMode::user().into()),
49         (&FRAME_RATE, 60.into()),
50         (&WIDTH, 1920.into()),
51         (&HEIGHT, 1080.into()),
52         (&RESIZE_MODE, ResizeMode::none().into()),
53     ]);
54     static ref VIDEO_1440P: MediaTrackSettings = MediaTrackSettings::from_iter([
55         (&DEVICE_ID, "1440p".into()),
56         (&ASPECT_RATIO, 0.5625.into()),
57         (&FACING_MODE, FacingMode::user().into()),
58         (&FRAME_RATE, 30.into()),
59         (&WIDTH, 2560.into()),
60         (&HEIGHT, 1440.into()),
61         (&RESIZE_MODE, ResizeMode::none().into()),
62     ]);
63     static ref VIDEO_2160P: MediaTrackSettings = MediaTrackSettings::from_iter([
64         (&DEVICE_ID, "2160p".into()),
65         (&ASPECT_RATIO, 0.5625.into()),
66         (&FACING_MODE, FacingMode::user().into()),
67         (&FRAME_RATE, 15.into()),
68         (&WIDTH, 3840.into()),
69         (&HEIGHT, 2160.into()),
70         (&RESIZE_MODE, ResizeMode::none().into()),
71     ]);
72 }
73 
default_possible_settings() -> Vec<MediaTrackSettings>74 fn default_possible_settings() -> Vec<MediaTrackSettings> {
75     vec![
76         VIDEO_480P.clone(),
77         VIDEO_720P.clone(),
78         VIDEO_1080P.clone(),
79         VIDEO_1440P.clone(),
80         VIDEO_2160P.clone(),
81     ]
82 }
83 
default_supported_constraints() -> MediaTrackSupportedConstraints84 fn default_supported_constraints() -> MediaTrackSupportedConstraints {
85     MediaTrackSupportedConstraints::from_iter(all_properties().into_iter().cloned())
86 }
87 
test_overconstrained( possible_settings: &[MediaTrackSettings], mandatory_constraints: ResolvedMandatoryMediaTrackConstraints, exposure_mode: DeviceInformationExposureMode, ) -> OverconstrainedError88 fn test_overconstrained(
89     possible_settings: &[MediaTrackSettings],
90     mandatory_constraints: ResolvedMandatoryMediaTrackConstraints,
91     exposure_mode: DeviceInformationExposureMode,
92 ) -> OverconstrainedError {
93     let constraints = ResolvedMediaTrackConstraints {
94         mandatory: mandatory_constraints,
95         advanced: ResolvedAdvancedMediaTrackConstraints::default(),
96     }
97     .to_sanitized(&default_supported_constraints());
98 
99     let result = select_settings_candidates(possible_settings.iter(), &constraints, exposure_mode);
100 
101     let actual = result.err().unwrap();
102 
103     let SelectSettingsError::Overconstrained(overconstrained_error) = actual;
104 
105     overconstrained_error
106 }
107 
test_constrained( possible_settings: &[MediaTrackSettings], mandatory_constraints: ResolvedMandatoryMediaTrackConstraints, advanced_constraints: ResolvedAdvancedMediaTrackConstraints, ) -> Vec<&MediaTrackSettings>108 fn test_constrained(
109     possible_settings: &[MediaTrackSettings],
110     mandatory_constraints: ResolvedMandatoryMediaTrackConstraints,
111     advanced_constraints: ResolvedAdvancedMediaTrackConstraints,
112 ) -> Vec<&MediaTrackSettings> {
113     let constraints = ResolvedMediaTrackConstraints {
114         mandatory: mandatory_constraints,
115         advanced: advanced_constraints,
116     }
117     .to_sanitized(&default_supported_constraints());
118 
119     let result = select_settings_candidates(
120         possible_settings.iter(),
121         &constraints,
122         DeviceInformationExposureMode::Exposed,
123     );
124 
125     result.unwrap()
126 }
127 
128 mod unconstrained {
129     use super::*;
130 
default_constraints() -> MediaTrackConstraints131     fn default_constraints() -> MediaTrackConstraints {
132         MediaTrackConstraints {
133             mandatory: MandatoryMediaTrackConstraints::default(),
134             advanced: AdvancedMediaTrackConstraints::default(),
135         }
136     }
137 
default_resolved_constraints() -> ResolvedMediaTrackConstraints138     fn default_resolved_constraints() -> ResolvedMediaTrackConstraints {
139         default_constraints().into_resolved()
140     }
141 
default_sanitized_constraints() -> SanitizedMediaTrackConstraints142     fn default_sanitized_constraints() -> SanitizedMediaTrackConstraints {
143         default_resolved_constraints().into_sanitized(&default_supported_constraints())
144     }
145 
146     #[test]
pass_through()147     fn pass_through() {
148         let possible_settings = default_possible_settings();
149         let sanitized_constraints = default_sanitized_constraints();
150 
151         let actual = select_settings_candidates(
152             &possible_settings[..],
153             &sanitized_constraints,
154             DeviceInformationExposureMode::Exposed,
155         )
156         .unwrap();
157         let expected: Vec<_> = possible_settings.iter().collect();
158 
159         assert_eq!(actual, expected);
160     }
161 }
162 
163 mod overconstrained {
164     use crate::MediaTrackProperty;
165 
166     use super::*;
167 
168     #[test]
protected()169     fn protected() {
170         let error = test_overconstrained(
171             &default_possible_settings(),
172             ResolvedMandatoryMediaTrackConstraints::from_iter([(
173                 GROUP_ID.clone(),
174                 ResolvedValueConstraint::default()
175                     .exact("missing-group".to_owned())
176                     .into(),
177             )]),
178             DeviceInformationExposureMode::Protected,
179         );
180 
181         assert_eq!(error.constraint, MediaTrackProperty::from(""));
182         assert_eq!(error.message, None);
183     }
184 
185     mod exposed {
186         use super::*;
187 
188         #[test]
missing()189         fn missing() {
190             let error = test_overconstrained(
191                 &default_possible_settings(),
192                 ResolvedMandatoryMediaTrackConstraints::from_iter([(
193                     GROUP_ID.clone(),
194                     ResolvedValueConstraint::default()
195                         .exact("missing-group".to_owned())
196                         .into(),
197                 )]),
198                 DeviceInformationExposureMode::Exposed,
199             );
200 
201             let constraint = &error.constraint;
202             let err_message = error.message.as_ref().expect("Error message.");
203 
204             assert_eq!(constraint, &GROUP_ID);
205             assert_eq!(
206                 err_message,
207                 "Setting was missing (does not satisfy (x == \"missing-group\"))."
208             );
209         }
210 
211         #[test]
mismatch()212         fn mismatch() {
213             let error = test_overconstrained(
214                 &default_possible_settings(),
215                 ResolvedMandatoryMediaTrackConstraints::from_iter([(
216                     DEVICE_ID.clone(),
217                     ResolvedValueConstraint::default()
218                         .exact("mismatched-device".to_owned())
219                         .into(),
220                 )]),
221                 DeviceInformationExposureMode::Exposed,
222             );
223 
224             let constraint = &error.constraint;
225             let err_message = error.message.as_ref().expect("Error message.");
226 
227             assert_eq!(constraint, &DEVICE_ID);
228             assert_eq!(
229             err_message,
230             "Setting was a mismatch ([\"1080p\", \"1440p\", \"2160p\", \"480p\", \"720p\"] do not satisfy (x == \"mismatched-device\"))."
231         );
232         }
233 
234         #[test]
too_small()235         fn too_small() {
236             let error = test_overconstrained(
237                 &default_possible_settings(),
238                 ResolvedMandatoryMediaTrackConstraints::from_iter([(
239                     FRAME_RATE.clone(),
240                     ResolvedValueRangeConstraint::default().min(1000).into(),
241                 )]),
242                 DeviceInformationExposureMode::Exposed,
243             );
244 
245             let constraint = &error.constraint;
246             let err_message = error.message.as_ref().expect("Error message.");
247 
248             assert_eq!(constraint, &FRAME_RATE);
249             assert_eq!(
250                 err_message,
251                 "Setting was too small ([120, 15, 240, 30, 60] do not satisfy (1000 <= x))."
252             );
253         }
254 
255         #[test]
too_large()256         fn too_large() {
257             let error = test_overconstrained(
258                 &default_possible_settings(),
259                 ResolvedMandatoryMediaTrackConstraints::from_iter([(
260                     FRAME_RATE.clone(),
261                     ResolvedValueRangeConstraint::default().max(10).into(),
262                 )]),
263                 DeviceInformationExposureMode::Exposed,
264             );
265 
266             let constraint = &error.constraint;
267             let err_message = error.message.as_ref().expect("Error message.");
268 
269             assert_eq!(constraint, &FRAME_RATE);
270             assert_eq!(
271                 err_message,
272                 "Setting was too large ([120, 15, 240, 30, 60] do not satisfy (x <= 10))."
273             );
274         }
275     }
276 }
277 
278 mod constrained {
279     use super::*;
280 
281     #[test]
specific_device_id()282     fn specific_device_id() {
283         let possible_settings = default_possible_settings();
284 
285         for target_settings in possible_settings.iter() {
286             let setting = match target_settings.get(&DEVICE_ID) {
287                 Some(setting) => setting,
288                 None => continue,
289             };
290 
291             let actual = test_constrained(
292                 &possible_settings,
293                 ResolvedMandatoryMediaTrackConstraints::from_iter([(
294                     DEVICE_ID.clone(),
295                     ResolvedMediaTrackConstraint::exact_from(setting.clone()),
296                 )]),
297                 ResolvedAdvancedMediaTrackConstraints::default(),
298             );
299 
300             let expected = vec![target_settings];
301 
302             assert_eq!(actual, expected);
303         }
304     }
305 
306     mod exact {
307         use super::*;
308 
309         #[test]
value()310         fn value() {
311             let possible_settings = vec![
312                 MediaTrackSettings::from_iter([
313                     (&DEVICE_ID, "a".into()),
314                     (&GROUP_ID, "group-0".into()),
315                 ]),
316                 MediaTrackSettings::from_iter([
317                     (&DEVICE_ID, "b".into()),
318                     (&GROUP_ID, "group-1".into()),
319                 ]),
320                 MediaTrackSettings::from_iter([
321                     (&DEVICE_ID, "c".into()),
322                     (&GROUP_ID, "group-2".into()),
323                 ]),
324             ];
325 
326             let actual = test_constrained(
327                 &possible_settings,
328                 ResolvedMandatoryMediaTrackConstraints::from_iter([(
329                     &GROUP_ID,
330                     ResolvedValueConstraint::default()
331                         .exact("group-1".to_owned())
332                         .into(),
333                 )]),
334                 ResolvedAdvancedMediaTrackConstraints::default(),
335             );
336 
337             let expected = vec![&possible_settings[1]];
338 
339             assert_eq!(actual, expected);
340         }
341 
342         #[test]
value_range()343         fn value_range() {
344             let possible_settings = vec![
345                 MediaTrackSettings::from_iter([(&DEVICE_ID, "a".into()), (&FRAME_RATE, 15.into())]),
346                 MediaTrackSettings::from_iter([(&DEVICE_ID, "b".into()), (&FRAME_RATE, 30.into())]),
347                 MediaTrackSettings::from_iter([(&DEVICE_ID, "c".into()), (&FRAME_RATE, 60.into())]),
348             ];
349 
350             let actual = test_constrained(
351                 &possible_settings,
352                 ResolvedMandatoryMediaTrackConstraints::from_iter([(
353                     &FRAME_RATE,
354                     ResolvedValueRangeConstraint::default().exact(30).into(),
355                 )]),
356                 ResolvedAdvancedMediaTrackConstraints::default(),
357             );
358 
359             let expected = vec![&possible_settings[1]];
360 
361             assert_eq!(actual, expected);
362         }
363 
364         #[test]
value_sequence()365         fn value_sequence() {
366             let possible_settings = vec![
367                 MediaTrackSettings::from_iter([
368                     (&DEVICE_ID, "a".into()),
369                     (&GROUP_ID, "group-0".into()),
370                 ]),
371                 MediaTrackSettings::from_iter([
372                     (&DEVICE_ID, "b".into()),
373                     (&GROUP_ID, "group-1".into()),
374                 ]),
375                 MediaTrackSettings::from_iter([
376                     (&DEVICE_ID, "c".into()),
377                     (&GROUP_ID, "group-2".into()),
378                 ]),
379             ];
380 
381             let actual = test_constrained(
382                 &possible_settings,
383                 ResolvedMandatoryMediaTrackConstraints::from_iter([(
384                     &GROUP_ID,
385                     ResolvedValueSequenceConstraint::default()
386                         .exact(vec!["group-1".to_owned(), "group-3".to_owned()])
387                         .into(),
388                 )]),
389                 ResolvedAdvancedMediaTrackConstraints::default(),
390             );
391 
392             let expected = vec![&possible_settings[1]];
393 
394             assert_eq!(actual, expected);
395         }
396     }
397 
398     mod ideal {
399         use super::*;
400 
401         #[test]
value()402         fn value() {
403             let possible_settings = vec![
404                 MediaTrackSettings::from_iter([
405                     (&DEVICE_ID, "a".into()),
406                     (&GROUP_ID, "group-0".into()),
407                 ]),
408                 MediaTrackSettings::from_iter([
409                     (&DEVICE_ID, "b".into()),
410                     (&GROUP_ID, "group-1".into()),
411                 ]),
412                 MediaTrackSettings::from_iter([
413                     (&DEVICE_ID, "c".into()),
414                     (&GROUP_ID, "group-2".into()),
415                 ]),
416             ];
417 
418             let actual = test_constrained(
419                 &possible_settings,
420                 ResolvedMandatoryMediaTrackConstraints::from_iter([(
421                     &GROUP_ID,
422                     ResolvedValueConstraint::default()
423                         .ideal("group-1".to_owned())
424                         .into(),
425                 )]),
426                 ResolvedAdvancedMediaTrackConstraints::default(),
427             );
428 
429             let expected = vec![&possible_settings[1]];
430 
431             assert_eq!(actual, expected);
432         }
433 
434         #[test]
value_range()435         fn value_range() {
436             let possible_settings = vec![
437                 MediaTrackSettings::from_iter([(&DEVICE_ID, "a".into()), (&FRAME_RATE, 15.into())]),
438                 MediaTrackSettings::from_iter([(&DEVICE_ID, "b".into()), (&FRAME_RATE, 30.into())]),
439                 MediaTrackSettings::from_iter([(&DEVICE_ID, "c".into()), (&FRAME_RATE, 60.into())]),
440             ];
441 
442             let actual = test_constrained(
443                 &possible_settings,
444                 ResolvedMandatoryMediaTrackConstraints::from_iter([(
445                     &FRAME_RATE,
446                     ResolvedValueRangeConstraint::default().ideal(32).into(),
447                 )]),
448                 ResolvedAdvancedMediaTrackConstraints::default(),
449             );
450 
451             let expected = vec![&possible_settings[1]];
452 
453             assert_eq!(actual, expected);
454         }
455 
456         #[test]
value_sequence()457         fn value_sequence() {
458             let possible_settings = vec![
459                 MediaTrackSettings::from_iter([
460                     (&DEVICE_ID, "a".into()),
461                     (&GROUP_ID, "group-0".into()),
462                 ]),
463                 MediaTrackSettings::from_iter([
464                     (&DEVICE_ID, "b".into()),
465                     (&GROUP_ID, "group-1".into()),
466                 ]),
467                 MediaTrackSettings::from_iter([
468                     (&DEVICE_ID, "c".into()),
469                     (&GROUP_ID, "group-2".into()),
470                 ]),
471             ];
472 
473             let actual = test_constrained(
474                 &possible_settings,
475                 ResolvedMandatoryMediaTrackConstraints::from_iter([(
476                     &GROUP_ID,
477                     ResolvedValueSequenceConstraint::default()
478                         .ideal(vec!["group-1".to_owned(), "group-3".to_owned()])
479                         .into(),
480                 )]),
481                 ResolvedAdvancedMediaTrackConstraints::default(),
482             );
483 
484             let expected = vec![&possible_settings[1]];
485 
486             assert_eq!(actual, expected);
487         }
488     }
489 }
490 
491 // ```
492 //                        ┌
493 // mandatory constraints: ┤   ┄───────────────────────────────────────────┤
494 //                        └
495 //                        ┌
496 //  advanced constraints: ┤                    ├─┤         ├────────────────────────────┄
497 //                        └
498 //                        ┌
499 //     possible settings: ┤   ●─────────────●──────────────●──────────────●─────────────●
500 //                        └  480p          720p          1080p          1440p         2160p
501 //                                                         └───────┬──────┘
502 //     selected settings: ─────────────────────────────────────────┘
503 // ```
504 mod smoke {
505     use crate::{MediaTrackConstraintSet, ValueConstraint, ValueRangeConstraint};
506 
507     use super::*;
508 
509     #[test]
native()510     fn native() {
511         let supported_constraints = MediaTrackSupportedConstraints::from_iter(vec![
512             &DEVICE_ID,
513             &HEIGHT,
514             &WIDTH,
515             &RESIZE_MODE,
516         ]);
517 
518         let possible_settings = vec![
519             MediaTrackSettings::from_iter([
520                 (&DEVICE_ID, "480p".into()),
521                 (&HEIGHT, 480.into()),
522                 (&WIDTH, 720.into()),
523                 (&RESIZE_MODE, ResizeMode::crop_and_scale().into()),
524             ]),
525             MediaTrackSettings::from_iter([
526                 (&DEVICE_ID, "720p".into()),
527                 (&HEIGHT, 720.into()),
528                 (&WIDTH, 1280.into()),
529                 (&RESIZE_MODE, ResizeMode::crop_and_scale().into()),
530             ]),
531             MediaTrackSettings::from_iter([
532                 (&DEVICE_ID, "1080p".into()),
533                 (&HEIGHT, 1080.into()),
534                 (&WIDTH, 1920.into()),
535                 (&RESIZE_MODE, ResizeMode::none().into()),
536             ]),
537             MediaTrackSettings::from_iter([
538                 (&DEVICE_ID, "1440p".into()),
539                 (&HEIGHT, 1440.into()),
540                 (&WIDTH, 2560.into()),
541                 (&RESIZE_MODE, ResizeMode::none().into()),
542             ]),
543             MediaTrackSettings::from_iter([
544                 (&DEVICE_ID, "2160p".into()),
545                 (&HEIGHT, 2160.into()),
546                 (&WIDTH, 3840.into()),
547                 (&RESIZE_MODE, ResizeMode::none().into()),
548             ]),
549         ];
550 
551         let constraints = MediaTrackConstraints {
552             mandatory: MandatoryMediaTrackConstraints::from_iter([
553                 (
554                     &WIDTH,
555                     ValueRangeConstraint::Constraint(
556                         ResolvedValueRangeConstraint::default().max(2560),
557                     )
558                     .into(),
559                 ),
560                 (
561                     &HEIGHT,
562                     ValueRangeConstraint::Constraint(
563                         ResolvedValueRangeConstraint::default().max(1440),
564                     )
565                     .into(),
566                 ),
567                 // Unsupported constraint, which should thus get ignored:
568                 (
569                     &FRAME_RATE,
570                     ValueRangeConstraint::Constraint(
571                         ResolvedValueRangeConstraint::default().exact(30.0),
572                     )
573                     .into(),
574                 ),
575                 // Ideal resize-mode:
576                 (
577                     &RESIZE_MODE,
578                     ValueConstraint::Bare(ResizeMode::none()).into(),
579                 ),
580             ]),
581             advanced: AdvancedMediaTrackConstraints::from_iter([
582                 // The first advanced constraint set of "exact 800p" does not match
583                 // any candidate and should thus get ignored by the algorithm:
584                 MediaTrackConstraintSet::from_iter([(
585                     &HEIGHT,
586                     ValueRangeConstraint::Constraint(
587                         ResolvedValueRangeConstraint::default().exact(800),
588                     )
589                     .into(),
590                 )]),
591                 // The second advanced constraint set of "no resizing" does match
592                 // candidates and should thus be applied by the algorithm:
593                 MediaTrackConstraintSet::from_iter([(
594                     &RESIZE_MODE,
595                     ValueConstraint::Constraint(
596                         ResolvedValueConstraint::default().exact(ResizeMode::none()),
597                     )
598                     .into(),
599                 )]),
600             ]),
601         };
602 
603         // Resolve bare values to proper constraints:
604         let resolved_constraints = constraints.into_resolved();
605 
606         // Sanitize constraints, removing empty and unsupported constraints:
607         let sanitized_constraints = resolved_constraints.to_sanitized(&supported_constraints);
608 
609         let actual = select_settings_candidates(
610             &possible_settings,
611             &sanitized_constraints,
612             DeviceInformationExposureMode::Exposed,
613         )
614         .unwrap();
615 
616         let expected = vec![&possible_settings[2], &possible_settings[3]];
617 
618         assert_eq!(actual, expected);
619     }
620 
621     #[test]
macros()622     fn macros() {
623         use crate::macros::*;
624 
625         let supported_constraints = MediaTrackSupportedConstraints::from_iter(vec![
626             &DEVICE_ID,
627             &HEIGHT,
628             &WIDTH,
629             &RESIZE_MODE,
630         ]);
631 
632         let possible_settings = vec![
633             settings![
634                 &DEVICE_ID => "480p",
635                 &HEIGHT => 480,
636                 &WIDTH => 720,
637                 &RESIZE_MODE => ResizeMode::crop_and_scale(),
638             ],
639             settings![
640                 &DEVICE_ID => "720p",
641                 &HEIGHT => 720,
642                 &WIDTH => 1280,
643                 &RESIZE_MODE => ResizeMode::crop_and_scale(),
644             ],
645             settings![
646                 &DEVICE_ID => "1080p",
647                 &HEIGHT => 1080,
648                 &WIDTH => 1920,
649                 &RESIZE_MODE => ResizeMode::none(),
650             ],
651             settings![
652                 &DEVICE_ID => "1440p",
653                 &HEIGHT => 1440,
654                 &WIDTH => 2560,
655                 &RESIZE_MODE => ResizeMode::none(),
656             ],
657             settings![
658                 &DEVICE_ID => "2160p",
659                 &HEIGHT => 2160,
660                 &WIDTH => 3840,
661                 &RESIZE_MODE => ResizeMode::none(),
662             ],
663         ];
664 
665         let constraints = constraints! {
666             mandatory: {
667                 &WIDTH => value_range_constraint!{
668                     max: 2560
669                 },
670                 &HEIGHT => value_range_constraint!{
671                     max: 1440
672                 },
673                 // Unsupported constraint, which should thus get ignored:
674                 &FRAME_RATE => value_range_constraint!{
675                     exact: 30.0
676                 },
677             },
678             advanced: [
679                 // The first advanced constraint set of "exact 800p" does not match
680                 // any candidate and should thus get ignored by the algorithm:
681                 {
682                     &HEIGHT => value_range_constraint!{
683                         exact: 800
684                     }
685                 },
686                 // The second advanced constraint set of "no resizing" does match
687                 // candidates and should thus be applied by the algorithm:
688                 {
689                     &RESIZE_MODE => value_constraint!{
690                         exact: ResizeMode::none()
691                     }
692                 },
693             ]
694         };
695 
696         // Resolve bare values to proper constraints:
697         let resolved_constraints = constraints.into_resolved();
698 
699         // Sanitize constraints, removing empty and unsupported constraints:
700         let sanitized_constraints = resolved_constraints.to_sanitized(&supported_constraints);
701 
702         let actual = select_settings_candidates(
703             &possible_settings,
704             &sanitized_constraints,
705             DeviceInformationExposureMode::Exposed,
706         )
707         .unwrap();
708 
709         let expected = vec![&possible_settings[2], &possible_settings[3]];
710 
711         assert_eq!(actual, expected);
712     }
713 
714     #[cfg(feature = "serde")]
715     #[test]
json()716     fn json() {
717         let supported_constraints = MediaTrackSupportedConstraints::from_iter(vec![
718             &DEVICE_ID,
719             &HEIGHT,
720             &WIDTH,
721             &RESIZE_MODE,
722         ]);
723 
724         // Deserialize possible settings from JSON:
725         let possible_settings: Vec<MediaTrackSettings> = {
726             let json = serde_json::json!([
727                 { "deviceId": "480p", "width": 720, "height": 480, "resizeMode": "crop-and-scale" },
728                 { "deviceId": "720p", "width": 1280, "height": 720, "resizeMode": "crop-and-scale" },
729                 { "deviceId": "1080p", "width": 1920, "height": 1080, "resizeMode": "none" },
730                 { "deviceId": "1440p", "width": 2560, "height": 1440, "resizeMode": "none" },
731                 { "deviceId": "2160p", "width": 3840, "height": 2160, "resizeMode": "none" },
732             ]);
733             serde_json::from_value(json).unwrap()
734         };
735 
736         // Deserialize constraints from JSON:
737         let constraints: MediaTrackConstraints = {
738             let json = serde_json::json!({
739                 "width": {
740                     "max": 2560,
741                 },
742                 "height": {
743                     "max": 1440,
744                 },
745                 // Unsupported constraint, which should thus get ignored:
746                 "frameRate": {
747                     "exact": 30.0
748                 },
749                 // Ideal resize-mode:
750                 "resizeMode": "none",
751                 "advanced": [
752                     // The first advanced constraint set of "exact 800p" does not match
753                     // any candidate and should thus get ignored by the algorithm:
754                     { "height": 800 },
755                     // The second advanced constraint set of "no resizing" does match
756                     // candidates and should thus be applied by the algorithm:
757                     { "resizeMode": "none" },
758                 ]
759             });
760             serde_json::from_value(json).unwrap()
761         };
762 
763         // Resolve bare values to proper constraints:
764         let resolved_constraints = constraints.into_resolved();
765 
766         // Sanitize constraints, removing empty and unsupported constraints:
767         let sanitized_constraints = resolved_constraints.into_sanitized(&supported_constraints);
768 
769         let actual = select_settings_candidates(
770             &possible_settings,
771             &sanitized_constraints,
772             DeviceInformationExposureMode::Exposed,
773         )
774         .unwrap();
775 
776         let expected = vec![&possible_settings[2], &possible_settings[3]];
777 
778         assert_eq!(actual, expected);
779     }
780 }
781