cleanup: webrtc-sys & fix RtcRuntime disposing crashes (#81)
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
@@ -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> {
|
||||
|
||||
@@ -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;
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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() })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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() })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {}
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user