use std::{
cell::{Cell, RefCell},
rc::Rc,
};
use derive_more::{AsRef, Into};
use medea_client_api_proto::{
AudioSettings as ProtoAudioConstraints, MediaSourceKind,
MediaType as ProtoTrackConstraints, MediaType, VideoSettings,
};
use wasm_bindgen::prelude::*;
use web_sys as sys;
use crate::{
media::MediaKind,
peer::{
media_exchange_state, mute_state, LocalStreamUpdateCriteria, MediaState,
},
utils::get_property_by_name,
};
#[derive(Clone, Debug, Default)]
pub struct LocalTracksConstraints(Rc<RefCell<MediaStreamSettings>>);
pub struct RecvConstraints {
is_audio_enabled: Cell<bool>,
is_video_enabled: Cell<bool>,
}
impl Default for RecvConstraints {
fn default() -> Self {
Self {
is_audio_enabled: Cell::new(true),
is_video_enabled: Cell::new(true),
}
}
}
impl RecvConstraints {
pub fn set_enabled(&self, enabled: bool, kind: MediaKind) {
match kind {
MediaKind::Audio => {
self.is_audio_enabled.set(enabled);
}
MediaKind::Video => {
self.is_video_enabled.set(enabled);
}
}
}
#[inline]
pub fn is_audio_enabled(&self) -> bool {
self.is_audio_enabled.get()
}
#[inline]
pub fn is_video_enabled(&self) -> bool {
self.is_video_enabled.get()
}
}
#[cfg(feature = "mockable")]
impl From<MediaStreamSettings> for LocalTracksConstraints {
#[inline]
fn from(from: MediaStreamSettings) -> Self {
Self(Rc::new(RefCell::new(from)))
}
}
impl LocalTracksConstraints {
#[inline]
#[must_use]
pub fn calculate_kinds_diff(
&self,
settings: &MediaStreamSettings,
) -> LocalStreamUpdateCriteria {
self.0.borrow().calculate_kinds_diff(&settings)
}
#[inline]
pub fn constrain(&self, other: MediaStreamSettings) {
self.0.borrow_mut().constrain(other)
}
#[inline]
#[must_use]
pub fn inner(&self) -> MediaStreamSettings {
self.0.borrow().clone()
}
#[inline]
pub fn set_media_state(
&self,
state: MediaState,
kind: MediaKind,
source_kind: Option<MediaSourceKind>,
) {
self.0
.borrow_mut()
.set_track_media_state(state, kind, source_kind);
}
#[inline]
pub fn set_media_exchange_state_by_kinds(
&self,
state: media_exchange_state::Stable,
kinds: LocalStreamUpdateCriteria,
) {
self.0
.borrow_mut()
.set_media_exchange_state_by_kinds(state, kinds)
}
#[inline]
#[must_use]
pub fn enabled(&self, kind: &MediaType) -> bool {
self.0.borrow().enabled(kind)
}
#[inline]
#[must_use]
pub fn muted(&self, kind: &MediaType) -> bool {
self.0.borrow().muted(kind)
}
#[inline]
#[must_use]
pub fn is_track_enabled(
&self,
kind: MediaKind,
source: MediaSourceKind,
) -> bool {
self.0.borrow().is_track_enabled(kind, source)
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct AudioMediaTracksSettings {
constraints: AudioTrackConstraints,
enabled: bool,
muted: bool,
}
impl Default for AudioMediaTracksSettings {
#[inline]
fn default() -> Self {
Self {
constraints: AudioTrackConstraints::default(),
enabled: true,
muted: false,
}
}
}
#[inline]
fn satisfies_track(track: &sys::MediaStreamTrack, kind: MediaKind) -> bool {
track.kind() == kind.as_str()
&& track.ready_state() == sys::MediaStreamTrackState::Live
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct VideoTrackConstraints<C> {
constraints: Option<C>,
enabled: bool,
muted: bool,
}
impl<C: Default> Default for VideoTrackConstraints<C> {
fn default() -> Self {
Self {
constraints: Some(C::default()),
enabled: true,
muted: false,
}
}
}
impl<C> VideoTrackConstraints<C> {
#[inline]
fn enabled(&self) -> bool {
self.enabled && self.is_constrained()
}
#[inline]
fn set(&mut self, cons: C) {
self.constraints = Some(cons);
}
#[inline]
fn unconstrain(&mut self) {
self.constraints.take();
}
#[inline]
fn is_constrained(&self) -> bool {
self.constraints.is_some()
}
#[inline]
fn constrain(&mut self, other: Self) {
self.constraints = other.constraints;
}
}
impl VideoTrackConstraints<DeviceVideoTrackConstraints> {
fn satisfies(&self, track: &sys::MediaStreamTrack) -> bool {
self.constraints
.as_ref()
.filter(|_| self.enabled())
.map_or(false, |device| device.satisfies(track))
}
}
impl VideoTrackConstraints<DisplayVideoTrackConstraints> {
fn satisfies(&self, track: &sys::MediaStreamTrack) -> bool {
self.constraints
.as_ref()
.filter(|_| self.enabled())
.map_or(false, |display| display.satisfies(track))
}
}
#[wasm_bindgen]
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct MediaStreamSettings {
audio: AudioMediaTracksSettings,
device_video: VideoTrackConstraints<DeviceVideoTrackConstraints>,
display_video: VideoTrackConstraints<DisplayVideoTrackConstraints>,
}
#[wasm_bindgen]
impl MediaStreamSettings {
#[must_use]
#[wasm_bindgen(constructor)]
pub fn new() -> Self {
Self {
audio: AudioMediaTracksSettings {
constraints: AudioTrackConstraints::default(),
enabled: false,
muted: false,
},
display_video: VideoTrackConstraints {
enabled: true,
constraints: None,
muted: false,
},
device_video: VideoTrackConstraints {
enabled: true,
constraints: None,
muted: false,
},
}
}
pub fn audio(&mut self, constraints: AudioTrackConstraints) {
self.audio.enabled = true;
self.audio.constraints = constraints;
}
pub fn device_video(&mut self, constraints: DeviceVideoTrackConstraints) {
self.device_video.set(constraints);
}
pub fn display_video(&mut self, constraints: DisplayVideoTrackConstraints) {
self.display_video.set(constraints);
}
}
impl MediaStreamSettings {
pub fn unconstrain_if_satisfies_video<T>(&mut self, track: T) -> bool
where
T: AsRef<sys::MediaStreamTrack>,
{
let track = track.as_ref();
if self.device_video.satisfies(track.as_ref()) {
self.device_video.unconstrain();
true
} else if self.display_video.satisfies(track.as_ref()) {
self.display_video.unconstrain();
true
} else {
false
}
}
#[must_use]
pub fn calculate_kinds_diff(
&self,
another: &Self,
) -> LocalStreamUpdateCriteria {
let mut kinds = LocalStreamUpdateCriteria::empty();
if self.device_video != another.device_video {
kinds.add(MediaKind::Video, MediaSourceKind::Device);
}
if self.display_video != another.display_video {
kinds.add(MediaKind::Video, MediaSourceKind::Display);
}
if self.audio != another.audio {
kinds.add(MediaKind::Audio, MediaSourceKind::Device);
}
kinds
}
#[inline]
#[must_use]
pub fn get_audio(&self) -> &AudioTrackConstraints {
&self.audio.constraints
}
#[inline]
#[must_use]
pub fn get_display_video(&self) -> Option<&DisplayVideoTrackConstraints> {
self.display_video.constraints.as_ref()
}
#[inline]
#[must_use]
pub fn get_device_video(&self) -> Option<&DeviceVideoTrackConstraints> {
self.device_video.constraints.as_ref()
}
#[inline]
pub fn set_track_media_state(
&mut self,
state: MediaState,
kind: MediaKind,
source_kind: Option<MediaSourceKind>,
) {
match kind {
MediaKind::Audio => match state {
MediaState::Mute(muted) => {
self.set_audio_muted(muted == mute_state::Stable::Muted);
}
MediaState::MediaExchange(media_exchange) => {
self.set_audio_publish(
media_exchange == media_exchange_state::Stable::Enabled,
);
}
},
MediaKind::Video => match state {
MediaState::Mute(muted) => {
self.set_video_muted(
muted == mute_state::Stable::Muted,
source_kind,
);
}
MediaState::MediaExchange(media_exchange) => {
self.set_video_publish(
media_exchange == media_exchange_state::Stable::Enabled,
source_kind,
);
}
},
}
}
#[inline]
pub fn set_media_exchange_state_by_kinds(
&mut self,
state: media_exchange_state::Stable,
kinds: LocalStreamUpdateCriteria,
) {
let enabled = state == media_exchange_state::Stable::Enabled;
if kinds.has(MediaKind::Audio, MediaSourceKind::Device) {
self.set_audio_publish(enabled);
}
if kinds.has(MediaKind::Video, MediaSourceKind::Device) {
self.set_video_publish(enabled, Some(MediaSourceKind::Device));
}
if kinds.has(MediaKind::Video, MediaSourceKind::Display) {
self.set_video_publish(enabled, Some(MediaSourceKind::Display));
}
}
fn set_audio_muted(&mut self, muted: bool) {
self.audio.muted = muted;
}
fn set_video_muted(
&mut self,
muted: bool,
source_kind: Option<MediaSourceKind>,
) {
match source_kind {
None => {
self.display_video.muted = muted;
self.device_video.muted = muted;
}
Some(MediaSourceKind::Device) => {
self.device_video.muted = muted;
}
Some(MediaSourceKind::Display) => {
self.display_video.muted = muted;
}
}
}
#[inline]
pub fn set_audio_publish(&mut self, enabled: bool) {
self.audio.enabled = enabled;
}
#[inline]
pub fn set_video_publish(
&mut self,
enabled: bool,
source_kind: Option<MediaSourceKind>,
) {
match source_kind {
None => {
self.display_video.enabled = enabled;
self.device_video.enabled = enabled;
}
Some(MediaSourceKind::Device) => {
self.device_video.enabled = enabled;
}
Some(MediaSourceKind::Display) => {
self.display_video.enabled = enabled;
}
}
}
#[inline]
#[must_use]
pub fn is_audio_enabled(&self) -> bool {
self.audio.enabled
}
#[inline]
#[must_use]
pub fn is_device_video_enabled(&self) -> bool {
self.device_video.enabled()
}
#[inline]
#[must_use]
pub fn is_display_video_enabled(&self) -> bool {
self.display_video.enabled()
}
#[inline]
#[must_use]
pub fn enabled(&self, kind: &MediaType) -> bool {
match kind {
MediaType::Video(video) => {
self.is_track_enabled(MediaKind::Video, video.source_kind)
}
MediaType::Audio(_) => {
self.is_track_enabled(MediaKind::Audio, MediaSourceKind::Device)
}
}
}
#[inline]
#[must_use]
pub fn muted(&self, kind: &MediaType) -> bool {
match kind {
MediaType::Video(video) => match video.source_kind {
MediaSourceKind::Device => self.device_video.muted,
MediaSourceKind::Display => self.display_video.muted,
},
MediaType::Audio(_) => self.audio.muted,
}
}
#[inline]
#[must_use]
pub fn is_track_enabled(
&self,
kind: MediaKind,
source: MediaSourceKind,
) -> bool {
match (kind, source) {
(MediaKind::Video, MediaSourceKind::Device) => {
self.device_video.enabled()
}
(MediaKind::Video, MediaSourceKind::Display) => {
self.display_video.enabled()
}
(MediaKind::Audio, _) => self.audio.enabled,
}
}
#[inline]
fn constrain(&mut self, other: Self) {
self.audio.enabled &= other.audio.enabled;
self.audio.constraints = other.audio.constraints;
self.display_video.constrain(other.display_video);
self.device_video.constrain(other.device_video);
}
}
#[derive(Debug)]
pub enum MultiSourceTracksConstraints {
Device(sys::MediaStreamConstraints),
Display(sys::DisplayMediaStreamConstraints),
DeviceAndDisplay(
sys::MediaStreamConstraints,
sys::DisplayMediaStreamConstraints,
),
}
impl From<MediaStreamSettings> for Option<MultiSourceTracksConstraints> {
fn from(constraints: MediaStreamSettings) -> Self {
let is_device_video_enabled = constraints.is_device_video_enabled();
let is_display_video_enabled = constraints.is_display_video_enabled();
let is_device_audio_enabled = constraints.is_audio_enabled();
let mut device_cons = None;
let mut display_cons = None;
if is_device_video_enabled {
if let Some(device_video_cons) =
constraints.device_video.constraints
{
device_cons
.get_or_insert_with(sys::MediaStreamConstraints::new)
.video(
&sys::MediaTrackConstraints::from(device_video_cons)
.into(),
);
}
}
if is_display_video_enabled {
if let Some(display_video_cons) =
constraints.display_video.constraints
{
display_cons
.get_or_insert_with(sys::DisplayMediaStreamConstraints::new)
.video(
&sys::MediaTrackConstraints::from(display_video_cons)
.into(),
);
}
}
if is_device_audio_enabled {
device_cons
.get_or_insert_with(sys::MediaStreamConstraints::new)
.audio(
&sys::MediaTrackConstraints::from(
constraints.audio.constraints,
)
.into(),
);
}
match (device_cons, display_cons) {
(Some(device_cons), Some(display_cons)) => {
Some(MultiSourceTracksConstraints::DeviceAndDisplay(
device_cons,
display_cons,
))
}
(Some(device_cons), None) => {
Some(MultiSourceTracksConstraints::Device(device_cons))
}
(None, Some(display_cons)) => {
Some(MultiSourceTracksConstraints::Display(display_cons))
}
(None, None) => None,
}
}
}
#[derive(Clone, Debug)]
pub enum VideoSource {
Device(DeviceVideoTrackConstraints),
Display(DisplayVideoTrackConstraints),
}
impl VideoSource {
#[inline]
#[must_use]
pub fn required(&self) -> bool {
match self {
VideoSource::Device(device) => device.required,
VideoSource::Display(display) => display.required,
}
}
#[inline]
pub fn satisfies<T: AsRef<sys::MediaStreamTrack>>(&self, track: T) -> bool {
let track = track.as_ref();
match self {
VideoSource::Display(display) => display.satisfies(&track),
VideoSource::Device(device) => device.satisfies(track),
}
}
}
impl From<VideoSettings> for VideoSource {
fn from(settings: VideoSettings) -> Self {
match settings.source_kind {
MediaSourceKind::Device => {
VideoSource::Device(DeviceVideoTrackConstraints {
device_id: None,
facing_mode: None,
width: None,
height: None,
required: settings.required,
})
}
MediaSourceKind::Display => {
VideoSource::Display(DisplayVideoTrackConstraints {
required: settings.required,
})
}
}
}
}
#[derive(Clone)]
pub enum TrackConstraints {
Audio(AudioTrackConstraints),
Video(VideoSource),
}
impl TrackConstraints {
pub fn satisfies<T: AsRef<sys::MediaStreamTrack>>(&self, track: T) -> bool {
match self {
Self::Audio(audio) => audio.satisfies(&track),
Self::Video(video) => video.satisfies(&track),
}
}
#[must_use]
pub fn required(&self) -> bool {
match self {
TrackConstraints::Video(video) => video.required(),
TrackConstraints::Audio(audio) => audio.required,
}
}
#[must_use]
pub fn media_source_kind(&self) -> MediaSourceKind {
match &self {
TrackConstraints::Audio(_) => MediaSourceKind::Device,
TrackConstraints::Video(VideoSource::Device(_)) => {
MediaSourceKind::Device
}
TrackConstraints::Video(VideoSource::Display(_)) => {
MediaSourceKind::Display
}
}
}
#[must_use]
pub fn media_kind(&self) -> MediaKind {
match &self {
TrackConstraints::Audio(_) => MediaKind::Audio,
TrackConstraints::Video(_) => MediaKind::Video,
}
}
}
impl From<ProtoTrackConstraints> for TrackConstraints {
fn from(caps: ProtoTrackConstraints) -> Self {
match caps {
ProtoTrackConstraints::Audio(audio) => Self::Audio(audio.into()),
ProtoTrackConstraints::Video(video) => Self::Video(video.into()),
}
}
}
#[wasm_bindgen]
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct AudioTrackConstraints {
device_id: Option<ConstrainString<DeviceId>>,
required: bool,
}
#[wasm_bindgen]
impl AudioTrackConstraints {
#[must_use]
#[wasm_bindgen(constructor)]
pub fn new() -> Self {
Self::default()
}
pub fn device_id(&mut self, device_id: String) {
self.device_id = Some(ConstrainString::Exact(DeviceId(device_id)));
}
}
impl AudioTrackConstraints {
pub fn satisfies<T: AsRef<sys::MediaStreamTrack>>(&self, track: T) -> bool {
let track = track.as_ref();
satisfies_track(track, MediaKind::Audio)
&& ConstrainString::satisfies(&self.device_id, track)
}
pub fn merge(&mut self, another: AudioTrackConstraints) {
if self.device_id.is_none() && another.device_id.is_some() {
self.device_id = another.device_id;
}
if !self.required && another.required {
self.required = another.required;
}
}
#[must_use]
pub fn required(&self) -> bool {
self.required
}
}
impl From<ProtoAudioConstraints> for AudioTrackConstraints {
#[inline]
fn from(caps: ProtoAudioConstraints) -> Self {
Self {
required: caps.required,
device_id: None,
}
}
}
impl From<AudioTrackConstraints> for sys::MediaTrackConstraints {
fn from(track_constraints: AudioTrackConstraints) -> Self {
let mut constraints = Self::new();
if let Some(device_id) = track_constraints.device_id {
constraints.device_id(&sys::ConstrainDomStringParameters::from(
&device_id,
));
}
constraints
}
}
trait Constraint {
const TRACK_SETTINGS_FIELD_NAME: &'static str;
}
#[derive(AsRef, Clone, Debug, Eq, PartialEq)]
#[as_ref(forward)]
struct DeviceId(String);
impl Constraint for DeviceId {
const TRACK_SETTINGS_FIELD_NAME: &'static str = "deviceId";
}
#[derive(Clone, Copy, Debug, Eq, Into, PartialEq)]
struct Height(u32);
impl Constraint for Height {
const TRACK_SETTINGS_FIELD_NAME: &'static str = "height";
}
#[derive(Clone, Copy, Debug, Eq, Into, PartialEq)]
struct Width(u32);
impl Constraint for Width {
const TRACK_SETTINGS_FIELD_NAME: &'static str = "width";
}
#[wasm_bindgen]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum FacingMode {
User,
Environment,
Left,
Right,
}
impl AsRef<str> for FacingMode {
fn as_ref(&self) -> &str {
match self {
FacingMode::User => "user",
FacingMode::Environment => "environment",
FacingMode::Left => "left",
FacingMode::Right => "right",
}
}
}
impl Constraint for FacingMode {
const TRACK_SETTINGS_FIELD_NAME: &'static str = "facingMode";
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum ConstrainU32<T> {
Exact(T),
Ideal(T),
Range(T, T),
}
impl<T: Constraint + Into<u32>> ConstrainU32<T> {
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
fn satisfies(this: Option<Self>, track: &sys::MediaStreamTrack) -> bool {
match this {
None | Some(ConstrainU32::Ideal(_)) => true,
Some(ConstrainU32::Exact(exact)) => get_property_by_name(
&track.get_settings(),
T::TRACK_SETTINGS_FIELD_NAME,
|v| v.as_f64().map(|v| v as u32),
)
.map_or(false, |val| val == exact.into()),
Some(ConstrainU32::Range(start, end)) => get_property_by_name(
&track.get_settings(),
T::TRACK_SETTINGS_FIELD_NAME,
|v| v.as_f64().map(|v| v as u32),
)
.map_or(false, |val| val >= start.into() && val <= end.into()),
}
}
}
impl<T: Constraint + Into<u32>> From<ConstrainU32<T>>
for sys::ConstrainDoubleRange
{
fn from(from: ConstrainU32<T>) -> Self {
let mut constraint = sys::ConstrainDoubleRange::new();
match from {
ConstrainU32::Exact(val) => {
constraint.exact(f64::from(val.into()));
}
ConstrainU32::Ideal(val) => {
constraint.ideal(f64::from(val.into()));
}
ConstrainU32::Range(min, max) => {
constraint
.min(f64::from(min.into()))
.max(f64::from(max.into()));
}
}
constraint
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum ConstrainString<T> {
Exact(T),
Ideal(T),
}
impl<T: Constraint + AsRef<str>> ConstrainString<T> {
fn satisfies(this: &Option<Self>, track: &sys::MediaStreamTrack) -> bool {
match this {
None | Some(ConstrainString::Ideal(_)) => true,
Some(ConstrainString::Exact(constrain)) => get_property_by_name(
&track.get_settings(),
T::TRACK_SETTINGS_FIELD_NAME,
|v| v.as_string(),
)
.map_or(false, |id| id.as_str() == constrain.as_ref()),
}
}
}
impl<T: AsRef<str>> From<&ConstrainString<T>>
for sys::ConstrainDomStringParameters
{
fn from(from: &ConstrainString<T>) -> Self {
let mut constraint = sys::ConstrainDomStringParameters::new();
match from {
ConstrainString::Exact(val) => {
constraint.exact(&JsValue::from_str(val.as_ref()))
}
ConstrainString::Ideal(val) => {
constraint.ideal(&JsValue::from_str(val.as_ref()))
}
};
constraint
}
}
#[wasm_bindgen]
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct DeviceVideoTrackConstraints {
required: bool,
device_id: Option<ConstrainString<DeviceId>>,
facing_mode: Option<ConstrainString<FacingMode>>,
height: Option<ConstrainU32<Height>>,
width: Option<ConstrainU32<Width>>,
}
impl DeviceVideoTrackConstraints {
#[must_use]
pub fn satisfies(&self, track: &sys::MediaStreamTrack) -> bool {
satisfies_track(track, MediaKind::Video)
&& ConstrainString::satisfies(&self.device_id, track)
&& ConstrainString::satisfies(&self.facing_mode, track)
&& ConstrainU32::satisfies(self.height, track)
&& ConstrainU32::satisfies(self.width, track)
&& !guess_is_from_display(&track)
}
pub fn merge(&mut self, another: DeviceVideoTrackConstraints) {
if self.device_id.is_none() && another.device_id.is_some() {
self.device_id = another.device_id;
}
if !self.required && another.required {
self.required = another.required;
}
if self.facing_mode.is_none() && another.facing_mode.is_some() {
self.facing_mode = another.facing_mode;
}
if self.height.is_none() && another.height.is_some() {
self.height = another.height;
}
if self.width.is_none() && another.width.is_some() {
self.width = another.width;
}
}
#[inline]
#[must_use]
pub fn required(&self) -> bool {
self.required
}
}
#[wasm_bindgen]
impl DeviceVideoTrackConstraints {
#[must_use]
#[wasm_bindgen(constructor)]
pub fn new() -> Self {
Self::default()
}
pub fn device_id(&mut self, device_id: String) {
self.device_id = Some(ConstrainString::Exact(DeviceId(device_id)));
}
pub fn exact_facing_mode(&mut self, facing_mode: FacingMode) {
self.facing_mode = Some(ConstrainString::Exact(facing_mode));
}
pub fn ideal_facing_mode(&mut self, facing_mode: FacingMode) {
self.facing_mode = Some(ConstrainString::Ideal(facing_mode));
}
pub fn exact_height(&mut self, height: u32) {
self.height = Some(ConstrainU32::Exact(Height(height)));
}
pub fn ideal_height(&mut self, height: u32) {
self.height = Some(ConstrainU32::Ideal(Height(height)));
}
pub fn height_in_range(&mut self, min: u32, max: u32) {
self.height = Some(ConstrainU32::Range(Height(min), Height(max)));
}
pub fn exact_width(&mut self, width: u32) {
self.width = Some(ConstrainU32::Exact(Width(width)));
}
pub fn ideal_width(&mut self, width: u32) {
self.width = Some(ConstrainU32::Ideal(Width(width)));
}
pub fn width_in_range(&mut self, min: u32, max: u32) {
self.width = Some(ConstrainU32::Range(Width(min), Width(max)));
}
}
#[wasm_bindgen]
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct DisplayVideoTrackConstraints {
required: bool,
}
impl DisplayVideoTrackConstraints {
#[allow(clippy::unused_self)]
#[inline]
#[must_use]
pub fn satisfies(&self, track: &sys::MediaStreamTrack) -> bool {
satisfies_track(track, MediaKind::Video)
&& guess_is_from_display(&track)
}
#[inline]
pub fn merge(&mut self, another: &Self) {
if !self.required && another.required {
self.required = another.required;
}
}
#[inline]
#[must_use]
pub fn required(&self) -> bool {
self.required
}
}
#[wasm_bindgen]
impl DisplayVideoTrackConstraints {
#[must_use]
#[wasm_bindgen(constructor)]
pub fn new() -> Self {
Self::default()
}
}
fn guess_is_from_display(track: &sys::MediaStreamTrack) -> bool {
let settings = track.get_settings();
let has_display_surface =
get_property_by_name(&settings, "displaySurface", |val| {
val.as_string()
})
.is_some();
if has_display_surface {
true
} else {
get_property_by_name(&settings, "logicalSurface", |val| val.as_string())
.is_some()
}
}
impl From<DeviceVideoTrackConstraints> for sys::MediaTrackConstraints {
fn from(track_constraints: DeviceVideoTrackConstraints) -> Self {
let mut constraints = Self::new();
if let Some(device_id) = track_constraints.device_id {
constraints.device_id(&sys::ConstrainDomStringParameters::from(
&device_id,
));
}
if let Some(facing_mode) = track_constraints.facing_mode {
constraints.facing_mode(&sys::ConstrainDomStringParameters::from(
&facing_mode,
));
}
if let Some(width) = track_constraints.width {
constraints.width(&sys::ConstrainDoubleRange::from(width));
}
if let Some(height) = track_constraints.height {
constraints.height(&sys::ConstrainDoubleRange::from(height));
}
constraints
}
}
impl From<DisplayVideoTrackConstraints> for sys::MediaTrackConstraints {
fn from(_: DisplayVideoTrackConstraints) -> Self {
Self::new()
}
}