use crate::context::{AudioContextLatencyCategory, AudioContextOptions};
use crate::media_streams::MediaStream;
pub fn enumerate_devices_sync() -> Vec<MediaDeviceInfo> {
crate::io::enumerate_devices_sync()
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum MediaDeviceInfoKind {
VideoInput,
AudioInput,
AudioOutput,
}
#[derive(Debug)]
pub struct MediaDeviceInfo {
device_id: String,
group_id: Option<String>,
kind: MediaDeviceInfoKind,
label: String,
device: Box<dyn std::any::Any>,
}
impl MediaDeviceInfo {
pub(crate) fn new(
device_id: String,
group_id: Option<String>,
kind: MediaDeviceInfoKind,
label: String,
device: Box<dyn std::any::Any>,
) -> Self {
Self {
device_id,
group_id,
kind,
label,
device,
}
}
pub fn device_id(&self) -> &str {
&self.device_id
}
pub fn group_id(&self) -> Option<&str> {
self.group_id.as_deref()
}
pub fn kind(&self) -> MediaDeviceInfoKind {
self.kind
}
pub fn label(&self) -> &str {
&self.label
}
pub(crate) fn device(self) -> Box<dyn std::any::Any> {
self.device
}
}
pub enum MediaStreamConstraints {
Audio,
AudioWithConstraints(MediaTrackConstraints),
}
#[derive(Default)]
#[non_exhaustive]
pub struct MediaTrackConstraints {
pub sample_rate: Option<f32>,
pub latency: Option<f64>,
pub device_id: Option<String>,
}
impl From<MediaTrackConstraints> for AudioContextOptions {
fn from(value: MediaTrackConstraints) -> Self {
let latency_hint = match value.latency {
Some(v) => AudioContextLatencyCategory::Custom(v),
None => AudioContextLatencyCategory::Interactive,
};
let sink_id = value.device_id.unwrap_or(String::from(""));
AudioContextOptions {
latency_hint,
sample_rate: value.sample_rate,
sink_id,
render_size_hint: Default::default(),
}
}
}
fn is_valid_device_id(device_id: &str) -> bool {
if device_id.is_empty() {
true
} else {
enumerate_devices_sync()
.into_iter()
.filter(|d| d.kind == MediaDeviceInfoKind::AudioInput)
.any(|d| d.device_id() == device_id)
}
}
pub fn get_user_media_sync(constraints: MediaStreamConstraints) -> MediaStream {
let mut options = match constraints {
MediaStreamConstraints::Audio => AudioContextOptions::default(),
MediaStreamConstraints::AudioWithConstraints(cs) => cs.into(),
};
if !is_valid_device_id(&options.sink_id) {
log::error!("NotFoundError: invalid deviceId {:?}", options.sink_id);
options.sink_id = String::from("");
}
crate::io::build_input(options)
}