pub mod audio;
pub mod capture;
pub mod display;
pub mod options;
use std::
{
thread,
io::Write,
net::TcpStream,
sync::
{
Arc,
Mutex,
RwLock,
atomic::{ AtomicBool, Ordering },
},
};
use crossbeam_channel::Receiver;
use winit::event_loop::EventLoopProxy;
use crate::
{
crypto,
options as chat_options,
network::
{
client,
screen::
{
self,
consts,
ScreenPacket,
},
},
};
pub struct ScreenShareRequest
{
pub rx: Receiver<Vec<u8>>,
pub running: Arc<AtomicBool>,
pub main_stream: Arc<Mutex<TcpStream>>
}
pub enum UserEvent {
NewSession(ScreenShareRequest),
NewFrame,
}
pub static SCREEN_SHARE_PROXY: RwLock<Option<EventLoopProxy<UserEvent>>> = RwLock::new(None);
pub fn screen(token: [u8; 32])
{
let mut stream = client::connect(chat_options::get_server_address()).expect("Screen upload connection failed");
stream.write_all(&token).unwrap();
let (tx, rx) = crossbeam_channel::bounded(consts::MULTIPLEX_CHANNEL_BOUND);
let (audio_tx, audio_rx) = crossbeam_channel::bounded(consts::MULTIPLEX_CHANNEL_BOUND);
let running = Arc::new(AtomicBool::new(true));
let running_capture = running.clone();
let running_audio = running.clone();
thread::spawn(move || capture::capture_loop(tx, running_capture, consts::TARGET_FPS));
thread::spawn(move || audio::spawn_audio_capture(audio_tx, running_audio));
let mut seq = 0usize;
let mut rex_stream = crypto::init_rex_stream(chat_options::get_keys().as_ref().unwrap(), &token).unwrap();
loop
{
if !options::get_use_screen()
{
running.store(false, Ordering::Relaxed);
return;
}
crossbeam_channel::select!
{
recv(rx) -> msg =>
{
let compressed_frame = match msg
{
Ok(f) => f,
Err(_) => return,
};
screen::send_frame(&mut stream, ScreenPacket
{
frame: Some(compressed_frame),
audio: None,
..Default::default()
}, &mut rex_stream, Some(&mut seq));
},
recv(audio_rx) -> msg =>
{
let audio_frame = match msg
{
Ok(f) => f,
Err(_) => return,
};
screen::send_frame(&mut stream, ScreenPacket
{
frame: None,
audio: Some(audio_frame.data),
..Default::default()
}, &mut rex_stream, Some(&mut seq));
}
}
}
}
pub fn attach(token: [u8; 32], main_stream: Arc<Mutex<TcpStream>>)
{
let mut stream = client::connect(chat_options::get_server_address()).expect("Screen download connection failed");
stream.write_all(&token).unwrap();
let (tx, rx) = crossbeam_channel::bounded(consts::MULTIPLEX_CHANNEL_BOUND);
let (audio_tx, audio_rx) = crossbeam_channel::bounded(consts::NETWORK_CHANNEL_BOUND);
let running = Arc::new(AtomicBool::new(true));
let running_audio = running.clone();
thread::spawn(move || audio::spawn_audio_playback(audio_rx, running_audio));
let mut rex_stream = crypto::init_rex_stream(chat_options::get_keys().as_ref().unwrap(), &token).unwrap();
let running_net = running.clone();
thread::spawn(move ||
{
let write_stream = Arc::new(Mutex::new(stream.try_clone().expect("Failed cloning stream")));
let mut streams = (&mut stream, write_stream);
let mut seq = 0usize;
while running_net.load(Ordering::Relaxed)
{
if !options::get_attach_screen()
{
running_net.store(false, Ordering::Relaxed);
return;
}
let read = match screen::receive_frame(&mut streams, &mut rex_stream, &mut seq)
{
Some(r) => r,
None =>
{
running_net.store(false, Ordering::Relaxed);
return;
}
};
if let Some(frame) = read.frame
{
tx.send(frame).ok();
if let Some(proxy) = SCREEN_SHARE_PROXY.read().unwrap().as_ref()
{
proxy.send_event(UserEvent::NewFrame).ok();
}
}
if let Some(audio) = read.audio
{
audio_tx.send(audio::AudioFrame { data: audio }).ok();
}
}
});
if let Some(proxy) = SCREEN_SHARE_PROXY.read().unwrap().as_ref()
{
proxy.send_event(UserEvent::NewSession(ScreenShareRequest
{
rx,
running,
main_stream,
})).ok();
}
}