rustfmt & signal_client improvememts

- handle ping message
- recv now only returns on SignalResponse
This commit is contained in:
Théo Monnom
2022-10-03 15:59:43 +02:00
parent 2213a70142
commit d64c7e5e08
35 changed files with 1584 additions and 174 deletions
+1
View File
@@ -1,4 +1,5 @@
use std::fmt::{Debug, Formatter};
use tracing::{event, Level};
use livekit_webrtc::peer_connection_factory::PeerConnectionFactory;
@@ -43,5 +43,3 @@ impl LocalParticipant {
self.engine.lock().await.publish_data(&data, kind).await.map_err(Into::into)
}
}
+15 -2
View File
@@ -1,14 +1,17 @@
use std::fmt::{Debug, Formatter};
use std::future::Future;
use std::pin::Pin;
use std::time::Duration;
use tracing::{Level, event};
use tracing::{event, Level};
use livekit_webrtc::jsep::{IceCandidate, SessionDescription};
use livekit_webrtc::peer_connection::{
IceConnectionState, PeerConnection, RTCOfferAnswerOptions, SignalingState,
};
use livekit_webrtc::rtc_error::RTCError;
const NEGOTIATION_FREQUENCY: Duration = Duration::from_millis(150); // TODO(theomonnom)
const NEGOTIATION_FREQUENCY: Duration = Duration::from_millis(150);
pub type OnOfferHandler = Box<dyn (FnMut(SessionDescription) -> Pin<Box<dyn Future<Output=()> + Send + 'static>>) + Send + Sync>;
@@ -20,6 +23,12 @@ pub struct PCTransport {
renegotiate: bool,
}
impl Debug for PCTransport {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
f.write_str("PCTransport")
}
}
impl PCTransport {
pub fn new(peer_connection: PeerConnection) -> Self {
Self {
@@ -45,6 +54,7 @@ impl PCTransport {
self.on_offer_handler = Some(handler);
}
#[tracing::instrument]
pub async fn add_ice_candidate(&mut self, ice_candidate: IceCandidate) -> Result<(), RTCError> {
if self.peer_connection.remote_description().is_none() {
self.pending_candidates.push(ice_candidate);
@@ -57,6 +67,7 @@ impl PCTransport {
Ok(())
}
#[tracing::instrument]
pub async fn set_remote_description(
&mut self,
remote_description: SessionDescription,
@@ -79,12 +90,14 @@ impl PCTransport {
Ok(())
}
#[tracing::instrument]
pub async fn negotiate(&mut self) -> Result<(), RTCError> {
// TODO(theomonnom) Debounce here with NEGOTIATION_FREQUENCY
self.create_and_send_offer(RTCOfferAnswerOptions::default())
.await
}
#[tracing::instrument]
async fn create_and_send_offer(
&mut self,
options: RTCOfferAnswerOptions,
+1 -17
View File
@@ -1,12 +1,9 @@
use std::sync::Arc;
use std::time::Duration;
use thiserror::Error;
use tokio::sync::Mutex;
use tokio::time::sleep;
use crate::local_participant::LocalParticipant;
use crate::proto::data_packet;
use crate::rtc_engine;
use crate::rtc_engine::{EngineError, RTCEngine};
@@ -23,12 +20,11 @@ pub struct Room {
engine: Arc<Mutex<RTCEngine>>,
}
#[tracing::instrument]
#[tracing::instrument(skip(url, token))]
pub async fn connect(url: &str, token: &str) -> Result<Room, RoomError> {
let engine = rtc_engine::connect(url, token).await?;
engine.on_data(Box::new(|packet| {
Box::pin(async move {})
})).await;
@@ -58,15 +54,3 @@ impl Room {
&self.name
}
}
// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2NjgxMzc0NDgsImlzcyI6IkFQSXpLYkFTaUNWYWtnSiIsIm5hbWUiOiJ3ZWIiLCJuYmYiOjE2NjQ1Mzc0NDgsInN1YiI6IndlYiIsInZpZGVvIjp7InJvb21DcmVhdGUiOnRydWUsInJvb21Kb2luIjp0cnVlfX0.6VMDdXJYrW3KWrEzxx4hzbmMQnjQIRILQ48Qrbx5j44
#[tokio::test]
async fn test_test() {
// console_subscriber::init();
let mut room = connect("ws://localhost:7880", "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2NzEyMzk4NjAsImlzcyI6IkFQSXpLYkFTaUNWYWtnSiIsIm5hbWUiOiJ0ZXN0IiwibmJmIjoxNjY0MDM5ODYwLCJzdWIiOiJ0ZXN0IiwidmlkZW8iOnsicm9vbUFkbWluIjp0cnVlLCJyb29tQ3JlYXRlIjp0cnVlLCJyb29tSm9pbiI6dHJ1ZX19.0Bee2jI2cSZveAbZ8MLc-ADoMYQ4l8IRxcAxpXAS6a8").await.unwrap();
room.local_participant().publish_data(b"This is a test", data_packet::Kind::Reliable).await.unwrap();
sleep(Duration::from_secs(60)).await;
}
+14 -14
View File
@@ -1,8 +1,8 @@
use std::fmt::{Debug, Formatter};
use std::future::Future;
use std::pin::Pin;
use std::sync::atomic::{AtomicBool, AtomicU8, Ordering};
use std::sync::{Arc, Weak};
use std::sync::atomic::{AtomicBool, AtomicU8, Ordering};
use std::time::Duration;
use lazy_static::lazy_static;
@@ -23,15 +23,15 @@ use livekit_webrtc::peer_connection_factory::{
};
use livekit_webrtc::rtc_error::RTCError;
use crate::{proto, signal_client};
use crate::lk_runtime::LKRuntime;
use crate::pc_transport::PCTransport;
use crate::proto::data_packet::Value;
use crate::proto::{
data_packet, signal_request, signal_response, DataPacket, JoinResponse, SignalTarget,
data_packet, DataPacket, JoinResponse, signal_request, signal_response, SignalTarget,
TrickleRequest, UserPacket,
};
use crate::proto::data_packet::Value;
use crate::signal_client::{SignalClient, SignalError};
use crate::{proto, signal_client};
const LOSSY_DC_LABEL: &str = "_lossy";
const RELIABLE_DC_LABEL: &str = "_reliable";
@@ -107,7 +107,7 @@ pub enum EngineMessage {
}
pub type OnDataHandler =
Box<dyn (FnMut(Packet) -> Pin<Box<dyn Future<Output = ()> + Send + 'static>>) + Send + Sync>;
Box<dyn (FnMut(Packet) -> Pin<Box<dyn Future<Output=()> + Send + 'static>>) + Send + Sync>;
struct EngineInternal {
publisher_pc: Arc<Mutex<PCTransport>>,
@@ -142,7 +142,7 @@ pub struct RTCEngine {
lk_runtime: Arc<LKRuntime>, // Keep a reference while we're using the RTCEngine
}
#[tracing::instrument]
#[tracing::instrument(skip(url, token))]
pub async fn connect(url: &str, token: &str) -> Result<RTCEngine, EngineError> {
// Acquire an existing/a new LKRuntime
let mut lk_runtime_ref = LK_RUNTIME.lock().await;
@@ -214,11 +214,11 @@ impl RTCEngine {
*self.internal.on_data_handler.lock().await = Some(f);
}
fn data_channel(&self, kind: data_packet::Kind) -> &Arc<Mutex<DataChannel>> {
fn data_channel(&self, kind: data_packet::Kind) -> Arc<Mutex<DataChannel>> {
if kind == data_packet::Kind::Reliable {
&self.internal.reliable_dc
self.internal.reliable_dc.clone()
} else {
&self.internal.lossy_dc
self.internal.lossy_dc.clone()
}
}
@@ -236,7 +236,7 @@ impl RTCEngine {
let mut publisher = publisher.lock().await;
if !publisher.is_connected()
&& publisher.peer_connection().ice_connection_state()
!= IceConnectionState::IceConnectionChecking
!= IceConnectionState::IceConnectionChecking
{
tokio::spawn({
let rtc_internal = self.internal.clone();
@@ -265,7 +265,7 @@ impl RTCEngine {
interval.tick().await;
}
})
.await;
.await;
if res.is_err() {
let err =
@@ -394,7 +394,7 @@ impl RTCEngine {
let _ = signal_client.send(signal_request::Message::Trickle(
TrickleRequest {
candidate_init: json,
target: target as i32
target: target as i32,
},
)).await;
});
@@ -469,7 +469,7 @@ impl RTCEngine {
data: user,
kind: data_packet::Kind::from_i32(data.kind).unwrap(),
})
.await;
.await;
}
}
Value::Speaker(_) => {
@@ -502,7 +502,7 @@ impl RTCEngine {
}
}
None => {
// TODO{theomonnom) Trigger reconnect
// TODO(theomonnom) Trigger reconnect
}
}
},
+106 -92
View File
@@ -1,20 +1,21 @@
use futures::future::poll_fn;
use futures_util::stream::{SplitSink, SplitStream};
use futures_util::{SinkExt, StreamExt};
use prost::Message as ProstMessage;
use std::fmt::{Debug, Formatter};
use futures::future::poll_fn;
use futures_util::{SinkExt, StreamExt};
use futures_util::stream::{SplitSink, SplitStream};
use prost::Message as ProstMessage;
use thiserror::Error;
use tokio::net::TcpStream;
use tokio::sync::{mpsc, oneshot};
use tokio::task::JoinHandle;
use tokio_tungstenite::tungstenite::{
protocol::frame::{coding::CloseCode, CloseFrame},
Error as WsError, Message,
};
use tokio_tungstenite::{connect_async, MaybeTlsStream, WebSocketStream};
use tracing::{event, span, Level};
use tokio_tungstenite::tungstenite::{Error as WsError, Message};
use tokio_tungstenite::tungstenite::protocol::CloseFrame;
use tokio_tungstenite::tungstenite::protocol::frame::coding::CloseCode;
use tracing::{event, Level};
use crate::proto::{signal_request, signal_response, SignalRequest, SignalResponse};
use crate::signal_client::SendMessage::Pong;
pub const PROTOCOL_VERSION: u32 = 8;
@@ -32,21 +33,26 @@ type SignalResult<T> = Result<T, SignalError>;
type WebSocket = WebSocketStream<MaybeTlsStream<TcpStream>>;
#[derive(Debug)]
struct RecvMessage {
response_chn: oneshot::Sender<Option<signal_response::Message>>,
enum RecvMessage {
Signal {
response_chn: oneshot::Sender<Option<signal_response::Message>>,
},
}
#[derive(Debug)]
struct SendMessage {
signal: signal_request::Message,
response_chn: oneshot::Sender<SignalResult<()>>,
enum SendMessage {
Signal {
signal: signal_request::Message,
response_chn: oneshot::Sender<SignalResult<()>>,
},
Pong {
ping_data: Vec<u8>,
},
}
pub struct SignalClient {
read_sender: mpsc::Sender<RecvMessage>,
write_sender: mpsc::Sender<SendMessage>,
write_shutdown_sender: oneshot::Sender<()>,
read_shutdown_sender: oneshot::Sender<()>,
read_tx: mpsc::Sender<RecvMessage>,
write_tx: mpsc::Sender<SendMessage>,
read_handle: JoinHandle<()>,
write_handle: JoinHandle<()>,
}
@@ -57,7 +63,7 @@ impl Debug for SignalClient {
}
}
#[tracing::instrument]
#[tracing::instrument(skip(url, token))]
pub async fn connect(url: &str, token: &str) -> SignalResult<SignalClient> {
let mut lk_url = url::Url::parse(url)?;
lk_url.set_path("/rtc");
@@ -74,21 +80,13 @@ pub async fn connect(url: &str, token: &str) -> SignalResult<SignalClient> {
let (read_tx, read_rx) = mpsc::channel::<RecvMessage>(8);
let (write_tx, write_rx) = mpsc::channel::<SendMessage>(8);
let (read_shutdown_tx, read_shutdown_rx) = oneshot::channel();
let (write_shutdown_tx, write_shutdown_rx) = oneshot::channel();
let read_handle = tokio::spawn(SignalClient::ws_read(read_rx, ws_reader, read_shutdown_rx));
let write_handle = tokio::spawn(SignalClient::ws_write(
write_rx,
ws_writer,
write_shutdown_rx,
));
let read_handle = tokio::spawn(SignalClient::ws_read(read_rx, ws_reader, write_tx.clone()));
let write_handle = tokio::spawn(SignalClient::ws_write(write_rx, ws_writer));
Ok(SignalClient {
read_sender: read_tx,
write_sender: write_tx,
write_shutdown_sender: write_shutdown_tx,
read_shutdown_sender: read_shutdown_tx,
read_tx,
write_tx,
read_handle,
write_handle,
})
@@ -96,99 +94,115 @@ pub async fn connect(url: &str, token: &str) -> SignalResult<SignalClient> {
impl SignalClient {
pub async fn close(self) {
let _ = self.write_shutdown_sender.send(());
let _ = self.write_handle.await;
let _ = self.read_shutdown_sender.send(());
drop(self.read_tx);
drop(self.write_tx);
let _ = self.read_handle.await;
let _ = self.write_handle.await;
}
pub async fn recv(&self) -> Option<signal_response::Message> {
let (send, recv) = oneshot::channel();
let msg = RecvMessage { response_chn: send };
let _ = self.read_sender.send(msg).await;
let msg = RecvMessage::Signal { response_chn: send };
let _ = self.read_tx.send(msg).await;
recv.await.expect("channel closed")
}
pub async fn send(&self, signal: signal_request::Message) -> SignalResult<()> {
let (send, recv) = oneshot::channel();
let msg = SendMessage {
let msg = SendMessage::Signal {
signal,
response_chn: send,
};
let _ = self.write_sender.send(msg).await;
let _ = self.write_tx.send(msg).await;
recv.await.expect("channel closed")
}
#[tracing::instrument]
async fn ws_write(
mut write_receiver: mpsc::Receiver<SendMessage>,
mut ws_writer: SplitSink<WebSocket, Message>,
mut shutdown_receiver: oneshot::Receiver<()>,
) {
loop {
tokio::select! {
Some(msg) = write_receiver.recv() => {
event!(Level::TRACE, "sending: {:?}", msg.signal);
while let Some(msg) = write_receiver.recv().await {
match msg {
SendMessage::Signal {
signal,
response_chn,
} => {
event!(Level::TRACE, "sending: {:?}", signal);
let req = SignalRequest {
message: Some(msg.signal),
message: Some(signal),
};
let write_res = ws_writer.send(Message::Binary(req.encode_to_vec())).await;
if let Err(err) = write_res {
event!(Level::ERROR, "failed to send message to ws: {:?}", err);
let _ = msg.response_chn.send(Err(err.into()));
event!(Level::ERROR, "failed to send signal: {:?}", err);
let _ = response_chn.send(Err(err.into()));
break;
}
let _ = msg.response_chn.send(Ok(()));
let _ = response_chn.send(Ok(()));
}
Pong { ping_data } => {
if let Err(err) = ws_writer.send(Message::Pong(ping_data)).await {
event!(Level::ERROR, "failed to send pong message: {:?}", err);
}
}
}
}
let _ = ws_writer
.send(Message::Close(Some(CloseFrame {
code: CloseCode::Normal,
reason: "disconnected by client".into(),
})))
.await;
let _ = ws_writer.flush().await;
}
async fn ws_read(
mut read_receiver: mpsc::Receiver<RecvMessage>,
mut ws_reader: SplitStream<WebSocket>,
write_tx: mpsc::Sender<SendMessage>,
) {
while let Some(RecvMessage::Signal { mut response_chn }) = read_receiver.recv().await {
tokio::select! {
read = Self::handle_msg(&mut ws_reader, &write_tx) => {
let _ = response_chn.send(read);
}
_ = poll_fn(|cx| response_chn.poll_closed(cx)) => {
continue; // Cancelled
},
_ = (&mut shutdown_receiver) => {
let _ = ws_writer.send(Message::Close(Some(CloseFrame {
code: CloseCode::Normal,
reason: "disconnected by client".into()
}))).await;
let _ = ws_writer.flush().await;
break;
}
}
}
async fn handle_msg(
ws_reader: &mut SplitStream<WebSocket>,
write_tx: &mpsc::Sender<SendMessage>,
) -> Option<signal_response::Message> {
loop {
let read = ws_reader.next().await?;
match read {
Ok(Message::Binary(data)) => {
let res = SignalResponse::decode(data.as_slice())
.expect("failed to decode SignalResponse");
event!(Level::TRACE, "received: {:?}", res);
return Some(res.message.unwrap());
}
Ok(Message::Ping(data)) => {
let _ = write_tx.send(Pong { ping_data: data });
continue;
}
Ok(Message::Close(close)) => {
event!(Level::DEBUG, "server closed the connection: {:?}", close);
return None;
}
_ => {
event!(Level::ERROR, "unhandled websocket message {:?}", read);
return None;
}
}
}
}
#[tracing::instrument]
async fn ws_read(
mut read_receiver: mpsc::Receiver<RecvMessage>,
mut ws_reader: SplitStream<WebSocket>,
mut shutdown_receiver: oneshot::Receiver<()>,
) {
loop {
tokio::select! {
Some(mut msg) = read_receiver.recv() => {
tokio::select! {
Some(read) = ws_reader.next() => {
match read {
Ok(Message::Binary(data)) => {
let res = SignalResponse::decode(data.as_slice()).expect("failed to decode SignalResponse");
let signal = res.message.unwrap();
event!(Level::TRACE, "received: {:?}", signal);
let _ = msg.response_chn.send(Some(signal));
}
_ => {
event!(Level::ERROR, "unhandled websocket message {:?}", read);
let _ = msg.response_chn.send(None);
}
}
},
_ = poll_fn(|cx| msg.response_chn.poll_closed(cx)) => {
continue; // Cancelled
},
else => {
break; // Connection closed
}
}
},
_ = (&mut shutdown_receiver) => break
}
}
}
}