cleanup: webrtc-sys & fix RtcRuntime disposing crashes (#81)

This commit is contained in:
Théo Monnom
2023-06-04 01:02:00 +02:00
committed by GitHub
parent 05ad1c95af
commit 55bda13069
80 changed files with 2209 additions and 1954 deletions
+10 -12
View File
@@ -2,11 +2,11 @@ use crate::audio_frame::AudioFrame;
use cxx::SharedPtr;
use parking_lot::Mutex;
use std::sync::Arc;
use webrtc_sys::media_stream as sys_ms;
use webrtc_sys::audio_track as sys_at;
#[derive(Clone)]
pub struct NativeAudioSource {
sys_handle: SharedPtr<sys_ms::ffi::AudioTrackSource>,
sys_handle: SharedPtr<sys_at::ffi::AudioTrackSource>,
inner: Arc<Mutex<AudioSourceInner>>,
}
@@ -21,14 +21,14 @@ struct AudioSourceInner {
impl Default for NativeAudioSource {
fn default() -> Self {
Self {
sys_handle: sys_ms::ffi::new_audio_track_source(),
sys_handle: sys_at::ffi::new_audio_track_source(),
inner: Default::default(),
}
}
}
impl NativeAudioSource {
pub fn sys_handle(&self) -> SharedPtr<sys_ms::ffi::AudioTrackSource> {
pub fn sys_handle(&self) -> SharedPtr<sys_at::ffi::AudioTrackSource> {
self.sys_handle.clone()
}
@@ -70,14 +70,12 @@ impl NativeAudioSource {
&frame.data[i..i + samples_10ms]
};
unsafe {
self.sys_handle.on_captured_frame(
data.as_ptr(),
frame.sample_rate as i32,
frame.num_channels as usize,
samples_10ms / frame.num_channels as usize,
)
}
self.sys_handle.on_captured_frame(
data,
frame.sample_rate as i32,
frame.num_channels as usize,
samples_10ms / frame.num_channels as usize,
);
i += needed_data;
}
+17 -22
View File
@@ -1,14 +1,15 @@
use crate::{audio_frame::AudioFrame, media_stream::RtcAudioTrack};
use cxx::UniquePtr;
use crate::audio_frame::AudioFrame;
use crate::audio_track::RtcAudioTrack;
use cxx::SharedPtr;
use futures::stream::Stream;
use std::pin::Pin;
use std::sync::Arc;
use std::task::{Context, Poll};
use tokio::sync::mpsc;
use webrtc_sys::media_stream as sys_ms;
use webrtc_sys::audio_track as sys_at;
pub struct NativeAudioStream {
native_observer: UniquePtr<sys_ms::ffi::NativeAudioSink>,
_observer: Box<AudioTrackObserver>,
native_sink: SharedPtr<sys_at::ffi::NativeAudioSink>,
audio_track: RtcAudioTrack,
frame_rx: mpsc::UnboundedReceiver<AudioFrame>,
}
@@ -16,21 +17,16 @@ pub struct NativeAudioStream {
impl NativeAudioStream {
pub fn new(audio_track: RtcAudioTrack) -> Self {
let (frame_tx, frame_rx) = mpsc::unbounded_channel();
let mut observer = Box::new(AudioTrackObserver { frame_tx });
let mut native_observer = unsafe {
sys_ms::ffi::new_native_audio_sink(Box::new(sys_ms::AudioSinkWrapper::new(
&mut *observer,
)))
};
let observer = Arc::new(AudioTrackObserver { frame_tx });
let native_sink = sys_at::ffi::new_native_audio_sink(Box::new(
sys_at::AudioSinkWrapper::new(observer.clone()),
));
unsafe {
sys_ms::ffi::media_to_audio(audio_track.sys_handle())
.add_sink(native_observer.pin_mut());
}
let audio = unsafe { sys_at::ffi::media_to_audio(audio_track.sys_handle()) };
audio.add_sink(&native_sink);
Self {
native_observer,
_observer: observer,
native_sink,
audio_track,
frame_rx,
}
@@ -41,11 +37,10 @@ impl NativeAudioStream {
}
pub fn close(&mut self) {
let audio = unsafe { sys_at::ffi::media_to_audio(self.audio_track.sys_handle()) };
audio.remove_sink(&self.native_sink);
self.frame_rx.close();
unsafe {
sys_ms::ffi::media_to_audio(self.audio_track.sys_handle())
.remove_sink(self.native_observer.pin_mut());
}
}
}
@@ -67,7 +62,7 @@ pub struct AudioTrackObserver {
frame_tx: mpsc::UnboundedSender<AudioFrame>,
}
impl sys_ms::AudioSink for AudioTrackObserver {
impl sys_at::AudioSink for AudioTrackObserver {
fn on_data(&self, data: &[i16], sample_rate: i32, nb_channels: usize, nb_frames: usize) {
// TODO(theomonnom): Should we avoid copy here?
let _ = self.frame_tx.send(AudioFrame {
+18
View File
@@ -0,0 +1,18 @@
use super::media_stream_track::impl_media_stream_track;
use crate::media_stream_track::RtcTrackState;
use cxx::SharedPtr;
use sys_at::ffi::audio_to_media;
use webrtc_sys::audio_track as sys_at;
#[derive(Clone)]
pub struct RtcAudioTrack {
pub(crate) sys_handle: SharedPtr<sys_at::ffi::AudioTrack>,
}
impl RtcAudioTrack {
impl_media_stream_track!(audio_to_media);
pub fn sys_handle(&self) -> SharedPtr<sys_at::ffi::MediaStreamTrack> {
audio_to_media(self.sys_handle.clone())
}
}
+8 -17
View File
@@ -39,30 +39,21 @@ impl From<DataChannelInit> for sys_dc::ffi::DataChannelInit {
#[derive(Clone)]
pub struct DataChannel {
#[allow(dead_code)]
native_observer: SharedPtr<sys_dc::ffi::NativeDataChannelObserver>,
observer: Arc<DataChannelObserver>,
pub(crate) sys_handle: SharedPtr<sys_dc::ffi::DataChannel>,
}
impl DataChannel {
pub fn configure(sys_handle: SharedPtr<sys_dc::ffi::DataChannel>) -> Self {
unsafe {
let observer = Arc::new(DataChannelObserver::default());
let dc = Self {
sys_handle: sys_handle.clone(),
native_observer: sys_dc::ffi::create_native_data_channel_observer(
Box::new(sys_dc::DataChannelObserverWrapper::new(observer.clone())),
&*sys_handle as *const _ as *mut _,
),
observer,
};
let observer = Arc::new(DataChannelObserver::default());
let dc = Self {
sys_handle: sys_handle.clone(),
observer: observer.clone(),
};
dc.sys_handle
.register_observer(&*dc.native_observer as *const _ as *mut _);
dc
}
dc.sys_handle
.register_observer(Box::new(sys_dc::DataChannelObserverWrapper::new(observer)));
dc
}
pub fn send(&self, data: &[u8], binary: bool) -> Result<(), DataChannelError> {
+8 -89
View File
@@ -1,20 +1,9 @@
use crate::media_stream::{self, MediaStreamTrack, RtcTrackState};
use crate::audio_track;
use crate::imp::audio_track::RtcAudioTrack;
use crate::imp::video_track::RtcVideoTrack;
use crate::video_track;
use cxx::SharedPtr;
use webrtc_sys::media_stream as sys_ms;
use webrtc_sys::media_stream::ffi::{
audio_to_media, media_to_audio, media_to_video, video_to_media,
};
use webrtc_sys::{MEDIA_TYPE_AUDIO, MEDIA_TYPE_VIDEO};
impl From<sys_ms::ffi::TrackState> for RtcTrackState {
fn from(state: sys_ms::ffi::TrackState) -> Self {
match state {
sys_ms::ffi::TrackState::Live => RtcTrackState::Live,
sys_ms::ffi::TrackState::Ended => RtcTrackState::Ended,
_ => panic!("unknown TrackState"),
}
}
}
#[derive(Clone)]
pub struct MediaStream {
@@ -26,93 +15,23 @@ impl MediaStream {
self.sys_handle.id()
}
pub fn audio_tracks(&self) -> Vec<media_stream::RtcAudioTrack> {
pub fn audio_tracks(&self) -> Vec<audio_track::RtcAudioTrack> {
self.sys_handle
.get_audio_tracks()
.into_iter()
.map(|t| media_stream::RtcAudioTrack {
.map(|t| audio_track::RtcAudioTrack {
handle: RtcAudioTrack { sys_handle: t.ptr },
})
.collect()
}
pub fn video_tracks(&self) -> Vec<media_stream::RtcVideoTrack> {
pub fn video_tracks(&self) -> Vec<video_track::RtcVideoTrack> {
self.sys_handle
.get_video_tracks()
.into_iter()
.map(|t| media_stream::RtcVideoTrack {
.map(|t| video_track::RtcVideoTrack {
handle: RtcVideoTrack { sys_handle: t.ptr },
})
.collect()
}
}
pub fn new_media_stream_track(
sys_handle: SharedPtr<sys_ms::ffi::MediaStreamTrack>,
) -> MediaStreamTrack {
if sys_handle.kind() == MEDIA_TYPE_AUDIO {
MediaStreamTrack::Audio(media_stream::RtcAudioTrack {
handle: RtcAudioTrack {
sys_handle: media_to_audio(sys_handle),
},
})
} else if sys_handle.kind() == MEDIA_TYPE_VIDEO {
MediaStreamTrack::Video(media_stream::RtcVideoTrack {
handle: RtcVideoTrack {
sys_handle: media_to_video(sys_handle),
},
})
} else {
panic!("unknown track kind")
}
}
macro_rules! impl_media_stream_track {
($cast:ident) => {
pub fn id(&self) -> String {
let ptr = sys_ms::ffi::$cast(self.sys_handle.clone());
ptr.id()
}
pub fn enabled(&self) -> bool {
let ptr = sys_ms::ffi::$cast(self.sys_handle.clone());
ptr.enabled()
}
pub fn set_enabled(&self, enabled: bool) -> bool {
let ptr = sys_ms::ffi::$cast(self.sys_handle.clone());
ptr.set_enabled(enabled)
}
pub fn state(&self) -> RtcTrackState {
let ptr = sys_ms::ffi::$cast(self.sys_handle.clone());
ptr.state().into()
}
};
}
#[derive(Clone)]
pub struct RtcVideoTrack {
pub(crate) sys_handle: SharedPtr<sys_ms::ffi::VideoTrack>,
}
impl RtcVideoTrack {
impl_media_stream_track!(video_to_media);
pub fn sys_handle(&self) -> SharedPtr<sys_ms::ffi::MediaStreamTrack> {
video_to_media(self.sys_handle.clone())
}
}
#[derive(Clone)]
pub struct RtcAudioTrack {
pub(crate) sys_handle: SharedPtr<sys_ms::ffi::AudioTrack>,
}
impl RtcAudioTrack {
impl_media_stream_track!(audio_to_media);
pub fn sys_handle(&self) -> SharedPtr<sys_ms::ffi::MediaStreamTrack> {
audio_to_media(self.sys_handle.clone())
}
}
@@ -0,0 +1,67 @@
use crate::audio_track;
use crate::imp::audio_track::RtcAudioTrack;
use crate::imp::video_track::RtcVideoTrack;
use crate::media_stream_track::MediaStreamTrack;
use crate::media_stream_track::RtcTrackState;
use crate::video_track;
use cxx::SharedPtr;
use webrtc_sys::audio_track::ffi::media_to_audio;
use webrtc_sys::media_stream_track as sys_mst;
use webrtc_sys::video_track::ffi::media_to_video;
use webrtc_sys::{MEDIA_TYPE_AUDIO, MEDIA_TYPE_VIDEO};
impl From<sys_mst::ffi::TrackState> for RtcTrackState {
fn from(state: sys_mst::ffi::TrackState) -> Self {
match state {
sys_mst::ffi::TrackState::Live => RtcTrackState::Live,
sys_mst::ffi::TrackState::Ended => RtcTrackState::Ended,
_ => panic!("unknown TrackState"),
}
}
}
pub fn new_media_stream_track(
sys_handle: SharedPtr<sys_mst::ffi::MediaStreamTrack>,
) -> MediaStreamTrack {
if sys_handle.kind() == MEDIA_TYPE_AUDIO {
MediaStreamTrack::Audio(audio_track::RtcAudioTrack {
handle: RtcAudioTrack {
sys_handle: unsafe { media_to_audio(sys_handle) },
},
})
} else if sys_handle.kind() == MEDIA_TYPE_VIDEO {
MediaStreamTrack::Video(video_track::RtcVideoTrack {
handle: RtcVideoTrack {
sys_handle: unsafe { media_to_video(sys_handle) },
},
})
} else {
panic!("unknown track kind")
}
}
macro_rules! impl_media_stream_track {
($cast:expr) => {
pub fn id(&self) -> String {
let ptr = $cast(self.sys_handle.clone());
ptr.id()
}
pub fn enabled(&self) -> bool {
let ptr = $cast(self.sys_handle.clone());
ptr.enabled()
}
pub fn set_enabled(&self, enabled: bool) -> bool {
let ptr = $cast(self.sys_handle.clone());
ptr.set_enabled(enabled)
}
pub fn state(&self) -> RtcTrackState {
let ptr = $cast(self.sys_handle.clone());
ptr.state().into()
}
};
}
pub(super) use impl_media_stream_track;
+8 -5
View File
@@ -1,9 +1,11 @@
pub mod audio_resampler;
pub mod audio_source;
pub mod audio_stream;
pub mod audio_track;
pub mod data_channel;
pub mod ice_candidate;
pub mod media_stream;
pub mod media_stream_track;
pub mod peer_connection;
pub mod peer_connection_factory;
pub mod rtp_parameters;
@@ -14,6 +16,7 @@ pub mod session_description;
pub mod video_frame;
pub mod video_source;
pub mod video_stream;
pub mod video_track;
pub mod yuv_helper;
use crate::MediaType;
@@ -21,17 +24,17 @@ use crate::{RtcError, RtcErrorType};
use webrtc_sys::rtc_error as sys_err;
use webrtc_sys::webrtc as sys_rtc;
impl From<sys_err::ffi::RTCErrorType> for RtcErrorType {
fn from(value: sys_err::ffi::RTCErrorType) -> Self {
impl From<sys_err::ffi::RtcErrorType> for RtcErrorType {
fn from(value: sys_err::ffi::RtcErrorType) -> Self {
match value {
sys_err::ffi::RTCErrorType::InvalidState => Self::InvalidState,
sys_err::ffi::RtcErrorType::InvalidState => Self::InvalidState,
_ => Self::Internal,
}
}
}
impl From<sys_err::ffi::RTCError> for RtcError {
fn from(value: sys_err::ffi::RTCError) -> Self {
impl From<sys_err::ffi::RtcError> for RtcError {
fn from(value: sys_err::ffi::RtcError) -> Self {
Self {
error_type: value.error_type.into(),
message: value.message,
+101 -89
View File
@@ -4,11 +4,13 @@ use crate::ice_candidate::IceCandidate;
use crate::imp::data_channel as imp_dc;
use crate::imp::ice_candidate as imp_ic;
use crate::imp::media_stream as imp_ms;
use crate::imp::media_stream_track as imp_mst;
use crate::imp::rtp_receiver as imp_rr;
use crate::imp::rtp_sender as imp_rs;
use crate::imp::rtp_transceiver as imp_rt;
use crate::imp::session_description as imp_sdp;
use crate::media_stream::{MediaStream, MediaStreamTrack};
use crate::media_stream::MediaStream;
use crate::media_stream_track::MediaStreamTrack;
use crate::peer_connection::{
AnswerOptions, IceCandidateError, IceConnectionState, IceGatheringState, OfferOptions,
OnConnectionChange, OnDataChannel, OnIceCandidate, OnIceCandidateError, OnIceConnectionChange,
@@ -21,17 +23,16 @@ use crate::rtp_transceiver::RtpTransceiver;
use crate::rtp_transceiver::RtpTransceiverInit;
use crate::MediaType;
use crate::{session_description::SessionDescription, RtcError};
use cxx::{SharedPtr, UniquePtr};
use cxx::SharedPtr;
use futures::channel::oneshot;
use parking_lot::Mutex;
use std::mem::ManuallyDrop;
use std::sync::Arc;
use webrtc_sys::data_channel as sys_dc;
use webrtc_sys::jsep as sys_jsep;
use webrtc_sys::peer_connection as sys_pc;
use webrtc_sys::rtc_error as sys_err;
impl From<OfferOptions> for sys_pc::ffi::RTCOfferAnswerOptions {
impl From<OfferOptions> for sys_pc::ffi::RtcOfferAnswerOptions {
fn from(options: OfferOptions) -> Self {
Self {
ice_restart: options.ice_restart,
@@ -42,7 +43,7 @@ impl From<OfferOptions> for sys_pc::ffi::RTCOfferAnswerOptions {
}
}
impl From<AnswerOptions> for sys_pc::ffi::RTCOfferAnswerOptions {
impl From<AnswerOptions> for sys_pc::ffi::RtcOfferAnswerOptions {
fn from(_options: AnswerOptions) -> Self {
Self::default()
}
@@ -111,10 +112,7 @@ impl From<sys_pc::ffi::SignalingState> for SignalingState {
#[derive(Clone)]
pub struct PeerConnection {
#[allow(dead_code)]
native_observer: SharedPtr<sys_pc::ffi::NativePeerConnectionObserver>,
observer: Arc<PeerObserver>,
pub(crate) sys_handle: SharedPtr<sys_pc::ffi::PeerConnection>,
}
@@ -122,12 +120,10 @@ impl PeerConnection {
pub fn configure(
sys_handle: SharedPtr<sys_pc::ffi::PeerConnection>,
observer: Arc<PeerObserver>,
native_observer: SharedPtr<sys_pc::ffi::NativePeerConnectionObserver>,
) -> Self {
Self {
sys_handle,
observer,
native_observer,
}
}
@@ -135,12 +131,29 @@ impl PeerConnection {
&self,
options: OfferOptions,
) -> Result<SessionDescription, RtcError> {
let (mut native_wrapper, mut sdp_rx, mut err_rx) = create_sdp_observer();
let (sdp_tx, mut sdp_rx) = oneshot::channel();
let (err_tx, mut err_rx) = oneshot::channel();
unsafe {
self.sys_handle
.create_offer(native_wrapper.pin_mut(), options.into());
}
let ctx = Box::new(sys_pc::AsyncContext(Box::new((sdp_tx, err_tx))));
type CtxType = (
oneshot::Sender<SessionDescription>,
oneshot::Sender<RtcError>,
);
self.sys_handle.create_offer(
options.into(),
ctx,
|ctx, sdp| {
let (sdp_tx, _) = *ctx.0.downcast::<CtxType>().unwrap();
let _ = sdp_tx.send(SessionDescription {
handle: imp_sdp::SessionDescription { sys_handle: sdp },
});
},
|ctx, error| {
let (_, err_tx) = *ctx.0.downcast::<CtxType>().unwrap();
let _ = err_tx.send(error.into());
},
);
futures::select! {
sdp = sdp_rx => Ok(sdp.unwrap()),
@@ -152,13 +165,29 @@ impl PeerConnection {
&self,
options: AnswerOptions,
) -> Result<SessionDescription, RtcError> {
let (mut native_wrapper, mut sdp_rx, mut err_rx) = create_sdp_observer();
let (sdp_tx, mut sdp_rx) = oneshot::channel();
let (err_tx, mut err_rx) = oneshot::channel();
unsafe {
self.sys_handle
.create_answer(native_wrapper.pin_mut(), options.into());
}
let ctx = Box::new(sys_pc::AsyncContext(Box::new((sdp_tx, err_tx))));
type CtxType = (
oneshot::Sender<SessionDescription>,
oneshot::Sender<RtcError>,
);
self.sys_handle.create_answer(
options.into(),
ctx,
|ctx, sdp| {
let (sdp_tx, _) = *ctx.0.downcast::<CtxType>().unwrap();
let _ = sdp_tx.send(SessionDescription {
handle: imp_sdp::SessionDescription { sys_handle: sdp },
});
},
|ctx, error| {
let (_, err_tx) = *ctx.0.downcast::<CtxType>().unwrap();
let _ = err_tx.send(error.into());
},
);
futures::select! {
sdp = sdp_rx => Ok(sdp.unwrap()),
err = err_rx => Err(err.unwrap()),
@@ -166,54 +195,66 @@ impl PeerConnection {
}
pub async fn set_local_description(&self, desc: SessionDescription) -> Result<(), RtcError> {
let (tx, rx) = oneshot::channel();
let wrapper =
sys_jsep::SetLocalSdpObserverWrapper(ManuallyDrop::new(Box::new(move |error| {
let _ = tx.send(if error.ok() { Ok(()) } else { Err(error) });
})));
let (tx, rx) = oneshot::channel::<Result<(), RtcError>>();
let ctx = Box::new(sys_pc::AsyncContext(Box::new(tx)));
let mut native_wrapper =
sys_jsep::ffi::create_native_set_local_sdp_observer(Box::new(wrapper));
self.sys_handle
.set_local_description(desc.handle.sys_handle, ctx, |ctx, err| {
let tx = ctx
.0
.downcast::<oneshot::Sender<Result<(), RtcError>>>()
.unwrap();
unsafe {
self.sys_handle
.set_local_description(desc.handle.sys_handle, native_wrapper.pin_mut());
}
if err.ok() {
let _ = tx.send(Ok(()));
} else {
let _ = tx.send(Err(err.into()));
}
});
rx.await.unwrap().map_err(Into::into)
rx.await.unwrap()
}
pub async fn set_remote_description(&self, desc: SessionDescription) -> Result<(), RtcError> {
let (tx, rx) = oneshot::channel();
let wrapper =
sys_jsep::SetRemoteSdpObserverWrapper(ManuallyDrop::new(Box::new(move |error| {
let _ = tx.send(if error.ok() { Ok(()) } else { Err(error) });
})));
let (tx, rx) = oneshot::channel::<Result<(), RtcError>>();
let ctx = Box::new(sys_pc::AsyncContext(Box::new(tx)));
let mut native_wrapper =
sys_jsep::ffi::create_native_set_remote_sdp_observer(Box::new(wrapper));
self.sys_handle
.set_remote_description(desc.handle.sys_handle, ctx, |ctx, err| {
let tx = ctx
.0
.downcast::<oneshot::Sender<Result<(), RtcError>>>()
.unwrap();
unsafe {
self.sys_handle
.set_remote_description(desc.handle.sys_handle, native_wrapper.pin_mut());
}
if err.ok() {
let _ = tx.send(Ok(()));
} else {
let _ = tx.send(Err(err.into()));
}
});
rx.await.unwrap().map_err(Into::into)
rx.await.unwrap()
}
pub async fn add_ice_candidate(&self, candidate: IceCandidate) -> Result<(), RtcError> {
let (tx, rx) = oneshot::channel();
let observer =
sys_pc::AddIceCandidateObserverWrapper(ManuallyDrop::new(Box::new(|error| {
let _ = tx.send(if error.ok() { Ok(()) } else { Err(error) });
})));
let (tx, rx) = oneshot::channel::<Result<(), RtcError>>();
let ctx = Box::new(sys_pc::AsyncContext(Box::new(tx)));
let mut native_observer =
sys_pc::ffi::create_native_add_ice_candidate_observer(Box::new(observer));
self.sys_handle
.add_ice_candidate(candidate.handle.sys_handle, native_observer.pin_mut());
.add_ice_candidate(candidate.handle.sys_handle, ctx, |ctx, err| {
let tx = ctx
.0
.downcast::<oneshot::Sender<Result<(), RtcError>>>()
.unwrap();
rx.await.unwrap().map_err(Into::into)
if err.ok() {
let _ = tx.send(Ok(()));
} else {
let _ = tx.send(Err(err.into()));
}
});
rx.await.unwrap()
}
pub fn create_data_channel(
@@ -221,16 +262,15 @@ impl PeerConnection {
label: &str,
init: DataChannelInit,
) -> Result<DataChannel, RtcError> {
let native_init = sys_dc::ffi::create_data_channel_init(init.into());
let res = self
.sys_handle
.create_data_channel(label.to_string(), native_init);
.create_data_channel(label.to_string(), init.into());
match res {
Ok(sys_handle) => Ok(DataChannel {
handle: imp_dc::DataChannel::configure(sys_handle),
}),
Err(e) => Err(unsafe { sys_err::ffi::RTCError::from(e.what()).into() }),
Err(e) => Err(unsafe { sys_err::ffi::RtcError::from(e.what()).into() }),
}
}
@@ -246,7 +286,7 @@ impl PeerConnection {
Ok(sys_handle) => Ok(RtpSender {
handle: imp_rs::RtpSender { sys_handle },
}),
Err(e) => unsafe { Err(sys_err::ffi::RTCError::from(e.what()).into()) },
Err(e) => unsafe { Err(sys_err::ffi::RtcError::from(e.what()).into()) },
}
}
@@ -265,7 +305,7 @@ impl PeerConnection {
sys_handle: sys_handle,
},
}),
Err(e) => unsafe { Err(sys_err::ffi::RTCError::from(e.what()).into()) },
Err(e) => unsafe { Err(sys_err::ffi::RtcError::from(e.what()).into()) },
}
}
@@ -284,7 +324,7 @@ impl PeerConnection {
sys_handle: cxx_handle,
},
}),
Err(e) => unsafe { Err(sys_err::ffi::RTCError::from(e.what()).into()) },
Err(e) => unsafe { Err(sys_err::ffi::RtcError::from(e.what()).into()) },
}
}
@@ -333,7 +373,7 @@ impl PeerConnection {
pub fn remove_track(&self, sender: RtpSender) -> Result<(), RtcError> {
self.sys_handle
.remove_track(sender.handle.sys_handle)
.map_err(|e| unsafe { sys_err::ffi::RTCError::from(e.what()).into() })
.map_err(|e| unsafe { sys_err::ffi::RtcError::from(e.what()).into() })
}
pub fn senders(&self) -> Vec<RtpSender> {
@@ -409,34 +449,6 @@ impl PeerConnection {
}
}
fn create_sdp_observer() -> (
UniquePtr<sys_pc::ffi::NativeCreateSdpObserverHandle>,
oneshot::Receiver<SessionDescription>,
oneshot::Receiver<RtcError>,
) {
let (sdp_tx, sdp_rx) = oneshot::channel();
let (err_tx, err_rx) = oneshot::channel();
let wrapper = sys_jsep::CreateSdpObserverWrapper {
on_success: ManuallyDrop::new(Box::new(move |session_description| {
let _ = sdp_tx.send(SessionDescription {
handle: imp_sdp::SessionDescription {
sys_handle: session_description,
},
});
})),
on_failure: ManuallyDrop::new(Box::new(move |error| {
let _ = err_tx.send(error.into());
})),
};
(
sys_jsep::ffi::create_native_create_sdp_observer(Box::new(wrapper)),
sdp_rx,
err_rx,
)
}
#[derive(Default)]
pub struct PeerObserver {
pub connection_change_handler: Mutex<Option<OnConnectionChange>>,
@@ -565,7 +577,7 @@ impl sys_pc::PeerConnectionObserver for PeerObserver {
handle: imp_ms::MediaStream { sys_handle: s.ptr },
})
.collect(),
track: imp_ms::new_media_stream_track(track),
track: imp_mst::new_media_stream_track(track),
transceiver: RtpTransceiver {
handle: imp_rt::RtpTransceiver {
sys_handle: transceiver,
@@ -1,89 +1,61 @@
use crate::audio_source::native::NativeAudioSource;
use crate::imp::media_stream as imp_ms;
use crate::audio_track::RtcAudioTrack;
use crate::imp::audio_track as imp_at;
use crate::imp::peer_connection as imp_pc;
use crate::media_stream::{RtcAudioTrack, RtcVideoTrack};
use crate::imp::video_track as imp_vt;
use crate::peer_connection::PeerConnection;
use crate::peer_connection_factory::{
ContinualGatheringPolicy, IceServer, IceTransportsType, RtcConfiguration,
};
use crate::rtp_parameters::RtpCapabilities;
use crate::video_source::native::NativeVideoSource;
use crate::video_track::RtcVideoTrack;
use crate::MediaType;
use crate::RtcError;
use cxx::SharedPtr;
use cxx::UniquePtr;
use lazy_static::lazy_static;
use parking_lot::Mutex;
use std::sync::{Arc, Weak};
use webrtc_sys::logsink as sys_ls;
use std::sync::Arc;
use webrtc_sys::peer_connection as sys_pc;
use webrtc_sys::peer_connection_factory as sys_pcf;
use webrtc_sys::rtc_error as sys_err;
use webrtc_sys::webrtc as sys_webrtc;
use webrtc_sys::webrtc as sys_rtc;
lazy_static! {
static ref RTC_RUNTIME: Mutex<Weak<RtcRuntime>> = Mutex::new(Weak::new());
}
pub struct RtcRuntime {
pub(crate) sys_handle: SharedPtr<sys_webrtc::ffi::RTCRuntime>,
_logsink: UniquePtr<sys_ls::ffi::LogSink>,
}
impl RtcRuntime {
pub fn instance() -> Arc<RtcRuntime> {
let mut lk_runtime_ref = RTC_RUNTIME.lock();
if let Some(lk_runtime) = lk_runtime_ref.upgrade() {
lk_runtime
} else {
log::trace!("RtcRuntime::new()");
let new_runtime = Arc::new(Self {
sys_handle: sys_webrtc::ffi::create_rtc_runtime(),
_logsink: sys_ls::ffi::new_log_sink(|msg, severity| {
// Forward logs from webrtc to rust log crate
let msg = msg
.strip_suffix("\r\n")
.or(msg.strip_suffix("\n"))
.unwrap_or(&msg);
let lvl = match severity {
sys_ls::ffi::LoggingSeverity::Verbose => log::Level::Trace,
sys_ls::ffi::LoggingSeverity::Info => log::Level::Debug, // Translte webrtc
// info to debug log level to avoid polluting the user logs
sys_ls::ffi::LoggingSeverity::Warning => log::Level::Warn,
sys_ls::ffi::LoggingSeverity::Error => log::Level::Error,
_ => log::Level::Debug,
};
log::log!(target: "libwebrtc", lvl, "{}", msg);
}),
});
*lk_runtime_ref = Arc::downgrade(&new_runtime);
new_runtime
}
}
}
impl Drop for RtcRuntime {
fn drop(&mut self) {
log::trace!("RtcRuntime::drop()");
}
static ref LOG_SINK: Mutex<Option<UniquePtr<sys_rtc::ffi::LogSink>>> = Default::default();
}
#[derive(Clone)]
pub struct PeerConnectionFactory {
sys_handle: SharedPtr<sys_pcf::ffi::PeerConnectionFactory>,
#[allow(unused)]
runtime: Arc<RtcRuntime>,
}
impl Default for PeerConnectionFactory {
fn default() -> Self {
let runtime = RtcRuntime::instance();
let mut log_sink = LOG_SINK.lock();
if log_sink.is_none() {
*log_sink = Some(sys_rtc::ffi::new_log_sink(|msg, severity| {
let msg = msg
.strip_suffix("\r\n")
.or(msg.strip_suffix("\n"))
.unwrap_or(&msg);
let lvl = match severity {
sys_rtc::ffi::LoggingSeverity::Verbose => log::Level::Trace,
sys_rtc::ffi::LoggingSeverity::Info => log::Level::Debug, // Translte webrtc
// info to debug log level to avoid polluting the user logs
sys_rtc::ffi::LoggingSeverity::Warning => log::Level::Warn,
sys_rtc::ffi::LoggingSeverity::Error => log::Level::Error,
_ => log::Level::Debug,
};
log::log!(target: "libwebrtc", lvl, "{}", msg);
}));
}
Self {
sys_handle: sys_pcf::ffi::create_peer_connection_factory(runtime.sys_handle.clone()),
runtime,
sys_handle: sys_pcf::ffi::create_peer_connection_factory(),
}
}
}
@@ -93,35 +65,26 @@ impl PeerConnectionFactory {
&self,
config: RtcConfiguration,
) -> Result<PeerConnection, RtcError> {
let native_config = sys_pcf::ffi::create_rtc_configuration(config.into());
let observer = Arc::new(imp_pc::PeerObserver::default());
let native_observer = sys_pc::ffi::create_native_peer_connection_observer(Box::new(
sys_pc::PeerConnectionObserverWrapper::new(observer.clone()),
));
unsafe {
let observer = Arc::new(imp_pc::PeerObserver::default());
let native_observer = sys_pc::ffi::create_native_peer_connection_observer(
self.runtime.sys_handle.clone(),
Box::new(sys_pc::PeerConnectionObserverWrapper::new(observer.clone())),
);
let res = self
.sys_handle
.create_peer_connection(config.into(), native_observer);
let res = self
.sys_handle
.create_peer_connection(native_config, &*native_observer as *const _ as *mut _);
match res {
Ok(sys_handle) => Ok(PeerConnection {
handle: imp_pc::PeerConnection::configure(
sys_handle,
observer,
native_observer,
),
}),
Err(e) => Err(sys_err::ffi::RTCError::from(e.what()).into()),
}
match res {
Ok(sys_handle) => Ok(PeerConnection {
handle: imp_pc::PeerConnection::configure(sys_handle, observer),
}),
Err(e) => Err(unsafe { sys_err::ffi::RtcError::from(e.what()).into() }),
}
}
pub fn create_video_track(&self, label: &str, source: NativeVideoSource) -> RtcVideoTrack {
RtcVideoTrack {
handle: imp_ms::RtcVideoTrack {
handle: imp_vt::RtcVideoTrack {
sys_handle: self
.sys_handle
.create_video_track(label.to_string(), source.handle.sys_handle()),
@@ -131,7 +94,7 @@ impl PeerConnectionFactory {
pub fn create_audio_track(&self, label: &str, source: NativeAudioSource) -> RtcAudioTrack {
RtcAudioTrack {
handle: imp_ms::RtcAudioTrack {
handle: imp_at::RtcAudioTrack {
sys_handle: self
.sys_handle
.create_audio_track(label.to_string(), source.handle.sys_handle()),
@@ -153,9 +116,9 @@ impl PeerConnectionFactory {
}
// Conversions
impl From<IceServer> for sys_pcf::ffi::ICEServer {
impl From<IceServer> for sys_pcf::ffi::IceServer {
fn from(value: IceServer) -> Self {
sys_pcf::ffi::ICEServer {
sys_pcf::ffi::IceServer {
urls: value.urls,
username: value.username,
password: value.password,
@@ -187,7 +150,7 @@ impl From<IceTransportsType> for sys_pcf::ffi::IceTransportsType {
}
}
impl From<RtcConfiguration> for sys_pcf::ffi::RTCConfiguration {
impl From<RtcConfiguration> for sys_pcf::ffi::RtcConfiguration {
fn from(value: RtcConfiguration) -> Self {
Self {
ice_servers: value.ice_servers.into_iter().map(Into::into).collect(),
@@ -196,3 +159,18 @@ impl From<RtcConfiguration> for sys_pcf::ffi::RTCConfiguration {
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_peer_connection_factory() {
let _ = env_logger::builder().is_test(true).try_init();
let factory = PeerConnectionFactory::default();
let source = NativeVideoSource::default();
let _track = factory.create_video_track("test", source);
drop(factory);
}
}
+3 -2
View File
@@ -1,5 +1,6 @@
use super::media_stream::new_media_stream_track;
use crate::{media_stream::MediaStreamTrack, rtp_parameters::RtpParameters};
use crate::imp::media_stream_track::new_media_stream_track;
use crate::media_stream_track::MediaStreamTrack;
use crate::rtp_parameters::RtpParameters;
use cxx::SharedPtr;
use webrtc_sys::rtp_receiver as sys_rr;
+6 -6
View File
@@ -1,9 +1,9 @@
use super::media_stream::new_media_stream_track;
use crate::{
media_stream::MediaStreamTrack, rtp_parameters::RtpParameters, RtcError, RtcErrorType,
};
use super::media_stream_track::new_media_stream_track;
use crate::media_stream_track::MediaStreamTrack;
use crate::{rtp_parameters::RtpParameters, RtcError, RtcErrorType};
use cxx::SharedPtr;
use webrtc_sys::{rtc_error::ffi::RTCError, rtp_sender as sys_rs};
use webrtc_sys::rtc_error as sys_err;
use webrtc_sys::rtp_sender as sys_rs;
#[derive(Clone)]
pub struct RtpSender {
@@ -41,6 +41,6 @@ impl RtpSender {
pub fn set_parameters(&self, parameters: RtpParameters) -> Result<(), RtcError> {
self.sys_handle
.set_parameters(parameters.into())
.map_err(|e| unsafe { RTCError::from(e.what()).into() })
.map_err(|e| unsafe { sys_err::ffi::RtcError::from(e.what()).into() })
}
}
+2 -2
View File
@@ -83,12 +83,12 @@ impl RtpTransceiver {
pub fn set_codec_preferences(&self, codecs: Vec<RtpCodecCapability>) -> Result<(), RtcError> {
self.sys_handle
.set_codec_preferences(codecs.into_iter().map(Into::into).collect())
.map_err(|e| unsafe { sys_err::ffi::RTCError::from(e.what()).into() })
.map_err(|e| unsafe { sys_err::ffi::RtcError::from(e.what()).into() })
}
pub fn stop(&self) -> Result<(), RtcError> {
self.sys_handle
.stop_standard()
.map_err(|e| unsafe { sys_err::ffi::RTCError::from(e.what()).into() })
.map_err(|e| unsafe { sys_err::ffi::RtcError::from(e.what()).into() })
}
}
+6 -7
View File
@@ -1,23 +1,23 @@
use crate::video_frame::{VideoFrame, VideoFrameBuffer};
use cxx::SharedPtr;
use webrtc_sys::media_stream as ms_sys;
use webrtc_sys::video_frame as vf_sys;
use webrtc_sys::video_track as vt_sys;
#[derive(Clone)]
pub struct NativeVideoSource {
sys_handle: SharedPtr<ms_sys::ffi::AdaptedVideoTrackSource>,
sys_handle: SharedPtr<vt_sys::ffi::VideoTrackSource>,
}
impl Default for NativeVideoSource {
fn default() -> Self {
Self {
sys_handle: ms_sys::ffi::new_adapted_video_track_source(),
sys_handle: vt_sys::ffi::new_video_track_source(),
}
}
}
impl NativeVideoSource {
pub fn sys_handle(&self) -> SharedPtr<ms_sys::ffi::AdaptedVideoTrackSource> {
pub fn sys_handle(&self) -> SharedPtr<vt_sys::ffi::VideoTrackSource> {
self.sys_handle.clone()
}
@@ -27,8 +27,7 @@ impl NativeVideoSource {
builder
.pin_mut()
.set_video_frame_buffer(frame.buffer.as_ref().sys_handle());
let frame = builder.pin_mut().build();
self.sys_handle.on_captured_frame(&frame);
self.sys_handle
.on_captured_frame(&builder.pin_mut().build());
}
}
+17 -23
View File
@@ -1,16 +1,16 @@
use super::video_frame::new_video_frame_buffer;
use crate::media_stream::RtcVideoTrack;
use crate::video_frame::{BoxVideoFrame, VideoFrame};
use cxx::UniquePtr;
use crate::video_track::RtcVideoTrack;
use cxx::{SharedPtr, UniquePtr};
use futures::stream::Stream;
use std::pin::Pin;
use std::sync::Arc;
use std::task::{Context, Poll};
use tokio::sync::mpsc;
use webrtc_sys::media_stream as sys_ms;
use webrtc_sys::video_track as sys_vt;
pub struct NativeVideoStream {
native_observer: UniquePtr<sys_ms::ffi::NativeVideoFrameSink>,
_observer: Box<VideoTrackObserver>,
native_sink: SharedPtr<sys_vt::ffi::NativeVideoSink>,
video_track: RtcVideoTrack,
frame_rx: mpsc::UnboundedReceiver<BoxVideoFrame>,
}
@@ -18,21 +18,16 @@ pub struct NativeVideoStream {
impl NativeVideoStream {
pub fn new(video_track: RtcVideoTrack) -> Self {
let (frame_tx, frame_rx) = mpsc::unbounded_channel();
let mut observer = Box::new(VideoTrackObserver { frame_tx });
let mut native_observer = unsafe {
sys_ms::ffi::new_native_video_frame_sink(Box::new(sys_ms::VideoFrameSinkWrapper::new(
&mut *observer,
)))
};
let observer = Arc::new(VideoTrackObserver { frame_tx });
let native_sink = sys_vt::ffi::new_native_video_sink(Box::new(
sys_vt::VideoSinkWrapper::new(observer.clone()),
));
unsafe {
sys_ms::ffi::media_to_video(video_track.sys_handle())
.add_sink(native_observer.pin_mut());
}
let video = unsafe { sys_vt::ffi::media_to_video(video_track.sys_handle()) };
video.add_sink(&native_sink);
Self {
native_observer,
_observer: observer,
native_sink,
video_track,
frame_rx,
}
@@ -43,11 +38,10 @@ impl NativeVideoStream {
}
pub fn close(&mut self) {
let video = unsafe { sys_vt::ffi::media_to_video(self.video_track.sys_handle()) };
video.remove_sink(&self.native_sink);
self.frame_rx.close();
unsafe {
sys_ms::ffi::media_to_video(self.video_track.sys_handle())
.remove_sink(self.native_observer.pin_mut());
}
}
}
@@ -69,7 +63,7 @@ struct VideoTrackObserver {
frame_tx: mpsc::UnboundedSender<BoxVideoFrame>,
}
impl sys_ms::VideoFrameSink for VideoTrackObserver {
impl sys_vt::VideoSink for VideoTrackObserver {
fn on_frame(&self, frame: UniquePtr<webrtc_sys::video_frame::ffi::VideoFrame>) {
let _ = self.frame_tx.send(VideoFrame {
rotation: frame.rotation().into(),
@@ -80,5 +74,5 @@ impl sys_ms::VideoFrameSink for VideoTrackObserver {
fn on_discarded_frame(&self) {}
fn on_constraints_changed(&self, _constraints: sys_ms::ffi::VideoTrackSourceConstraints) {}
fn on_constraints_changed(&self, _constraints: sys_vt::ffi::VideoTrackSourceConstraints) {}
}
+18
View File
@@ -0,0 +1,18 @@
use super::media_stream_track::impl_media_stream_track;
use crate::media_stream_track::RtcTrackState;
use cxx::SharedPtr;
use sys_vt::ffi::video_to_media;
use webrtc_sys::video_track as sys_vt;
#[derive(Clone)]
pub struct RtcVideoTrack {
pub(crate) sys_handle: SharedPtr<sys_vt::ffi::VideoTrack>,
}
impl RtcVideoTrack {
impl_media_stream_track!(video_to_media);
pub fn sys_handle(&self) -> SharedPtr<sys_vt::ffi::MediaStreamTrack> {
video_to_media(self.sys_handle.clone())
}
}