#[cfg(windows)]
pub mod windows;
#[cfg(target_os = "macos")]
pub mod macos;
#[cfg(not(any(windows, target_os = "macos")))]
compile_error!("DiscRec targets Windows and macOS only. See docs/02-constraints.md");
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Source {
DiscordOutput,
Microphone,
}
#[derive(Clone, Debug)]
pub struct Frame {
pub source: Source,
pub sample_pos: u64,
pub channels: u16,
pub sample_rate: u32,
pub samples: Vec<f32>,
}
#[derive(Copy, Clone, Debug)]
pub struct StreamFormat {
pub sample_rate: u32,
pub channels: u16,
}
#[derive(Debug)]
pub enum CaptureError {
UnsupportedOs {
needs: &'static str,
},
PermissionDenied,
NoSignal,
DiscordNotFound,
Platform(String),
}
impl std::fmt::Display for CaptureError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
CaptureError::UnsupportedOs { needs } => write!(f, "This needs {needs} or later."),
CaptureError::PermissionDenied => {
write!(f, "DiscRec needs permission to record audio.")
}
CaptureError::NoSignal => write!(f, "Started, but no audio is coming through."),
CaptureError::DiscordNotFound => write!(f, "Start Discord first."),
CaptureError::Platform(msg) => write!(f, "{msg}"),
}
}
}
impl std::error::Error for CaptureError {}
pub type FrameSink = std::sync::mpsc::Sender<Frame>;
pub trait CaptureBackend: Send {
fn start(&mut self, discord_pid: u32, sink: FrameSink) -> Result<(), CaptureError>;
fn stop(&mut self) -> Result<(), CaptureError>;
fn format(&self) -> StreamFormat;
}
#[cfg(windows)]
pub fn backend() -> Box<dyn CaptureBackend> {
Box::new(windows::WasapiBackend::new())
}
#[cfg(target_os = "macos")]
pub fn backend() -> Box<dyn CaptureBackend> {
Box::new(macos::CoreAudioBackend::new())
}