241 lines · 6.3 KB · Rust
RawDownload
use anyhow::Context as _;use collections::HashMap;use cpal::DeviceId; mod remote_video_track_view;pub use remote_video_track_view::{RemoteVideoTrackView, RemoteVideoTrackViewEvent};use rodio::DeviceTrait as _; mod record;pub use record::CaptureInput; #[cfg(any(    rust_analyzer,    not(any(        test,        feature = "test-support",        all(target_os = "windows", target_env = "gnu"),        target_os = "freebsd"    ))))]mod livekit_client;#[cfg(any(    rust_analyzer,    not(any(        test,        feature = "test-support",        all(target_os = "windows", target_env = "gnu"),        target_os = "freebsd"    ))))]pub use livekit_client::*; #[cfg(all(    not(rust_analyzer),    any(        test,        feature = "test-support",        all(target_os = "windows", target_env = "gnu"),        target_os = "freebsd"    )))]mod mock_client;#[cfg(all(    not(rust_analyzer),    any(        test,        feature = "test-support",        all(target_os = "windows", target_env = "gnu"),        target_os = "freebsd"    )))]pub mod test;#[cfg(all(    not(rust_analyzer),    any(        test,        feature = "test-support",        all(target_os = "windows", target_env = "gnu"),        target_os = "freebsd"    )))]pub use mock_client::*; #[derive(Debug, Clone)]pub enum Participant {    Local(LocalParticipant),    Remote(RemoteParticipant),} #[derive(Debug, Clone)]pub enum TrackPublication {    Local(LocalTrackPublication),    Remote(RemoteTrackPublication),} impl TrackPublication {    pub fn sid(&self) -> TrackSid {        match self {            TrackPublication::Local(local) => local.sid(),            TrackPublication::Remote(remote) => remote.sid(),        }    }     pub fn is_muted(&self) -> bool {        match self {            TrackPublication::Local(local) => local.is_muted(),            TrackPublication::Remote(remote) => remote.is_muted(),        }    }} #[derive(Clone, Debug)]pub enum RemoteTrack {    Audio(RemoteAudioTrack),    Video(RemoteVideoTrack),} impl RemoteTrack {    pub fn sid(&self) -> TrackSid {        match self {            RemoteTrack::Audio(remote_audio_track) => remote_audio_track.sid(),            RemoteTrack::Video(remote_video_track) => remote_video_track.sid(),        }    }} #[derive(Clone, Debug)]pub enum LocalTrack {    Audio(LocalAudioTrack),    Video(LocalVideoTrack),} #[derive(Clone, Debug)]#[non_exhaustive]pub enum RoomEvent {    ParticipantConnected(RemoteParticipant),    ParticipantDisconnected(RemoteParticipant),    LocalTrackPublished {        publication: LocalTrackPublication,        track: LocalTrack,        participant: LocalParticipant,    },    LocalTrackUnpublished {        publication: LocalTrackPublication,        participant: LocalParticipant,    },    LocalTrackSubscribed {        track: LocalTrack,    },    TrackSubscribed {        track: RemoteTrack,        publication: RemoteTrackPublication,        participant: RemoteParticipant,    },    TrackUnsubscribed {        track: RemoteTrack,        publication: RemoteTrackPublication,        participant: RemoteParticipant,    },    TrackSubscriptionFailed {        participant: RemoteParticipant,        // error: livekit::track::TrackError,        track_sid: TrackSid,    },    TrackPublished {        publication: RemoteTrackPublication,        participant: RemoteParticipant,    },    TrackUnpublished {        publication: RemoteTrackPublication,        participant: RemoteParticipant,    },    TrackMuted {        participant: Participant,        publication: TrackPublication,    },    TrackUnmuted {        participant: Participant,        publication: TrackPublication,    },    RoomMetadataChanged {        old_metadata: String,        metadata: String,    },    ParticipantMetadataChanged {        participant: Participant,        old_metadata: String,        metadata: String,    },    ParticipantNameChanged {        participant: Participant,        old_name: String,        name: String,    },    ParticipantAttributesChanged {        participant: Participant,        changed_attributes: HashMap<String, String>,    },    ActiveSpeakersChanged {        speakers: Vec<Participant>,    },    ConnectionStateChanged(ConnectionState),    Connected {        participants_with_tracks: Vec<(RemoteParticipant, Vec<RemoteTrackPublication>)>,    },    Disconnected {        reason: &'static str,    },    Reconnecting,    Reconnected,} pub(crate) fn default_device(    input: bool,    device_id: Option<&DeviceId>,) -> anyhow::Result<(cpal::Device, cpal::SupportedStreamConfig)> {    let device = audio::resolve_device(device_id, input)?;    let config = if input {        device            .default_input_config()            .context("failed to get default input config")?    } else {        device            .default_output_config()            .context("failed to get default output config")?    };    Ok((device, config))} pub(crate) fn get_sample_data(    sample_format: cpal::SampleFormat,    data: &cpal::Data,) -> anyhow::Result<Vec<i16>> {    match sample_format {        cpal::SampleFormat::I8 => Ok(convert_sample_data::<i8, i16>(data)),        cpal::SampleFormat::I16 => Ok(data.as_slice::<i16>().unwrap().to_vec()),        cpal::SampleFormat::I24 => Ok(convert_sample_data::<cpal::I24, i16>(data)),        cpal::SampleFormat::I32 => Ok(convert_sample_data::<i32, i16>(data)),        cpal::SampleFormat::I64 => Ok(convert_sample_data::<i64, i16>(data)),        cpal::SampleFormat::U8 => Ok(convert_sample_data::<u8, i16>(data)),        cpal::SampleFormat::U16 => Ok(convert_sample_data::<u16, i16>(data)),        cpal::SampleFormat::U32 => Ok(convert_sample_data::<u32, i16>(data)),        cpal::SampleFormat::U64 => Ok(convert_sample_data::<u64, i16>(data)),        cpal::SampleFormat::F32 => Ok(convert_sample_data::<f32, i16>(data)),        cpal::SampleFormat::F64 => Ok(convert_sample_data::<f64, i16>(data)),        _ => anyhow::bail!("Unsupported sample format"),    }} pub(crate) fn convert_sample_data<    TSource: cpal::SizedSample,    TDest: cpal::SizedSample + cpal::FromSample<TSource>,>(    data: &cpal::Data,) -> Vec<TDest> {    data.as_slice::<TSource>()        .unwrap()        .iter()        .map(|e| e.to_sample::<TDest>())        .collect()}