mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-03-20 19:51:04 +03:00
linux android use cpal (#9914)
Signed-off-by: 21pages <sunboeasy@gmail.com>
This commit is contained in:
149
src/client.rs
149
src/client.rs
@@ -2,14 +2,12 @@ use async_trait::async_trait;
|
||||
use bytes::Bytes;
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
use clipboard_master::{CallbackResult, ClipboardHandler};
|
||||
#[cfg(not(any(target_os = "android", 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(any(target_os = "android", target_os = "linux")))]
|
||||
use ringbuf::{ring_buffer::RbBase, Rb};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sha2::{Digest, Sha256};
|
||||
@@ -117,7 +115,6 @@ 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(any(target_os = "android", target_os = "linux")))]
|
||||
pub const AUDIO_BUFFER_MS: usize = 3000;
|
||||
|
||||
#[cfg(feature = "flutter")]
|
||||
@@ -140,7 +137,6 @@ struct TextClipboardState {
|
||||
running: bool,
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "android", target_os = "linux")))]
|
||||
lazy_static::lazy_static! {
|
||||
static ref AUDIO_HOST: Host = cpal::default_host();
|
||||
}
|
||||
@@ -163,66 +159,6 @@ pub fn get_key_state(key: enigo::Key) -> bool {
|
||||
ENIGO.lock().unwrap().get_key_state(key)
|
||||
}
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(target_os = "android")] {
|
||||
|
||||
use hbb_common::libc::{c_float, c_int};
|
||||
type Oboe = *mut c_void;
|
||||
extern "C" {
|
||||
fn create_oboe_player(channels: c_int, sample_rate: c_int) -> Oboe;
|
||||
fn push_oboe_data(oboe: Oboe, d: *const c_float, n: c_int);
|
||||
fn destroy_oboe_player(oboe: Oboe);
|
||||
}
|
||||
|
||||
struct OboePlayer {
|
||||
raw: Oboe,
|
||||
}
|
||||
|
||||
impl Default for OboePlayer {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
raw: std::ptr::null_mut(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl OboePlayer {
|
||||
fn new(channels: i32, sample_rate: i32) -> Self {
|
||||
unsafe {
|
||||
Self {
|
||||
raw: create_oboe_player(channels, sample_rate),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
fn is_null(&self) -> bool {
|
||||
self.raw.is_null()
|
||||
}
|
||||
|
||||
fn push(&mut self, d: &[f32]) {
|
||||
if self.raw.is_null() {
|
||||
return;
|
||||
}
|
||||
unsafe {
|
||||
push_oboe_data(self.raw, d.as_ptr(), d.len() as _);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for OboePlayer {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
if !self.raw.is_null() {
|
||||
destroy_oboe_player(self.raw);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
impl Client {
|
||||
/// Start a new connection.
|
||||
pub async fn start(
|
||||
@@ -887,30 +823,20 @@ impl ClipboardHandler for ClientClipboardHandler {
|
||||
#[derive(Default)]
|
||||
pub struct AudioHandler {
|
||||
audio_decoder: Option<(AudioDecoder, Vec<f32>)>,
|
||||
#[cfg(target_os = "android")]
|
||||
oboe: Option<OboePlayer>,
|
||||
#[cfg(target_os = "linux")]
|
||||
simple: Option<psimple::Simple>,
|
||||
#[cfg(not(any(target_os = "android", target_os = "linux")))]
|
||||
audio_buffer: AudioBuffer,
|
||||
sample_rate: (u32, u32),
|
||||
#[cfg(not(any(target_os = "android", target_os = "linux")))]
|
||||
audio_stream: Option<Box<dyn StreamTrait>>,
|
||||
channels: u16,
|
||||
#[cfg(not(any(target_os = "android", target_os = "linux")))]
|
||||
device_channel: u16,
|
||||
#[cfg(not(any(target_os = "android", target_os = "linux")))]
|
||||
ready: Arc<std::sync::Mutex<bool>>,
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "android", target_os = "linux")))]
|
||||
struct AudioBuffer(
|
||||
pub Arc<std::sync::Mutex<ringbuf::HeapRb<f32>>>,
|
||||
usize,
|
||||
[usize; 30],
|
||||
);
|
||||
|
||||
#[cfg(not(any(target_os = "android", target_os = "linux")))]
|
||||
impl Default for AudioBuffer {
|
||||
fn default() -> Self {
|
||||
Self(
|
||||
@@ -923,7 +849,6 @@ impl Default for AudioBuffer {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "android", target_os = "linux")))]
|
||||
impl AudioBuffer {
|
||||
pub fn resize(&mut self, sample_rate: usize, channels: usize) {
|
||||
let capacity = sample_rate * channels * AUDIO_BUFFER_MS / 1000;
|
||||
@@ -1026,48 +951,6 @@ impl AudioBuffer {
|
||||
|
||||
impl AudioHandler {
|
||||
/// Start the audio playback.
|
||||
#[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(target_os = "android")]
|
||||
fn start_audio(&mut self, format0: AudioFormat) -> ResultType<()> {
|
||||
self.oboe = Some(OboePlayer::new(
|
||||
format0.channels as _,
|
||||
format0.sample_rate as _,
|
||||
));
|
||||
self.sample_rate = (format0.sample_rate, format0.sample_rate);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Start the audio playback.
|
||||
#[cfg(not(any(target_os = "android", target_os = "linux")))]
|
||||
fn start_audio(&mut self, format0: AudioFormat) -> ResultType<()> {
|
||||
let device = AUDIO_HOST
|
||||
.default_output_device()
|
||||
@@ -1130,24 +1013,13 @@ impl AudioHandler {
|
||||
/// Handle audio frame and play it.
|
||||
#[inline]
|
||||
pub fn handle_frame(&mut self, frame: AudioFrame) {
|
||||
#[cfg(not(any(target_os = "android", 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;
|
||||
}
|
||||
#[cfg(target_os = "android")]
|
||||
if self.oboe.is_none() {
|
||||
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(any(target_os = "android", target_os = "linux")))]
|
||||
{
|
||||
let sample_rate0 = self.sample_rate.0;
|
||||
let sample_rate = self.sample_rate.1;
|
||||
@@ -1171,22 +1043,11 @@ impl AudioHandler {
|
||||
}
|
||||
self.audio_buffer.append_pcm(&buffer);
|
||||
}
|
||||
#[cfg(target_os = "android")]
|
||||
{
|
||||
self.oboe.as_mut().map(|x| x.push(&buffer[0..n]));
|
||||
}
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
let data_u8 =
|
||||
unsafe { std::slice::from_raw_parts::<u8>(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(any(target_os = "android", target_os = "linux")))]
|
||||
fn build_output_stream<T: cpal::Sample + cpal::SizedSample + cpal::FromSample<f32>>(
|
||||
&mut self,
|
||||
config: &StreamConfig,
|
||||
@@ -1212,6 +1073,8 @@ impl AudioHandler {
|
||||
let mut n = data.len();
|
||||
let mut lock = audio_buffer.lock().unwrap();
|
||||
let mut having = lock.occupied_len();
|
||||
// android two timestamps, one from zero, another not
|
||||
#[cfg(not(target_os = "android"))]
|
||||
if having < n {
|
||||
let tms = info.timestamp();
|
||||
let how_long = tms
|
||||
@@ -1220,7 +1083,8 @@ impl AudioHandler {
|
||||
.unwrap_or(Duration::from_millis(0));
|
||||
|
||||
// must long enough to fight back scheuler delay
|
||||
if how_long > Duration::from_millis(6) {
|
||||
if how_long > Duration::from_millis(6) && how_long < Duration::from_millis(3000)
|
||||
{
|
||||
drop(lock);
|
||||
std::thread::sleep(how_long.div_f32(1.2));
|
||||
lock = audio_buffer.lock().unwrap();
|
||||
@@ -1231,7 +1095,10 @@ impl AudioHandler {
|
||||
n = having;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
if having < n {
|
||||
n = having;
|
||||
}
|
||||
let mut elems = vec![0.0f32; n];
|
||||
if n > 0 {
|
||||
lock.pop_slice(&mut elems);
|
||||
|
||||
Reference in New Issue
Block a user