diff --git a/Cargo.lock b/Cargo.lock index 3fc53573b..5dfddf127 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5466,7 +5466,7 @@ dependencies = [ [[package]] name = "rust-pulsectl" version = "0.2.12" -source = "git+https://github.com/open-trade/pulsectl#5e68f4c2b7c644fa321984688602d71e8ad0bba3" +source = "git+https://github.com/rustdesk-org/pulsectl#aa34dde499aa912a3abc5289cc0b547bd07dd6e2" dependencies = [ "libpulse-binding", ] @@ -5813,7 +5813,7 @@ dependencies = [ [[package]] name = "sciter-rs" version = "0.5.57" -source = "git+https://github.com/open-trade/rust-sciter?branch=dyn#5322f3a755a0e6bf999fbc60d1efc35246c0f821" +source = "git+https://github.com/rustdesk-org/rust-sciter?branch=dyn#5322f3a755a0e6bf999fbc60d1efc35246c0f821" dependencies = [ "lazy_static", "libc", diff --git a/Cargo.toml b/Cargo.toml index dae69ead3..f2f3076be 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -78,6 +78,9 @@ fon = "0.6" zip = "0.6" shutdown_hooks = "0.1" totp-rs = { version = "5.4", default-features = false, features = ["gen_secret", "otpauth"] } + +[target.'cfg(not(target_os = "linux"))'.dependencies] +# https://github.com/rustdesk/rustdesk/discussions/10197, not use cpal on linux cpal = { git = "https://github.com/rustdesk-org/cpal", branch = "osx-screencapturekit" } ringbuf = "0.3" diff --git a/src/client.rs b/src/client.rs index 83b6de43a..051614383 100644 --- a/src/client.rs +++ b/src/client.rs @@ -2,12 +2,14 @@ use async_trait::async_trait; use bytes::Bytes; #[cfg(not(any(target_os = "android", target_os = "ios")))] use clipboard_master::{CallbackResult, ClipboardHandler}; +#[cfg(not(target_os = "linux"))] use cpal::{ traits::{DeviceTrait, HostTrait, StreamTrait}, Device, Host, StreamConfig, }; use crossbeam_queue::ArrayQueue; use magnum_opus::{Channels::*, Decoder as AudioDecoder}; +#[cfg(not(target_os = "linux"))] use ringbuf::{ring_buffer::RbBase, Rb}; use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; @@ -117,6 +119,7 @@ pub const SCRAP_OTHER_VERSION_OR_X11_REQUIRED: &str = pub const SCRAP_X11_REQUIRED: &str = "x11 expected"; pub const SCRAP_X11_REF_URL: &str = "https://rustdesk.com/docs/en/manual/linux/#x11-required"; +#[cfg(not(target_os = "linux"))] pub const AUDIO_BUFFER_MS: usize = 3000; #[cfg(feature = "flutter")] @@ -139,6 +142,7 @@ struct TextClipboardState { running: bool, } +#[cfg(not(target_os = "linux"))] lazy_static::lazy_static! { static ref AUDIO_HOST: Host = cpal::default_host(); } @@ -861,20 +865,28 @@ impl ClipboardHandler for ClientClipboardHandler { #[derive(Default)] pub struct AudioHandler { audio_decoder: Option<(AudioDecoder, Vec)>, + #[cfg(target_os = "linux")] + simple: Option, + #[cfg(not(target_os = "linux"))] audio_buffer: AudioBuffer, sample_rate: (u32, u32), + #[cfg(not(target_os = "linux"))] audio_stream: Option>, channels: u16, + #[cfg(not(target_os = "linux"))] device_channel: u16, + #[cfg(not(target_os = "linux"))] ready: Arc>, } +#[cfg(not(target_os = "linux"))] struct AudioBuffer( pub Arc>>, usize, [usize; 30], ); +#[cfg(not(target_os = "linux"))] impl Default for AudioBuffer { fn default() -> Self { Self( @@ -887,6 +899,7 @@ impl Default for AudioBuffer { } } +#[cfg(not(target_os = "linux"))] impl AudioBuffer { pub fn resize(&mut self, sample_rate: usize, channels: usize) { let capacity = sample_rate * channels * AUDIO_BUFFER_MS / 1000; @@ -989,7 +1002,37 @@ impl AudioBuffer { } impl AudioHandler { + #[cfg(target_os = "linux")] + fn start_audio(&mut self, format0: AudioFormat) -> ResultType<()> { + use psimple::Simple; + use pulse::sample::{Format, Spec}; + use pulse::stream::Direction; + + let spec = Spec { + format: Format::F32le, + channels: format0.channels as _, + rate: format0.sample_rate as _, + }; + if !spec.is_valid() { + bail!("Invalid audio format"); + } + + self.simple = Some(Simple::new( + None, // Use the default server + &crate::get_app_name(), // Our application’s name + Direction::Playback, // We want a playback stream + None, // Use the default device + "playback", // Description of our stream + &spec, // Our sample format + None, // Use default channel map + None, // Use default buffering attributes + )?); + self.sample_rate = (format0.sample_rate, format0.sample_rate); + Ok(()) + } + /// Start the audio playback. + #[cfg(not(target_os = "linux"))] fn start_audio(&mut self, format0: AudioFormat) -> ResultType<()> { let device = AUDIO_HOST .default_output_device() @@ -1057,13 +1100,20 @@ impl AudioHandler { /// Handle audio frame and play it. #[inline] pub fn handle_frame(&mut self, frame: AudioFrame) { + #[cfg(not(target_os = "linux"))] if self.audio_stream.is_none() || !self.ready.lock().unwrap().clone() { return; } + #[cfg(target_os = "linux")] + if self.simple.is_none() { + log::debug!("PulseAudio simple binding does not exists"); + return; + } self.audio_decoder.as_mut().map(|(d, buffer)| { if let Ok(n) = d.decode_float(&frame.data, buffer, false) { let channels = self.channels; let n = n * (channels as usize); + #[cfg(not(target_os = "linux"))] { let sample_rate0 = self.sample_rate.0; let sample_rate = self.sample_rate.1; @@ -1087,11 +1137,18 @@ impl AudioHandler { } self.audio_buffer.append_pcm(&buffer); } + #[cfg(target_os = "linux")] + { + let data_u8 = + unsafe { std::slice::from_raw_parts::(buffer.as_ptr() as _, n * 4) }; + self.simple.as_mut().map(|x| x.write(data_u8)); + } } }); } /// Build audio output stream for current device. + #[cfg(not(target_os = "linux"))] fn build_output_stream>( &mut self, config: &StreamConfig,