move packet copy to async threads

(probably not great but oh well. can't seem to avoid it because tungstenite blows)
This commit is contained in:
Lily Tsuru 2024-10-11 00:58:17 -04:00
parent a34f833c80
commit 7c66291479
2 changed files with 115 additions and 98 deletions

View file

@ -33,27 +33,33 @@ use axum::{
use futures::{sink::SinkExt, stream::StreamExt};
#[derive(Clone)]
enum WsMessage {
VideoPacket { packet: ffmpeg::Packet },
Json(String),
}
struct AppState {
encoder_tx: Arc<TokioMutex<mpsc::Sender<EncodeThreadInput>>>,
inputs: Arc<TokioMutex<Vec<u32>>>,
websocket_broadcast_tx: broadcast::Sender<ws::Message>,
websocket_broadcast_tx: broadcast::Sender<WsMessage>,
websocket_count: TokioMutex<usize>,
}
impl AppState {
fn new(encoder_tx: mpsc::Sender<EncodeThreadInput>) -> Self {
let (chat_tx, _chat_rx) = broadcast::channel(10);
let (broadcast_tx, _) = broadcast::channel(10);
Self {
encoder_tx: Arc::new(TokioMutex::new(encoder_tx)),
inputs: Arc::new(TokioMutex::new(Vec::new())),
websocket_broadcast_tx: chat_tx,
websocket_broadcast_tx: broadcast_tx,
websocket_count: TokioMutex::const_new(0usize),
}
}
}
#[tokio::main(flavor = "multi_thread", worker_threads = 8)]
#[tokio::main(flavor = "multi_thread", worker_threads = 2)]
async fn main() -> anyhow::Result<()> {
// Setup a tracing subscriber
let subscriber = tracing_subscriber::FmtSubscriber::builder()
@ -75,12 +81,14 @@ async fn main() -> anyhow::Result<()> {
let state_clone = state.clone();
// retro event handler. drives the encoder thread too
tokio::spawn(async move {
let _ = std::thread::Builder::new()
.name("retro_event_rx".into())
.spawn(move || {
let surface_clone = surface.clone();
let frame_clone = frame.clone();
// start the thread now that we're alive
let _ = event_in_tx.send(retro_thread::RetroInEvent::Start).await;
// start the libretro thread looping now that we're alive
let _ = event_in_tx.blocking_send(retro_thread::RetroInEvent::Start);
loop {
match event_rx.try_recv() {
@ -111,7 +119,10 @@ async fn main() -> anyhow::Result<()> {
// for this to work from y = 0..height
let dest_line_slice = unsafe {
let dest_line_ptr = buf_ptr.add(line_stride);
std::slice::from_raw_parts_mut(dest_line_ptr, width as usize)
std::slice::from_raw_parts_mut(
dest_line_ptr,
width as usize,
)
};
dest_line_slice.copy_from_slice(
@ -122,10 +133,8 @@ async fn main() -> anyhow::Result<()> {
let _ = state_clone
.encoder_tx
.lock()
.await
.send(encoder_thread::EncodeThreadInput::SendFrame)
.await;
.blocking_lock()
.blocking_send(encoder_thread::EncodeThreadInput::SendFrame);
}
RetroEvent::Resize { size } => {
@ -140,16 +149,13 @@ async fn main() -> anyhow::Result<()> {
));
}
let _ = state_clone
.encoder_tx
.lock()
.await
.send(encoder_thread::EncodeThreadInput::Init { size: size.clone() })
.await;
let _ = state_clone.encoder_tx.blocking_lock().blocking_send(
encoder_thread::EncodeThreadInput::Init { size: size.clone() },
);
}
RetroEvent::WantInputs { tx } => {
let inputs = state_clone.inputs.lock().await;
let inputs = state_clone.inputs.blocking_lock();
//tracing::info!("giving inputs {:?}", inputs);
tx.send(inputs.clone()).expect("FUCK");
}
@ -161,23 +167,20 @@ async fn main() -> anyhow::Result<()> {
match encoder_rx.try_recv() {
Ok(msg) => match msg {
encoder_thread::EncodeThreadOutput::Frame { mut packet } => {
let vec = {
let data = packet.data_mut().expect("packet is empty somehow");
data.to_vec()
};
encoder_thread::EncodeThreadOutput::Frame { packet } => {
let _ = state_clone
.websocket_broadcast_tx
.send(ws::Message::Binary(vec));
.send(WsMessage::VideoPacket { packet });
}
},
Err(TryRecvError::Empty) => {}
_ => break,
}
tokio::time::sleep(Duration::from_millis(1)).await;
std::thread::sleep(Duration::from_millis(1));
}
});
})
.expect("failed to spawn retro RX thread, it's probably over");
// Axum websocket server
let app: Router<()> = Router::new()
@ -254,10 +257,24 @@ async fn handle_socket(socket: WebSocket, who: SocketAddr, state: Arc<AppState>)
let mut sub = send_clone.websocket_broadcast_tx.subscribe();
while let Ok(msg) = sub.recv().await {
match msg {
WsMessage::VideoPacket { mut packet } => {
// :(. At least this copy doesn't occur on the driver threads anymore..
let data = packet.data_mut().expect("shouldn't be taken");
let msg = ws::Message::Binary(data.to_vec());
if sender.send(msg).await.is_err() {
break;
}
}
WsMessage::Json(s) => {
let msg = ws::Message::Text(s);
if sender.send(msg).await.is_err() {
break;
}
}
}
}
});
let username_clone = Arc::clone(&username);
@ -286,12 +303,9 @@ async fn handle_socket(socket: WebSocket, who: SocketAddr, state: Arc<AppState>)
"msg": json["msg"].as_str().unwrap()
});
recv_clone
.websocket_broadcast_tx
.send(ws::Message::Text(
recv_clone.websocket_broadcast_tx.send(WsMessage::Json(
serde_json::to_string(&send).expect("oh well"),
))
.expect("boom");
));
continue;
}

View file

@ -441,9 +441,12 @@ pub fn spawn_retro_thread(
let (event_in_tx, event_in_rx) = mpsc::channel(8);
let fb_clone = surface.clone();
std::thread::spawn(move || {
// discard the join handle
let _ = std::thread::Builder::new()
.name("retro_game".into())
.spawn(move || {
retro_thread_main(fb_clone, event_tx, event_in_rx);
});
}).expect("failed to spawn the game thread");
(event_rx, event_in_tx)
}