use std::fmt::Debug; use std::sync::{Arc, Mutex}; use cxx::UniquePtr; use log::trace; use thiserror::Error; use tokio::sync::mpsc; use libwebrtc_sys::data_channel as sys_dc; use libwebrtc_sys::jsep as sys_jsep; use libwebrtc_sys::peer_connection as sys_pc; pub use libwebrtc_sys::peer_connection::ffi::IceConnectionState; pub use libwebrtc_sys::peer_connection::ffi::IceGatheringState; pub use libwebrtc_sys::peer_connection::ffi::PeerConnectionState; pub use libwebrtc_sys::peer_connection::ffi::RTCOfferAnswerOptions; pub use libwebrtc_sys::peer_connection::ffi::SignalingState; use crate::data_channel::{DataChannel, DataChannelInit}; use crate::jsep::{IceCandidate, SessionDescription}; use crate::media_stream::MediaStream; use crate::rtc_error::RTCError; use crate::rtp_receiver::RtpReceiver; use crate::rtp_transceiver::RtpTransceiver; #[derive(Error, Debug)] pub enum SdpError { #[error("recv failure: {0}")] RecvError(String), #[error("internal libwebrtc error")] RTCError(#[from] RTCError), } pub struct PeerConnection { cxx_handle: UniquePtr, observer: Box, // Keep alive for C++ native_observer: UniquePtr, } impl PeerConnection { pub(crate) fn new( cxx_handle: UniquePtr, observer: Box, native_observer: UniquePtr, ) -> Self { Self { cxx_handle, observer, native_observer, } } pub async fn create_offer(&mut self) -> Result { let (tx, mut rx) = mpsc::channel(1); let wrapper = sys_jsep::CreateSdpObserverWrapper::new(Box::new(InternalCreateSdpObserver { tx })); let mut native_wrapper = sys_jsep::ffi::create_native_create_sdp_observer(Box::new(wrapper)); unsafe { self.cxx_handle .pin_mut() .create_offer(native_wrapper.pin_mut(), RTCOfferAnswerOptions::default()); } match rx.recv().await { Some(value) => value.map_err(Into::into), None => Err(SdpError::RecvError("channel closed".to_string())), } } pub async fn create_answer(&mut self) -> Result { let (tx, mut rx) = mpsc::channel(1); let wrapper = sys_jsep::CreateSdpObserverWrapper::new(Box::new(InternalCreateSdpObserver { tx })); let mut native_wrapper = sys_jsep::ffi::create_native_create_sdp_observer(Box::new(wrapper)); unsafe { self.cxx_handle .pin_mut() .create_answer(native_wrapper.pin_mut(), RTCOfferAnswerOptions::default()); } match rx.recv().await { Some(value) => value.map_err(Into::into), None => Err(SdpError::RecvError("channel closed".to_string())), } } pub async fn set_local_description( &mut self, desc: SessionDescription, ) -> Result<(), SdpError> { let (tx, mut rx) = mpsc::channel(1); let wrapper = sys_jsep::SetLocalSdpObserverWrapper::new(Box::new(InternalSetLocalSdpObserver { tx })); let mut native_wrapper = sys_jsep::ffi::create_native_set_local_sdp_observer(Box::new(wrapper)); unsafe { self.cxx_handle .pin_mut() .set_local_description(desc.release(), native_wrapper.pin_mut()); } match rx.recv().await { Some(value) => value.map_err(Into::into), None => Err(SdpError::RecvError("channel closed".to_string())), } } pub async fn set_remote_description( &mut self, desc: SessionDescription, ) -> Result<(), SdpError> { let (tx, mut rx) = mpsc::channel(1); let wrapper = sys_jsep::SetRemoteSdpObserverWrapper::new(Box::new(InternalSetRemoteSdpObserver { tx, })); let mut native_wrapper = sys_jsep::ffi::create_native_set_remote_sdp_observer(Box::new(wrapper)); unsafe { self.cxx_handle .pin_mut() .set_remote_description(desc.release(), native_wrapper.pin_mut()); } match rx.recv().await { Some(value) => value.map_err(Into::into), None => Err(SdpError::RecvError("channel closed".to_string())), } } pub fn create_data_channel( &mut self, label: &str, init: DataChannelInit, ) -> Result { let native_init = sys_dc::ffi::create_data_channel_init(init.into()); let res = self .cxx_handle .pin_mut() .create_data_channel(label.to_string(), native_init); match res { Ok(cxx_handle) => Ok(DataChannel::new(cxx_handle)), Err(e) => Err(unsafe { RTCError::from(e.what()) }), } } pub async fn add_ice_candidate(&mut self, candidate: IceCandidate) -> Result<(), SdpError> { let (tx, mut rx) = mpsc::channel(1); let observer = sys_pc::AddIceCandidateObserverWrapper::new(Box::new(move |error| { tx.blocking_send(error).unwrap(); })); let mut native_observer = sys_pc::ffi::create_native_add_ice_candidate_observer(Box::new(observer)); self.cxx_handle .pin_mut() .add_ice_candidate(candidate.release(), native_observer.pin_mut()); match rx.recv().await { Some(value) => Ok(()), None => Err(SdpError::RecvError("channel closed".to_string())), } } pub fn close(&mut self) { self.cxx_handle.pin_mut().close(); } pub fn on_signaling_change(&mut self, handler: OnSignalingChangeHandler) { *self.observer.on_signaling_change_handler.lock().unwrap() = Some(handler); } pub fn on_add_stream(&mut self, handler: OnAddStreamHandler) { *self.observer.on_add_stream_handler.lock().unwrap() = Some(handler); } pub fn on_remove_stream(&mut self, handler: OnRemoveStreamHandler) { *self.observer.on_remove_stream_handler.lock().unwrap() = Some(handler); } pub fn on_data_channel(&mut self, handler: OnDataChannelHandler) { *self.observer.on_data_channel_handler.lock().unwrap() = Some(handler); } pub fn on_renegotiation_needed(&mut self, handler: OnRenegotiationNeededHandler) { *self .observer .on_renegotiation_needed_handler .lock() .unwrap() = Some(handler); } pub fn on_ice_connection_change(&mut self, handler: OnIceConnectionChangeHandler) { *self .observer .on_ice_connection_change_handler .lock() .unwrap() = Some(handler); } pub fn on_standardized_ice_connection_change( &mut self, handler: OnStandardizedIceConnectionChangeHandler, ) { *self .observer .on_standardized_ice_connection_change_handler .lock() .unwrap() = Some(handler); } pub fn on_connection_change(&mut self, handler: OnConnectionChangeHandler) { *self.observer.on_connection_change_handler.lock().unwrap() = Some(handler); } pub fn on_ice_gathering_change(&mut self, handler: OnIceGatheringChangeHandler) { *self .observer .on_ice_gathering_change_handler .lock() .unwrap() = Some(handler); } pub fn on_ice_candidate(&mut self, handler: OnIceCandidateHandler) { *self.observer.on_ice_candidate_handler.lock().unwrap() = Some(handler); } pub fn on_ice_candidate_error(&mut self, handler: OnIceCandidateErrorHandler) { *self.observer.on_ice_candidate_error_handler.lock().unwrap() = Some(handler); } pub fn on_ice_candidates_removed(&mut self, handler: OnIceCandidatesRemovedHandler) { *self .observer .on_ice_candidates_removed_handler .lock() .unwrap() = Some(handler); } pub fn on_ice_connection_receiving_change( &mut self, handler: OnIceConnectionReceivingChangeHandler, ) { *self .observer .on_ice_connection_receiving_change_handler .lock() .unwrap() = Some(handler); } pub fn on_ice_selected_candidate_pair_changed( &mut self, handler: OnIceSelectedCandidatePairChangedHandler, ) { *self .observer .on_ice_selected_candidate_pair_changed_handler .lock() .unwrap() = Some(handler); } pub fn on_add_track(&mut self, handler: OnAddTrackHandler) { *self.observer.on_add_track_handler.lock().unwrap() = Some(handler); } pub fn on_track(&mut self, handler: OnTrackHandler) { *self.observer.on_track_handler.lock().unwrap() = Some(handler); } pub fn on_remove_track(&mut self, handler: OnRemoveTrackHandler) { *self.observer.on_remove_track_handler.lock().unwrap() = Some(handler); } pub fn on_interesting_usage(&mut self, handler: OnInterestingUsageHandler) { *self.observer.on_interesting_usage_handler.lock().unwrap() = Some(handler); } } // CreateSdpObserver struct InternalCreateSdpObserver { tx: mpsc::Sender>, } impl sys_jsep::CreateSdpObserver for InternalCreateSdpObserver { fn on_success( &self, session_description: UniquePtr, ) { self.tx .blocking_send(Ok(SessionDescription::new(session_description))) .unwrap(); } fn on_failure(&self, error: RTCError) { self.tx.blocking_send(Err(error)).unwrap(); } } // SetLocalSdpObserver struct InternalSetLocalSdpObserver { tx: mpsc::Sender>, } impl sys_jsep::SetLocalSdpObserver for InternalSetLocalSdpObserver { fn on_set_local_description_complete(&self, error: RTCError) { let res = if error.ok() { Ok(()) } else { Err(error) }; self.tx.blocking_send(res).unwrap(); } } // SetRemoteSdpObserver struct InternalSetRemoteSdpObserver { tx: mpsc::Sender>, } impl sys_jsep::SetRemoteSdpObserver for InternalSetRemoteSdpObserver { fn on_set_remote_description_complete(&self, error: RTCError) { let res = if error.ok() { Ok(()) } else { Err(error) }; self.tx.blocking_send(res).unwrap(); } } // PeerConnectionObserver // TODO(theomonnom) Should we return futures? pub type OnSignalingChangeHandler = Box; pub type OnAddStreamHandler = Box; pub type OnRemoveStreamHandler = Box; pub type OnDataChannelHandler = Box; pub type OnRenegotiationNeededHandler = Box; pub type OnNegotiationNeededEventHandler = Box; pub type OnIceConnectionChangeHandler = Box; pub type OnStandardizedIceConnectionChangeHandler = Box; pub type OnConnectionChangeHandler = Box; pub type OnIceGatheringChangeHandler = Box; pub type OnIceCandidateHandler = Box; pub type OnIceCandidateErrorHandler = Box; pub type OnIceCandidatesRemovedHandler = Box) + Send + Sync>; pub type OnIceConnectionReceivingChangeHandler = Box; pub type OnIceSelectedCandidatePairChangedHandler = Box; pub type OnAddTrackHandler = Box) + Send + Sync>; pub type OnTrackHandler = Box; pub type OnRemoveTrackHandler = Box; pub type OnInterestingUsageHandler = Box; pub(crate) struct InternalObserver { on_signaling_change_handler: Arc>>, on_add_stream_handler: Arc>>, on_remove_stream_handler: Arc>>, on_data_channel_handler: Arc>>, on_renegotiation_needed_handler: Arc>>, on_negotiation_needed_event_handler: Arc>>, on_ice_connection_change_handler: Arc>>, on_standardized_ice_connection_change_handler: Arc>>, on_connection_change_handler: Arc>>, on_ice_gathering_change_handler: Arc>>, on_ice_candidate_handler: Arc>>, on_ice_candidate_error_handler: Arc>>, on_ice_candidates_removed_handler: Arc>>, on_ice_connection_receiving_change_handler: Arc>>, on_ice_selected_candidate_pair_changed_handler: Arc>>, on_add_track_handler: Arc>>, on_track_handler: Arc>>, on_remove_track_handler: Arc>>, on_interesting_usage_handler: Arc>>, } impl Default for InternalObserver { fn default() -> Self { Self { on_signaling_change_handler: Arc::new(Default::default()), on_add_stream_handler: Arc::new(Default::default()), on_remove_stream_handler: Arc::new(Default::default()), on_data_channel_handler: Arc::new(Default::default()), on_renegotiation_needed_handler: Arc::new(Default::default()), on_negotiation_needed_event_handler: Arc::new(Default::default()), on_ice_connection_change_handler: Arc::new(Default::default()), on_standardized_ice_connection_change_handler: Arc::new(Default::default()), on_connection_change_handler: Arc::new(Default::default()), on_ice_gathering_change_handler: Arc::new(Default::default()), on_ice_candidate_handler: Arc::new(Default::default()), on_ice_candidate_error_handler: Arc::new(Default::default()), on_ice_candidates_removed_handler: Arc::new(Default::default()), on_ice_connection_receiving_change_handler: Arc::new(Default::default()), on_ice_selected_candidate_pair_changed_handler: Arc::new(Default::default()), on_add_track_handler: Arc::new(Default::default()), on_track_handler: Arc::new(Default::default()), on_remove_track_handler: Arc::new(Default::default()), on_interesting_usage_handler: Arc::new(Default::default()), } } } // Observers are being called on the Signaling Thread impl sys_pc::PeerConnectionObserver for InternalObserver { fn on_signaling_change(&self, new_state: SignalingState) { trace!("on_signaling_change, {:?}", new_state); let mut handler = self.on_signaling_change_handler.lock().unwrap(); if let Some(f) = handler.as_mut() { f(new_state); } } fn on_add_stream( &self, stream: UniquePtr, ) { trace!("on_add_stream"); let mut handler = self.on_add_stream_handler.lock().unwrap(); if let Some(f) = handler.as_mut() { // TODO(theomonnom) } } fn on_remove_stream( &self, stream: UniquePtr, ) { trace!("on_remove_stream"); let mut handler = self.on_remove_stream_handler.lock().unwrap(); if let Some(f) = handler.as_mut() { // TODO(theomonnom) } } fn on_data_channel( &self, data_channel: UniquePtr, ) { trace!("on_data_channel"); let mut handler = self.on_data_channel_handler.lock().unwrap(); if let Some(f) = handler.as_mut() { f(DataChannel::new(data_channel)); } } fn on_renegotiation_needed(&self) { trace!("on_renegotiation_needed"); let mut handler = self.on_renegotiation_needed_handler.lock().unwrap(); if let Some(f) = handler.as_mut() { f(); } } fn on_negotiation_needed_event(&self, event: u32) { trace!("on_negotiation_needed_event"); let mut handler = self.on_negotiation_needed_event_handler.lock().unwrap(); if let Some(f) = handler.as_mut() { f(event); } } fn on_ice_connection_change(&self, new_state: IceConnectionState) { trace!("on_ice_connection_change"); let mut handler = self.on_ice_connection_change_handler.lock().unwrap(); if let Some(f) = handler.as_mut() { f(new_state); } } fn on_standardized_ice_connection_change(&self, new_state: IceConnectionState) { trace!("on_standardized_ice_connection_change"); let mut handler = self .on_standardized_ice_connection_change_handler .lock() .unwrap(); if let Some(f) = handler.as_mut() { f(new_state); } } fn on_connection_change(&self, new_state: PeerConnectionState) { trace!("on_connection_change"); let mut handler = self.on_connection_change_handler.lock().unwrap(); if let Some(f) = handler.as_mut() { f(new_state); } } fn on_ice_gathering_change(&self, new_state: IceGatheringState) { trace!("on_ice_gathering_change"); let mut handler = self.on_ice_gathering_change_handler.lock().unwrap(); if let Some(f) = handler.as_mut() { f(new_state); } } fn on_ice_candidate(&self, candidate: UniquePtr) { trace!("on_ice_candidate"); let mut handler = self.on_ice_candidate_handler.lock().unwrap(); if let Some(f) = handler.as_mut() { f(IceCandidate::new(candidate)); } } fn on_ice_candidate_error( &self, address: String, port: i32, url: String, error_code: i32, error_text: String, ) { trace!("on_ice_candidate_error"); let mut handler = self.on_ice_candidate_error_handler.lock().unwrap(); if let Some(f) = handler.as_mut() { f(address, port, url, error_code, error_text); } } fn on_ice_candidates_removed( &self, removed: Vec>, ) { trace!("on_ice_candidates_removed"); let mut handler = self.on_ice_candidates_removed_handler.lock().unwrap(); if let Some(f) = handler.as_mut() { // TODO(theomonnom) } } fn on_ice_connection_receiving_change(&self, receiving: bool) { trace!("on_ice_connection_receiving_change"); let mut handler = self .on_ice_connection_receiving_change_handler .lock() .unwrap(); if let Some(f) = handler.as_mut() { f(receiving); } } fn on_ice_selected_candidate_pair_changed( &self, event: libwebrtc_sys::peer_connection::ffi::CandidatePairChangeEvent, ) { trace!("on_ice_selected_candidate_pair_changed"); let mut handler = self .on_ice_selected_candidate_pair_changed_handler .lock() .unwrap(); if let Some(f) = handler.as_mut() { f(event); } } fn on_add_track( &self, receiver: UniquePtr, streams: Vec>, ) { trace!("on_add_track"); let mut handler = self.on_add_track_handler.lock().unwrap(); if let Some(f) = handler.as_mut() { // TODO(theomonnom) } } fn on_track( &self, transceiver: UniquePtr, ) { trace!("on_track"); let mut handler = self.on_track_handler.lock().unwrap(); if let Some(f) = handler.as_mut() { // TODO(theomonnom) } } fn on_remove_track(&self, receiver: UniquePtr) { trace!("on_remove_track"); let mut handler = self.on_remove_track_handler.lock().unwrap(); if let Some(f) = handler.as_mut() { // TODO(theomonnom) } } fn on_interesting_usage(&self, usage_pattern: i32) { trace!("on_interesting_usage"); let mut handler = self.on_interesting_usage_handler.lock().unwrap(); if let Some(f) = handler.as_mut() { f(usage_pattern); } } } #[cfg(test)] mod tests { use log::trace; use tokio::sync::mpsc; use crate::data_channel::{DataChannel, DataChannelInit}; use crate::jsep::IceCandidate; use crate::peer_connection_factory::{ICEServer, PeerConnectionFactory, RTCConfiguration}; use crate::webrtc::RTCRuntime; fn init_log() { let _ = env_logger::builder().is_test(true).try_init(); } #[tokio::test] async fn create_pc() { init_log(); let test = RTCRuntime::new(); let factory = PeerConnectionFactory::new(); let config = RTCConfiguration { ice_servers: vec![ICEServer { urls: vec!["stun:stun1.l.google.com:19302".to_string()], username: "".into(), password: "".into(), }], }; let mut bob = factory.create_peer_connection(config.clone()).unwrap(); let mut alice = factory.create_peer_connection(config.clone()).unwrap(); let (bob_ice_tx, mut bob_ice_rx) = mpsc::channel::(16); let (alice_ice_tx, mut alice_ice_rx) = mpsc::channel::(16); let (alice_dc_tx, mut alice_dc_rx) = mpsc::channel::(16); bob.on_ice_candidate(Box::new(move |candidate| { bob_ice_tx.blocking_send(candidate).unwrap(); })); alice.on_ice_candidate(Box::new(move |candidate| { alice_ice_tx.blocking_send(candidate).unwrap(); })); alice.on_data_channel(Box::new(move |dc| { alice_dc_tx.blocking_send(dc).unwrap(); })); let mut bob_dc = bob .create_data_channel("test_dc", DataChannelInit::default()) .unwrap(); let offer = bob.create_offer().await.unwrap(); trace!("Bob offer: {:?}", offer); bob.set_local_description(offer.clone()).await.unwrap(); alice.set_remote_description(offer).await.unwrap(); let answer = alice.create_answer().await.unwrap(); trace!("Alice answer: {:?}", answer); alice.set_local_description(answer.clone()).await.unwrap(); bob.set_remote_description(answer).await.unwrap(); let bob_ice = bob_ice_rx.recv().await.unwrap(); let alice_ice = alice_ice_rx.recv().await.unwrap(); bob.add_ice_candidate(alice_ice).await.unwrap(); alice.add_ice_candidate(bob_ice).await.unwrap(); let (data_tx, mut data_rx) = mpsc::channel::(1); let mut alice_dc = alice_dc_rx.recv().await.unwrap(); alice_dc.on_message(Box::new(move |data, is_binary| { data_tx .blocking_send(String::from_utf8_lossy(data).to_string()) .unwrap(); })); assert!(bob_dc.send(b"This is a test", true)); assert_eq!(data_rx.recv().await.unwrap(), "This is a test"); alice.close(); bob.close(); } }