RtpTransceiver bindings & requirements for publishing tracks (#39)
- RtpSender
- RtpReceiver
- RtpTransceiver
- RtpParameters
- VideoFrameBuilder
- Interior mutability on c++ side
- Cleanup bindings ( Use #pragma once instead of include guards )
- webrtc-sys/src/* headers are now used in only one place
- Avoid confusion between generated headers and our headers
- AdaptedVideoTrackSource
- Cleanup the workaround with unsupported Vec<Shared<T>>
- Put everything inside one file
This commit is contained in:
@@ -91,7 +91,7 @@ impl FFIServer {
|
||||
|
||||
pub async fn close(&self) {
|
||||
// Close all rooms
|
||||
for (k, (handle, shutdown_tx)) in self.rooms.write().drain() {
|
||||
for (_, (handle, shutdown_tx)) in self.rooms.write().drain() {
|
||||
let _ = shutdown_tx.send(());
|
||||
let _ = handle.await;
|
||||
}
|
||||
|
||||
@@ -116,4 +116,3 @@ fn on_video_frame(server: &'static FFIServer, track_sid: TrackSid) -> OnFrameHan
|
||||
);
|
||||
})
|
||||
}
|
||||
//
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
use std::fmt::{Debug, Formatter};
|
||||
|
||||
use cxx::UniquePtr;
|
||||
use cxx::{SharedPtr, UniquePtr};
|
||||
|
||||
pub use sys_jsep::ffi::{SdpParseError, SdpType};
|
||||
use webrtc_sys::jsep as sys_jsep;
|
||||
|
||||
// TODO Maybe we can replace that by a serialized IceCandidateInit
|
||||
#[derive(Clone)]
|
||||
pub struct IceCandidate {
|
||||
cxx_handle: UniquePtr<sys_jsep::ffi::IceCandidate>,
|
||||
cxx_handle: SharedPtr<sys_jsep::ffi::IceCandidate>,
|
||||
}
|
||||
|
||||
impl Debug for IceCandidate {
|
||||
@@ -34,11 +34,11 @@ impl IceCandidate {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn new(cxx_handle: UniquePtr<sys_jsep::ffi::IceCandidate>) -> Self {
|
||||
pub(crate) fn new(cxx_handle: SharedPtr<sys_jsep::ffi::IceCandidate>) -> Self {
|
||||
Self { cxx_handle }
|
||||
}
|
||||
|
||||
pub(crate) fn release(self) -> UniquePtr<sys_jsep::ffi::IceCandidate> {
|
||||
pub(crate) fn release(self) -> SharedPtr<sys_jsep::ffi::IceCandidate> {
|
||||
self.cxx_handle
|
||||
}
|
||||
|
||||
|
||||
@@ -3,12 +3,13 @@ pub mod jsep;
|
||||
pub mod media_stream;
|
||||
pub mod peer_connection;
|
||||
pub mod peer_connection_factory;
|
||||
pub mod prelude;
|
||||
pub mod rtc_error;
|
||||
pub mod rtp_parameters;
|
||||
pub mod rtp_receiver;
|
||||
pub mod rtp_sender;
|
||||
pub mod rtp_transceiver;
|
||||
pub mod video_frame;
|
||||
pub mod video_frame_buffer;
|
||||
pub mod webrtc;
|
||||
pub mod yuv_helper;
|
||||
|
||||
pub mod prelude;
|
||||
|
||||
+100
-111
@@ -1,7 +1,6 @@
|
||||
use cxx::UniquePtr;
|
||||
use cxx::{SharedPtr, UniquePtr};
|
||||
use livekit_utils::enum_dispatch;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::pin::Pin;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use webrtc_sys::media_stream as sys_ms;
|
||||
use webrtc_sys::MEDIA_TYPE_VIDEO;
|
||||
@@ -27,19 +26,19 @@ pub enum MediaStreamTrackHandle {
|
||||
}
|
||||
|
||||
impl MediaStreamTrackHandle {
|
||||
pub(crate) fn new(cxx_handle: UniquePtr<sys_ms::ffi::MediaStreamTrack>) -> Self {
|
||||
unsafe {
|
||||
if cxx_handle.kind() == MEDIA_TYPE_VIDEO {
|
||||
Self::Video(VideoTrack::new(UniquePtr::from_raw(
|
||||
sys_ms::ffi::media_to_video(cxx_handle.into_raw())
|
||||
as *mut sys_ms::ffi::VideoTrack,
|
||||
)))
|
||||
} else {
|
||||
Self::Audio(AudioTrack::new(UniquePtr::from_raw(
|
||||
sys_ms::ffi::media_to_audio(cxx_handle.into_raw())
|
||||
as *mut sys_ms::ffi::AudioTrack,
|
||||
)))
|
||||
}
|
||||
pub(crate) fn new(cxx_handle: SharedPtr<sys_ms::ffi::MediaStreamTrack>) -> Self {
|
||||
if cxx_handle.kind() == MEDIA_TYPE_VIDEO {
|
||||
Self::Video(VideoTrack::new(cxx_handle))
|
||||
} else {
|
||||
Self::Audio(AudioTrack::new(cxx_handle))
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(theomonnom): enum_dispatch with visibility support?
|
||||
pub(crate) fn cxx_handle(&self) -> SharedPtr<sys_ms::ffi::MediaStreamTrack> {
|
||||
match self {
|
||||
Self::Video(video) => video.cxx_handle(),
|
||||
Self::Audio(audio) => audio.cxx_handle(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -67,58 +66,123 @@ impl MediaStreamTrackTrait for MediaStreamTrackHandle {
|
||||
}
|
||||
|
||||
pub struct AudioTrack {
|
||||
cxx_handle: Mutex<UniquePtr<sys_ms::ffi::AudioTrack>>,
|
||||
cxx_handle: SharedPtr<sys_ms::ffi::MediaStreamTrack>,
|
||||
}
|
||||
|
||||
impl AudioTrack {
|
||||
pub(crate) fn new(cxx_handle: UniquePtr<sys_ms::ffi::AudioTrack>) -> Arc<Self> {
|
||||
Arc::new(Self {
|
||||
cxx_handle: Mutex::new(cxx_handle),
|
||||
})
|
||||
fn new(cxx_handle: SharedPtr<sys_ms::ffi::MediaStreamTrack>) -> Arc<Self> {
|
||||
Arc::new(Self { cxx_handle })
|
||||
}
|
||||
|
||||
pub(crate) fn cxx_handle(&self) -> SharedPtr<sys_ms::ffi::MediaStreamTrack> {
|
||||
self.cxx_handle.clone()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct VideoTrack {
|
||||
cxx_handle: Mutex<UniquePtr<sys_ms::ffi::VideoTrack>>,
|
||||
cxx_handle: SharedPtr<sys_ms::ffi::MediaStreamTrack>,
|
||||
observer: Box<InternalVideoTrackSink>,
|
||||
|
||||
// Keep alive for c++
|
||||
native_observer: UniquePtr<sys_ms::ffi::NativeVideoFrameSink>,
|
||||
}
|
||||
|
||||
impl VideoTrack {
|
||||
fn new(cxx_handle: SharedPtr<sys_ms::ffi::MediaStreamTrack>) -> Arc<Self> {
|
||||
let mut observer = Box::new(InternalVideoTrackSink::default());
|
||||
|
||||
let mut track = unsafe {
|
||||
Self {
|
||||
cxx_handle,
|
||||
native_observer: {
|
||||
sys_ms::ffi::create_native_video_frame_sink(Box::new(
|
||||
sys_ms::VideoFrameSinkWrapper::new(&mut *observer),
|
||||
))
|
||||
},
|
||||
observer,
|
||||
}
|
||||
};
|
||||
|
||||
unsafe {
|
||||
(*track.video_handle()).add_sink(track.native_observer.pin_mut());
|
||||
}
|
||||
|
||||
Arc::new(track)
|
||||
}
|
||||
|
||||
pub(crate) fn cxx_handle(&self) -> SharedPtr<sys_ms::ffi::MediaStreamTrack> {
|
||||
self.cxx_handle.clone()
|
||||
}
|
||||
|
||||
fn video_handle(&self) -> *const sys_ms::ffi::VideoTrack {
|
||||
unsafe { sys_ms::ffi::media_to_video(&*self.cxx_handle) }
|
||||
}
|
||||
|
||||
pub fn set_should_receive(&self, should_receive: bool) {
|
||||
unsafe { (*self.video_handle()).set_should_receive(should_receive) }
|
||||
}
|
||||
|
||||
pub fn set_content_hint(&self, hint: ContentHint) {
|
||||
unsafe { (*self.video_handle()).set_content_hint(hint) }
|
||||
}
|
||||
|
||||
pub fn should_receive(&self) -> bool {
|
||||
unsafe { (*self.video_handle()).should_receive() }
|
||||
}
|
||||
|
||||
pub fn content_hint(&self) -> ContentHint {
|
||||
unsafe { (*self.video_handle()).content_hint() }
|
||||
}
|
||||
|
||||
pub fn on_frame(&self, handler: OnFrameHandler) {
|
||||
*self.observer.on_frame_handler.lock().unwrap() = Some(handler);
|
||||
}
|
||||
|
||||
pub fn on_discarded_frame(&self, handler: OnDiscardedFrameHandler) {
|
||||
*self.observer.on_discarded_frame_handler.lock().unwrap() = Some(handler);
|
||||
}
|
||||
|
||||
pub fn on_constraints_changed(&self, handler: OnConstraintsChangedHandler) {
|
||||
*self.observer.on_constraints_changed_handler.lock().unwrap() = Some(handler);
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for VideoTrack {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
(*self.video_handle()).remove_sink(self.native_observer.pin_mut());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_media_stream_track_trait {
|
||||
($x:ty, $cast:ident) => {
|
||||
($x:ty) => {
|
||||
impl MediaStreamTrackTrait for $x {
|
||||
fn kind(&self) -> String {
|
||||
unsafe { (*sys_ms::ffi::$cast(&**self.cxx_handle.lock().unwrap())).kind() }
|
||||
self.cxx_handle.kind()
|
||||
}
|
||||
|
||||
fn id(&self) -> String {
|
||||
unsafe { (*sys_ms::ffi::$cast(&**self.cxx_handle.lock().unwrap())).id() }
|
||||
self.cxx_handle.id()
|
||||
}
|
||||
|
||||
fn enabled(&self) -> bool {
|
||||
unsafe { (*sys_ms::ffi::$cast(&**self.cxx_handle.lock().unwrap())).enabled() }
|
||||
self.cxx_handle.enabled()
|
||||
}
|
||||
|
||||
fn set_enabled(&self, enabled: bool) -> bool {
|
||||
unsafe {
|
||||
let media = sys_ms::ffi::$cast(&**self.cxx_handle.lock().unwrap())
|
||||
as *mut sys_ms::ffi::MediaStreamTrack;
|
||||
|
||||
Pin::new_unchecked(&mut *media).set_enabled(enabled)
|
||||
}
|
||||
self.cxx_handle.set_enabled(enabled)
|
||||
}
|
||||
|
||||
fn state(&self) -> TrackState {
|
||||
unsafe { (*sys_ms::ffi::$cast(&**self.cxx_handle.lock().unwrap())).state() }
|
||||
self.cxx_handle.state()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_media_stream_track_trait!(VideoTrack, video_to_media);
|
||||
impl_media_stream_track_trait!(AudioTrack, audio_to_media);
|
||||
impl_media_stream_track_trait!(VideoTrack);
|
||||
impl_media_stream_track_trait!(AudioTrack);
|
||||
|
||||
pub type OnFrameHandler = Box<dyn FnMut(VideoFrame, VideoFrameBuffer) + Send + Sync>;
|
||||
pub type OnDiscardedFrameHandler = Box<dyn FnMut() + Send + Sync>;
|
||||
@@ -167,83 +231,8 @@ impl sys_ms::VideoFrameSink for InternalVideoTrackSink {
|
||||
}
|
||||
}
|
||||
|
||||
impl VideoTrack {
|
||||
fn new(cxx_handle: UniquePtr<sys_ms::ffi::VideoTrack>) -> Arc<Self> {
|
||||
let mut observer = Box::new(InternalVideoTrackSink::default());
|
||||
|
||||
let mut track = unsafe {
|
||||
Self {
|
||||
cxx_handle: Mutex::new(cxx_handle),
|
||||
native_observer: sys_ms::ffi::create_native_video_frame_sink(Box::new(
|
||||
sys_ms::VideoFrameSinkWrapper::new(&mut *observer),
|
||||
)),
|
||||
observer,
|
||||
}
|
||||
};
|
||||
|
||||
unsafe {
|
||||
track
|
||||
.cxx_handle
|
||||
.lock()
|
||||
.unwrap()
|
||||
.pin_mut()
|
||||
.add_sink(track.native_observer.pin_mut());
|
||||
}
|
||||
|
||||
Arc::new(track)
|
||||
}
|
||||
|
||||
pub fn set_should_receive(&self, should_receive: bool) {
|
||||
self.cxx_handle
|
||||
.lock()
|
||||
.unwrap()
|
||||
.pin_mut()
|
||||
.set_should_receive(should_receive)
|
||||
}
|
||||
|
||||
pub fn set_content_hint(&self, hint: ContentHint) {
|
||||
self.cxx_handle
|
||||
.lock()
|
||||
.unwrap()
|
||||
.pin_mut()
|
||||
.set_content_hint(hint)
|
||||
}
|
||||
|
||||
pub fn should_receive(&self) -> bool {
|
||||
self.cxx_handle.lock().unwrap().should_receive()
|
||||
}
|
||||
|
||||
pub fn content_hint(&self) -> ContentHint {
|
||||
self.cxx_handle.lock().unwrap().content_hint()
|
||||
}
|
||||
|
||||
pub fn on_frame(&self, handler: OnFrameHandler) {
|
||||
*self.observer.on_frame_handler.lock().unwrap() = Some(handler);
|
||||
}
|
||||
|
||||
pub fn on_discarded_frame(&self, handler: OnDiscardedFrameHandler) {
|
||||
*self.observer.on_discarded_frame_handler.lock().unwrap() = Some(handler);
|
||||
}
|
||||
|
||||
pub fn on_constraints_changed(&self, handler: OnConstraintsChangedHandler) {
|
||||
*self.observer.on_constraints_changed_handler.lock().unwrap() = Some(handler);
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for VideoTrack {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
self.cxx_handle
|
||||
.lock()
|
||||
.unwrap()
|
||||
.pin_mut()
|
||||
.remove_sink(self.native_observer.pin_mut());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MediaStream {
|
||||
cxx_handle: UniquePtr<sys_ms::ffi::MediaStream>,
|
||||
cxx_handle: SharedPtr<sys_ms::ffi::MediaStream>,
|
||||
}
|
||||
|
||||
impl Debug for MediaStream {
|
||||
@@ -255,7 +244,7 @@ impl Debug for MediaStream {
|
||||
}
|
||||
|
||||
impl MediaStream {
|
||||
pub(crate) fn new(cxx_handle: UniquePtr<sys_ms::ffi::MediaStream>) -> Self {
|
||||
pub(crate) fn new(cxx_handle: SharedPtr<sys_ms::ffi::MediaStream>) -> Self {
|
||||
Self { cxx_handle }
|
||||
}
|
||||
|
||||
|
||||
@@ -1,28 +1,26 @@
|
||||
use crate::prelude::*;
|
||||
use cxx::{SharedPtr, UniquePtr};
|
||||
use log::trace;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::mem::ManuallyDrop;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use cxx::UniquePtr;
|
||||
use log::trace;
|
||||
use tokio::sync::{mpsc, oneshot};
|
||||
|
||||
use webrtc_sys::candidate as sys_ca;
|
||||
use webrtc_sys::data_channel as sys_dc;
|
||||
use webrtc_sys::jsep as sys_jsep;
|
||||
use webrtc_sys::media_stream as sys_ms;
|
||||
use webrtc_sys::peer_connection as sys_pc;
|
||||
use webrtc_sys::rtp_receiver as sys_rr;
|
||||
use webrtc_sys::rtp_sender as sys_rs;
|
||||
use webrtc_sys::rtp_transceiver as sys_rt;
|
||||
|
||||
pub use webrtc_sys::peer_connection::ffi::IceConnectionState;
|
||||
pub use webrtc_sys::peer_connection::ffi::IceGatheringState;
|
||||
use webrtc_sys::peer_connection::ffi::NativeCreateSdpObserverHandle;
|
||||
pub use webrtc_sys::peer_connection::ffi::PeerConnectionState;
|
||||
pub use webrtc_sys::peer_connection::ffi::RTCOfferAnswerOptions;
|
||||
pub use webrtc_sys::peer_connection::ffi::SignalingState;
|
||||
|
||||
use crate::data_channel::{DataChannel, DataChannelInit};
|
||||
use crate::jsep::{IceCandidate, SessionDescription};
|
||||
use crate::media_stream::{AudioTrack, MediaStream, VideoTrack};
|
||||
use crate::rtc_error::RTCError;
|
||||
use crate::rtp_receiver::RtpReceiver;
|
||||
use crate::rtp_transceiver::RtpTransceiver;
|
||||
|
||||
pub struct PeerConnection {
|
||||
cxx_handle: UniquePtr<sys_pc::ffi::PeerConnection>,
|
||||
observer: Box<InternalObserver>,
|
||||
@@ -38,8 +36,6 @@ impl Debug for PeerConnection {
|
||||
.field("signaling_state", &self.signaling_state())
|
||||
.field("ice_connection_state", &self.ice_connection_state())
|
||||
.field("ice_gathering_state", &self.ice_gathering_state())
|
||||
.field("local_description", &self.local_description())
|
||||
.field("remote_description", &self.remote_description())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
@@ -58,7 +54,7 @@ impl PeerConnection {
|
||||
}
|
||||
|
||||
fn create_sdp_observer() -> (
|
||||
UniquePtr<NativeCreateSdpObserverHandle>,
|
||||
UniquePtr<sys_pc::ffi::NativeCreateSdpObserverHandle>,
|
||||
mpsc::Receiver<Result<SessionDescription, RTCError>>,
|
||||
) {
|
||||
let (tx, rx) = mpsc::channel(1);
|
||||
@@ -81,14 +77,13 @@ impl PeerConnection {
|
||||
}
|
||||
|
||||
pub async fn create_offer(
|
||||
&mut self,
|
||||
&self,
|
||||
options: RTCOfferAnswerOptions,
|
||||
) -> Result<SessionDescription, RTCError> {
|
||||
let (mut native_wrapper, mut rx) = Self::create_sdp_observer();
|
||||
|
||||
unsafe {
|
||||
self.cxx_handle
|
||||
.pin_mut()
|
||||
.create_offer(native_wrapper.pin_mut(), options);
|
||||
}
|
||||
|
||||
@@ -96,24 +91,20 @@ impl PeerConnection {
|
||||
}
|
||||
|
||||
pub async fn create_answer(
|
||||
&mut self,
|
||||
&self,
|
||||
options: RTCOfferAnswerOptions,
|
||||
) -> Result<SessionDescription, RTCError> {
|
||||
let (mut native_wrapper, mut rx) = Self::create_sdp_observer();
|
||||
|
||||
unsafe {
|
||||
self.cxx_handle
|
||||
.pin_mut()
|
||||
.create_answer(native_wrapper.pin_mut(), options);
|
||||
}
|
||||
|
||||
rx.recv().await.unwrap()
|
||||
}
|
||||
|
||||
pub async fn set_local_description(
|
||||
&mut self,
|
||||
desc: SessionDescription,
|
||||
) -> Result<(), RTCError> {
|
||||
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| {
|
||||
@@ -124,17 +115,13 @@ impl PeerConnection {
|
||||
|
||||
unsafe {
|
||||
self.cxx_handle
|
||||
.pin_mut()
|
||||
.set_local_description(desc.release(), native_wrapper.pin_mut());
|
||||
}
|
||||
|
||||
rx.await.unwrap()
|
||||
}
|
||||
|
||||
pub async fn set_remote_description(
|
||||
&mut self,
|
||||
desc: SessionDescription,
|
||||
) -> Result<(), RTCError> {
|
||||
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| {
|
||||
@@ -145,22 +132,92 @@ impl PeerConnection {
|
||||
|
||||
unsafe {
|
||||
self.cxx_handle
|
||||
.pin_mut()
|
||||
.set_remote_description(desc.release(), native_wrapper.pin_mut());
|
||||
}
|
||||
|
||||
rx.await.unwrap()
|
||||
}
|
||||
|
||||
pub fn add_track(
|
||||
&self,
|
||||
track: MediaStreamTrackHandle,
|
||||
stream_ids: &Vec<String>,
|
||||
) -> Result<RtpSender, RTCError> {
|
||||
let res = self.cxx_handle.add_track(track.cxx_handle(), stream_ids);
|
||||
match res {
|
||||
Ok(cxx_handle) => Ok(RtpSender::new(cxx_handle)),
|
||||
Err(e) => unsafe { Err(RTCError::from(e.what())) },
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remove_track(&self, sender: RtpSender) -> Result<(), RTCError> {
|
||||
self.cxx_handle
|
||||
.remove_track(sender.cxx_handle())
|
||||
.map_err(|e| unsafe { RTCError::from(e.what()) })
|
||||
}
|
||||
|
||||
pub fn add_transceiver(
|
||||
&self,
|
||||
track: MediaStreamTrackHandle,
|
||||
init: RtpTransceiverInit,
|
||||
) -> Result<RtpTransceiver, RTCError> {
|
||||
let res = self
|
||||
.cxx_handle
|
||||
.add_transceiver(track.cxx_handle(), init.into());
|
||||
|
||||
match res {
|
||||
Ok(cxx_handle) => Ok(RtpTransceiver::new(cxx_handle)),
|
||||
Err(e) => unsafe { Err(RTCError::from(e.what())) },
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_transceiver_for_media(
|
||||
&self,
|
||||
media_type: MediaType,
|
||||
init: RtpTransceiverInit,
|
||||
) -> Result<RtpTransceiver, RTCError> {
|
||||
let res = self
|
||||
.cxx_handle
|
||||
.add_transceiver_for_media(media_type, init.into());
|
||||
|
||||
match res {
|
||||
Ok(cxx_handle) => Ok(RtpTransceiver::new(cxx_handle)),
|
||||
Err(e) => unsafe { Err(RTCError::from(e.what())) },
|
||||
}
|
||||
}
|
||||
|
||||
pub fn senders(&self) -> Vec<RtpSender> {
|
||||
self.cxx_handle
|
||||
.get_senders()
|
||||
.into_iter()
|
||||
.map(|sender| RtpSender::new(sender.ptr))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn receivers(&self) -> Vec<RtpReceiver> {
|
||||
self.cxx_handle
|
||||
.get_receivers()
|
||||
.into_iter()
|
||||
.map(|receiver| RtpReceiver::new(receiver.ptr))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn transceivers(&self) -> Vec<RtpTransceiver> {
|
||||
self.cxx_handle
|
||||
.get_transceivers()
|
||||
.into_iter()
|
||||
.map(|transceiver| RtpTransceiver::new(transceiver.ptr))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn create_data_channel(
|
||||
&mut self,
|
||||
&self,
|
||||
label: &str,
|
||||
init: DataChannelInit,
|
||||
) -> Result<DataChannel, RTCError> {
|
||||
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 {
|
||||
@@ -170,7 +227,7 @@ impl PeerConnection {
|
||||
}
|
||||
|
||||
// TODO(theomonnom) Use IceCandidateInit instead of IceCandidate
|
||||
pub async fn add_ice_candidate(&mut self, candidate: IceCandidate) -> Result<(), RTCError> {
|
||||
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| {
|
||||
@@ -180,7 +237,6 @@ impl PeerConnection {
|
||||
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());
|
||||
|
||||
rx.await.unwrap()
|
||||
@@ -415,7 +471,7 @@ impl sys_pc::PeerConnectionObserver for InternalObserver {
|
||||
}
|
||||
}
|
||||
|
||||
fn on_add_stream(&self, stream: UniquePtr<webrtc_sys::media_stream::ffi::MediaStream>) {
|
||||
fn on_add_stream(&self, stream: SharedPtr<sys_ms::ffi::MediaStream>) {
|
||||
trace!("on_add_stream");
|
||||
let mut handler = self.on_add_stream_handler.lock().unwrap();
|
||||
if let Some(f) = handler.as_mut() {
|
||||
@@ -423,7 +479,7 @@ impl sys_pc::PeerConnectionObserver for InternalObserver {
|
||||
}
|
||||
}
|
||||
|
||||
fn on_remove_stream(&self, stream: UniquePtr<webrtc_sys::media_stream::ffi::MediaStream>) {
|
||||
fn on_remove_stream(&self, stream: SharedPtr<sys_ms::ffi::MediaStream>) {
|
||||
trace!("on_remove_stream");
|
||||
let mut handler = self.on_remove_stream_handler.lock().unwrap();
|
||||
if let Some(f) = handler.as_mut() {
|
||||
@@ -431,7 +487,7 @@ impl sys_pc::PeerConnectionObserver for InternalObserver {
|
||||
}
|
||||
}
|
||||
|
||||
fn on_data_channel(&self, data_channel: UniquePtr<webrtc_sys::data_channel::ffi::DataChannel>) {
|
||||
fn on_data_channel(&self, data_channel: UniquePtr<sys_dc::ffi::DataChannel>) {
|
||||
trace!("on_data_channel");
|
||||
let mut handler = self.on_data_channel_handler.lock().unwrap();
|
||||
if let Some(f) = handler.as_mut() {
|
||||
@@ -493,7 +549,7 @@ impl sys_pc::PeerConnectionObserver for InternalObserver {
|
||||
}
|
||||
}
|
||||
|
||||
fn on_ice_candidate(&self, candidate: UniquePtr<webrtc_sys::jsep::ffi::IceCandidate>) {
|
||||
fn on_ice_candidate(&self, candidate: SharedPtr<sys_jsep::ffi::IceCandidate>) {
|
||||
trace!("on_ice_candidate");
|
||||
let mut handler = self.on_ice_candidate_handler.lock().unwrap();
|
||||
if let Some(f) = handler.as_mut() {
|
||||
@@ -516,10 +572,7 @@ impl sys_pc::PeerConnectionObserver for InternalObserver {
|
||||
}
|
||||
}
|
||||
|
||||
fn on_ice_candidates_removed(
|
||||
&self,
|
||||
removed: Vec<UniquePtr<webrtc_sys::candidate::ffi::Candidate>>,
|
||||
) {
|
||||
fn on_ice_candidates_removed(&self, removed: Vec<SharedPtr<sys_ca::ffi::Candidate>>) {
|
||||
trace!("on_ice_candidates_removed");
|
||||
let mut handler = self.on_ice_candidates_removed_handler.lock().unwrap();
|
||||
if let Some(f) = handler.as_mut() {
|
||||
@@ -538,10 +591,7 @@ impl sys_pc::PeerConnectionObserver for InternalObserver {
|
||||
}
|
||||
}
|
||||
|
||||
fn on_ice_selected_candidate_pair_changed(
|
||||
&self,
|
||||
event: webrtc_sys::peer_connection::ffi::CandidatePairChangeEvent,
|
||||
) {
|
||||
fn on_ice_selected_candidate_pair_changed(&self, event: sys_pc::ffi::CandidatePairChangeEvent) {
|
||||
trace!("on_ice_selected_candidate_pair_changed");
|
||||
let mut handler = self
|
||||
.on_ice_selected_candidate_pair_changed_handler
|
||||
@@ -554,8 +604,8 @@ impl sys_pc::PeerConnectionObserver for InternalObserver {
|
||||
|
||||
fn on_add_track(
|
||||
&self,
|
||||
receiver: UniquePtr<webrtc_sys::rtp_receiver::ffi::RtpReceiver>,
|
||||
streams: Vec<UniquePtr<webrtc_sys::media_stream::ffi::MediaStream>>,
|
||||
receiver: SharedPtr<sys_rr::ffi::RtpReceiver>,
|
||||
streams: Vec<SharedPtr<sys_ms::ffi::MediaStream>>,
|
||||
) {
|
||||
trace!("on_add_track");
|
||||
let mut handler = self.on_add_track_handler.lock().unwrap();
|
||||
@@ -565,7 +615,7 @@ impl sys_pc::PeerConnectionObserver for InternalObserver {
|
||||
}
|
||||
}
|
||||
|
||||
fn on_track(&self, transceiver: UniquePtr<webrtc_sys::rtp_transceiver::ffi::RtpTransceiver>) {
|
||||
fn on_track(&self, transceiver: SharedPtr<sys_rt::ffi::RtpTransceiver>) {
|
||||
trace!("on_track");
|
||||
let mut handler = self.on_track_handler.lock().unwrap();
|
||||
if let Some(f) = handler.as_mut() {
|
||||
@@ -573,7 +623,7 @@ impl sys_pc::PeerConnectionObserver for InternalObserver {
|
||||
}
|
||||
}
|
||||
|
||||
fn on_remove_track(&self, receiver: UniquePtr<webrtc_sys::rtp_receiver::ffi::RtpReceiver>) {
|
||||
fn on_remove_track(&self, receiver: SharedPtr<sys_rr::ffi::RtpReceiver>) {
|
||||
trace!("on_remove_track");
|
||||
let mut handler = self.on_remove_track_handler.lock().unwrap();
|
||||
if let Some(f) = handler.as_mut() {
|
||||
|
||||
@@ -12,9 +12,11 @@ pub use crate::peer_connection_factory::{
|
||||
ContinualGatheringPolicy, ICEServer, IceTransportsType, PeerConnectionFactory, RTCConfiguration,
|
||||
};
|
||||
pub use crate::rtc_error::RTCError;
|
||||
pub use crate::rtp_parameters::*;
|
||||
pub use crate::rtp_receiver::RtpReceiver;
|
||||
pub use crate::rtp_transceiver::RtpTransceiver;
|
||||
pub use crate::rtp_sender::RtpSender;
|
||||
pub use crate::rtp_transceiver::{RtpTransceiver, RtpTransceiverInit};
|
||||
pub use crate::video_frame::{VideoFrame, VideoRotation};
|
||||
pub use crate::video_frame_buffer::*;
|
||||
pub use crate::webrtc::RTCRuntime;
|
||||
pub use crate::webrtc::*;
|
||||
pub use crate::yuv_helper::ConvertError;
|
||||
|
||||
@@ -0,0 +1,462 @@
|
||||
use crate::prelude::*;
|
||||
use std::collections::HashMap;
|
||||
use std::vec::Vec;
|
||||
use webrtc_sys::rtp_parameters as ps_sys;
|
||||
|
||||
// Don't exporting structs here (only enum), cxx doesn't support Option and HashMap
|
||||
pub use ps_sys::ffi::{
|
||||
DegradationPreference, FecMechanism, RtcpFeedbackMessageType, RtcpFeedbackType,
|
||||
RtpExtensionFilter,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RtcpFeedback {
|
||||
pub feedback_type: RtcpFeedbackType,
|
||||
pub message_type: Option<RtcpFeedbackMessageType>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RtpCodecCapability {
|
||||
pub mime_type: String,
|
||||
pub name: String,
|
||||
pub kind: MediaType,
|
||||
pub clock_rate: Option<i32>,
|
||||
pub preferred_payload_type: Option<i32>,
|
||||
pub max_ptime: Option<i32>,
|
||||
pub ptime: Option<i32>,
|
||||
pub num_channels: Option<i32>,
|
||||
pub rtcp_feedback: Vec<RtcpFeedback>,
|
||||
pub parameters: HashMap<String, String>,
|
||||
pub options: HashMap<String, String>,
|
||||
pub max_temporal_layer_extensions: i32,
|
||||
pub max_spatial_layer_extensions: i32,
|
||||
pub svc_multi_stream_support: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RtpHeaderExtensionCapability {
|
||||
pub uri: String,
|
||||
pub preferred_id: Option<i32>,
|
||||
pub preferred_encrypt: bool,
|
||||
pub direction: RtpTransceiverDirection,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RtpExtension {
|
||||
pub uri: String,
|
||||
pub id: i32,
|
||||
pub encrypt: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RtpFecParameters {
|
||||
pub ssrc: Option<u32>,
|
||||
pub mechanism: FecMechanism,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RtpRtxParameters {
|
||||
pub ssrc: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RtpEncodingParameters {
|
||||
pub ssrc: Option<u32>,
|
||||
pub bitrate_priority: f64,
|
||||
pub network_priority: Priority,
|
||||
pub max_bitrate_bps: Option<i32>,
|
||||
pub min_bitrate_bps: Option<i32>,
|
||||
pub max_framerate: Option<f64>,
|
||||
pub num_temporal_layers: Option<i32>,
|
||||
pub scale_resolution_down_by: Option<f64>,
|
||||
pub scalability_mode: Option<String>,
|
||||
pub active: bool,
|
||||
pub rid: String,
|
||||
pub adaptive_ptime: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RtpCodecParameters {
|
||||
pub mime_type: String,
|
||||
pub name: String,
|
||||
pub kind: MediaType,
|
||||
pub payload_type: i32,
|
||||
pub clock_rate: Option<i32>,
|
||||
pub num_channels: Option<i32>,
|
||||
pub max_ptime: Option<i32>,
|
||||
pub ptime: Option<i32>,
|
||||
pub rtcp_feedback: Vec<RtcpFeedback>,
|
||||
pub parameters: HashMap<String, String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RtpCapabilities {
|
||||
pub codecs: Vec<RtpCodecCapability>,
|
||||
pub header_extensions: Vec<RtpHeaderExtensionCapability>,
|
||||
pub fec: Vec<FecMechanism>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RtcpParameters {
|
||||
pub ssrc: Option<u32>,
|
||||
pub cname: String,
|
||||
pub reduced_size: bool,
|
||||
pub mux: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RtpParameters {
|
||||
pub transaction_id: String,
|
||||
pub mid: String,
|
||||
pub codecs: Vec<RtpCodecParameters>,
|
||||
pub header_extensions: Vec<RtpExtension>,
|
||||
pub encodings: Vec<RtpEncodingParameters>,
|
||||
pub rtcp: RtcpParameters,
|
||||
pub degradation_preference: Option<DegradationPreference>,
|
||||
}
|
||||
|
||||
fn into_map(vec: Vec<ps_sys::ffi::StringKeyValue>) -> HashMap<String, String> {
|
||||
let mut map = HashMap::with_capacity(vec.len());
|
||||
for pair in vec {
|
||||
map.insert(pair.key, pair.value);
|
||||
}
|
||||
map
|
||||
}
|
||||
|
||||
impl From<ps_sys::ffi::RtcpFeedback> for RtcpFeedback {
|
||||
fn from(value: ps_sys::ffi::RtcpFeedback) -> Self {
|
||||
Self {
|
||||
feedback_type: value.feedback_type,
|
||||
message_type: value.has_message_type.then_some(value.message_type),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ps_sys::ffi::RtpCodecCapability> for RtpCodecCapability {
|
||||
fn from(value: ps_sys::ffi::RtpCodecCapability) -> Self {
|
||||
Self {
|
||||
mime_type: value.mime_type,
|
||||
name: value.name,
|
||||
kind: value.kind,
|
||||
clock_rate: value.has_clock_rate.then_some(value.clock_rate),
|
||||
preferred_payload_type: value
|
||||
.has_preferred_payload_type
|
||||
.then_some(value.preferred_payload_type),
|
||||
max_ptime: value.has_max_ptime.then_some(value.max_ptime),
|
||||
ptime: value.has_ptime.then_some(value.ptime),
|
||||
num_channels: value.has_num_channels.then_some(value.num_channels),
|
||||
rtcp_feedback: value.rtcp_feedback.into_iter().map(Into::into).collect(),
|
||||
parameters: into_map(value.parameters),
|
||||
options: into_map(value.options),
|
||||
max_temporal_layer_extensions: value.max_temporal_layer_extensions,
|
||||
max_spatial_layer_extensions: value.max_spatial_layer_extensions,
|
||||
svc_multi_stream_support: value.svc_multi_stream_support,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ps_sys::ffi::RtpHeaderExtensionCapability> for RtpHeaderExtensionCapability {
|
||||
fn from(value: ps_sys::ffi::RtpHeaderExtensionCapability) -> Self {
|
||||
Self {
|
||||
uri: value.uri,
|
||||
preferred_id: value.has_preferred_id.then_some(value.preferred_id),
|
||||
preferred_encrypt: value.preferred_encrypt,
|
||||
direction: value.direction,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ps_sys::ffi::RtpExtension> for RtpExtension {
|
||||
fn from(value: ps_sys::ffi::RtpExtension) -> Self {
|
||||
Self {
|
||||
uri: value.uri,
|
||||
id: value.id,
|
||||
encrypt: value.encrypt,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ps_sys::ffi::RtpFecParameters> for RtpFecParameters {
|
||||
fn from(value: ps_sys::ffi::RtpFecParameters) -> Self {
|
||||
Self {
|
||||
ssrc: value.has_ssrc.then_some(value.ssrc),
|
||||
mechanism: value.mechanism,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ps_sys::ffi::RtpRtxParameters> for RtpRtxParameters {
|
||||
fn from(value: ps_sys::ffi::RtpRtxParameters) -> Self {
|
||||
Self {
|
||||
ssrc: value.has_ssrc.then_some(value.ssrc),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ps_sys::ffi::RtpEncodingParameters> for RtpEncodingParameters {
|
||||
fn from(value: ps_sys::ffi::RtpEncodingParameters) -> Self {
|
||||
Self {
|
||||
ssrc: value.has_ssrc.then_some(value.ssrc),
|
||||
bitrate_priority: value.bitrate_priority,
|
||||
network_priority: value.network_priority,
|
||||
max_bitrate_bps: value.has_max_bitrate_bps.then_some(value.max_bitrate_bps),
|
||||
min_bitrate_bps: value.has_min_bitrate_bps.then_some(value.min_bitrate_bps),
|
||||
max_framerate: value.has_max_framerate.then_some(value.max_framerate),
|
||||
num_temporal_layers: value
|
||||
.has_num_temporal_layers
|
||||
.then_some(value.num_temporal_layers),
|
||||
scale_resolution_down_by: value
|
||||
.has_scale_resolution_down_by
|
||||
.then_some(value.scale_resolution_down_by),
|
||||
scalability_mode: value.has_scalability_mode.then_some(value.scalability_mode),
|
||||
active: value.active,
|
||||
rid: value.rid,
|
||||
adaptive_ptime: value.adaptive_ptime,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ps_sys::ffi::RtpCodecParameters> for RtpCodecParameters {
|
||||
fn from(value: ps_sys::ffi::RtpCodecParameters) -> Self {
|
||||
Self {
|
||||
mime_type: value.mime_type,
|
||||
name: value.name,
|
||||
kind: value.kind,
|
||||
payload_type: value.payload_type,
|
||||
clock_rate: value.has_clock_rate.then_some(value.clock_rate),
|
||||
num_channels: value.has_num_channels.then_some(value.num_channels),
|
||||
max_ptime: value.has_max_ptime.then_some(value.max_ptime),
|
||||
ptime: value.has_ptime.then_some(value.ptime),
|
||||
rtcp_feedback: value.rtcp_feedback.into_iter().map(Into::into).collect(),
|
||||
parameters: into_map(value.parameters),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ps_sys::ffi::RtpCapabilities> for RtpCapabilities {
|
||||
fn from(value: ps_sys::ffi::RtpCapabilities) -> Self {
|
||||
Self {
|
||||
codecs: value.codecs.into_iter().map(Into::into).collect(),
|
||||
header_extensions: value
|
||||
.header_extensions
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect(),
|
||||
fec: value.fec.into_iter().map(Into::into).collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ps_sys::ffi::RtcpParameters> for RtcpParameters {
|
||||
fn from(value: ps_sys::ffi::RtcpParameters) -> Self {
|
||||
Self {
|
||||
ssrc: value.has_ssrc.then_some(value.ssrc),
|
||||
cname: value.cname,
|
||||
reduced_size: value.reduced_size,
|
||||
mux: value.mux,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ps_sys::ffi::RtpParameters> for RtpParameters {
|
||||
fn from(value: ps_sys::ffi::RtpParameters) -> Self {
|
||||
Self {
|
||||
transaction_id: value.transaction_id,
|
||||
mid: value.mid,
|
||||
codecs: value.codecs.into_iter().map(Into::into).collect(),
|
||||
header_extensions: value
|
||||
.header_extensions
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect(),
|
||||
encodings: value.encodings.into_iter().map(Into::into).collect(),
|
||||
rtcp: value.rtcp.into(),
|
||||
degradation_preference: value
|
||||
.has_degradation_preference
|
||||
.then_some(value.degradation_preference),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ignore the value inside unwrap_or for the following implementations
|
||||
|
||||
fn into_vec(map: HashMap<String, String>) -> Vec<ps_sys::ffi::StringKeyValue> {
|
||||
let mut vec = Vec::with_capacity(map.len());
|
||||
for (key, value) in map {
|
||||
vec.push(ps_sys::ffi::StringKeyValue { key, value })
|
||||
}
|
||||
vec
|
||||
}
|
||||
|
||||
impl From<RtcpFeedback> for ps_sys::ffi::RtcpFeedback {
|
||||
fn from(value: RtcpFeedback) -> Self {
|
||||
Self {
|
||||
feedback_type: value.feedback_type,
|
||||
has_message_type: value.message_type.is_some(),
|
||||
message_type: value
|
||||
.message_type
|
||||
.unwrap_or(RtcpFeedbackMessageType::GenericNACK),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RtpCodecCapability> for ps_sys::ffi::RtpCodecCapability {
|
||||
fn from(value: RtpCodecCapability) -> Self {
|
||||
Self {
|
||||
mime_type: value.mime_type,
|
||||
name: value.name,
|
||||
kind: value.kind,
|
||||
has_clock_rate: value.clock_rate.is_some(),
|
||||
clock_rate: value.clock_rate.unwrap_or(0),
|
||||
has_preferred_payload_type: value.preferred_payload_type.is_some(),
|
||||
preferred_payload_type: value.preferred_payload_type.unwrap_or(0),
|
||||
has_max_ptime: value.max_ptime.is_some(),
|
||||
max_ptime: value.max_ptime.unwrap_or(0),
|
||||
has_ptime: value.ptime.is_some(),
|
||||
ptime: value.ptime.unwrap_or(0),
|
||||
has_num_channels: value.num_channels.is_some(),
|
||||
num_channels: value.num_channels.unwrap_or(0),
|
||||
rtcp_feedback: value.rtcp_feedback.into_iter().map(Into::into).collect(),
|
||||
parameters: into_vec(value.parameters),
|
||||
options: into_vec(value.options),
|
||||
max_temporal_layer_extensions: value.max_temporal_layer_extensions,
|
||||
max_spatial_layer_extensions: value.max_spatial_layer_extensions,
|
||||
svc_multi_stream_support: value.svc_multi_stream_support,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RtpHeaderExtensionCapability> for ps_sys::ffi::RtpHeaderExtensionCapability {
|
||||
fn from(value: RtpHeaderExtensionCapability) -> Self {
|
||||
Self {
|
||||
uri: value.uri,
|
||||
has_preferred_id: value.preferred_id.is_some(),
|
||||
preferred_id: value.preferred_id.unwrap_or(0),
|
||||
preferred_encrypt: value.preferred_encrypt,
|
||||
direction: value.direction,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RtpExtension> for ps_sys::ffi::RtpExtension {
|
||||
fn from(value: RtpExtension) -> Self {
|
||||
Self {
|
||||
uri: value.uri,
|
||||
id: value.id,
|
||||
encrypt: value.encrypt,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RtpFecParameters> for ps_sys::ffi::RtpFecParameters {
|
||||
fn from(value: RtpFecParameters) -> Self {
|
||||
Self {
|
||||
has_ssrc: value.ssrc.is_some(),
|
||||
ssrc: value.ssrc.unwrap_or(0),
|
||||
mechanism: value.mechanism,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RtpRtxParameters> for ps_sys::ffi::RtpRtxParameters {
|
||||
fn from(value: RtpRtxParameters) -> Self {
|
||||
Self {
|
||||
has_ssrc: value.ssrc.is_some(),
|
||||
ssrc: value.ssrc.unwrap_or(0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RtpEncodingParameters> for ps_sys::ffi::RtpEncodingParameters {
|
||||
fn from(value: RtpEncodingParameters) -> Self {
|
||||
Self {
|
||||
has_ssrc: value.ssrc.is_some(),
|
||||
ssrc: value.ssrc.unwrap_or(0),
|
||||
bitrate_priority: value.bitrate_priority,
|
||||
network_priority: value.network_priority,
|
||||
has_max_bitrate_bps: value.max_bitrate_bps.is_some(),
|
||||
max_bitrate_bps: value.max_bitrate_bps.unwrap_or(0),
|
||||
has_min_bitrate_bps: value.min_bitrate_bps.is_some(),
|
||||
min_bitrate_bps: value.min_bitrate_bps.unwrap_or(0),
|
||||
has_max_framerate: value.max_framerate.is_some(),
|
||||
max_framerate: value.max_framerate.unwrap_or(0.0),
|
||||
has_num_temporal_layers: value.num_temporal_layers.is_some(),
|
||||
num_temporal_layers: value.num_temporal_layers.unwrap_or(0),
|
||||
has_scale_resolution_down_by: value.scale_resolution_down_by.is_some(),
|
||||
scale_resolution_down_by: value.scale_resolution_down_by.unwrap_or(0.0),
|
||||
has_scalability_mode: value.scalability_mode.is_some(),
|
||||
scalability_mode: value.scalability_mode.unwrap_or(String::new()),
|
||||
active: value.active,
|
||||
rid: value.rid,
|
||||
adaptive_ptime: value.adaptive_ptime,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RtpCodecParameters> for ps_sys::ffi::RtpCodecParameters {
|
||||
fn from(value: RtpCodecParameters) -> Self {
|
||||
Self {
|
||||
mime_type: value.mime_type,
|
||||
name: value.name,
|
||||
kind: value.kind,
|
||||
payload_type: value.payload_type,
|
||||
has_clock_rate: value.clock_rate.is_some(),
|
||||
clock_rate: value.clock_rate.unwrap_or(0),
|
||||
has_num_channels: value.num_channels.is_some(),
|
||||
num_channels: value.num_channels.unwrap_or(0),
|
||||
has_max_ptime: value.max_ptime.is_some(),
|
||||
max_ptime: value.max_ptime.unwrap_or(0),
|
||||
has_ptime: value.ptime.is_some(),
|
||||
ptime: value.ptime.unwrap_or(0),
|
||||
rtcp_feedback: value.rtcp_feedback.into_iter().map(Into::into).collect(),
|
||||
parameters: into_vec(value.parameters),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RtpCapabilities> for ps_sys::ffi::RtpCapabilities {
|
||||
fn from(value: RtpCapabilities) -> Self {
|
||||
Self {
|
||||
codecs: value.codecs.into_iter().map(Into::into).collect(),
|
||||
header_extensions: value
|
||||
.header_extensions
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect(),
|
||||
fec: value.fec.into_iter().map(Into::into).collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RtcpParameters> for ps_sys::ffi::RtcpParameters {
|
||||
fn from(value: RtcpParameters) -> Self {
|
||||
Self {
|
||||
has_ssrc: value.ssrc.is_some(),
|
||||
ssrc: value.ssrc.unwrap_or(0),
|
||||
cname: value.cname,
|
||||
reduced_size: value.reduced_size,
|
||||
mux: value.mux,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RtpParameters> for ps_sys::ffi::RtpParameters {
|
||||
fn from(value: RtpParameters) -> Self {
|
||||
Self {
|
||||
transaction_id: value.transaction_id,
|
||||
mid: value.mid,
|
||||
codecs: value.codecs.into_iter().map(Into::into).collect(),
|
||||
header_extensions: value
|
||||
.header_extensions
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect(),
|
||||
encodings: value.encodings.into_iter().map(Into::into).collect(),
|
||||
rtcp: value.rtcp.into(),
|
||||
has_degradation_preference: value.degradation_preference.is_some(),
|
||||
degradation_preference: value
|
||||
.degradation_preference
|
||||
.unwrap_or(DegradationPreference::Balanced),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,26 +1,67 @@
|
||||
use crate::media_stream::{MediaStreamTrackHandle, MediaStreamTrackTrait};
|
||||
use cxx::UniquePtr;
|
||||
use crate::media_stream::{MediaStream, MediaStreamTrackHandle};
|
||||
use crate::rtp_parameters::RtpParameters;
|
||||
use cxx::SharedPtr;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use webrtc_sys::rtp_receiver as sys_rec;
|
||||
use webrtc_sys::webrtc as sys_webrtc;
|
||||
|
||||
pub use sys_webrtc::ffi::MediaType;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct RtpReceiver {
|
||||
cxx_handle: UniquePtr<sys_rec::ffi::RtpReceiver>,
|
||||
cxx_handle: SharedPtr<sys_rec::ffi::RtpReceiver>,
|
||||
}
|
||||
|
||||
impl Debug for RtpReceiver {
|
||||
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
|
||||
f.debug_struct("RtpReceiver")
|
||||
.field("track", &self.track())
|
||||
.field("media_type", &self.media_type())
|
||||
.field("id", &self.id())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl RtpReceiver {
|
||||
pub(crate) fn new(cxx_handle: UniquePtr<sys_rec::ffi::RtpReceiver>) -> Self {
|
||||
pub(crate) fn new(cxx_handle: SharedPtr<sys_rec::ffi::RtpReceiver>) -> Self {
|
||||
Self { cxx_handle }
|
||||
}
|
||||
|
||||
pub(crate) fn cxx_handle(&self) -> SharedPtr<sys_rec::ffi::RtpReceiver> {
|
||||
self.cxx_handle.clone()
|
||||
}
|
||||
|
||||
pub fn track(&self) -> MediaStreamTrackHandle {
|
||||
MediaStreamTrackHandle::new(self.cxx_handle.track())
|
||||
}
|
||||
|
||||
pub fn stream_ids(&self) -> Vec<String> {
|
||||
self.cxx_handle.stream_ids()
|
||||
}
|
||||
|
||||
pub fn streams(&self) -> Vec<MediaStream> {
|
||||
let ptrs = self.cxx_handle.streams();
|
||||
let mut vec = Vec::with_capacity(ptrs.len());
|
||||
for stream in ptrs {
|
||||
vec.push(MediaStream::new(stream.ptr));
|
||||
}
|
||||
vec
|
||||
}
|
||||
|
||||
pub fn media_type(&self) -> MediaType {
|
||||
self.cxx_handle.media_type()
|
||||
}
|
||||
|
||||
pub fn id(&self) -> String {
|
||||
self.cxx_handle.id()
|
||||
}
|
||||
|
||||
pub fn parameters(&self) -> RtpParameters {
|
||||
self.cxx_handle.get_parameters().into()
|
||||
}
|
||||
|
||||
pub fn set_jitter_buffer_minimum_delay(&self, delay_seconds: Option<f64>) {
|
||||
self.cxx_handle
|
||||
.set_jitter_buffer_minimum_delay(delay_seconds.is_some(), delay_seconds.unwrap_or(0.0));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
use crate::media_stream::{MediaStream, MediaStreamTrackHandle};
|
||||
use crate::prelude::*;
|
||||
use crate::rtp_parameters::{RtpEncodingParameters, RtpParameters};
|
||||
use cxx::SharedPtr;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use webrtc_sys::rtp_sender as sys_rs;
|
||||
use webrtc_sys::webrtc as sys_webrtc;
|
||||
|
||||
pub use sys_webrtc::ffi::MediaType;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct RtpSender {
|
||||
cxx_handle: SharedPtr<sys_rs::ffi::RtpSender>,
|
||||
}
|
||||
|
||||
impl Debug for RtpSender {
|
||||
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
|
||||
f.debug_struct("RtpSender")
|
||||
.field("track", &self.track())
|
||||
.field("media_type", &self.media_type())
|
||||
.field("ssrc", &self.ssrc())
|
||||
.field("id", &self.id())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl RtpSender {
|
||||
pub(crate) fn new(cxx_handle: SharedPtr<sys_rs::ffi::RtpSender>) -> Self {
|
||||
Self { cxx_handle }
|
||||
}
|
||||
|
||||
pub(crate) fn cxx_handle(&self) -> SharedPtr<sys_rs::ffi::RtpSender> {
|
||||
self.cxx_handle.clone()
|
||||
}
|
||||
|
||||
pub fn set_track(&self, track: MediaStreamTrackHandle) -> bool {
|
||||
self.cxx_handle.set_track(track.cxx_handle())
|
||||
}
|
||||
|
||||
pub fn track(&self) -> MediaStreamTrackHandle {
|
||||
MediaStreamTrackHandle::new(self.cxx_handle.track())
|
||||
}
|
||||
|
||||
pub fn ssrc(&self) -> u32 {
|
||||
self.cxx_handle.ssrc()
|
||||
}
|
||||
|
||||
pub fn media_type(&self) -> MediaType {
|
||||
self.cxx_handle.media_type()
|
||||
}
|
||||
|
||||
pub fn id(&self) -> String {
|
||||
self.cxx_handle.id()
|
||||
}
|
||||
|
||||
pub fn stream_ids(&self) -> Vec<String> {
|
||||
self.cxx_handle.stream_ids()
|
||||
}
|
||||
|
||||
pub fn set_streams(&self, stream_ids: &Vec<String>) {
|
||||
self.cxx_handle.set_streams(stream_ids);
|
||||
}
|
||||
|
||||
pub fn init_send_encodings(&self) -> Vec<RtpEncodingParameters> {
|
||||
self.cxx_handle
|
||||
.init_send_encodings()
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn parameters(&self) -> RtpParameters {
|
||||
self.cxx_handle.get_parameters().into()
|
||||
}
|
||||
|
||||
pub fn set_parameters(&self, params: RtpParameters) -> Result<(), RTCError> {
|
||||
self.cxx_handle
|
||||
.set_parameters(params.into())
|
||||
.map_err(|e| unsafe { RTCError::from(e.what()) })
|
||||
}
|
||||
}
|
||||
@@ -1,2 +1,119 @@
|
||||
use crate::prelude::*;
|
||||
use cxx::SharedPtr;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use webrtc_sys::rtp_transceiver as sys_rt;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RtpTransceiver {}
|
||||
pub struct RtpTransceiverInit {
|
||||
pub direction: RtpTransceiverDirection,
|
||||
pub stream_ids: Vec<String>,
|
||||
pub send_encodings: Vec<RtpEncodingParameters>,
|
||||
}
|
||||
|
||||
impl From<RtpTransceiverInit> for sys_rt::ffi::RtpTransceiverInit {
|
||||
fn from(value: RtpTransceiverInit) -> Self {
|
||||
Self {
|
||||
direction: value.direction,
|
||||
stream_ids: value.stream_ids,
|
||||
send_encodings: value.send_encodings.into_iter().map(Into::into).collect()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct RtpTransceiver {
|
||||
cxx_handle: SharedPtr<sys_rt::ffi::RtpTransceiver>,
|
||||
}
|
||||
|
||||
impl Debug for RtpTransceiver {
|
||||
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
|
||||
f.debug_struct("RtpTransceiver")
|
||||
.field("media_type", &self.media_type())
|
||||
.field("mid", &self.mid())
|
||||
.field("direction", &self.direction())
|
||||
.field("stopped", &self.stopped())
|
||||
.field("stopping", &self.stopping())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl RtpTransceiver {
|
||||
pub(crate) fn new(cxx_handle: SharedPtr<sys_rt::ffi::RtpTransceiver>) -> Self {
|
||||
Self { cxx_handle }
|
||||
}
|
||||
|
||||
pub(crate) fn cxx_handle(&self) -> SharedPtr<sys_rt::ffi::RtpTransceiver> {
|
||||
self.cxx_handle.clone()
|
||||
}
|
||||
|
||||
pub fn media_type(&self) -> MediaType {
|
||||
self.cxx_handle.media_type()
|
||||
}
|
||||
|
||||
pub fn mid(&self) -> Option<String> {
|
||||
self.cxx_handle.mid().ok()
|
||||
}
|
||||
|
||||
pub fn sender(&self) -> RtpSender {
|
||||
RtpSender::new(self.cxx_handle.sender())
|
||||
}
|
||||
|
||||
pub fn receiver(&self) -> RtpReceiver {
|
||||
RtpReceiver::new(self.cxx_handle.receiver())
|
||||
}
|
||||
|
||||
pub fn stopped(&self) -> bool {
|
||||
self.cxx_handle.stopped()
|
||||
}
|
||||
|
||||
pub fn stopping(&self) -> bool {
|
||||
self.cxx_handle.stopping()
|
||||
}
|
||||
|
||||
pub fn direction(&self) -> RtpTransceiverDirection {
|
||||
self.cxx_handle.direction()
|
||||
}
|
||||
|
||||
pub fn set_direction(&self, direction: RtpTransceiverDirection) -> Result<(), RTCError> {
|
||||
self.cxx_handle.set_direction(direction)
|
||||
.map_err(|e| unsafe { RTCError::from(e.what()) })
|
||||
}
|
||||
|
||||
pub fn current_direction(&self) -> Option<RtpTransceiverDirection> {
|
||||
self.cxx_handle.current_direction().ok()
|
||||
}
|
||||
|
||||
pub fn fired_direction(&self) -> Option<RtpTransceiverDirection> {
|
||||
self.cxx_handle.fired_direction().ok()
|
||||
}
|
||||
|
||||
pub fn stop_standard(&self) -> Result<(), RTCError> {
|
||||
self.cxx_handle.stop_standard()
|
||||
.map_err(|e| unsafe { RTCError::from(e.what()) })
|
||||
}
|
||||
|
||||
pub fn set_codec_preferences(&self, codecs: Vec<RtpCodecCapability>) -> Result<(), RTCError> {
|
||||
let ffi_codecs = codecs.into_iter().map(Into::into).collect();
|
||||
self.cxx_handle.set_codec_preferences(ffi_codecs)
|
||||
.map_err(|e| unsafe { RTCError::from(e.what()) })
|
||||
}
|
||||
|
||||
pub fn codec_preferences(&self) -> Vec<RtpCodecCapability> {
|
||||
self.cxx_handle.codec_preferences().into_iter().map(Into::into).collect()
|
||||
}
|
||||
|
||||
pub fn header_extensions_to_offer(&self) -> Vec<RtpHeaderExtensionCapability> {
|
||||
self.cxx_handle.header_extensions_to_offer().into_iter().map(Into::into).collect()
|
||||
}
|
||||
|
||||
pub fn header_extensions_negotiated(&self) -> Vec<RtpHeaderExtensionCapability> {
|
||||
self.cxx_handle.header_extensions_negotiated().into_iter().map(Into::into).collect()
|
||||
}
|
||||
|
||||
pub fn set_offered_rtp_header_extensions(&self, headers: Vec<RtpHeaderExtensionCapability>) -> Result<(), RTCError> {
|
||||
let ffi_headers = headers.into_iter().map(Into::into).collect();
|
||||
self.cxx_handle.set_offered_rtp_header_extensions(ffi_headers)
|
||||
.map_err(|e| unsafe { RTCError::from(e.what()) })
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::video_frame_buffer::VideoFrameBuffer;
|
||||
use cxx::UniquePtr;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use webrtc_sys::video_frame as vf_sys;
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -22,10 +23,33 @@ impl From<vf_sys::ffi::VideoRotation> for VideoRotation {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<VideoRotation> for vf_sys::ffi::VideoRotation {
|
||||
fn from(rotation: VideoRotation) -> Self {
|
||||
match rotation {
|
||||
VideoRotation::VideoRotation0 => Self::VideoRotation0,
|
||||
VideoRotation::VideoRotation90 => Self::VideoRotation90,
|
||||
VideoRotation::VideoRotation180 => Self::VideoRotation180,
|
||||
VideoRotation::VideoRotation270 => Self::VideoRotation270,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct VideoFrame {
|
||||
cxx_handle: UniquePtr<vf_sys::ffi::VideoFrame>,
|
||||
}
|
||||
|
||||
impl Debug for VideoFrame {
|
||||
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
|
||||
f.debug_struct("VideoFrame")
|
||||
.field("width", &self.width())
|
||||
.field("height", &self.height())
|
||||
.field("id", &self.id())
|
||||
.field("rotation", &self.rotation())
|
||||
.field("timestamp", &self.timestamp())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl VideoFrame {
|
||||
pub(crate) fn new(cxx_handle: UniquePtr<vf_sys::ffi::VideoFrame>) -> Self {
|
||||
Self { cxx_handle }
|
||||
@@ -74,4 +98,54 @@ impl VideoFrame {
|
||||
pub(crate) unsafe fn video_frame_buffer(&self) -> VideoFrameBuffer {
|
||||
VideoFrameBuffer::new(self.cxx_handle.video_frame_buffer())
|
||||
}
|
||||
|
||||
pub fn builder() -> VideoFrameBuilder {
|
||||
VideoFrameBuilder::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct VideoFrameBuilder {
|
||||
cxx_handle: UniquePtr<vf_sys::ffi::VideoFrameBuilder>,
|
||||
}
|
||||
|
||||
impl Debug for VideoFrameBuilder {
|
||||
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
|
||||
f.debug_struct("VideoFrameBuilder").finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for VideoFrameBuilder {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
cxx_handle: vf_sys::ffi::create_video_frame_builder(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl VideoFrameBuilder {
|
||||
pub fn set_video_frame_buffer(mut self, buffer: VideoFrameBuffer) -> Self {
|
||||
self.cxx_handle
|
||||
.pin_mut()
|
||||
.set_video_frame_buffer(buffer.release());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_timestamp_us(mut self, ts_us: i64) -> Self {
|
||||
self.cxx_handle.pin_mut().set_timestamp_us(ts_us);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_rotation(mut self, rotation: VideoRotation) -> Self {
|
||||
self.cxx_handle.pin_mut().set_rotation(rotation.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_id(mut self, id: u16) -> Self {
|
||||
self.cxx_handle.pin_mut().set_id(id);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(mut self) -> VideoFrame {
|
||||
VideoFrame::new(self.cxx_handle.pin_mut().build())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,18 @@ use webrtc_sys::video_frame_buffer as vfb_sys;
|
||||
|
||||
use crate::yuv_helper::{self, ConvertError};
|
||||
|
||||
macro_rules! recursive_cast {
|
||||
($ptr:expr $(, $fnc:ident)*) => {
|
||||
{
|
||||
let ptr = $ptr;
|
||||
$(
|
||||
let ptr = unsafe { vfb_sys::ffi::$fnc(ptr) };
|
||||
)*
|
||||
ptr
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum VideoFrameBufferType {
|
||||
Native,
|
||||
@@ -94,29 +106,74 @@ impl VideoFrameBuffer {
|
||||
pub(crate) fn new(mut cxx_handle: UniquePtr<vfb_sys::ffi::VideoFrameBuffer>) -> Self {
|
||||
unsafe {
|
||||
match cxx_handle.buffer_type().into() {
|
||||
VideoFrameBufferType::Native => Self::Native(NativeBuffer::new(cxx_handle)),
|
||||
VideoFrameBufferType::Native => Self::Native(NativeBuffer::from(cxx_handle)),
|
||||
VideoFrameBufferType::I420 => {
|
||||
Self::I420(I420Buffer::new(cxx_handle.pin_mut().get_i420()))
|
||||
Self::I420(I420Buffer::from(cxx_handle.pin_mut().get_i420()))
|
||||
}
|
||||
VideoFrameBufferType::I420A => {
|
||||
Self::I420A(I420ABuffer::new(cxx_handle.pin_mut().get_i420a()))
|
||||
Self::I420A(I420ABuffer::from(cxx_handle.pin_mut().get_i420a()))
|
||||
}
|
||||
VideoFrameBufferType::I422 => {
|
||||
Self::I422(I422Buffer::new(cxx_handle.pin_mut().get_i422()))
|
||||
Self::I422(I422Buffer::from(cxx_handle.pin_mut().get_i422()))
|
||||
}
|
||||
VideoFrameBufferType::I444 => {
|
||||
Self::I444(I444Buffer::new(cxx_handle.pin_mut().get_i444()))
|
||||
Self::I444(I444Buffer::from(cxx_handle.pin_mut().get_i444()))
|
||||
}
|
||||
VideoFrameBufferType::I010 => {
|
||||
Self::I010(I010Buffer::new(cxx_handle.pin_mut().get_i010()))
|
||||
Self::I010(I010Buffer::from(cxx_handle.pin_mut().get_i010()))
|
||||
}
|
||||
VideoFrameBufferType::NV12 => {
|
||||
Self::NV12(NV12Buffer::new(cxx_handle.pin_mut().get_nv12()))
|
||||
Self::NV12(NV12Buffer::from(cxx_handle.pin_mut().get_nv12()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_unsafe)]
|
||||
pub(crate) fn release(self) -> UniquePtr<vfb_sys::ffi::VideoFrameBuffer> {
|
||||
unsafe {
|
||||
match self {
|
||||
VideoFrameBuffer::Native(native) => native.release(),
|
||||
VideoFrameBuffer::I420(i420) => UniquePtr::from_raw(recursive_cast!(
|
||||
i420.release().into_raw(),
|
||||
i420_to_yuv8,
|
||||
yuv8_to_yuv,
|
||||
yuv_to_vfb
|
||||
) as *mut _),
|
||||
VideoFrameBuffer::I420A(i420a) => UniquePtr::from_raw(recursive_cast!(
|
||||
i420a.release().into_raw(),
|
||||
i420a_to_yuv8,
|
||||
yuv8_to_yuv,
|
||||
yuv_to_vfb
|
||||
) as *mut _),
|
||||
VideoFrameBuffer::I422(i422) => UniquePtr::from_raw(recursive_cast!(
|
||||
i422.release().into_raw(),
|
||||
i422_to_yuv8,
|
||||
yuv8_to_yuv,
|
||||
yuv_to_vfb
|
||||
) as *mut _),
|
||||
VideoFrameBuffer::I444(i444) => UniquePtr::from_raw(recursive_cast!(
|
||||
i444.release().into_raw(),
|
||||
i444_to_yuv8,
|
||||
yuv8_to_yuv,
|
||||
yuv_to_vfb
|
||||
) as *mut _),
|
||||
VideoFrameBuffer::I010(i010) => UniquePtr::from_raw(recursive_cast!(
|
||||
i010.release().into_raw(),
|
||||
i010_to_yuv16b,
|
||||
yuv16b_to_yuv,
|
||||
yuv_to_vfb
|
||||
) as *mut _),
|
||||
VideoFrameBuffer::NV12(nv12) => UniquePtr::from_raw(recursive_cast!(
|
||||
nv12.release().into_raw(),
|
||||
nv12_to_biyuv8,
|
||||
biyuv8_to_biyuv,
|
||||
biyuv_to_vfb
|
||||
) as *mut _),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_argb(
|
||||
&self,
|
||||
format: VideoFormatType,
|
||||
@@ -195,18 +252,6 @@ impl VideoFrameBufferTrait for VideoFrameBuffer {
|
||||
);
|
||||
}
|
||||
|
||||
macro_rules! recursive_cast {
|
||||
($ptr:expr $(, $fnc:ident)*) => {
|
||||
{
|
||||
let ptr = $ptr;
|
||||
$(
|
||||
let ptr = unsafe { vfb_sys::ffi::$fnc(ptr) };
|
||||
)*
|
||||
ptr
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_video_frame_buffer {
|
||||
($x:ty $(, $cast:ident)*) => {
|
||||
|
||||
@@ -241,7 +286,7 @@ macro_rules! impl_video_frame_buffer {
|
||||
as *mut vfb_sys::ffi::VideoFrameBuffer;
|
||||
|
||||
unsafe {
|
||||
I420Buffer::new(Pin::new_unchecked(&mut *ptr).to_i420())
|
||||
I420Buffer::from(Pin::new_unchecked(&mut *ptr).to_i420())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -456,43 +501,78 @@ impl_biyuv_buffer!(NV12Buffer, nv12_to_biyuv8, biyuv8_to_biyuv);
|
||||
impl_biyuv8_buffer!(NV12Buffer, nv12_to_biyuv8);
|
||||
|
||||
impl NativeBuffer {
|
||||
fn new(cxx_handle: UniquePtr<vfb_sys::ffi::VideoFrameBuffer>) -> Self {
|
||||
fn from(cxx_handle: UniquePtr<vfb_sys::ffi::VideoFrameBuffer>) -> Self {
|
||||
Self { cxx_handle }
|
||||
}
|
||||
|
||||
pub(crate) fn release(self) -> UniquePtr<vfb_sys::ffi::VideoFrameBuffer> {
|
||||
self.cxx_handle
|
||||
}
|
||||
}
|
||||
|
||||
impl I420Buffer {
|
||||
fn new(cxx_handle: UniquePtr<vfb_sys::ffi::I420Buffer>) -> Self {
|
||||
pub fn new(width: u32, height: u32) -> Self {
|
||||
Self::from(vfb_sys::ffi::create_i420_buffer(
|
||||
width as i32,
|
||||
height as i32,
|
||||
))
|
||||
}
|
||||
|
||||
fn from(cxx_handle: UniquePtr<vfb_sys::ffi::I420Buffer>) -> Self {
|
||||
Self { cxx_handle }
|
||||
}
|
||||
|
||||
pub(crate) fn release(self) -> UniquePtr<vfb_sys::ffi::I420Buffer> {
|
||||
self.cxx_handle
|
||||
}
|
||||
}
|
||||
|
||||
impl I420ABuffer {
|
||||
fn new(cxx_handle: UniquePtr<vfb_sys::ffi::I420ABuffer>) -> Self {
|
||||
fn from(cxx_handle: UniquePtr<vfb_sys::ffi::I420ABuffer>) -> Self {
|
||||
Self { cxx_handle }
|
||||
}
|
||||
|
||||
pub(crate) fn release(self) -> UniquePtr<vfb_sys::ffi::I420ABuffer> {
|
||||
self.cxx_handle
|
||||
}
|
||||
}
|
||||
|
||||
impl I422Buffer {
|
||||
fn new(cxx_handle: UniquePtr<vfb_sys::ffi::I422Buffer>) -> Self {
|
||||
fn from(cxx_handle: UniquePtr<vfb_sys::ffi::I422Buffer>) -> Self {
|
||||
Self { cxx_handle }
|
||||
}
|
||||
|
||||
pub(crate) fn release(self) -> UniquePtr<vfb_sys::ffi::I422Buffer> {
|
||||
self.cxx_handle
|
||||
}
|
||||
}
|
||||
|
||||
impl I444Buffer {
|
||||
fn new(cxx_handle: UniquePtr<vfb_sys::ffi::I444Buffer>) -> Self {
|
||||
fn from(cxx_handle: UniquePtr<vfb_sys::ffi::I444Buffer>) -> Self {
|
||||
Self { cxx_handle }
|
||||
}
|
||||
|
||||
pub(crate) fn release(self) -> UniquePtr<vfb_sys::ffi::I444Buffer> {
|
||||
self.cxx_handle
|
||||
}
|
||||
}
|
||||
|
||||
impl I010Buffer {
|
||||
fn new(cxx_handle: UniquePtr<vfb_sys::ffi::I010Buffer>) -> Self {
|
||||
fn from(cxx_handle: UniquePtr<vfb_sys::ffi::I010Buffer>) -> Self {
|
||||
Self { cxx_handle }
|
||||
}
|
||||
|
||||
pub(crate) fn release(self) -> UniquePtr<vfb_sys::ffi::I010Buffer> {
|
||||
self.cxx_handle
|
||||
}
|
||||
}
|
||||
|
||||
impl NV12Buffer {
|
||||
fn new(cxx_handle: UniquePtr<vfb_sys::ffi::NV12Buffer>) -> Self {
|
||||
fn from(cxx_handle: UniquePtr<vfb_sys::ffi::NV12Buffer>) -> Self {
|
||||
Self { cxx_handle }
|
||||
}
|
||||
|
||||
pub(crate) fn release(self) -> UniquePtr<vfb_sys::ffi::NV12Buffer> {
|
||||
self.cxx_handle
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,10 @@ use cxx::SharedPtr;
|
||||
|
||||
use webrtc_sys::webrtc as sys_rtc;
|
||||
|
||||
pub use sys_rtc::ffi::MediaType;
|
||||
pub use sys_rtc::ffi::Priority;
|
||||
pub use sys_rtc::ffi::RtpTransceiverDirection;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct RTCRuntime {
|
||||
cxx_handle: SharedPtr<sys_rtc::ffi::RTCRuntime>,
|
||||
|
||||
@@ -31,6 +31,8 @@ impl LocalParticipant {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn publish_track(&self) {}
|
||||
|
||||
pub async fn publish_data(
|
||||
&self,
|
||||
data: &[u8],
|
||||
|
||||
@@ -137,6 +137,8 @@ fn main() {
|
||||
"src/data_channel.rs",
|
||||
"src/jsep.rs",
|
||||
"src/candidate.rs",
|
||||
"src/rtp_parameters.rs",
|
||||
"src/rtp_sender.rs",
|
||||
"src/rtp_receiver.rs",
|
||||
"src/rtp_transceiver.rs",
|
||||
"src/rtc_error.rs",
|
||||
@@ -144,6 +146,7 @@ fn main() {
|
||||
"src/video_frame.rs",
|
||||
"src/video_frame_buffer.rs",
|
||||
"src/yuv_helper.rs",
|
||||
"src/helper.rs",
|
||||
]);
|
||||
|
||||
builder.file("src/peer_connection.cpp");
|
||||
@@ -153,9 +156,13 @@ fn main() {
|
||||
builder.file("src/jsep.cpp");
|
||||
builder.file("src/candidate.cpp");
|
||||
builder.file("src/rtp_receiver.cpp");
|
||||
builder.file("src/rtp_sender.cpp");
|
||||
builder.file("src/rtp_transceiver.cpp");
|
||||
builder.file("src/rtp_parameters.cpp");
|
||||
builder.file("src/rtc_error.cpp");
|
||||
builder.file("src/webrtc.cpp");
|
||||
builder.file("src/video_frame.cpp");
|
||||
builder.file("src/video_frame_buffer.cpp");
|
||||
builder.file("src/video_encoder_factory.cpp");
|
||||
builder.file("src/video_decoder_factory.cpp");
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
-Ilibwebrtc/src
|
||||
-Ilibwebrtc/src/third_party/abseil-cpp
|
||||
-Ilibwebrtc/src/third_party/libc++
|
||||
-Ilibwebrtc/src/third_party/libyuv/include
|
||||
-I../target/cxxbridge
|
||||
-DWEBRTC_MAC
|
||||
-DWEBRTC_POSIX
|
||||
|
||||
@@ -2,13 +2,17 @@
|
||||
// Created by Théo Monnom on 01/09/2022.
|
||||
//
|
||||
|
||||
#ifndef CLIENT_SDK_NATIVE_CANDIDATE_H
|
||||
#define CLIENT_SDK_NATIVE_CANDIDATE_H
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "api/candidate.h"
|
||||
|
||||
namespace livekit {
|
||||
class Candidate;
|
||||
}
|
||||
#include "webrtc-sys/src/candidate.rs.h"
|
||||
|
||||
// cricket::Candidate
|
||||
namespace livekit {
|
||||
|
||||
@@ -20,10 +24,8 @@ class Candidate {
|
||||
cricket::Candidate candidate_;
|
||||
};
|
||||
|
||||
static std::unique_ptr<Candidate> _unique_candidate() {
|
||||
static std::shared_ptr<Candidate> _shared_candidate() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace livekit
|
||||
|
||||
#endif // CLIENT_SDK_NATIVE_CANDIDATE_H
|
||||
|
||||
@@ -2,19 +2,22 @@
|
||||
// Created by Théo Monnom on 01/09/2022.
|
||||
//
|
||||
|
||||
#ifndef CLIENT_SDK_NATIVE_DATA_CHANNEL_H
|
||||
#define CLIENT_SDK_NATIVE_DATA_CHANNEL_H
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "api/data_channel_interface.h"
|
||||
#include "livekit/webrtc.h"
|
||||
#include "rust/cxx.h"
|
||||
#include "rust_types.h"
|
||||
#include "webrtc.h"
|
||||
|
||||
namespace livekit {
|
||||
class DataChannel;
|
||||
using NativeDataChannelInit = webrtc::DataChannelInit;
|
||||
class NativeDataChannelObserver;
|
||||
} // namespace livekit
|
||||
#include "webrtc-sys/src/data_channel.rs.h"
|
||||
|
||||
namespace livekit {
|
||||
|
||||
class DataChannel {
|
||||
public:
|
||||
@@ -22,8 +25,8 @@ class DataChannel {
|
||||
std::shared_ptr<RTCRuntime> rtc_runtime,
|
||||
rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel);
|
||||
|
||||
void register_observer(NativeDataChannelObserver& observer);
|
||||
void unregister_observer();
|
||||
void register_observer(NativeDataChannelObserver& observer) const;
|
||||
void unregister_observer() const;
|
||||
bool send(const DataBuffer& buffer) const;
|
||||
rust::String label() const;
|
||||
DataState state() const;
|
||||
@@ -57,5 +60,3 @@ class NativeDataChannelObserver : public webrtc::DataChannelObserver {
|
||||
std::unique_ptr<NativeDataChannelObserver> create_native_data_channel_observer(
|
||||
rust::Box<DataChannelObserverWrapper> observer);
|
||||
} // namespace livekit
|
||||
|
||||
#endif // CLIENT_SDK_NATIVE_DATA_CHANNEL_H
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include "rust/cxx.h"
|
||||
|
||||
namespace livekit {
|
||||
class MediaStream;
|
||||
class AudioTrack;
|
||||
class VideoTrack;
|
||||
class Candidate;
|
||||
class RtpSender;
|
||||
class RtpReceiver;
|
||||
class RtpTransceiver;
|
||||
} // namespace livekit
|
||||
#include "webrtc-sys/src/helper.rs.h"
|
||||
|
||||
namespace livekit {
|
||||
|
||||
// Impl not needed
|
||||
static rust::Vec<MediaStreamPtr> _vec_media_stream_ptr() {
|
||||
throw;
|
||||
}
|
||||
static rust::Vec<CandidatePtr> _vec_candidate_ptr() {
|
||||
throw;
|
||||
}
|
||||
static rust::Vec<AudioTrackPtr> _vec_audio_track_ptr() {
|
||||
throw;
|
||||
}
|
||||
static rust::Vec<VideoTrackPtr> _vec_video_track_ptr() {
|
||||
throw;
|
||||
}
|
||||
static rust::Vec<RtpSenderPtr> _vec_rtp_sender_ptr() {
|
||||
throw;
|
||||
}
|
||||
static rust::Vec<RtpReceiverPtr> _vec_rtp_receiver_ptr() {
|
||||
throw;
|
||||
}
|
||||
static rust::Vec<RtpTransceiverPtr> _vec_rtp_transceiver_ptr() {
|
||||
throw;
|
||||
}
|
||||
|
||||
} // namespace livekit
|
||||
@@ -2,15 +2,24 @@
|
||||
// Created by Théo Monnom on 01/09/2022.
|
||||
//
|
||||
|
||||
#ifndef CLIENT_SDK_NATIVE_JSEP_H
|
||||
#define CLIENT_SDK_NATIVE_JSEP_H
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "api/jsep.h"
|
||||
#include "api/ref_counted_base.h"
|
||||
#include "api/set_local_description_observer_interface.h"
|
||||
#include "api/set_remote_description_observer_interface.h"
|
||||
#include "rust/cxx.h"
|
||||
#include "rust_types.h"
|
||||
|
||||
namespace livekit {
|
||||
class IceCandidate;
|
||||
class SessionDescription;
|
||||
struct NativeCreateSdpObserverHandle;
|
||||
struct NativeSetLocalSdpObserverHandle;
|
||||
struct NativeSetRemoteSdpObserverHandle;
|
||||
}; // namespace livekit
|
||||
#include "webrtc-sys/src/jsep.rs.h"
|
||||
|
||||
namespace livekit {
|
||||
|
||||
@@ -31,11 +40,11 @@ class IceCandidate {
|
||||
std::unique_ptr<webrtc::IceCandidateInterface> ice_candidate_;
|
||||
};
|
||||
|
||||
std::unique_ptr<IceCandidate> create_ice_candidate(rust::String sdp_mid,
|
||||
std::shared_ptr<IceCandidate> create_ice_candidate(rust::String sdp_mid,
|
||||
int sdp_mline_index,
|
||||
rust::String sdp);
|
||||
|
||||
static std::unique_ptr<IceCandidate> _unique_ice_candidate() {
|
||||
static std::shared_ptr<IceCandidate> _shared_ice_candidate() {
|
||||
return nullptr; // Ignore
|
||||
}
|
||||
|
||||
@@ -126,5 +135,3 @@ std::unique_ptr<NativeSetRemoteSdpObserverHandle>
|
||||
create_native_set_remote_sdp_observer(
|
||||
rust::Box<SetRemoteSdpObserverWrapper> observer);
|
||||
} // namespace livekit
|
||||
|
||||
#endif // CLIENT_SDK_NATIVE_JSEP_H
|
||||
|
||||
@@ -2,78 +2,92 @@
|
||||
// Created by Théo Monnom on 31/08/2022.
|
||||
//
|
||||
|
||||
#ifndef CLIENT_SDK_NATIVE_MEDIA_STREAM_INTERFACE_H
|
||||
#define CLIENT_SDK_NATIVE_MEDIA_STREAM_INTERFACE_H
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "api/media_stream_interface.h"
|
||||
#include "livekit/rust_types.h"
|
||||
#include "api/video/video_frame.h"
|
||||
#include "livekit/helper.h"
|
||||
#include "livekit/video_frame.h"
|
||||
#include "media/base/adapted_video_track_source.h"
|
||||
#include "rtc_base/synchronization/mutex.h"
|
||||
#include "rtc_base/timestamp_aligner.h"
|
||||
#include "rust/cxx.h"
|
||||
|
||||
namespace livekit {
|
||||
|
||||
class MediaStream;
|
||||
class MediaStreamTrack;
|
||||
class VideoTrack;
|
||||
class AudioTrack;
|
||||
class NativeVideoFrameSink;
|
||||
class AdaptedVideoTrackSource;
|
||||
} // namespace livekit
|
||||
#include "webrtc-sys/src/media_stream.rs.h"
|
||||
|
||||
namespace livekit {
|
||||
|
||||
class MediaStream {
|
||||
public:
|
||||
explicit MediaStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream);
|
||||
|
||||
rust::String id() const;
|
||||
rust::Vec<VideoTrackPtr> get_video_tracks() const;
|
||||
rust::Vec<AudioTrackPtr> get_audio_tracks() const;
|
||||
|
||||
std::shared_ptr<AudioTrack> find_audio_track(rust::String track_id) const;
|
||||
std::shared_ptr<VideoTrack> find_video_track(rust::String track_id) const;
|
||||
|
||||
bool add_audio_track(std::shared_ptr<AudioTrack> audio_track) const;
|
||||
bool add_video_track(std::shared_ptr<VideoTrack> video_track) const;
|
||||
bool remove_audio_track(std::shared_ptr<AudioTrack> audio_track) const;
|
||||
bool remove_video_track(std::shared_ptr<VideoTrack> video_track) const;
|
||||
|
||||
private:
|
||||
rtc::scoped_refptr<webrtc::MediaStreamInterface> media_stream_;
|
||||
};
|
||||
|
||||
static std::unique_ptr<MediaStream> _unique_media_stream() {
|
||||
return nullptr; // Ignore
|
||||
}
|
||||
|
||||
class MediaStreamTrack {
|
||||
protected:
|
||||
explicit MediaStreamTrack(
|
||||
rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track);
|
||||
|
||||
public:
|
||||
static std::unique_ptr<MediaStreamTrack> from(
|
||||
static std::shared_ptr<MediaStreamTrack> from(
|
||||
rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track);
|
||||
|
||||
rust::String kind() const;
|
||||
rust::String id() const;
|
||||
|
||||
bool enabled() const;
|
||||
bool set_enabled(bool enable);
|
||||
bool set_enabled(bool enable) const;
|
||||
|
||||
TrackState state() const;
|
||||
|
||||
rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> get() const {
|
||||
return track_;
|
||||
}
|
||||
|
||||
protected:
|
||||
rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track_;
|
||||
};
|
||||
|
||||
static std::unique_ptr<MediaStreamTrack> _unique_media_stream_track() {
|
||||
return nullptr; // Ignore
|
||||
}
|
||||
|
||||
class AudioTrack : public MediaStreamTrack {
|
||||
public:
|
||||
explicit AudioTrack(rtc::scoped_refptr<webrtc::AudioTrackInterface> track);
|
||||
};
|
||||
|
||||
static std::unique_ptr<AudioTrack> _unique_audio_track() {
|
||||
return nullptr; // Ignore
|
||||
}
|
||||
|
||||
class VideoTrack : public MediaStreamTrack {
|
||||
public:
|
||||
explicit VideoTrack(rtc::scoped_refptr<webrtc::VideoTrackInterface> track);
|
||||
|
||||
void add_sink(NativeVideoFrameSink& sink);
|
||||
void remove_sink(NativeVideoFrameSink& sink);
|
||||
void add_sink(NativeVideoFrameSink& sink) const;
|
||||
void remove_sink(NativeVideoFrameSink& sink) const;
|
||||
|
||||
void set_should_receive(bool should_receive);
|
||||
void set_should_receive(bool should_receive) const;
|
||||
bool should_receive() const;
|
||||
ContentHint content_hint() const;
|
||||
void set_content_hint(ContentHint hint);
|
||||
void set_content_hint(ContentHint hint) const;
|
||||
|
||||
private:
|
||||
webrtc::VideoTrackInterface* track() const {
|
||||
@@ -81,10 +95,6 @@ class VideoTrack : public MediaStreamTrack {
|
||||
}
|
||||
};
|
||||
|
||||
static std::unique_ptr<VideoTrack> _unique_video_track() {
|
||||
return nullptr; // Ignore
|
||||
}
|
||||
|
||||
class NativeVideoFrameSink
|
||||
: public rtc::VideoSinkInterface<webrtc::VideoFrame> {
|
||||
public:
|
||||
@@ -102,22 +112,61 @@ class NativeVideoFrameSink
|
||||
std::unique_ptr<NativeVideoFrameSink> create_native_video_frame_sink(
|
||||
rust::Box<VideoFrameSinkWrapper> observer);
|
||||
|
||||
static const MediaStreamTrack* video_to_media(const VideoTrack* track) {
|
||||
return track;
|
||||
}
|
||||
// Native impl of the WebRTC interface
|
||||
class NativeVideoTrackSource : public rtc::AdaptedVideoTrackSource {
|
||||
public:
|
||||
NativeVideoTrackSource();
|
||||
~NativeVideoTrackSource() override;
|
||||
|
||||
static const MediaStreamTrack* audio_to_media(const AudioTrack* track) {
|
||||
return track;
|
||||
}
|
||||
bool is_screencast() const override;
|
||||
absl::optional<bool> needs_denoising() const override;
|
||||
webrtc::MediaSourceInterface::SourceState state() const override;
|
||||
bool remote() const override;
|
||||
|
||||
bool on_captured_frame(const webrtc::VideoFrame& frame);
|
||||
|
||||
private:
|
||||
webrtc::Mutex mutex_;
|
||||
rtc::TimestampAligner timestamp_aligner_;
|
||||
};
|
||||
|
||||
class AdaptedVideoTrackSource {
|
||||
public:
|
||||
AdaptedVideoTrackSource(rtc::scoped_refptr<NativeVideoTrackSource> source);
|
||||
|
||||
bool on_captured_frame(std::unique_ptr<VideoFrame> frame)
|
||||
const; // frames pushed from Rust (+interior mutability)
|
||||
|
||||
rtc::scoped_refptr<NativeVideoTrackSource> get() const;
|
||||
|
||||
private:
|
||||
rtc::scoped_refptr<NativeVideoTrackSource> source_;
|
||||
};
|
||||
|
||||
std::unique_ptr<AdaptedVideoTrackSource> create_adapted_video_track_source();
|
||||
|
||||
static const VideoTrack* media_to_video(const MediaStreamTrack* track) {
|
||||
return static_cast<const VideoTrack*>(track);
|
||||
}
|
||||
|
||||
static const AudioTrack* media_to_audio(const MediaStreamTrack* track) {
|
||||
return static_cast<const AudioTrack*>(track);
|
||||
return static_cast<const AudioTrack*>(track);
|
||||
}
|
||||
|
||||
static std::shared_ptr<MediaStreamTrack> _shared_media_stream_track() {
|
||||
return nullptr; // Ignore
|
||||
}
|
||||
|
||||
static std::shared_ptr<AudioTrack> _shared_audio_track() {
|
||||
return nullptr; // Ignore
|
||||
}
|
||||
|
||||
static std::shared_ptr<VideoTrack> _shared_video_track() {
|
||||
return nullptr; // Ignore
|
||||
}
|
||||
|
||||
static std::shared_ptr<MediaStream> _shared_media_stream() {
|
||||
return nullptr; // Ignore
|
||||
}
|
||||
|
||||
} // namespace livekit
|
||||
|
||||
#endif // CLIENT_SDK_NATIVE_MEDIA_STREAM_INTERFACE_H
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef OBJC_VIDEO_FACTORY_H
|
||||
#define OBJC_VIDEO_FACTORY_H
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "api/video_codecs/video_decoder_factory.h"
|
||||
#include "api/video_codecs/video_encoder_factory.h"
|
||||
|
||||
@@ -11,5 +11,3 @@ std::unique_ptr<webrtc::VideoEncoderFactory> CreateObjCVideoEncoderFactory();
|
||||
std::unique_ptr<webrtc::VideoDecoderFactory> CreateObjCVideoDecoderFactory();
|
||||
|
||||
} // namespace livekit
|
||||
|
||||
#endif // OBJC_VIDEO_FACTORY_H
|
||||
|
||||
@@ -2,20 +2,30 @@
|
||||
// Created by Théo Monnom on 30/08/2022.
|
||||
//
|
||||
|
||||
#ifndef CLIENT_SDK_NATIVE_PEER_CONNECTION_H
|
||||
#define CLIENT_SDK_NATIVE_PEER_CONNECTION_H
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "api/peer_connection_interface.h"
|
||||
#include "data_channel.h"
|
||||
#include "jsep.h"
|
||||
#include "livekit/data_channel.h"
|
||||
#include "livekit/helper.h"
|
||||
#include "livekit/jsep.h"
|
||||
#include "livekit/media_stream.h"
|
||||
#include "livekit/rtp_receiver.h"
|
||||
#include "livekit/rtp_sender.h"
|
||||
#include "livekit/rtp_transceiver.h"
|
||||
#include "livekit/webrtc.h"
|
||||
#include "rust/cxx.h"
|
||||
#include "rust_types.h"
|
||||
#include "webrtc.h"
|
||||
|
||||
namespace livekit {
|
||||
class NativeAddIceCandidateObserver;
|
||||
class PeerConnection;
|
||||
class NativeAddIceCandidateObserver;
|
||||
class NativePeerConnectionObserver;
|
||||
} // namespace livekit
|
||||
#include "webrtc-sys/src/peer_connection.rs.h"
|
||||
|
||||
namespace livekit {
|
||||
|
||||
class PeerConnection {
|
||||
public:
|
||||
@@ -24,23 +34,54 @@ class PeerConnection {
|
||||
rtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection);
|
||||
|
||||
void create_offer(NativeCreateSdpObserverHandle& observer,
|
||||
RTCOfferAnswerOptions options);
|
||||
RTCOfferAnswerOptions options) const;
|
||||
|
||||
void create_answer(NativeCreateSdpObserverHandle& observer,
|
||||
RTCOfferAnswerOptions options);
|
||||
RTCOfferAnswerOptions options) const;
|
||||
|
||||
void set_local_description(std::unique_ptr<SessionDescription> desc,
|
||||
NativeSetLocalSdpObserverHandle& observer);
|
||||
NativeSetLocalSdpObserverHandle& observer) const;
|
||||
|
||||
void set_remote_description(std::unique_ptr<SessionDescription> desc,
|
||||
NativeSetRemoteSdpObserverHandle& observer);
|
||||
NativeSetRemoteSdpObserverHandle& observer) const;
|
||||
|
||||
std::unique_ptr<DataChannel> create_data_channel(
|
||||
rust::String label,
|
||||
std::unique_ptr<NativeDataChannelInit> init);
|
||||
void add_ice_candidate(std::unique_ptr<IceCandidate> candidate,
|
||||
NativeAddIceCandidateObserver& observer);
|
||||
std::unique_ptr<NativeDataChannelInit> init) const;
|
||||
|
||||
void add_ice_candidate(std::shared_ptr<IceCandidate> candidate,
|
||||
NativeAddIceCandidateObserver& observer) const;
|
||||
|
||||
std::shared_ptr<RtpSender> add_track(
|
||||
std::shared_ptr<MediaStreamTrack> track,
|
||||
const rust::Vec<rust::String>& stream_ids) const;
|
||||
|
||||
void remove_track(std::shared_ptr<RtpSender> sender) const;
|
||||
|
||||
std::shared_ptr<RtpTransceiver> add_transceiver(
|
||||
std::shared_ptr<MediaStreamTrack> track,
|
||||
RtpTransceiverInit init) const;
|
||||
|
||||
std::shared_ptr<RtpTransceiver> add_transceiver_for_media(
|
||||
MediaType media_type,
|
||||
RtpTransceiverInit init) const;
|
||||
|
||||
rust::Vec<RtpSenderPtr> get_senders() const;
|
||||
|
||||
rust::Vec<RtpReceiverPtr> get_receivers() const;
|
||||
|
||||
rust::Vec<RtpTransceiverPtr> get_transceivers() const;
|
||||
|
||||
std::unique_ptr<SessionDescription> local_description() const;
|
||||
|
||||
std::unique_ptr<SessionDescription> remote_description() const;
|
||||
|
||||
SignalingState signaling_state() const;
|
||||
|
||||
IceGatheringState ice_gathering_state() const;
|
||||
|
||||
IceConnectionState ice_connection_state() const;
|
||||
|
||||
void close();
|
||||
|
||||
private:
|
||||
@@ -140,5 +181,3 @@ create_native_peer_connection_observer(
|
||||
std::shared_ptr<RTCRuntime> rtc_runtime,
|
||||
rust::Box<PeerConnectionObserverWrapper> observer);
|
||||
} // namespace livekit
|
||||
|
||||
#endif // CLIENT_SDK_NATIVE_PEER_CONNECTION_H
|
||||
|
||||
@@ -2,18 +2,22 @@
|
||||
// Created by Théo Monnom on 03/08/2022.
|
||||
//
|
||||
|
||||
#ifndef PEER_CONNECTION_FACTORY_H
|
||||
#define PEER_CONNECTION_FACTORY_H
|
||||
#pragma once
|
||||
|
||||
#include "api/peer_connection_interface.h"
|
||||
#include "peer_connection.h"
|
||||
#include "rust_types.h"
|
||||
#include "webrtc.h"
|
||||
|
||||
namespace livekit {
|
||||
using NativeRTCConfiguration =
|
||||
webrtc::PeerConnectionInterface::RTCConfiguration;
|
||||
|
||||
class PeerConnectionFactory;
|
||||
} // namespace livekit
|
||||
#include "webrtc-sys/src/peer_connection_factory.rs.h"
|
||||
|
||||
namespace livekit {
|
||||
|
||||
class PeerConnectionFactory {
|
||||
public:
|
||||
explicit PeerConnectionFactory(std::shared_ptr<RTCRuntime> rtc_runtime);
|
||||
@@ -33,5 +37,3 @@ std::unique_ptr<PeerConnectionFactory> create_peer_connection_factory(
|
||||
std::unique_ptr<NativeRTCConfiguration> create_rtc_configuration(
|
||||
RTCConfiguration conf);
|
||||
} // namespace livekit
|
||||
|
||||
#endif // PEER_CONNECTION_FACTORY_H
|
||||
|
||||
@@ -2,13 +2,11 @@
|
||||
// Created by theom on 04/09/2022.
|
||||
//
|
||||
|
||||
#ifndef CLIENT_SDK_NATIVE_RTC_ERROR_H
|
||||
#define CLIENT_SDK_NATIVE_RTC_ERROR_H
|
||||
#pragma once
|
||||
|
||||
#include "api/rtc_error.h"
|
||||
#include "webrtc-sys/src/rtc_error.rs.h"
|
||||
#include "rust/cxx.h"
|
||||
#include "rust_types.h"
|
||||
#include "webrtc-sys/src/rtc_error.rs.h"
|
||||
|
||||
namespace livekit {
|
||||
|
||||
@@ -22,5 +20,3 @@ void throw_error();
|
||||
#endif
|
||||
|
||||
} // namespace livekit
|
||||
|
||||
#endif // CLIENT_SDK_NATIVE_RTC_ERROR_H
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "api/media_types.h"
|
||||
#include "api/priority.h"
|
||||
#include "api/rtp_parameters.h"
|
||||
#include "api/rtp_transceiver_direction.h"
|
||||
#include "webrtc-sys/src/rtp_parameters.rs.h"
|
||||
|
||||
namespace livekit {
|
||||
|
||||
webrtc::RtcpFeedback to_native_rtcp_feedback(RtcpFeedback feedback);
|
||||
webrtc::RtpCodecCapability to_native_rtp_codec_capability(
|
||||
RtpCodecCapability capability);
|
||||
webrtc::RtpHeaderExtensionCapability to_native_rtp_header_extension_capability(
|
||||
RtpHeaderExtensionCapability header);
|
||||
webrtc::RtpExtension to_native_rtp_extension(RtpExtension ext);
|
||||
webrtc::RtpFecParameters to_rtp_fec_parameters(RtpFecParameters fec);
|
||||
webrtc::RtpRtxParameters to_rtp_rtx_parameters(RtpRtxParameters rtx);
|
||||
webrtc::RtpEncodingParameters to_native_rtp_encoding_paramters(
|
||||
RtpEncodingParameters parameters);
|
||||
webrtc::RtpCodecParameters to_native_rtp_codec_parameters(
|
||||
RtpCodecParameters params);
|
||||
webrtc::RtpCapabilities to_rtp_capabilities(RtpCapabilities capabilities);
|
||||
webrtc::RtcpParameters to_native_rtcp_paramaters(RtcpParameters params);
|
||||
webrtc::RtpParameters to_native_rtp_parameters(RtpParameters params);
|
||||
|
||||
RtcpFeedback to_rust_rtcp_feedback(webrtc::RtcpFeedback feedback);
|
||||
RtpCodecCapability to_rust_rtp_codec_capability(
|
||||
webrtc::RtpCodecCapability capability);
|
||||
RtpHeaderExtensionCapability to_rust_rtp_header_extension_capability(
|
||||
webrtc::RtpHeaderExtensionCapability header);
|
||||
RtpExtension to_rust_rtp_extension(webrtc::RtpExtension ext);
|
||||
RtpFecParameters to_rust_rtp_fec_parameters(webrtc::RtpFecParameters fec);
|
||||
RtpRtxParameters to_rust_rtp_rtx_parameters(webrtc::RtpRtxParameters param);
|
||||
RtpEncodingParameters to_rust_rtp_encoding_parameters(
|
||||
webrtc::RtpEncodingParameters params);
|
||||
RtpCodecParameters to_rust_rtp_codec_parameters(
|
||||
webrtc::RtpCodecParameters params);
|
||||
RtpCapabilities to_rust_rtp_capabilities(webrtc::RtpCapabilities capabilities);
|
||||
RtcpParameters to_rust_rtcp_parameters(webrtc::RtcpParameters params);
|
||||
RtpParameters to_rust_rtp_parameters(webrtc::RtpParameters params);
|
||||
|
||||
} // namespace livekit
|
||||
@@ -2,30 +2,51 @@
|
||||
// Created by Théo Monnom on 01/09/2022.
|
||||
//
|
||||
|
||||
#ifndef CLIENT_SDK_NATIVE_RTP_RECEIVER_H
|
||||
#define CLIENT_SDK_NATIVE_RTP_RECEIVER_H
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "api/rtp_receiver_interface.h"
|
||||
#include "livekit/helper.h"
|
||||
#include "livekit/media_stream.h"
|
||||
#include "livekit/rtp_parameters.h"
|
||||
#include "rust/cxx.h"
|
||||
|
||||
namespace livekit {
|
||||
class RtpReceiver;
|
||||
}
|
||||
#include "webrtc-sys/src/rtp_receiver.rs.h"
|
||||
namespace livekit {
|
||||
|
||||
// TODO(theomonnom): Implement RtpReceiverObserverInterface?
|
||||
// TODO(theomonnom): RtpSource
|
||||
// TODO(theomonnom): FrameTransformer & FrameDecryptor interface
|
||||
class RtpReceiver {
|
||||
public:
|
||||
explicit RtpReceiver(
|
||||
rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver);
|
||||
|
||||
std::unique_ptr<MediaStreamTrack> track() const;
|
||||
std::shared_ptr<MediaStreamTrack> track() const;
|
||||
|
||||
rust::Vec<rust::String> stream_ids() const;
|
||||
rust::Vec<MediaStreamPtr> streams() const;
|
||||
|
||||
MediaType media_type() const;
|
||||
rust::String id() const;
|
||||
|
||||
RtpParameters get_parameters() const;
|
||||
|
||||
// bool set_parameters(RtpParameters parameters) const; // Seems unsupported
|
||||
|
||||
void set_jitter_buffer_minimum_delay(bool is_some,
|
||||
double delay_seconds) const;
|
||||
|
||||
private:
|
||||
rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver_;
|
||||
};
|
||||
|
||||
static std::unique_ptr<RtpReceiver> _unique_rtp_receiver() {
|
||||
return nullptr; // Ignore
|
||||
static std::shared_ptr<RtpReceiver> _shared_rtp_receiver() {
|
||||
return nullptr;
|
||||
}
|
||||
} // namespace livekit
|
||||
|
||||
#endif // CLIENT_SDK_NATIVE_RTP_RECEIVER_H
|
||||
} // namespace livekit
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "api/rtp_sender_interface.h"
|
||||
#include "livekit/media_stream.h"
|
||||
#include "livekit/rtc_error.h"
|
||||
#include "livekit/rtp_parameters.h"
|
||||
#include "rust/cxx.h"
|
||||
|
||||
namespace livekit {
|
||||
class RtpSender;
|
||||
}
|
||||
#include "webrtc-sys/src/rtp_sender.rs.h"
|
||||
|
||||
namespace livekit {
|
||||
|
||||
// TODO(theomonnom): FrameTransformer & FrameEncryptor interface
|
||||
class RtpSender {
|
||||
public:
|
||||
explicit RtpSender(rtc::scoped_refptr<webrtc::RtpSenderInterface> sender);
|
||||
|
||||
bool set_track(std::shared_ptr<MediaStreamTrack> track) const;
|
||||
|
||||
std::shared_ptr<MediaStreamTrack> track() const;
|
||||
|
||||
uint32_t ssrc() const;
|
||||
|
||||
MediaType media_type() const;
|
||||
|
||||
rust::String id() const;
|
||||
|
||||
rust::Vec<rust::String> stream_ids() const;
|
||||
|
||||
void set_streams(const rust::Vec<rust::String>& stream_ids) const;
|
||||
|
||||
rust::Vec<RtpEncodingParameters> init_send_encodings() const;
|
||||
|
||||
RtpParameters get_parameters() const;
|
||||
|
||||
void set_parameters(RtpParameters params) const;
|
||||
|
||||
rtc::scoped_refptr<webrtc::RtpSenderInterface> get() const { return sender_; }
|
||||
|
||||
private:
|
||||
rtc::scoped_refptr<webrtc::RtpSenderInterface> sender_;
|
||||
};
|
||||
|
||||
static std::shared_ptr<RtpSender> _shared_rtp_sender() {
|
||||
return nullptr; // Ignore
|
||||
}
|
||||
} // namespace livekit
|
||||
@@ -2,27 +2,73 @@
|
||||
// Created by Théo Monnom on 02/09/2022.
|
||||
//
|
||||
|
||||
#ifndef CLIENT_SDK_NATIVE_RTP_TRANSCEIVER_H
|
||||
#define CLIENT_SDK_NATIVE_RTP_TRANSCEIVER_H
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "api/rtp_parameters.h"
|
||||
#include "api/rtp_transceiver_direction.h"
|
||||
#include "api/rtp_transceiver_interface.h"
|
||||
#include "livekit/rtc_error.h"
|
||||
#include "livekit/rtp_parameters.h"
|
||||
#include "livekit/rtp_receiver.h"
|
||||
#include "livekit/rtp_sender.h"
|
||||
#include "rust/cxx.h"
|
||||
|
||||
namespace livekit {
|
||||
class RtpTransceiver;
|
||||
}
|
||||
#include "webrtc-sys/src/rtp_transceiver.rs.h"
|
||||
|
||||
namespace livekit {
|
||||
|
||||
webrtc::RtpTransceiverInit to_native_rtp_transceiver_init(
|
||||
RtpTransceiverInit init);
|
||||
|
||||
class RtpTransceiver {
|
||||
public:
|
||||
explicit RtpTransceiver(
|
||||
rtc::scoped_refptr<webrtc::RtpTransceiverInterface> transceiver);
|
||||
|
||||
MediaType media_type() const;
|
||||
|
||||
rust::String mid() const;
|
||||
|
||||
std::shared_ptr<RtpSender> sender() const;
|
||||
|
||||
std::shared_ptr<RtpReceiver> receiver() const;
|
||||
|
||||
bool stopped() const;
|
||||
|
||||
bool stopping() const;
|
||||
|
||||
RtpTransceiverDirection direction() const;
|
||||
|
||||
void set_direction(RtpTransceiverDirection direction) const;
|
||||
|
||||
RtpTransceiverDirection current_direction() const;
|
||||
|
||||
RtpTransceiverDirection fired_direction() const;
|
||||
|
||||
void stop_standard() const;
|
||||
|
||||
void set_codec_preferences(rust::Vec<RtpCodecCapability> codecs) const;
|
||||
|
||||
rust::Vec<RtpCodecCapability> codec_preferences() const;
|
||||
|
||||
rust::Vec<RtpHeaderExtensionCapability> header_extensions_to_offer() const;
|
||||
|
||||
rust::Vec<RtpHeaderExtensionCapability> header_extensions_negotiated() const;
|
||||
|
||||
void set_offered_rtp_header_extensions(
|
||||
rust::Vec<RtpHeaderExtensionCapability> header_extensions_to_offer) const;
|
||||
|
||||
private:
|
||||
rtc::scoped_refptr<webrtc::RtpTransceiverInterface> transceiver_;
|
||||
};
|
||||
|
||||
static std::unique_ptr<RtpTransceiver> _unique_rtp_transceiver() {
|
||||
return nullptr; // Ignore
|
||||
static std::shared_ptr<RtpTransceiver> _shared_rtp_transceiver() {
|
||||
return nullptr;
|
||||
}
|
||||
} // namespace livekit
|
||||
|
||||
#endif // CLIENT_SDK_NATIVE_RTP_TRANSCEIVER_H
|
||||
} // namespace livekit
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
//
|
||||
// Created by Théo Monnom on 30/08/2022.
|
||||
//
|
||||
|
||||
#ifndef RUST_TYPES_H
|
||||
#define RUST_TYPES_H
|
||||
|
||||
#include "api/peer_connection_interface.h"
|
||||
|
||||
namespace livekit {
|
||||
struct RTCConfiguration;
|
||||
struct PeerConnectionObserverWrapper;
|
||||
struct CreateSdpObserverWrapper;
|
||||
struct SetLocalSdpObserverWrapper;
|
||||
struct SetRemoteSdpObserverWrapper;
|
||||
struct DataChannelObserverWrapper;
|
||||
struct AddIceCandidateObserverWrapper;
|
||||
struct VideoFrameSinkWrapper;
|
||||
|
||||
// Shared types
|
||||
enum class PeerConnectionState;
|
||||
enum class SignalingState;
|
||||
enum class IceConnectionState;
|
||||
enum class IceGatheringState;
|
||||
enum class SdpType;
|
||||
enum class DataState;
|
||||
enum class TrackState;
|
||||
enum class ContentHint;
|
||||
enum class VideoRotation;
|
||||
enum class VideoFrameBufferType;
|
||||
struct SdpParseError;
|
||||
struct RTCOfferAnswerOptions;
|
||||
struct RTCError;
|
||||
struct DataChannelInit;
|
||||
struct DataBuffer;
|
||||
} // namespace livekit
|
||||
|
||||
#endif // RUST_TYPES_H
|
||||
@@ -1,8 +1,7 @@
|
||||
#ifndef VIDEO_DECODER_FACTORY_H
|
||||
#define VIDEO_DECODER_FACTORY_H
|
||||
#pragma once
|
||||
|
||||
#include "api/video_codecs/video_decoder_factory.h"
|
||||
#include "api/video_codecs/video_decoder.h"
|
||||
#include "api/video_codecs/video_decoder_factory.h"
|
||||
|
||||
namespace livekit {
|
||||
class VideoDecoderFactory : public webrtc::VideoDecoderFactory {
|
||||
@@ -18,5 +17,3 @@ class VideoDecoderFactory : public webrtc::VideoDecoderFactory {
|
||||
std::vector<std::unique_ptr<webrtc::VideoDecoderFactory>> factories_;
|
||||
};
|
||||
} // namespace livekit
|
||||
|
||||
#endif // VIDEO_DECODER_FACTORY_H
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
#ifndef VIDEO_ENCODER_FACTORY_H
|
||||
#define VIDEO_ENCODER_FACTORY_H
|
||||
#pragma once
|
||||
|
||||
#include "api/video_codecs/video_encoder_factory.h"
|
||||
#include "api/video_codecs/video_encoder.h"
|
||||
#include "api/video_codecs/video_encoder_factory.h"
|
||||
|
||||
namespace livekit {
|
||||
class VideoEncoderFactory : public webrtc::VideoEncoderFactory {
|
||||
@@ -18,5 +17,3 @@ class VideoEncoderFactory : public webrtc::VideoEncoderFactory {
|
||||
std::vector<std::unique_ptr<webrtc::VideoEncoderFactory>> factories_;
|
||||
};
|
||||
} // namespace livekit
|
||||
|
||||
#endif // VIDEO_ENCODER_FACTORY_H
|
||||
|
||||
@@ -2,47 +2,59 @@
|
||||
// Created by theom on 14/11/2022.
|
||||
//
|
||||
|
||||
#ifndef LIVEKIT_WEBRTC_VIDEO_FRAME_H
|
||||
#define LIVEKIT_WEBRTC_VIDEO_FRAME_H
|
||||
#pragma once
|
||||
|
||||
#include "api/video/video_frame.h"
|
||||
#include "livekit/rust_types.h"
|
||||
#include "livekit/video_frame_buffer.h"
|
||||
#include "rtc_base/checks.h"
|
||||
|
||||
namespace livekit {
|
||||
class VideoFrame;
|
||||
class VideoFrameBuilder;
|
||||
} // namespace livekit
|
||||
#include "webrtc-sys/src/video_frame.rs.h"
|
||||
|
||||
namespace livekit {
|
||||
|
||||
class VideoFrame {
|
||||
public:
|
||||
explicit VideoFrame(const webrtc::VideoFrame& frame)
|
||||
: frame_(std::move(frame)) {}
|
||||
explicit VideoFrame(const webrtc::VideoFrame& frame);
|
||||
|
||||
int width() const { return frame_.width(); }
|
||||
int height() const { return frame_.height(); }
|
||||
uint32_t size() const { return frame_.size(); }
|
||||
uint16_t id() const { return frame_.id(); }
|
||||
int64_t timestamp_us() const { return frame_.timestamp_us(); }
|
||||
int64_t ntp_time_ms() const { return frame_.ntp_time_ms(); }
|
||||
uint32_t transport_frame_id() const { return frame_.transport_frame_id(); }
|
||||
uint32_t timestamp() const { return frame_.timestamp(); }
|
||||
int width() const;
|
||||
int height() const;
|
||||
uint32_t size() const;
|
||||
uint16_t id() const;
|
||||
int64_t timestamp_us() const;
|
||||
int64_t ntp_time_ms() const;
|
||||
uint32_t transport_frame_id() const;
|
||||
uint32_t timestamp() const;
|
||||
|
||||
VideoRotation rotation() const {
|
||||
return static_cast<VideoRotation>(frame_.rotation());
|
||||
}
|
||||
VideoRotation rotation() const;
|
||||
std::unique_ptr<VideoFrameBuffer> video_frame_buffer() const;
|
||||
|
||||
// TODO(theomonnom) This shouldn't create a new shared_ptr at each call
|
||||
std::unique_ptr<VideoFrameBuffer> video_frame_buffer() const {
|
||||
return std::make_unique<VideoFrameBuffer>(frame_.video_frame_buffer());
|
||||
}
|
||||
webrtc::VideoFrame get() const;
|
||||
|
||||
private:
|
||||
webrtc::VideoFrame frame_;
|
||||
};
|
||||
|
||||
static std::unique_ptr<VideoFrame> _unique_video_frame() {
|
||||
return nullptr; // Ignore
|
||||
}
|
||||
// Allow to create VideoFrames from Rust,
|
||||
// the builder pattern will be redone in Rust
|
||||
class VideoFrameBuilder {
|
||||
public:
|
||||
VideoFrameBuilder() = default;
|
||||
|
||||
// TODO(theomonnom): other setters?
|
||||
void set_video_frame_buffer(std::unique_ptr<VideoFrameBuffer> buffer);
|
||||
void set_timestamp_us(int64_t timestamp_us);
|
||||
void set_rotation(VideoRotation rotation);
|
||||
void set_id(uint16_t id);
|
||||
std::unique_ptr<VideoFrame> build();
|
||||
|
||||
private:
|
||||
webrtc::VideoFrame::Builder builder_;
|
||||
};
|
||||
|
||||
std::unique_ptr<VideoFrameBuilder> create_video_frame_builder();
|
||||
|
||||
} // namespace livekit
|
||||
|
||||
#endif // LIVEKIT_WEBRTC_VIDEO_FRAME_H
|
||||
|
||||
@@ -2,75 +2,50 @@
|
||||
// Created by theom on 14/11/2022.
|
||||
//
|
||||
|
||||
#ifndef LIVEKIT_WEBRTC_VIDEO_FRAME_BUFFER_H
|
||||
#define LIVEKIT_WEBRTC_VIDEO_FRAME_BUFFER_H
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "api/video/i420_buffer.h"
|
||||
#include "api/video/video_frame_buffer.h"
|
||||
#include "rust_types.h"
|
||||
|
||||
namespace livekit {
|
||||
|
||||
class VideoFrameBuffer;
|
||||
class PlanarYuvBuffer;
|
||||
class PlanarYuv8Buffer;
|
||||
class PlanarYuv16BBuffer;
|
||||
class BiplanarYuvBuffer;
|
||||
class BiplanarYuv8Buffer;
|
||||
class I420Buffer;
|
||||
class I420ABuffer;
|
||||
class I422Buffer;
|
||||
class I444Buffer;
|
||||
class I010Buffer;
|
||||
class NV12Buffer;
|
||||
} // namespace livekit
|
||||
#include "webrtc-sys/src/video_frame_buffer.rs.h"
|
||||
|
||||
namespace livekit {
|
||||
|
||||
class VideoFrameBuffer {
|
||||
public:
|
||||
explicit VideoFrameBuffer(rtc::scoped_refptr<webrtc::VideoFrameBuffer> buffer)
|
||||
: buffer_(std::move(buffer)) {}
|
||||
explicit VideoFrameBuffer(
|
||||
rtc::scoped_refptr<webrtc::VideoFrameBuffer> buffer);
|
||||
|
||||
VideoFrameBufferType buffer_type() const {
|
||||
return static_cast<VideoFrameBufferType>(buffer_->type());
|
||||
}
|
||||
VideoFrameBufferType buffer_type() const;
|
||||
|
||||
int width() const { return buffer_->width(); }
|
||||
int height() const { return buffer_->height(); }
|
||||
int width() const;
|
||||
int height() const;
|
||||
|
||||
std::unique_ptr<I420Buffer> to_i420() {
|
||||
return std::make_unique<I420Buffer>(buffer_->ToI420());
|
||||
}
|
||||
|
||||
// const_cast is valid here because we take the ownership on the rust side
|
||||
std::unique_ptr<I420Buffer> get_i420() {
|
||||
return std::make_unique<I420Buffer>(
|
||||
rtc::scoped_refptr<webrtc::I420BufferInterface>(
|
||||
const_cast<webrtc::I420BufferInterface*>(buffer_->GetI420())));
|
||||
}
|
||||
|
||||
std::unique_ptr<I420ABuffer> get_i420a() {
|
||||
return std::make_unique<I420ABuffer>(
|
||||
rtc::scoped_refptr<webrtc::I420ABufferInterface>(
|
||||
const_cast<webrtc::I420ABufferInterface*>(buffer_->GetI420A())));
|
||||
}
|
||||
|
||||
std::unique_ptr<I422Buffer> get_i422() {
|
||||
return std::make_unique<I422Buffer>(
|
||||
rtc::scoped_refptr<webrtc::I422BufferInterface>(
|
||||
const_cast<webrtc::I422BufferInterface*>(buffer_->GetI422())));
|
||||
}
|
||||
|
||||
std::unique_ptr<I444Buffer> get_i444() {
|
||||
return std::make_unique<I444Buffer>(
|
||||
rtc::scoped_refptr<webrtc::I444BufferInterface>(
|
||||
const_cast<webrtc::I444BufferInterface*>(buffer_->GetI444())));
|
||||
}
|
||||
|
||||
std::unique_ptr<I010Buffer> get_i010() {
|
||||
return std::make_unique<I010Buffer>(
|
||||
rtc::scoped_refptr<webrtc::I010BufferInterface>(
|
||||
const_cast<webrtc::I010BufferInterface*>(buffer_->GetI010())));
|
||||
}
|
||||
|
||||
std::unique_ptr<NV12Buffer> get_nv12() {
|
||||
return std::make_unique<NV12Buffer>(
|
||||
rtc::scoped_refptr<webrtc::NV12BufferInterface>(
|
||||
const_cast<webrtc::NV12BufferInterface*>(buffer_->GetNV12())));
|
||||
}
|
||||
// Takes ownership
|
||||
std::unique_ptr<I420Buffer> to_i420();
|
||||
std::unique_ptr<I420Buffer> get_i420();
|
||||
std::unique_ptr<I420ABuffer> get_i420a();
|
||||
std::unique_ptr<I422Buffer> get_i422();
|
||||
std::unique_ptr<I444Buffer> get_i444();
|
||||
std::unique_ptr<I010Buffer> get_i010();
|
||||
std::unique_ptr<NV12Buffer> get_nv12();
|
||||
rtc::scoped_refptr<webrtc::VideoFrameBuffer> get() const;
|
||||
|
||||
protected:
|
||||
rtc::scoped_refptr<webrtc::VideoFrameBuffer> buffer_;
|
||||
@@ -78,120 +53,102 @@ class VideoFrameBuffer {
|
||||
|
||||
class PlanarYuvBuffer : public VideoFrameBuffer {
|
||||
public:
|
||||
explicit PlanarYuvBuffer(rtc::scoped_refptr<webrtc::PlanarYuvBuffer> buffer)
|
||||
: VideoFrameBuffer(buffer) {}
|
||||
explicit PlanarYuvBuffer(rtc::scoped_refptr<webrtc::PlanarYuvBuffer> buffer);
|
||||
|
||||
int chroma_width() const { return buffer()->ChromaWidth(); }
|
||||
int chroma_height() const { return buffer()->ChromaHeight(); }
|
||||
int chroma_width() const;
|
||||
int chroma_height() const;
|
||||
|
||||
int stride_y() const { return buffer()->StrideY(); }
|
||||
int stride_u() const { return buffer()->StrideU(); }
|
||||
int stride_v() const { return buffer()->StrideV(); }
|
||||
int stride_y() const;
|
||||
int stride_u() const;
|
||||
int stride_v() const;
|
||||
|
||||
private:
|
||||
webrtc::PlanarYuvBuffer* buffer() const {
|
||||
return static_cast<webrtc::PlanarYuvBuffer*>(buffer_.get());
|
||||
}
|
||||
webrtc::PlanarYuvBuffer* buffer() const;
|
||||
};
|
||||
|
||||
class PlanarYuv8Buffer : public PlanarYuvBuffer {
|
||||
public:
|
||||
explicit PlanarYuv8Buffer(rtc::scoped_refptr<webrtc::PlanarYuv8Buffer> buffer)
|
||||
: PlanarYuvBuffer(buffer) {}
|
||||
explicit PlanarYuv8Buffer(
|
||||
rtc::scoped_refptr<webrtc::PlanarYuv8Buffer> buffer);
|
||||
|
||||
const uint8_t* data_y() const { return buffer()->DataY(); }
|
||||
const uint8_t* data_u() const { return buffer()->DataU(); }
|
||||
const uint8_t* data_v() const { return buffer()->DataV(); }
|
||||
const uint8_t* data_y() const;
|
||||
const uint8_t* data_u() const;
|
||||
const uint8_t* data_v() const;
|
||||
|
||||
private:
|
||||
webrtc::PlanarYuv8Buffer* buffer() const {
|
||||
return static_cast<webrtc::PlanarYuv8Buffer*>(buffer_.get());
|
||||
}
|
||||
webrtc::PlanarYuv8Buffer* buffer() const;
|
||||
};
|
||||
|
||||
class PlanarYuv16BBuffer : public PlanarYuvBuffer {
|
||||
public:
|
||||
explicit PlanarYuv16BBuffer(
|
||||
rtc::scoped_refptr<webrtc::PlanarYuv16BBuffer> buffer)
|
||||
: PlanarYuvBuffer(buffer) {}
|
||||
rtc::scoped_refptr<webrtc::PlanarYuv16BBuffer> buffer);
|
||||
|
||||
const uint16_t* data_y() const { return buffer()->DataY(); }
|
||||
const uint16_t* data_u() const { return buffer()->DataU(); }
|
||||
const uint16_t* data_v() const { return buffer()->DataV(); }
|
||||
const uint16_t* data_y() const;
|
||||
const uint16_t* data_u() const;
|
||||
const uint16_t* data_v() const;
|
||||
|
||||
private:
|
||||
webrtc::PlanarYuv16BBuffer* buffer() const {
|
||||
return static_cast<webrtc::PlanarYuv16BBuffer*>(buffer_.get());
|
||||
}
|
||||
webrtc::PlanarYuv16BBuffer* buffer() const;
|
||||
};
|
||||
|
||||
class BiplanarYuvBuffer : public VideoFrameBuffer {
|
||||
public:
|
||||
explicit BiplanarYuvBuffer(
|
||||
rtc::scoped_refptr<webrtc::BiplanarYuvBuffer> buffer)
|
||||
: VideoFrameBuffer(buffer) {}
|
||||
rtc::scoped_refptr<webrtc::BiplanarYuvBuffer> buffer);
|
||||
|
||||
int chroma_width() const { return buffer()->ChromaWidth(); }
|
||||
int chroma_height() const { return buffer()->ChromaHeight(); }
|
||||
int chroma_width() const;
|
||||
int chroma_height() const;
|
||||
|
||||
int stride_y() const { return buffer()->StrideY(); }
|
||||
int stride_uv() const { return buffer()->StrideUV(); }
|
||||
int stride_y() const;
|
||||
int stride_uv() const;
|
||||
|
||||
private:
|
||||
webrtc::BiplanarYuvBuffer* buffer() const {
|
||||
return static_cast<webrtc::BiplanarYuvBuffer*>(buffer_.get());
|
||||
}
|
||||
webrtc::BiplanarYuvBuffer* buffer() const;
|
||||
};
|
||||
|
||||
class BiplanarYuv8Buffer : public BiplanarYuvBuffer {
|
||||
public:
|
||||
explicit BiplanarYuv8Buffer(
|
||||
rtc::scoped_refptr<webrtc::BiplanarYuv8Buffer> buffer)
|
||||
: BiplanarYuvBuffer(buffer) {}
|
||||
rtc::scoped_refptr<webrtc::BiplanarYuv8Buffer> buffer);
|
||||
|
||||
const uint8_t* data_y() const { return buffer()->DataY(); }
|
||||
const uint8_t* data_uv() const { return buffer()->DataUV(); }
|
||||
const uint8_t* data_y() const;
|
||||
const uint8_t* data_uv() const;
|
||||
|
||||
private:
|
||||
webrtc::BiplanarYuv8Buffer* buffer() const {
|
||||
return static_cast<webrtc::BiplanarYuv8Buffer*>(buffer_.get());
|
||||
}
|
||||
webrtc::BiplanarYuv8Buffer* buffer() const;
|
||||
};
|
||||
|
||||
std::unique_ptr<I420Buffer> create_i420_buffer(int width, int height);
|
||||
|
||||
class I420Buffer : public PlanarYuv8Buffer {
|
||||
public:
|
||||
explicit I420Buffer(rtc::scoped_refptr<webrtc::I420BufferInterface> buffer)
|
||||
: PlanarYuv8Buffer(buffer) {}
|
||||
explicit I420Buffer(rtc::scoped_refptr<webrtc::I420BufferInterface> buffer);
|
||||
};
|
||||
|
||||
class I420ABuffer : public I420Buffer {
|
||||
public:
|
||||
explicit I420ABuffer(rtc::scoped_refptr<webrtc::I420ABufferInterface> buffer)
|
||||
: I420Buffer(buffer) {}
|
||||
explicit I420ABuffer(rtc::scoped_refptr<webrtc::I420ABufferInterface> buffer);
|
||||
};
|
||||
|
||||
class I422Buffer : public PlanarYuv8Buffer {
|
||||
public:
|
||||
explicit I422Buffer(rtc::scoped_refptr<webrtc::I422BufferInterface> buffer)
|
||||
: PlanarYuv8Buffer(buffer) {}
|
||||
explicit I422Buffer(rtc::scoped_refptr<webrtc::I422BufferInterface> buffer);
|
||||
};
|
||||
|
||||
class I444Buffer : public PlanarYuv8Buffer {
|
||||
public:
|
||||
explicit I444Buffer(rtc::scoped_refptr<webrtc::I444BufferInterface> buffer)
|
||||
: PlanarYuv8Buffer(buffer) {}
|
||||
explicit I444Buffer(rtc::scoped_refptr<webrtc::I444BufferInterface> buffer);
|
||||
};
|
||||
|
||||
class I010Buffer : public PlanarYuv16BBuffer {
|
||||
public:
|
||||
explicit I010Buffer(rtc::scoped_refptr<webrtc::I010BufferInterface> buffer)
|
||||
: PlanarYuv16BBuffer(buffer) {}
|
||||
explicit I010Buffer(rtc::scoped_refptr<webrtc::I010BufferInterface> buffer);
|
||||
};
|
||||
|
||||
class NV12Buffer : public BiplanarYuv8Buffer {
|
||||
public:
|
||||
explicit NV12Buffer(rtc::scoped_refptr<webrtc::NV12BufferInterface> buffer)
|
||||
: BiplanarYuv8Buffer(buffer) {}
|
||||
explicit NV12Buffer(rtc::scoped_refptr<webrtc::NV12BufferInterface> buffer);
|
||||
};
|
||||
|
||||
static const VideoFrameBuffer* yuv_to_vfb(const PlanarYuvBuffer* yuv) {
|
||||
@@ -240,9 +197,7 @@ static const BiplanarYuv8Buffer* nv12_to_biyuv8(const NV12Buffer* nv12) {
|
||||
}
|
||||
|
||||
static std::unique_ptr<VideoFrameBuffer> _unique_video_frame_buffer() {
|
||||
return nullptr; // Ignore
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace livekit
|
||||
|
||||
#endif // LIVEKIT_WEBRTC_VIDEO_FRAME_BUFFER_H
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
// Created by theom on 18/09/2022.
|
||||
//
|
||||
|
||||
#ifndef LIVEKIT_WEBRTC_WEBRTC_H
|
||||
#define LIVEKIT_WEBRTC_WEBRTC_H
|
||||
#pragma once
|
||||
|
||||
#include "rtc_base/physical_socket_server.h"
|
||||
#include "rtc_base/ssl_adapter.h"
|
||||
@@ -12,6 +11,11 @@
|
||||
#include "rtc_base/win32_socket_init.h"
|
||||
#endif
|
||||
|
||||
namespace livekit {
|
||||
class RTCRuntime;
|
||||
}
|
||||
#include "webrtc-sys/src/webrtc.rs.h"
|
||||
|
||||
namespace livekit {
|
||||
|
||||
class RTCRuntime {
|
||||
@@ -30,15 +34,14 @@ class RTCRuntime {
|
||||
std::unique_ptr<rtc::Thread> network_thread_;
|
||||
std::unique_ptr<rtc::Thread> worker_thread_;
|
||||
std::unique_ptr<rtc::Thread> signaling_thread_;
|
||||
|
||||
#ifdef WEBRTC_WIN
|
||||
rtc::WinsockInitializer winsock_;
|
||||
rtc::PhysicalSocketServer ss_;
|
||||
rtc::AutoSocketServerThread main_thread_ {&ss_};
|
||||
rtc::AutoSocketServerThread main_thread_{&ss_};
|
||||
#endif
|
||||
};
|
||||
|
||||
std::shared_ptr<RTCRuntime> create_rtc_runtime();
|
||||
|
||||
} // namespace livekit
|
||||
|
||||
#endif // LIVEKIT_WEBRTC_WEBRTC_H
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
// Created by Théo Monnom on 01/12/2022.
|
||||
//
|
||||
|
||||
#ifndef CLIENT_SDK_NATIVE_YUV_HELPER_H
|
||||
#define CLIENT_SDK_NATIVE_YUV_HELPER_H
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "api/video/yuv_helper.h"
|
||||
#include "webrtc-sys/src/yuv_helper.rs.h"
|
||||
|
||||
namespace livekit {
|
||||
|
||||
@@ -68,5 +68,3 @@ static void i420_to_rgba(const uint8_t* src_y,
|
||||
}
|
||||
|
||||
} // namespace livekit
|
||||
|
||||
#endif // CLIENT_SDK_NATIVE_YUV_HELPER_H
|
||||
|
||||
@@ -5,6 +5,6 @@ pub mod ffi {
|
||||
|
||||
type Candidate; // cricket::Candidate
|
||||
|
||||
fn _unique_candidate() -> UniquePtr<Candidate>; // Ignore
|
||||
fn _shared_candidate() -> SharedPtr<Candidate>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "webrtc-sys/src/data_channel.rs.h"
|
||||
|
||||
namespace livekit {
|
||||
|
||||
DataChannel::DataChannel(
|
||||
@@ -16,11 +14,11 @@ DataChannel::DataChannel(
|
||||
: rtc_runtime_(std::move(rtc_runtime)),
|
||||
data_channel_(std::move(data_channel)) {}
|
||||
|
||||
void DataChannel::register_observer(NativeDataChannelObserver& observer) {
|
||||
void DataChannel::register_observer(NativeDataChannelObserver& observer) const {
|
||||
data_channel_->RegisterObserver(&observer);
|
||||
}
|
||||
|
||||
void DataChannel::unregister_observer() {
|
||||
void DataChannel::unregister_observer() const {
|
||||
data_channel_->UnregisterObserver();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::fmt::Debug;
|
||||
use crate::impl_thread_safety;
|
||||
use std::slice;
|
||||
|
||||
#[cxx::bridge(namespace = "livekit")]
|
||||
@@ -63,12 +63,12 @@ pub mod ffi {
|
||||
/// SAFETY
|
||||
/// The observer must live as the datachannel uses it
|
||||
unsafe fn register_observer(
|
||||
self: Pin<&mut DataChannel>,
|
||||
self: &DataChannel,
|
||||
observer: Pin<&mut NativeDataChannelObserver>,
|
||||
);
|
||||
|
||||
fn unregister_observer(self: Pin<&mut DataChannel>);
|
||||
fn send(self: &DataChannel, data: &DataBuffer) -> bool;
|
||||
fn unregister_observer(self: &DataChannel);
|
||||
fn send(self: &DataChannel, data: &DataBuffer) -> bool;
|
||||
fn label(self: &DataChannel) -> String;
|
||||
fn state(self: &DataChannel) -> DataState;
|
||||
fn close(self: &DataChannel);
|
||||
@@ -82,11 +82,8 @@ pub mod ffi {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for ffi::DataChannel {}
|
||||
unsafe impl Sync for ffi::DataChannel {}
|
||||
|
||||
unsafe impl Send for ffi::NativeDataChannelObserver {}
|
||||
unsafe impl Sync for ffi::NativeDataChannelObserver {}
|
||||
impl_thread_safety!(ffi::DataChannel, Send + Sync);
|
||||
impl_thread_safety!(ffi::NativeDataChannelObserver, Send + Sync);
|
||||
|
||||
// DataChannelObserver
|
||||
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
#[cxx::bridge(namespace = "livekit")]
|
||||
pub mod ffi {
|
||||
|
||||
// Wrapper to opaque C++ objects
|
||||
// https://github.com/dtolnay/cxx/issues/741
|
||||
// Used to allow SharedPtr/UniquePtr type inside a rust::Vec
|
||||
pub struct MediaStreamPtr {
|
||||
pub ptr: SharedPtr<MediaStream>,
|
||||
}
|
||||
|
||||
pub struct CandidatePtr {
|
||||
pub ptr: SharedPtr<Candidate>,
|
||||
}
|
||||
|
||||
pub struct AudioTrackPtr {
|
||||
pub ptr: SharedPtr<AudioTrack>,
|
||||
}
|
||||
|
||||
pub struct VideoTrackPtr {
|
||||
pub ptr: SharedPtr<VideoTrack>,
|
||||
}
|
||||
|
||||
pub struct RtpSenderPtr {
|
||||
pub ptr: SharedPtr<RtpSender>,
|
||||
}
|
||||
|
||||
pub struct RtpReceiverPtr {
|
||||
pub ptr: SharedPtr<RtpReceiver>,
|
||||
}
|
||||
|
||||
pub struct RtpTransceiverPtr {
|
||||
pub ptr: SharedPtr<RtpTransceiver>,
|
||||
}
|
||||
|
||||
unsafe extern "C++" {
|
||||
include!("livekit/helper.h");
|
||||
|
||||
type MediaStream = crate::media_stream::ffi::MediaStream;
|
||||
type AudioTrack = crate::media_stream::ffi::AudioTrack;
|
||||
type VideoTrack = crate::media_stream::ffi::VideoTrack;
|
||||
type Candidate = crate::candidate::ffi::Candidate;
|
||||
type RtpSender = crate::rtp_sender::ffi::RtpSender;
|
||||
type RtpReceiver = crate::rtp_receiver::ffi::RtpReceiver;
|
||||
type RtpTransceiver = crate::rtp_transceiver::ffi::RtpTransceiver;
|
||||
|
||||
fn _vec_media_stream_ptr() -> Vec<MediaStreamPtr>;
|
||||
fn _vec_candidate_ptr() -> Vec<CandidatePtr>;
|
||||
fn _vec_audio_track_ptr() -> Vec<AudioTrackPtr>;
|
||||
fn _vec_video_track_ptr() -> Vec<VideoTrackPtr>;
|
||||
fn _vec_rtp_sender_ptr() -> Vec<RtpSenderPtr>;
|
||||
fn _vec_rtp_receiver_ptr() -> Vec<RtpReceiverPtr>;
|
||||
fn _vec_rtp_transceiver_ptr() -> Vec<RtpTransceiverPtr>;
|
||||
}
|
||||
}
|
||||
@@ -7,8 +7,8 @@
|
||||
#include <iomanip>
|
||||
#include <memory>
|
||||
|
||||
#include "webrtc-sys/src/jsep.rs.h"
|
||||
#include "livekit/rtc_error.h"
|
||||
#include "rtc_base/ref_counted_object.h"
|
||||
|
||||
namespace livekit {
|
||||
|
||||
@@ -47,7 +47,7 @@ std::unique_ptr<webrtc::IceCandidateInterface> IceCandidate::release() {
|
||||
return std::move(ice_candidate_);
|
||||
}
|
||||
|
||||
std::unique_ptr<IceCandidate> create_ice_candidate(rust::String sdp_mid,
|
||||
std::shared_ptr<IceCandidate> create_ice_candidate(rust::String sdp_mid,
|
||||
int sdp_mline_index,
|
||||
rust::String sdp) {
|
||||
webrtc::SdpParseError error;
|
||||
@@ -57,7 +57,7 @@ std::unique_ptr<IceCandidate> create_ice_candidate(rust::String sdp_mid,
|
||||
throw std::runtime_error(serialize_sdp_error(error));
|
||||
}
|
||||
|
||||
return std::make_unique<IceCandidate>(
|
||||
return std::make_shared<IceCandidate>(
|
||||
std::unique_ptr<webrtc::IceCandidateInterface>(ice_rtc));
|
||||
}
|
||||
|
||||
|
||||
+14
-15
@@ -1,10 +1,10 @@
|
||||
use crate::impl_thread_safety;
|
||||
use cxx::UniquePtr;
|
||||
use std::error::Error;
|
||||
use std::fmt::{Debug, Display, Formatter};
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::mem::ManuallyDrop;
|
||||
use std::str::FromStr;
|
||||
|
||||
use cxx::UniquePtr;
|
||||
|
||||
use crate::rtc_error::ffi::RTCError;
|
||||
|
||||
#[cxx::bridge(namespace = "livekit")]
|
||||
@@ -39,11 +39,15 @@ pub mod ffi {
|
||||
fn on_set_remote_description_complete(self: &SetRemoteSdpObserverWrapper, error: RTCError);
|
||||
}
|
||||
|
||||
unsafe extern "C++" {
|
||||
include!("webrtc-sys/src/rtc_error.rs.h");
|
||||
include!("livekit/jsep.h");
|
||||
extern "C++" {
|
||||
include!("livekit/rtc_error.h");
|
||||
|
||||
type RTCError = crate::rtc_error::ffi::RTCError;
|
||||
}
|
||||
|
||||
unsafe extern "C++" {
|
||||
include!("livekit/jsep.h");
|
||||
|
||||
type IceCandidate;
|
||||
type SessionDescription;
|
||||
type NativeCreateSdpObserverHandle;
|
||||
@@ -72,13 +76,13 @@ pub mod ffi {
|
||||
sdp_mid: String,
|
||||
sdp_mline_index: i32,
|
||||
sdp: String,
|
||||
) -> Result<UniquePtr<IceCandidate>>;
|
||||
) -> Result<SharedPtr<IceCandidate>>;
|
||||
fn create_session_description(
|
||||
sdp_type: SdpType,
|
||||
sdp: String,
|
||||
) -> Result<UniquePtr<SessionDescription>>;
|
||||
|
||||
fn _unique_ice_candidate() -> UniquePtr<IceCandidate>; // Ignore
|
||||
fn _shared_ice_candidate() -> SharedPtr<IceCandidate>; // Ignore
|
||||
fn _unique_session_description() -> UniquePtr<SessionDescription>; // Ignore
|
||||
}
|
||||
}
|
||||
@@ -95,13 +99,8 @@ impl Display for ffi::SdpParseError {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for ffi::SessionDescription {}
|
||||
|
||||
unsafe impl Sync for ffi::SessionDescription {}
|
||||
|
||||
unsafe impl Send for ffi::IceCandidate {}
|
||||
|
||||
unsafe impl Sync for ffi::IceCandidate {}
|
||||
impl_thread_safety!(ffi::SessionDescription, Send + Sync);
|
||||
impl_thread_safety!(ffi::IceCandidate, Send + Sync);
|
||||
|
||||
impl ffi::SdpParseError {
|
||||
/// # Safety
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
pub mod candidate;
|
||||
pub mod data_channel;
|
||||
pub mod helper;
|
||||
pub mod jsep;
|
||||
pub mod media_stream;
|
||||
pub mod peer_connection;
|
||||
pub mod peer_connection_factory;
|
||||
pub mod rtc_error;
|
||||
pub mod rtp_parameters;
|
||||
pub mod rtp_receiver;
|
||||
pub mod rtp_sender;
|
||||
pub mod rtp_transceiver;
|
||||
pub mod video_frame;
|
||||
pub mod video_frame_buffer;
|
||||
|
||||
+156
-17
@@ -4,23 +4,91 @@
|
||||
|
||||
#include "livekit/media_stream.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
||||
#include "api/media_stream_interface.h"
|
||||
#include "webrtc-sys/src/media_stream.rs.h"
|
||||
#include "api/video/video_frame.h"
|
||||
#include "rtc_base/ref_counted_object.h"
|
||||
|
||||
namespace livekit {
|
||||
|
||||
MediaStream::MediaStream(
|
||||
rtc::scoped_refptr<webrtc::MediaStreamInterface> stream)
|
||||
: media_stream_(std::move(stream)) {}
|
||||
|
||||
rust::String MediaStream::id() const {
|
||||
return media_stream_->id();
|
||||
}
|
||||
|
||||
rust::Vec<VideoTrackPtr> MediaStream::get_video_tracks() const {
|
||||
rust::Vec<VideoTrackPtr> rust;
|
||||
for (auto video : media_stream_->GetVideoTracks())
|
||||
rust.push_back(VideoTrackPtr{std::make_shared<VideoTrack>(video)});
|
||||
|
||||
return rust;
|
||||
}
|
||||
|
||||
rust::Vec<AudioTrackPtr> MediaStream::get_audio_tracks() const {
|
||||
rust::Vec<AudioTrackPtr> rust;
|
||||
for (auto audio : media_stream_->GetAudioTracks())
|
||||
rust.push_back(AudioTrackPtr{std::make_shared<AudioTrack>(audio)});
|
||||
|
||||
return rust;
|
||||
}
|
||||
|
||||
std::shared_ptr<AudioTrack> MediaStream::find_audio_track(
|
||||
rust::String track_id) const {
|
||||
return std::make_shared<AudioTrack>(
|
||||
media_stream_->FindAudioTrack(track_id.c_str()));
|
||||
}
|
||||
|
||||
std::shared_ptr<VideoTrack> MediaStream::find_video_track(
|
||||
rust::String track_id) const {
|
||||
return std::make_shared<VideoTrack>(
|
||||
media_stream_->FindVideoTrack(track_id.c_str()));
|
||||
}
|
||||
|
||||
bool MediaStream::add_audio_track(
|
||||
std::shared_ptr<AudioTrack> audio_track) const {
|
||||
return media_stream_->AddTrack(
|
||||
rtc::scoped_refptr<webrtc::AudioTrackInterface>(
|
||||
static_cast<webrtc::AudioTrackInterface*>(audio_track->get().get())));
|
||||
}
|
||||
|
||||
bool MediaStream::add_video_track(
|
||||
std::shared_ptr<VideoTrack> video_track) const {
|
||||
return media_stream_->AddTrack(
|
||||
rtc::scoped_refptr<webrtc::VideoTrackInterface>(
|
||||
static_cast<webrtc::VideoTrackInterface*>(video_track->get().get())));
|
||||
}
|
||||
|
||||
bool MediaStream::remove_audio_track(
|
||||
std::shared_ptr<AudioTrack> audio_track) const {
|
||||
return media_stream_->RemoveTrack(
|
||||
rtc::scoped_refptr<webrtc::AudioTrackInterface>(
|
||||
static_cast<webrtc::AudioTrackInterface*>(audio_track->get().get())));
|
||||
}
|
||||
|
||||
bool MediaStream::remove_video_track(
|
||||
std::shared_ptr<VideoTrack> video_track) const {
|
||||
return media_stream_->RemoveTrack(
|
||||
rtc::scoped_refptr<webrtc::VideoTrackInterface>(
|
||||
static_cast<webrtc::VideoTrackInterface*>(video_track->get().get())));
|
||||
}
|
||||
|
||||
MediaStreamTrack::MediaStreamTrack(
|
||||
rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track)
|
||||
: track_(std::move(track)) {}
|
||||
|
||||
std::unique_ptr<MediaStreamTrack> MediaStreamTrack::from(
|
||||
std::shared_ptr<MediaStreamTrack> MediaStreamTrack::from(
|
||||
rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track) {
|
||||
if (track->kind() == webrtc::MediaStreamTrackInterface::kVideoKind) {
|
||||
return std::make_unique<VideoTrack>(
|
||||
return std::make_shared<VideoTrack>(
|
||||
rtc::scoped_refptr<webrtc::VideoTrackInterface>(
|
||||
static_cast<webrtc::VideoTrackInterface*>(track.get())));
|
||||
} else {
|
||||
return std::make_unique<AudioTrack>(
|
||||
return std::make_shared<AudioTrack>(
|
||||
rtc::scoped_refptr<webrtc::AudioTrackInterface>(
|
||||
static_cast<webrtc::AudioTrackInterface*>(track.get())));
|
||||
}
|
||||
@@ -38,7 +106,7 @@ bool MediaStreamTrack::enabled() const {
|
||||
return track_->enabled();
|
||||
}
|
||||
|
||||
bool MediaStreamTrack::set_enabled(bool enable) {
|
||||
bool MediaStreamTrack::set_enabled(bool enable) const {
|
||||
return track_->set_enabled(enable);
|
||||
}
|
||||
|
||||
@@ -46,29 +114,21 @@ TrackState MediaStreamTrack::state() const {
|
||||
return static_cast<TrackState>(track_->state());
|
||||
}
|
||||
|
||||
MediaStream::MediaStream(
|
||||
rtc::scoped_refptr<webrtc::MediaStreamInterface> stream)
|
||||
: media_stream_(std::move(stream)) {}
|
||||
|
||||
rust::String MediaStream::id() const {
|
||||
return media_stream_->id();
|
||||
}
|
||||
|
||||
AudioTrack::AudioTrack(rtc::scoped_refptr<webrtc::AudioTrackInterface> track)
|
||||
: MediaStreamTrack(std::move(track)) {}
|
||||
|
||||
VideoTrack::VideoTrack(rtc::scoped_refptr<webrtc::VideoTrackInterface> track)
|
||||
: MediaStreamTrack(std::move(track)) {}
|
||||
|
||||
void VideoTrack::add_sink(NativeVideoFrameSink& sink) {
|
||||
void VideoTrack::add_sink(NativeVideoFrameSink& sink) const {
|
||||
track()->AddOrUpdateSink(&sink, rtc::VideoSinkWants());
|
||||
}
|
||||
|
||||
void VideoTrack::remove_sink(NativeVideoFrameSink& sink) {
|
||||
void VideoTrack::remove_sink(NativeVideoFrameSink& sink) const {
|
||||
track()->RemoveSink(&sink);
|
||||
}
|
||||
|
||||
void VideoTrack::set_should_receive(bool should_receive) {
|
||||
void VideoTrack::set_should_receive(bool should_receive) const {
|
||||
track()->set_should_receive(should_receive);
|
||||
}
|
||||
|
||||
@@ -80,7 +140,7 @@ ContentHint VideoTrack::content_hint() const {
|
||||
return static_cast<ContentHint>(track()->content_hint());
|
||||
}
|
||||
|
||||
void VideoTrack::set_content_hint(ContentHint hint) {
|
||||
void VideoTrack::set_content_hint(ContentHint hint) const {
|
||||
track()->set_content_hint(
|
||||
static_cast<webrtc::VideoTrackInterface::ContentHint>(hint));
|
||||
}
|
||||
@@ -110,4 +170,83 @@ std::unique_ptr<NativeVideoFrameSink> create_native_video_frame_sink(
|
||||
return std::make_unique<NativeVideoFrameSink>(std::move(observer));
|
||||
}
|
||||
|
||||
NativeVideoTrackSource::NativeVideoTrackSource()
|
||||
: rtc::AdaptedVideoTrackSource(1) {}
|
||||
|
||||
NativeVideoTrackSource::~NativeVideoTrackSource() {}
|
||||
|
||||
bool NativeVideoTrackSource::is_screencast() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
absl::optional<bool> NativeVideoTrackSource::needs_denoising() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
webrtc::MediaSourceInterface::SourceState NativeVideoTrackSource::state()
|
||||
const {
|
||||
// TODO(theomonnom): expose source state to Rust
|
||||
return SourceState::kLive;
|
||||
}
|
||||
|
||||
bool NativeVideoTrackSource::remote() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NativeVideoTrackSource::on_captured_frame(
|
||||
const webrtc::VideoFrame& frame) {
|
||||
webrtc::MutexLock lock(&mutex_);
|
||||
|
||||
int64_t aligned_timestamp_us = timestamp_aligner_.TranslateTimestamp(
|
||||
frame.timestamp_us(), rtc::TimeMicros());
|
||||
|
||||
int adapted_width, adapted_height, crop_width, crop_height, crop_x, crop_y;
|
||||
if (!AdaptFrame(frame.width(), frame.height(), frame.timestamp_us(),
|
||||
&adapted_width, &adapted_height, &crop_width, &crop_height,
|
||||
&crop_x, &crop_y)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO(theomonnom): Should this be handled by the users?
|
||||
rtc::scoped_refptr<webrtc::VideoFrameBuffer> buffer =
|
||||
frame.video_frame_buffer();
|
||||
if (adapted_width != frame.width() || adapted_height != frame.height()) {
|
||||
buffer = buffer->CropAndScale(crop_x, crop_y, crop_width, crop_height,
|
||||
adapted_width, adapted_height);
|
||||
}
|
||||
|
||||
if (apply_rotation() && frame.rotation() != webrtc::kVideoRotation_0) {
|
||||
// If the buffer is I420, rtc::AdaptedVideoTrackSource will handle the
|
||||
// rotation for us.
|
||||
buffer = buffer->ToI420();
|
||||
}
|
||||
|
||||
OnFrame(webrtc::VideoFrame::Builder()
|
||||
.set_video_frame_buffer(buffer)
|
||||
.set_rotation(frame.rotation())
|
||||
.set_timestamp_us(aligned_timestamp_us)
|
||||
.build());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
AdaptedVideoTrackSource::AdaptedVideoTrackSource(
|
||||
rtc::scoped_refptr<NativeVideoTrackSource> source)
|
||||
: source_(source) {}
|
||||
|
||||
bool AdaptedVideoTrackSource::on_captured_frame(
|
||||
std::unique_ptr<VideoFrame> frame) const {
|
||||
return source_->on_captured_frame(frame->get());
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<NativeVideoTrackSource> AdaptedVideoTrackSource::get()
|
||||
const {
|
||||
return source_;
|
||||
}
|
||||
|
||||
std::unique_ptr<AdaptedVideoTrackSource> create_adapted_video_track_source() {
|
||||
return std::make_unique<AdaptedVideoTrackSource>(
|
||||
rtc::make_ref_counted<NativeVideoTrackSource>());
|
||||
}
|
||||
|
||||
} // namespace livekit
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use cxx::UniquePtr;
|
||||
|
||||
use crate::impl_thread_safety;
|
||||
use crate::video_frame::ffi::VideoFrame;
|
||||
use cxx::UniquePtr;
|
||||
|
||||
#[cxx::bridge(namespace = "livekit")]
|
||||
pub mod ffi {
|
||||
@@ -22,51 +22,68 @@ pub mod ffi {
|
||||
}
|
||||
|
||||
// -1 = optional
|
||||
#[derive(Debug)]
|
||||
pub struct VideoTrackSourceConstraints {
|
||||
pub min_fps: f64,
|
||||
pub max_fps: f64,
|
||||
}
|
||||
|
||||
extern "C++" {
|
||||
include!("livekit/video_frame.h");
|
||||
include!("livekit/helper.h");
|
||||
|
||||
type VideoFrame = crate::video_frame::ffi::VideoFrame;
|
||||
type VideoTrackPtr = crate::helper::ffi::VideoTrackPtr;
|
||||
type AudioTrackPtr = crate::helper::ffi::AudioTrackPtr;
|
||||
}
|
||||
|
||||
unsafe extern "C++" {
|
||||
include!("livekit/media_stream.h");
|
||||
include!("livekit/video_frame.h");
|
||||
|
||||
type NativeVideoFrameSink;
|
||||
type MediaStreamTrack;
|
||||
type MediaStream;
|
||||
type AudioTrack;
|
||||
type VideoTrack;
|
||||
type VideoFrame = crate::video_frame::ffi::VideoFrame;
|
||||
type AdaptedVideoTrackSource;
|
||||
|
||||
fn id(self: &MediaStream) -> String;
|
||||
fn get_audio_tracks(self: &MediaStream) -> Vec<AudioTrackPtr>;
|
||||
fn get_video_tracks(self: &MediaStream) -> Vec<VideoTrackPtr>;
|
||||
fn find_audio_track(self: &MediaStream, track_id: String) -> SharedPtr<AudioTrack>;
|
||||
fn find_video_track(self: &MediaStream, track_id: String) -> SharedPtr<VideoTrack>;
|
||||
fn add_audio_track(self: &MediaStream, audio_track: SharedPtr<AudioTrack>) -> bool;
|
||||
fn add_video_track(self: &MediaStream, video_track: SharedPtr<VideoTrack>) -> bool;
|
||||
fn remove_audio_track(self: &MediaStream, audio_track: SharedPtr<AudioTrack>) -> bool;
|
||||
fn remove_video_track(self: &MediaStream, video_track: SharedPtr<VideoTrack>) -> bool;
|
||||
|
||||
fn kind(self: &MediaStreamTrack) -> String;
|
||||
fn id(self: &MediaStreamTrack) -> String;
|
||||
fn enabled(self: &MediaStreamTrack) -> bool;
|
||||
fn set_enabled(self: Pin<&mut MediaStreamTrack>, enable: bool) -> bool;
|
||||
fn set_enabled(self: &MediaStreamTrack, enable: bool) -> bool;
|
||||
fn state(self: &MediaStreamTrack) -> TrackState;
|
||||
|
||||
unsafe fn add_sink(self: Pin<&mut VideoTrack>, sink: Pin<&mut NativeVideoFrameSink>);
|
||||
unsafe fn remove_sink(self: Pin<&mut VideoTrack>, sink: Pin<&mut NativeVideoFrameSink>);
|
||||
unsafe fn add_sink(self: &VideoTrack, sink: Pin<&mut NativeVideoFrameSink>);
|
||||
unsafe fn remove_sink(self: &VideoTrack, sink: Pin<&mut NativeVideoFrameSink>);
|
||||
|
||||
fn set_should_receive(self: Pin<&mut VideoTrack>, should_receive: bool);
|
||||
fn set_should_receive(self: &VideoTrack, should_receive: bool);
|
||||
fn should_receive(self: &VideoTrack) -> bool;
|
||||
fn content_hint(self: &VideoTrack) -> ContentHint;
|
||||
fn set_content_hint(self: Pin<&mut VideoTrack>, hint: ContentHint);
|
||||
fn set_content_hint(self: &VideoTrack, hint: ContentHint);
|
||||
|
||||
fn create_native_video_frame_sink(
|
||||
observer: Box<VideoFrameSinkWrapper>,
|
||||
) -> UniquePtr<NativeVideoFrameSink>;
|
||||
|
||||
unsafe fn video_to_media(track: *const VideoTrack) -> *const MediaStreamTrack;
|
||||
unsafe fn audio_to_media(track: *const AudioTrack) -> *const MediaStreamTrack;
|
||||
fn on_captured_frame(self: &AdaptedVideoTrackSource, frame: UniquePtr<VideoFrame>) -> bool;
|
||||
|
||||
unsafe fn media_to_video(track: *const MediaStreamTrack) -> *const VideoTrack;
|
||||
unsafe fn media_to_audio(track: *const MediaStreamTrack) -> *const AudioTrack;
|
||||
|
||||
fn _unique_media_stream_track() -> UniquePtr<MediaStreamTrack>; // Ignore
|
||||
fn _unique_media_stream() -> UniquePtr<MediaStream>; // Ignore
|
||||
fn _unique_audio_track() -> UniquePtr<AudioTrack>; // Ignore
|
||||
fn _unique_video_track() -> UniquePtr<VideoTrack>; // Ignore
|
||||
fn _shared_media_stream_track() -> SharedPtr<MediaStreamTrack>;
|
||||
fn _shared_audio_track() -> SharedPtr<AudioTrack>;
|
||||
fn _shared_video_track() -> SharedPtr<VideoTrack>;
|
||||
fn _shared_media_stream() -> SharedPtr<MediaStream>;
|
||||
}
|
||||
|
||||
extern "Rust" {
|
||||
@@ -81,16 +98,11 @@ pub mod ffi {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Sync for ffi::MediaStreamTrack {}
|
||||
unsafe impl Send for ffi::MediaStreamTrack {}
|
||||
unsafe impl Sync for ffi::MediaStream {}
|
||||
unsafe impl Send for ffi::MediaStream {}
|
||||
unsafe impl Send for ffi::AudioTrack {}
|
||||
unsafe impl Sync for ffi::AudioTrack {}
|
||||
unsafe impl Send for ffi::VideoTrack {}
|
||||
unsafe impl Sync for ffi::VideoTrack {}
|
||||
unsafe impl Send for ffi::NativeVideoFrameSink {}
|
||||
unsafe impl Sync for ffi::NativeVideoFrameSink {}
|
||||
impl_thread_safety!(ffi::MediaStreamTrack, Send + Sync);
|
||||
impl_thread_safety!(ffi::MediaStream, Send + Sync);
|
||||
impl_thread_safety!(ffi::AudioTrack, Send + Sync);
|
||||
impl_thread_safety!(ffi::VideoTrack, Send + Sync);
|
||||
impl_thread_safety!(ffi::NativeVideoFrameSink, Send + Sync);
|
||||
|
||||
pub trait VideoFrameSink: Send + Sync {
|
||||
fn on_frame(&self, frame: UniquePtr<VideoFrame>);
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
//
|
||||
|
||||
#include "livekit/peer_connection.h"
|
||||
#include "livekit/media_stream.h"
|
||||
|
||||
#include "webrtc-sys/src/peer_connection.rs.h"
|
||||
#include "livekit/media_stream.h"
|
||||
#include "livekit/rtc_error.h"
|
||||
#include "livekit/rtp_transceiver.h"
|
||||
|
||||
namespace livekit {
|
||||
|
||||
@@ -32,35 +32,35 @@ PeerConnection::PeerConnection(
|
||||
|
||||
void PeerConnection::create_offer(
|
||||
NativeCreateSdpObserverHandle& observer_handle,
|
||||
RTCOfferAnswerOptions options) {
|
||||
RTCOfferAnswerOptions options) const {
|
||||
peer_connection_->CreateOffer(observer_handle.observer.get(),
|
||||
toNativeOfferAnswerOptions(options));
|
||||
}
|
||||
|
||||
void PeerConnection::create_answer(
|
||||
NativeCreateSdpObserverHandle& observer_handle,
|
||||
RTCOfferAnswerOptions options) {
|
||||
RTCOfferAnswerOptions options) const {
|
||||
peer_connection_->CreateAnswer(observer_handle.observer.get(),
|
||||
toNativeOfferAnswerOptions(options));
|
||||
}
|
||||
|
||||
void PeerConnection::set_local_description(
|
||||
std::unique_ptr<SessionDescription> desc,
|
||||
NativeSetLocalSdpObserverHandle& observer) {
|
||||
NativeSetLocalSdpObserverHandle& observer) const {
|
||||
peer_connection_->SetLocalDescription(desc->clone()->release(),
|
||||
observer.observer);
|
||||
}
|
||||
|
||||
void PeerConnection::set_remote_description(
|
||||
std::unique_ptr<SessionDescription> desc,
|
||||
NativeSetRemoteSdpObserverHandle& observer) {
|
||||
NativeSetRemoteSdpObserverHandle& observer) const {
|
||||
peer_connection_->SetRemoteDescription(desc->clone()->release(),
|
||||
observer.observer);
|
||||
}
|
||||
|
||||
std::unique_ptr<DataChannel> PeerConnection::create_data_channel(
|
||||
rust::String label,
|
||||
std::unique_ptr<NativeDataChannelInit> init) {
|
||||
std::unique_ptr<NativeDataChannelInit> init) const {
|
||||
auto result =
|
||||
peer_connection_->CreateDataChannelOrError(label.c_str(), init.get());
|
||||
|
||||
@@ -71,9 +71,76 @@ std::unique_ptr<DataChannel> PeerConnection::create_data_channel(
|
||||
return std::make_unique<DataChannel>(rtc_runtime_, result.value());
|
||||
}
|
||||
|
||||
std::shared_ptr<RtpSender> PeerConnection::add_track(
|
||||
std::shared_ptr<MediaStreamTrack> track,
|
||||
const rust::Vec<rust::String>& stream_ids) const {
|
||||
std::vector<std::string> std_stream_ids(stream_ids.begin(), stream_ids.end());
|
||||
auto result = peer_connection_->AddTrack(track->get(), std_stream_ids);
|
||||
if (!result.ok()) {
|
||||
throw std::runtime_error(serialize_error(to_error(result.error())));
|
||||
}
|
||||
|
||||
return std::make_shared<RtpSender>(result.value());
|
||||
}
|
||||
|
||||
void PeerConnection::remove_track(std::shared_ptr<RtpSender> sender) const {
|
||||
auto error = peer_connection_->RemoveTrackOrError(sender->get());
|
||||
if (!error.ok())
|
||||
throw std::runtime_error(serialize_error(to_error(error)));
|
||||
}
|
||||
|
||||
std::shared_ptr<RtpTransceiver> PeerConnection::add_transceiver(
|
||||
std::shared_ptr<MediaStreamTrack> track,
|
||||
RtpTransceiverInit init) const {
|
||||
auto result = peer_connection_->AddTransceiver(
|
||||
track->get(), to_native_rtp_transceiver_init(init));
|
||||
if (result.ok())
|
||||
throw std::runtime_error(serialize_error(to_error(result.error())));
|
||||
|
||||
return std::make_shared<RtpTransceiver>(result.value());
|
||||
}
|
||||
|
||||
std::shared_ptr<RtpTransceiver> PeerConnection::add_transceiver_for_media(
|
||||
MediaType media_type,
|
||||
RtpTransceiverInit init) const {
|
||||
auto result = peer_connection_->AddTransceiver(
|
||||
static_cast<cricket::MediaType>(media_type),
|
||||
to_native_rtp_transceiver_init(init));
|
||||
|
||||
if (result.ok())
|
||||
throw std::runtime_error(serialize_error(to_error(result.error())));
|
||||
|
||||
return std::make_shared<RtpTransceiver>(result.value());
|
||||
}
|
||||
|
||||
rust::Vec<RtpSenderPtr> PeerConnection::get_senders() const {
|
||||
rust::Vec<RtpSenderPtr> vec;
|
||||
for (auto sender : peer_connection_->GetSenders())
|
||||
vec.push_back(RtpSenderPtr{std::make_shared<RtpSender>(sender)});
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
rust::Vec<RtpReceiverPtr> PeerConnection::get_receivers() const {
|
||||
rust::Vec<RtpReceiverPtr> vec;
|
||||
for (auto receiver : peer_connection_->GetReceivers())
|
||||
vec.push_back(RtpReceiverPtr{std::make_shared<RtpReceiver>(receiver)});
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
rust::Vec<RtpTransceiverPtr> PeerConnection::get_transceivers() const {
|
||||
rust::Vec<RtpTransceiverPtr> vec;
|
||||
for (auto transceiver : peer_connection_->GetTransceivers())
|
||||
vec.push_back(
|
||||
RtpTransceiverPtr{std::make_shared<RtpTransceiver>(transceiver)});
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
void PeerConnection::add_ice_candidate(
|
||||
std::unique_ptr<IceCandidate> candidate,
|
||||
NativeAddIceCandidateObserver& observer) {
|
||||
std::shared_ptr<IceCandidate> candidate,
|
||||
NativeAddIceCandidateObserver& observer) const {
|
||||
peer_connection_->AddIceCandidate(
|
||||
candidate->release(),
|
||||
[&](const webrtc::RTCError& err) { observer.OnComplete(to_error(err)); });
|
||||
|
||||
@@ -1,21 +1,19 @@
|
||||
use std::fmt::Debug;
|
||||
use std::mem::ManuallyDrop;
|
||||
|
||||
use cxx::UniquePtr;
|
||||
|
||||
use crate::candidate::ffi::Candidate;
|
||||
use crate::data_channel::ffi::DataChannel;
|
||||
use crate::impl_thread_safety;
|
||||
use crate::jsep::ffi::IceCandidate;
|
||||
use crate::media_stream::ffi::MediaStream;
|
||||
use crate::rtc_error::ffi::RTCError;
|
||||
use crate::rtp_receiver::ffi::RtpReceiver;
|
||||
use crate::rtp_transceiver::ffi::RtpTransceiver;
|
||||
use cxx::{SharedPtr, UniquePtr};
|
||||
use std::mem::ManuallyDrop;
|
||||
|
||||
#[cxx::bridge(namespace = "livekit")]
|
||||
pub mod ffi {
|
||||
struct CandidatePair {
|
||||
local: UniquePtr<Candidate>,
|
||||
remote: UniquePtr<Candidate>,
|
||||
local: SharedPtr<Candidate>,
|
||||
remote: SharedPtr<Candidate>,
|
||||
}
|
||||
|
||||
struct CandidatePairChangeEvent {
|
||||
@@ -80,39 +78,44 @@ pub mod ffi {
|
||||
use_obsolete_sctp_sdp: bool,
|
||||
}
|
||||
|
||||
// Wrapper to opaque C++ objects
|
||||
// https://github.com/dtolnay/cxx/issues/741
|
||||
struct MediaStreamPtr {
|
||||
pub ptr: UniquePtr<MediaStream>,
|
||||
}
|
||||
|
||||
struct CandidatePtr {
|
||||
pub ptr: UniquePtr<Candidate>,
|
||||
}
|
||||
|
||||
unsafe extern "C++" {
|
||||
include!("livekit/peer_connection.h");
|
||||
include!("livekit/jsep.h");
|
||||
include!("livekit/data_channel.h");
|
||||
include!("livekit/rtp_receiver.h");
|
||||
include!("livekit/rtp_transceiver.h");
|
||||
include!("livekit/media_stream.h");
|
||||
extern "C++" {
|
||||
include!("livekit/rtc_error.h");
|
||||
include!("livekit/helper.h");
|
||||
include!("livekit/candidate.h");
|
||||
include!("webrtc-sys/src/rtc_error.rs.h");
|
||||
include!("livekit/media_stream.h");
|
||||
include!("livekit/rtp_transceiver.h");
|
||||
include!("livekit/rtp_sender.h");
|
||||
include!("livekit/rtp_receiver.h");
|
||||
include!("livekit/data_channel.h");
|
||||
include!("livekit/jsep.h");
|
||||
include!("livekit/webrtc.h");
|
||||
|
||||
type MediaStreamPtr = crate::helper::ffi::MediaStreamPtr;
|
||||
type CandidatePtr = crate::helper::ffi::CandidatePtr;
|
||||
type RtpSenderPtr = crate::helper::ffi::RtpSenderPtr;
|
||||
type RtpReceiverPtr = crate::helper::ffi::RtpReceiverPtr;
|
||||
type RtpTransceiverPtr = crate::helper::ffi::RtpTransceiverPtr;
|
||||
type RTCError = crate::rtc_error::ffi::RTCError;
|
||||
type Candidate = crate::candidate::ffi::Candidate;
|
||||
type IceCandidate = crate::jsep::ffi::IceCandidate;
|
||||
type DataChannel = crate::data_channel::ffi::DataChannel;
|
||||
type RtpSender = crate::rtp_sender::ffi::RtpSender;
|
||||
type RtpReceiver = crate::rtp_receiver::ffi::RtpReceiver;
|
||||
type RtpTransceiver = crate::rtp_transceiver::ffi::RtpTransceiver;
|
||||
type RtpTransceiverInit = crate::rtp_transceiver::ffi::RtpTransceiverInit;
|
||||
type MediaStream = crate::media_stream::ffi::MediaStream;
|
||||
type MediaStreamTrack = crate::media_stream::ffi::MediaStreamTrack;
|
||||
type NativeCreateSdpObserverHandle = crate::jsep::ffi::NativeCreateSdpObserverHandle;
|
||||
type NativeSetLocalSdpObserverHandle = crate::jsep::ffi::NativeSetLocalSdpObserverHandle;
|
||||
type NativeSetRemoteSdpObserverHandle = crate::jsep::ffi::NativeSetRemoteSdpObserverHandle;
|
||||
type NativeDataChannelInit = crate::data_channel::ffi::NativeDataChannelInit;
|
||||
type SessionDescription = crate::jsep::ffi::SessionDescription;
|
||||
type MediaType = crate::webrtc::ffi::MediaType;
|
||||
type RTCRuntime = crate::webrtc::ffi::RTCRuntime;
|
||||
}
|
||||
|
||||
unsafe extern "C++" {
|
||||
include!("livekit/peer_connection.h");
|
||||
|
||||
type NativeAddIceCandidateObserver;
|
||||
type NativePeerConnectionObserver;
|
||||
@@ -121,7 +124,7 @@ pub mod ffi {
|
||||
/// SAFETY
|
||||
/// The observer must live as long as the operation ends
|
||||
unsafe fn create_offer(
|
||||
self: Pin<&mut PeerConnection>,
|
||||
self: &PeerConnection,
|
||||
observer: Pin<&mut NativeCreateSdpObserverHandle>,
|
||||
options: RTCOfferAnswerOptions,
|
||||
);
|
||||
@@ -129,7 +132,7 @@ pub mod ffi {
|
||||
/// SAFETY
|
||||
/// The observer must live as long as the operation ends
|
||||
unsafe fn create_answer(
|
||||
self: Pin<&mut PeerConnection>,
|
||||
self: &PeerConnection,
|
||||
observer: Pin<&mut NativeCreateSdpObserverHandle>,
|
||||
options: RTCOfferAnswerOptions,
|
||||
);
|
||||
@@ -137,7 +140,7 @@ pub mod ffi {
|
||||
/// SAFETY
|
||||
/// The observer must live as long as the operation ends
|
||||
unsafe fn set_local_description(
|
||||
self: Pin<&mut PeerConnection>,
|
||||
self: &PeerConnection,
|
||||
desc: UniquePtr<SessionDescription>,
|
||||
observer: Pin<&mut NativeSetLocalSdpObserverHandle>,
|
||||
);
|
||||
@@ -145,20 +148,46 @@ pub mod ffi {
|
||||
/// SAFETY
|
||||
/// The observer must live as long as the operation ends
|
||||
unsafe fn set_remote_description(
|
||||
self: Pin<&mut PeerConnection>,
|
||||
self: &PeerConnection,
|
||||
desc: UniquePtr<SessionDescription>,
|
||||
observer: Pin<&mut NativeSetRemoteSdpObserverHandle>,
|
||||
);
|
||||
|
||||
fn add_track(
|
||||
self: &PeerConnection,
|
||||
track: SharedPtr<MediaStreamTrack>,
|
||||
stream_ids: &Vec<String>,
|
||||
) -> Result<SharedPtr<RtpSender>>;
|
||||
|
||||
fn remove_track(self: &PeerConnection, sender: SharedPtr<RtpSender>) -> Result<()>;
|
||||
|
||||
fn add_transceiver(
|
||||
self: &PeerConnection,
|
||||
track: SharedPtr<MediaStreamTrack>,
|
||||
init: RtpTransceiverInit,
|
||||
) -> Result<SharedPtr<RtpTransceiver>>;
|
||||
|
||||
fn add_transceiver_for_media(
|
||||
self: &PeerConnection,
|
||||
media_type: MediaType,
|
||||
init: RtpTransceiverInit,
|
||||
) -> Result<SharedPtr<RtpTransceiver>>;
|
||||
|
||||
fn get_senders(self: &PeerConnection) -> Vec<RtpSenderPtr>;
|
||||
|
||||
fn get_receivers(self: &PeerConnection) -> Vec<RtpReceiverPtr>;
|
||||
|
||||
fn get_transceivers(self: &PeerConnection) -> Vec<RtpTransceiverPtr>;
|
||||
|
||||
fn create_data_channel(
|
||||
self: Pin<&mut PeerConnection>,
|
||||
self: &PeerConnection,
|
||||
label: String,
|
||||
init: UniquePtr<NativeDataChannelInit>,
|
||||
) -> Result<UniquePtr<DataChannel>>;
|
||||
|
||||
fn add_ice_candidate(
|
||||
self: Pin<&mut PeerConnection>,
|
||||
candidate: UniquePtr<IceCandidate>,
|
||||
self: &PeerConnection,
|
||||
candidate: SharedPtr<IceCandidate>,
|
||||
observer: Pin<&mut NativeAddIceCandidateObserver>,
|
||||
);
|
||||
|
||||
@@ -194,8 +223,8 @@ pub mod ffi {
|
||||
type PeerConnectionObserverWrapper;
|
||||
|
||||
fn on_signaling_change(self: &PeerConnectionObserverWrapper, new_state: SignalingState);
|
||||
fn on_add_stream(self: &PeerConnectionObserverWrapper, stream: UniquePtr<MediaStream>);
|
||||
fn on_remove_stream(self: &PeerConnectionObserverWrapper, stream: UniquePtr<MediaStream>);
|
||||
fn on_add_stream(self: &PeerConnectionObserverWrapper, stream: SharedPtr<MediaStream>);
|
||||
fn on_remove_stream(self: &PeerConnectionObserverWrapper, stream: SharedPtr<MediaStream>);
|
||||
fn on_data_channel(
|
||||
self: &PeerConnectionObserverWrapper,
|
||||
data_channel: UniquePtr<DataChannel>,
|
||||
@@ -220,7 +249,7 @@ pub mod ffi {
|
||||
);
|
||||
fn on_ice_candidate(
|
||||
self: &PeerConnectionObserverWrapper,
|
||||
candidate: UniquePtr<IceCandidate>,
|
||||
candidate: SharedPtr<IceCandidate>,
|
||||
);
|
||||
fn on_ice_candidate_error(
|
||||
self: &PeerConnectionObserverWrapper,
|
||||
@@ -244,39 +273,22 @@ pub mod ffi {
|
||||
);
|
||||
fn on_add_track(
|
||||
self: &PeerConnectionObserverWrapper,
|
||||
receiver: UniquePtr<RtpReceiver>,
|
||||
receiver: SharedPtr<RtpReceiver>,
|
||||
streams: Vec<MediaStreamPtr>,
|
||||
);
|
||||
fn on_track(self: &PeerConnectionObserverWrapper, transceiver: UniquePtr<RtpTransceiver>);
|
||||
fn on_remove_track(self: &PeerConnectionObserverWrapper, receiver: UniquePtr<RtpReceiver>);
|
||||
fn on_track(self: &PeerConnectionObserverWrapper, transceiver: SharedPtr<RtpTransceiver>);
|
||||
fn on_remove_track(self: &PeerConnectionObserverWrapper, receiver: SharedPtr<RtpReceiver>);
|
||||
fn on_interesting_usage(self: &PeerConnectionObserverWrapper, usage_pattern: i32);
|
||||
}
|
||||
}
|
||||
|
||||
// https://webrtc.github.io/webrtc-org/native-code/native-apis/
|
||||
unsafe impl Send for ffi::PeerConnection {}
|
||||
|
||||
unsafe impl Sync for ffi::PeerConnection {}
|
||||
|
||||
unsafe impl Send for ffi::NativePeerConnectionObserver {}
|
||||
|
||||
unsafe impl Sync for ffi::NativePeerConnectionObserver {}
|
||||
|
||||
unsafe impl Sync for ffi::NativeAddIceCandidateObserver {}
|
||||
|
||||
unsafe impl Send for ffi::NativeAddIceCandidateObserver {}
|
||||
|
||||
unsafe impl Sync for ffi::NativeSetRemoteSdpObserverHandle {}
|
||||
|
||||
unsafe impl Send for ffi::NativeSetRemoteSdpObserverHandle {}
|
||||
|
||||
unsafe impl Sync for ffi::NativeSetLocalSdpObserverHandle {}
|
||||
|
||||
unsafe impl Send for ffi::NativeSetLocalSdpObserverHandle {}
|
||||
|
||||
unsafe impl Sync for ffi::NativeCreateSdpObserverHandle {}
|
||||
|
||||
unsafe impl Send for ffi::NativeCreateSdpObserverHandle {}
|
||||
impl_thread_safety!(ffi::PeerConnection, Send + Sync);
|
||||
impl_thread_safety!(ffi::NativePeerConnectionObserver, Send + Sync);
|
||||
impl_thread_safety!(ffi::NativeAddIceCandidateObserver, Send + Sync);
|
||||
impl_thread_safety!(ffi::NativeSetRemoteSdpObserverHandle, Send + Sync);
|
||||
impl_thread_safety!(ffi::NativeSetLocalSdpObserverHandle, Send + Sync);
|
||||
impl_thread_safety!(ffi::NativeCreateSdpObserverHandle, Send + Sync);
|
||||
|
||||
impl Default for ffi::RTCOfferAnswerOptions {
|
||||
/*
|
||||
@@ -311,8 +323,8 @@ impl AddIceCandidateObserverWrapper {
|
||||
|
||||
pub trait PeerConnectionObserver: Send + Sync {
|
||||
fn on_signaling_change(&self, new_state: ffi::SignalingState);
|
||||
fn on_add_stream(&self, stream: UniquePtr<MediaStream>);
|
||||
fn on_remove_stream(&self, stream: UniquePtr<MediaStream>);
|
||||
fn on_add_stream(&self, stream: SharedPtr<MediaStream>);
|
||||
fn on_remove_stream(&self, stream: SharedPtr<MediaStream>);
|
||||
fn on_data_channel(&self, data_channel: UniquePtr<DataChannel>);
|
||||
fn on_renegotiation_needed(&self);
|
||||
fn on_negotiation_needed_event(&self, event: u32);
|
||||
@@ -320,7 +332,7 @@ pub trait PeerConnectionObserver: Send + Sync {
|
||||
fn on_standardized_ice_connection_change(&self, new_state: ffi::IceConnectionState);
|
||||
fn on_connection_change(&self, new_state: ffi::PeerConnectionState);
|
||||
fn on_ice_gathering_change(&self, new_state: ffi::IceGatheringState);
|
||||
fn on_ice_candidate(&self, candidate: UniquePtr<IceCandidate>);
|
||||
fn on_ice_candidate(&self, candidate: SharedPtr<IceCandidate>);
|
||||
fn on_ice_candidate_error(
|
||||
&self,
|
||||
address: String,
|
||||
@@ -329,12 +341,12 @@ pub trait PeerConnectionObserver: Send + Sync {
|
||||
error_code: i32,
|
||||
error_text: String,
|
||||
);
|
||||
fn on_ice_candidates_removed(&self, removed: Vec<UniquePtr<Candidate>>);
|
||||
fn on_ice_candidates_removed(&self, removed: Vec<SharedPtr<Candidate>>);
|
||||
fn on_ice_connection_receiving_change(&self, receiving: bool);
|
||||
fn on_ice_selected_candidate_pair_changed(&self, event: ffi::CandidatePairChangeEvent);
|
||||
fn on_add_track(&self, receiver: UniquePtr<RtpReceiver>, streams: Vec<UniquePtr<MediaStream>>);
|
||||
fn on_track(&self, transceiver: UniquePtr<RtpTransceiver>);
|
||||
fn on_remove_track(&self, receiver: UniquePtr<RtpReceiver>);
|
||||
fn on_add_track(&self, receiver: SharedPtr<RtpReceiver>, streams: Vec<SharedPtr<MediaStream>>);
|
||||
fn on_track(&self, transceiver: SharedPtr<RtpTransceiver>);
|
||||
fn on_remove_track(&self, receiver: SharedPtr<RtpReceiver>);
|
||||
fn on_interesting_usage(&self, usage_pattern: i32);
|
||||
}
|
||||
|
||||
@@ -356,13 +368,13 @@ impl PeerConnectionObserverWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
fn on_add_stream(&self, stream: UniquePtr<MediaStream>) {
|
||||
fn on_add_stream(&self, stream: SharedPtr<MediaStream>) {
|
||||
unsafe {
|
||||
(*self.observer).on_add_stream(stream);
|
||||
}
|
||||
}
|
||||
|
||||
fn on_remove_stream(&self, stream: UniquePtr<MediaStream>) {
|
||||
fn on_remove_stream(&self, stream: SharedPtr<MediaStream>) {
|
||||
unsafe {
|
||||
(*self.observer).on_remove_stream(stream);
|
||||
}
|
||||
@@ -410,7 +422,7 @@ impl PeerConnectionObserverWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
fn on_ice_candidate(&self, candidate: UniquePtr<IceCandidate>) {
|
||||
fn on_ice_candidate(&self, candidate: SharedPtr<IceCandidate>) {
|
||||
unsafe {
|
||||
(*self.observer).on_ice_candidate(candidate);
|
||||
}
|
||||
@@ -453,7 +465,7 @@ impl PeerConnectionObserverWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
fn on_add_track(&self, receiver: UniquePtr<RtpReceiver>, streams: Vec<ffi::MediaStreamPtr>) {
|
||||
fn on_add_track(&self, receiver: SharedPtr<RtpReceiver>, streams: Vec<ffi::MediaStreamPtr>) {
|
||||
let mut vec = Vec::new();
|
||||
|
||||
for v in streams {
|
||||
@@ -465,13 +477,13 @@ impl PeerConnectionObserverWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
fn on_track(&self, transceiver: UniquePtr<RtpTransceiver>) {
|
||||
fn on_track(&self, transceiver: SharedPtr<RtpTransceiver>) {
|
||||
unsafe {
|
||||
(*self.observer).on_track(transceiver);
|
||||
}
|
||||
}
|
||||
|
||||
fn on_remove_track(&self, receiver: UniquePtr<RtpReceiver>) {
|
||||
fn on_remove_track(&self, receiver: SharedPtr<RtpReceiver>) {
|
||||
unsafe {
|
||||
(*self.observer).on_remove_track(receiver);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#include "livekit/video_decoder_factory.h"
|
||||
#include "livekit/video_encoder_factory.h"
|
||||
#include "media/engine/webrtc_media_engine.h"
|
||||
#include "webrtc-sys/src/peer_connection_factory.rs.h"
|
||||
|
||||
namespace livekit {
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use crate::impl_thread_safety;
|
||||
|
||||
#[cxx::bridge(namespace = "livekit")]
|
||||
pub mod ffi {
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -55,6 +57,4 @@ pub mod ffi {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for ffi::PeerConnectionFactory {}
|
||||
|
||||
unsafe impl Sync for ffi::PeerConnectionFactory {}
|
||||
impl_thread_safety!(ffi::PeerConnectionFactory, Send + Sync);
|
||||
|
||||
@@ -53,4 +53,4 @@ void throw_error() {
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace livekit
|
||||
} // namespace livekit
|
||||
|
||||
@@ -0,0 +1,446 @@
|
||||
#include "livekit/rtp_parameters.h"
|
||||
|
||||
namespace livekit {
|
||||
|
||||
webrtc::RtcpFeedback to_native_rtcp_feedback(RtcpFeedback feedback) {
|
||||
webrtc::RtcpFeedback native;
|
||||
native.type = static_cast<webrtc::RtcpFeedbackType>(feedback.feedback_type);
|
||||
if (feedback.has_message_type)
|
||||
native.message_type =
|
||||
static_cast<webrtc::RtcpFeedbackMessageType>(feedback.message_type);
|
||||
|
||||
return native;
|
||||
}
|
||||
|
||||
webrtc::RtpCodecCapability to_native_rtp_codec_capability(
|
||||
RtpCodecCapability capability) {
|
||||
webrtc::RtpCodecCapability native;
|
||||
// native.mime_type(); IGNORED
|
||||
|
||||
native.name = capability.name.c_str();
|
||||
native.kind = static_cast<cricket::MediaType>(capability.kind);
|
||||
|
||||
if (capability.has_clock_rate)
|
||||
native.clock_rate = native.clock_rate;
|
||||
|
||||
if (capability.has_preferred_payload_type)
|
||||
native.preferred_payload_type = capability.preferred_payload_type;
|
||||
|
||||
if (capability.has_max_ptime)
|
||||
native.max_ptime = capability.max_ptime;
|
||||
|
||||
if (capability.has_ptime)
|
||||
native.ptime = capability.ptime;
|
||||
|
||||
if (capability.has_num_channels)
|
||||
native.num_channels = capability.num_channels;
|
||||
|
||||
for (auto feedback : capability.rtcp_feedback)
|
||||
native.rtcp_feedback.push_back(to_native_rtcp_feedback(feedback));
|
||||
|
||||
for (auto pair : capability.parameters)
|
||||
native.parameters.insert(std::pair(pair.key, pair.value));
|
||||
|
||||
for (auto pair : capability.options)
|
||||
native.options.insert(std::pair(pair.key, pair.value));
|
||||
|
||||
native.max_temporal_layer_extensions =
|
||||
capability.max_temporal_layer_extensions;
|
||||
|
||||
native.max_spatial_layer_extensions = capability.max_spatial_layer_extensions;
|
||||
|
||||
native.svc_multi_stream_support = capability.svc_multi_stream_support;
|
||||
|
||||
return native;
|
||||
}
|
||||
|
||||
webrtc::RtpHeaderExtensionCapability to_native_rtp_header_extension_capability(
|
||||
RtpHeaderExtensionCapability header) {
|
||||
webrtc::RtpHeaderExtensionCapability native;
|
||||
native.uri = header.uri.c_str();
|
||||
|
||||
if (header.has_preferred_id)
|
||||
native.preferred_id = header.preferred_id;
|
||||
|
||||
native.preferred_encrypt = header.preferred_encrypt;
|
||||
native.direction =
|
||||
static_cast<webrtc::RtpTransceiverDirection>(header.direction);
|
||||
|
||||
return native;
|
||||
}
|
||||
|
||||
webrtc::RtpExtension to_native_rtp_extension(RtpExtension ext) {
|
||||
webrtc::RtpExtension native;
|
||||
native.uri = ext.uri.c_str();
|
||||
native.id = ext.id;
|
||||
native.encrypt = ext.encrypt;
|
||||
return native;
|
||||
}
|
||||
|
||||
webrtc::RtpFecParameters to_rtp_fec_parameters(RtpFecParameters fec) {
|
||||
webrtc::RtpFecParameters native;
|
||||
|
||||
if (fec.has_ssrc)
|
||||
native.ssrc = fec.ssrc;
|
||||
|
||||
native.mechanism = static_cast<webrtc::FecMechanism>(fec.mechanism);
|
||||
return native;
|
||||
}
|
||||
|
||||
webrtc::RtpRtxParameters to_rtp_rtx_parameters(RtpRtxParameters rtx) {
|
||||
webrtc::RtpRtxParameters native;
|
||||
|
||||
if (rtx.has_ssrc)
|
||||
native.ssrc = rtx.ssrc;
|
||||
return native;
|
||||
}
|
||||
|
||||
webrtc::RtpEncodingParameters to_native_rtp_encoding_paramters(
|
||||
RtpEncodingParameters parameters) {
|
||||
webrtc::RtpEncodingParameters native;
|
||||
native.rid = parameters.rid.c_str();
|
||||
|
||||
if (parameters.has_ssrc)
|
||||
native.ssrc = parameters.ssrc;
|
||||
|
||||
native.active = parameters.active;
|
||||
if (parameters.has_max_framerate)
|
||||
native.max_framerate = parameters.max_framerate;
|
||||
|
||||
native.adaptive_ptime = parameters.adaptive_ptime;
|
||||
if (parameters.has_max_bitrate_bps)
|
||||
native.max_bitrate_bps = parameters.max_bitrate_bps;
|
||||
|
||||
if (parameters.has_min_bitrate_bps)
|
||||
native.min_bitrate_bps = parameters.min_bitrate_bps;
|
||||
|
||||
native.bitrate_priority = parameters.bitrate_priority;
|
||||
native.network_priority =
|
||||
static_cast<webrtc::Priority>(parameters.network_priority);
|
||||
|
||||
if (parameters.has_scalability_mode)
|
||||
native.scalability_mode = parameters.scalability_mode.c_str();
|
||||
|
||||
if (parameters.has_num_temporal_layers)
|
||||
native.num_temporal_layers = parameters.num_temporal_layers;
|
||||
|
||||
if (parameters.has_scale_resolution_down_by)
|
||||
native.scale_resolution_down_by = parameters.scale_resolution_down_by;
|
||||
return native;
|
||||
}
|
||||
|
||||
webrtc::RtpCodecParameters to_native_rtp_codec_parameters(
|
||||
RtpCodecParameters params) {
|
||||
webrtc::RtpCodecParameters native;
|
||||
native.name = params.name.c_str();
|
||||
native.kind = static_cast<cricket::MediaType>(params.kind);
|
||||
native.payload_type = params.payload_type;
|
||||
|
||||
for (auto pair : params.parameters)
|
||||
native.parameters.insert(std::pair(pair.key, pair.value));
|
||||
|
||||
for (auto feedback : params.rtcp_feedback)
|
||||
native.rtcp_feedback.push_back(to_native_rtcp_feedback(feedback));
|
||||
|
||||
if (params.has_num_channels)
|
||||
native.num_channels = params.num_channels;
|
||||
|
||||
if (params.has_ptime)
|
||||
native.ptime = params.ptime;
|
||||
|
||||
if (params.has_max_ptime)
|
||||
native.max_ptime = params.max_ptime;
|
||||
|
||||
if (params.has_clock_rate)
|
||||
native.clock_rate = params.clock_rate;
|
||||
|
||||
return native;
|
||||
}
|
||||
|
||||
webrtc::RtpCapabilities to_rtp_capabilities(RtpCapabilities capabilities) {
|
||||
webrtc::RtpCapabilities native;
|
||||
for (auto codec : capabilities.codecs)
|
||||
native.codecs.push_back(to_native_rtp_codec_capability(codec));
|
||||
|
||||
for (auto header : capabilities.header_extensions)
|
||||
native.header_extensions.push_back(
|
||||
to_native_rtp_header_extension_capability(header));
|
||||
|
||||
for (auto fec : capabilities.fec)
|
||||
native.fec.push_back(static_cast<webrtc::FecMechanism>(fec));
|
||||
|
||||
return native;
|
||||
}
|
||||
|
||||
webrtc::RtcpParameters to_native_rtcp_paramaters(RtcpParameters params) {
|
||||
webrtc::RtcpParameters native;
|
||||
if (params.has_ssrc)
|
||||
native.ssrc = params.ssrc;
|
||||
|
||||
native.mux = params.mux;
|
||||
native.cname = params.cname.c_str();
|
||||
native.reduced_size = params.reduced_size;
|
||||
return native;
|
||||
}
|
||||
|
||||
webrtc::RtpParameters to_native_rtp_parameters(RtpParameters params) {
|
||||
webrtc::RtpParameters native;
|
||||
native.transaction_id = params.transaction_id.c_str();
|
||||
native.mid = params.mid.c_str();
|
||||
|
||||
for (auto codec : params.codecs)
|
||||
native.codecs.push_back(to_native_rtp_codec_parameters(codec));
|
||||
|
||||
for (auto header : params.header_extensions)
|
||||
native.header_extensions.push_back(to_native_rtp_extension(header));
|
||||
|
||||
for (auto encoding : params.encodings)
|
||||
native.encodings.push_back(to_native_rtp_encoding_paramters(encoding));
|
||||
|
||||
native.rtcp = to_native_rtcp_paramaters(params.rtcp);
|
||||
|
||||
if (params.has_degradation_preference)
|
||||
native.degradation_preference = static_cast<webrtc::DegradationPreference>(
|
||||
params.degradation_preference);
|
||||
|
||||
return native;
|
||||
}
|
||||
|
||||
RtcpFeedback to_rust_rtcp_feedback(webrtc::RtcpFeedback feedback) {
|
||||
RtcpFeedback rust;
|
||||
rust.feedback_type = static_cast<RtcpFeedbackType>(feedback.type);
|
||||
|
||||
if (feedback.message_type.has_value()) {
|
||||
rust.has_message_type = true;
|
||||
rust.message_type =
|
||||
static_cast<RtcpFeedbackMessageType>(feedback.message_type.value());
|
||||
}
|
||||
|
||||
return rust;
|
||||
}
|
||||
|
||||
RtpCodecCapability to_rust_rtp_codec_capability(
|
||||
webrtc::RtpCodecCapability capability) {
|
||||
RtpCodecCapability rust;
|
||||
rust.mime_type = capability.mime_type();
|
||||
rust.name = capability.name;
|
||||
rust.kind = static_cast<MediaType>(capability.kind);
|
||||
|
||||
if (capability.clock_rate.has_value()) {
|
||||
rust.has_clock_rate = true;
|
||||
rust.clock_rate = capability.clock_rate.value();
|
||||
}
|
||||
|
||||
if (capability.preferred_payload_type.has_value()) {
|
||||
rust.has_preferred_payload_type = true;
|
||||
rust.preferred_payload_type = capability.preferred_payload_type.value();
|
||||
}
|
||||
|
||||
if (capability.max_ptime.has_value()) {
|
||||
rust.has_max_ptime = true;
|
||||
rust.max_ptime = capability.max_ptime.value();
|
||||
}
|
||||
|
||||
if (capability.ptime.has_value()) {
|
||||
rust.has_ptime = true;
|
||||
rust.ptime = capability.ptime.value();
|
||||
}
|
||||
|
||||
if (capability.num_channels.has_value()) {
|
||||
rust.has_num_channels = true;
|
||||
rust.num_channels = capability.num_channels.value();
|
||||
}
|
||||
|
||||
for (auto feedback : capability.rtcp_feedback)
|
||||
rust.rtcp_feedback.push_back(to_rust_rtcp_feedback(feedback));
|
||||
|
||||
for (auto param : capability.parameters)
|
||||
rust.parameters.push_back(StringKeyValue{param.first, param.second});
|
||||
|
||||
for (auto option : capability.options)
|
||||
rust.options.push_back(StringKeyValue{option.first, option.second});
|
||||
|
||||
rust.max_temporal_layer_extensions = capability.max_temporal_layer_extensions;
|
||||
rust.max_spatial_layer_extensions = capability.max_spatial_layer_extensions;
|
||||
rust.svc_multi_stream_support = capability.svc_multi_stream_support;
|
||||
return rust;
|
||||
}
|
||||
|
||||
RtpHeaderExtensionCapability to_rust_rtp_header_extension_capability(
|
||||
webrtc::RtpHeaderExtensionCapability header) {
|
||||
RtpHeaderExtensionCapability rust;
|
||||
rust.uri = header.uri;
|
||||
if (header.preferred_id.has_value()) {
|
||||
rust.has_preferred_id = true;
|
||||
rust.preferred_id = header.preferred_id.value();
|
||||
}
|
||||
|
||||
rust.preferred_encrypt = header.preferred_encrypt;
|
||||
rust.direction = static_cast<RtpTransceiverDirection>(header.direction);
|
||||
return rust;
|
||||
}
|
||||
|
||||
RtpExtension to_rust_rtp_extension(webrtc::RtpExtension ext) {
|
||||
RtpExtension rust;
|
||||
rust.uri = ext.uri;
|
||||
rust.id = ext.id;
|
||||
rust.encrypt = ext.encrypt;
|
||||
return rust;
|
||||
}
|
||||
|
||||
RtpFecParameters to_rust_rtp_fec_parameters(webrtc::RtpFecParameters fec) {
|
||||
RtpFecParameters rust;
|
||||
if (fec.ssrc.has_value()) {
|
||||
rust.has_ssrc = true;
|
||||
rust.ssrc = fec.ssrc.value();
|
||||
}
|
||||
|
||||
rust.mechanism = static_cast<FecMechanism>(rust.mechanism);
|
||||
return rust;
|
||||
}
|
||||
|
||||
RtpRtxParameters to_rust_rtp_rtx_parameters(webrtc::RtpRtxParameters param) {
|
||||
RtpRtxParameters rust;
|
||||
if (param.ssrc.has_value()) {
|
||||
rust.has_ssrc = param.ssrc.has_value();
|
||||
rust.ssrc = param.ssrc.value();
|
||||
}
|
||||
return rust;
|
||||
}
|
||||
|
||||
RtpEncodingParameters to_rust_rtp_encoding_parameters(
|
||||
webrtc::RtpEncodingParameters params) {
|
||||
RtpEncodingParameters rust;
|
||||
if (params.ssrc.has_value()) {
|
||||
rust.has_ssrc = params.ssrc.has_value();
|
||||
rust.ssrc = params.ssrc.value();
|
||||
}
|
||||
|
||||
rust.bitrate_priority = params.bitrate_priority;
|
||||
rust.network_priority = static_cast<Priority>(params.network_priority);
|
||||
if (params.max_bitrate_bps.has_value()) {
|
||||
rust.has_max_bitrate_bps = true;
|
||||
rust.max_bitrate_bps = params.max_bitrate_bps.value();
|
||||
}
|
||||
|
||||
if (params.min_bitrate_bps.has_value()) {
|
||||
rust.has_min_bitrate_bps = true;
|
||||
rust.min_bitrate_bps = params.min_bitrate_bps.value();
|
||||
}
|
||||
|
||||
if (params.max_framerate.has_value()) {
|
||||
rust.has_max_framerate = true;
|
||||
rust.max_framerate = params.max_framerate.value();
|
||||
}
|
||||
|
||||
if (params.num_temporal_layers.has_value()) {
|
||||
rust.has_num_temporal_layers = true;
|
||||
rust.num_temporal_layers = params.num_temporal_layers.value();
|
||||
}
|
||||
|
||||
if (params.scale_resolution_down_by.has_value()) {
|
||||
rust.has_scale_resolution_down_by = true;
|
||||
rust.scale_resolution_down_by = params.scale_resolution_down_by.value();
|
||||
}
|
||||
|
||||
if (params.scalability_mode.has_value()) {
|
||||
rust.has_scalability_mode = true;
|
||||
rust.scalability_mode = params.scalability_mode.value();
|
||||
}
|
||||
|
||||
rust.active = params.active;
|
||||
rust.rid = params.rid;
|
||||
rust.adaptive_ptime = params.adaptive_ptime;
|
||||
return rust;
|
||||
}
|
||||
|
||||
RtpCodecParameters to_rust_rtp_codec_parameters(
|
||||
webrtc::RtpCodecParameters params) {
|
||||
RtpCodecParameters rust;
|
||||
rust.mime_type = params.mime_type();
|
||||
rust.name = params.name;
|
||||
rust.kind = static_cast<MediaType>(params.kind);
|
||||
rust.payload_type = params.payload_type;
|
||||
if (params.clock_rate.has_value()) {
|
||||
rust.has_clock_rate = true;
|
||||
rust.clock_rate = params.clock_rate.value();
|
||||
}
|
||||
|
||||
if (params.num_channels.has_value()) {
|
||||
rust.has_num_channels = true;
|
||||
rust.num_channels = params.num_channels.value();
|
||||
}
|
||||
|
||||
if (params.max_ptime.has_value()) {
|
||||
rust.has_max_ptime = true;
|
||||
rust.max_ptime = params.max_ptime.value();
|
||||
}
|
||||
|
||||
if (params.ptime.has_value()) {
|
||||
rust.has_ptime = true;
|
||||
rust.ptime = params.ptime.value();
|
||||
}
|
||||
|
||||
for (auto feedback : params.rtcp_feedback)
|
||||
rust.rtcp_feedback.push_back(to_rust_rtcp_feedback(feedback));
|
||||
|
||||
for (auto pair : params.parameters)
|
||||
rust.parameters.push_back(StringKeyValue{pair.first, pair.second});
|
||||
|
||||
return rust;
|
||||
}
|
||||
|
||||
RtpCapabilities to_rust_rtp_capabilities(webrtc::RtpCapabilities capabilities) {
|
||||
RtpCapabilities rust;
|
||||
for (auto codec : capabilities.codecs)
|
||||
rust.codecs.push_back(to_rust_rtp_codec_capability(codec));
|
||||
|
||||
for (auto header : capabilities.header_extensions)
|
||||
rust.header_extensions.push_back(
|
||||
to_rust_rtp_header_extension_capability(header));
|
||||
|
||||
for (auto fec : capabilities.fec)
|
||||
rust.fec.push_back(static_cast<FecMechanism>(fec));
|
||||
|
||||
return rust;
|
||||
}
|
||||
|
||||
RtcpParameters to_rust_rtcp_parameters(webrtc::RtcpParameters params) {
|
||||
RtcpParameters rust;
|
||||
if (params.ssrc.has_value()) {
|
||||
rust.has_ssrc = true;
|
||||
rust.ssrc = params.ssrc.value();
|
||||
}
|
||||
|
||||
rust.cname = params.cname;
|
||||
rust.reduced_size = params.reduced_size;
|
||||
rust.mux = params.mux;
|
||||
return rust;
|
||||
}
|
||||
|
||||
RtpParameters to_rust_rtp_parameters(webrtc::RtpParameters params) {
|
||||
RtpParameters rust;
|
||||
rust.transaction_id = params.transaction_id;
|
||||
rust.mid = params.mid;
|
||||
|
||||
for (auto codec : params.codecs)
|
||||
rust.codecs.push_back(to_rust_rtp_codec_parameters(codec));
|
||||
|
||||
for (auto header : params.header_extensions)
|
||||
rust.header_extensions.push_back(to_rust_rtp_extension(header));
|
||||
|
||||
for (auto encoding : params.encodings)
|
||||
rust.encodings.push_back(to_rust_rtp_encoding_parameters(encoding));
|
||||
|
||||
rust.rtcp = to_rust_rtcp_parameters(params.rtcp);
|
||||
|
||||
if (params.degradation_preference.has_value()) {
|
||||
rust.has_degradation_preference = true;
|
||||
rust.degradation_preference = static_cast<DegradationPreference>(
|
||||
params.degradation_preference.value());
|
||||
}
|
||||
|
||||
return rust;
|
||||
}
|
||||
|
||||
} // namespace livekit
|
||||
@@ -0,0 +1,194 @@
|
||||
use cxx::UniquePtr;
|
||||
|
||||
pub const DEFAULT_BITRATE_PRIORITY: f64 = 1.0;
|
||||
|
||||
#[cxx::bridge(namespace = "livekit")]
|
||||
pub mod ffi {
|
||||
|
||||
// Used to replace std::map
|
||||
#[derive(Debug)]
|
||||
pub struct StringKeyValue {
|
||||
pub key: String,
|
||||
pub value: String,
|
||||
}
|
||||
|
||||
#[repr(i32)]
|
||||
#[derive(Debug)]
|
||||
pub enum FecMechanism {
|
||||
RED,
|
||||
REDAndULPFEC,
|
||||
FLEXFEC,
|
||||
}
|
||||
|
||||
#[repr(i32)]
|
||||
#[derive(Debug)]
|
||||
pub enum RtcpFeedbackType {
|
||||
CCM,
|
||||
LNTF,
|
||||
NACK,
|
||||
REMB,
|
||||
TransportCC,
|
||||
}
|
||||
|
||||
#[repr(i32)]
|
||||
#[derive(Debug)]
|
||||
pub enum RtcpFeedbackMessageType {
|
||||
GenericNACK,
|
||||
PLI,
|
||||
FIR,
|
||||
}
|
||||
|
||||
#[repr(i32)]
|
||||
#[derive(Debug)]
|
||||
pub enum DegradationPreference {
|
||||
Disabled,
|
||||
MaintainFramerate,
|
||||
MaintainResolution,
|
||||
Balanced,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RtcpFeedback {
|
||||
pub feedback_type: RtcpFeedbackType,
|
||||
pub has_message_type: bool,
|
||||
pub message_type: RtcpFeedbackMessageType,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RtpCodecCapability {
|
||||
pub mime_type: String, // filled with mime_type fnc
|
||||
pub name: String,
|
||||
pub kind: MediaType,
|
||||
pub has_clock_rate: bool,
|
||||
pub clock_rate: i32,
|
||||
pub has_preferred_payload_type: bool,
|
||||
pub preferred_payload_type: i32,
|
||||
pub has_max_ptime: bool,
|
||||
pub max_ptime: i32,
|
||||
pub has_ptime: bool,
|
||||
pub ptime: i32,
|
||||
pub has_num_channels: bool,
|
||||
pub num_channels: i32,
|
||||
pub rtcp_feedback: Vec<RtcpFeedback>,
|
||||
pub parameters: Vec<StringKeyValue>,
|
||||
pub options: Vec<StringKeyValue>,
|
||||
pub max_temporal_layer_extensions: i32,
|
||||
pub max_spatial_layer_extensions: i32,
|
||||
pub svc_multi_stream_support: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RtpHeaderExtensionCapability {
|
||||
pub uri: String,
|
||||
pub has_preferred_id: bool,
|
||||
pub preferred_id: i32,
|
||||
pub preferred_encrypt: bool,
|
||||
pub direction: RtpTransceiverDirection,
|
||||
}
|
||||
|
||||
#[repr(i32)]
|
||||
#[derive(Debug)]
|
||||
pub enum RtpExtensionFilter {
|
||||
DiscardEncryptedExtension,
|
||||
PreferEncryptedExtension,
|
||||
RequireEncryptedExtension,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RtpExtension {
|
||||
// TODO(theomonnom): export available URI inside api/rtp_parameters.h
|
||||
pub uri: String,
|
||||
pub id: i32,
|
||||
pub encrypt: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RtpFecParameters {
|
||||
pub has_ssrc: bool,
|
||||
pub ssrc: u32,
|
||||
pub mechanism: FecMechanism,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RtpRtxParameters {
|
||||
pub has_ssrc: bool,
|
||||
pub ssrc: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RtpEncodingParameters {
|
||||
pub has_ssrc: bool,
|
||||
pub ssrc: u32,
|
||||
pub bitrate_priority: f64,
|
||||
pub network_priority: Priority, // Todo link type
|
||||
pub has_max_bitrate_bps: bool,
|
||||
pub max_bitrate_bps: i32,
|
||||
pub has_min_bitrate_bps: bool,
|
||||
pub min_bitrate_bps: i32,
|
||||
pub has_max_framerate: bool,
|
||||
pub max_framerate: f64,
|
||||
pub has_num_temporal_layers: bool,
|
||||
pub num_temporal_layers: i32,
|
||||
pub has_scale_resolution_down_by: bool,
|
||||
pub scale_resolution_down_by: f64,
|
||||
pub has_scalability_mode: bool,
|
||||
pub scalability_mode: String,
|
||||
pub active: bool,
|
||||
pub rid: String,
|
||||
pub adaptive_ptime: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RtpCodecParameters {
|
||||
pub mime_type: String, // filled with mime_type fnc
|
||||
pub name: String,
|
||||
pub kind: MediaType,
|
||||
pub payload_type: i32,
|
||||
pub has_clock_rate: bool,
|
||||
pub clock_rate: i32,
|
||||
pub has_num_channels: bool,
|
||||
pub num_channels: i32,
|
||||
pub has_max_ptime: bool,
|
||||
pub max_ptime: i32,
|
||||
pub has_ptime: bool,
|
||||
pub ptime: i32,
|
||||
pub rtcp_feedback: Vec<RtcpFeedback>,
|
||||
pub parameters: Vec<StringKeyValue>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RtpCapabilities {
|
||||
pub codecs: Vec<RtpCodecCapability>,
|
||||
pub header_extensions: Vec<RtpHeaderExtensionCapability>,
|
||||
pub fec: Vec<FecMechanism>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RtcpParameters {
|
||||
pub has_ssrc: bool,
|
||||
pub ssrc: u32,
|
||||
pub cname: String,
|
||||
pub reduced_size: bool,
|
||||
pub mux: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RtpParameters {
|
||||
pub transaction_id: String,
|
||||
pub mid: String,
|
||||
pub codecs: Vec<RtpCodecParameters>,
|
||||
pub header_extensions: Vec<RtpExtension>,
|
||||
pub encodings: Vec<RtpEncodingParameters>,
|
||||
pub rtcp: RtcpParameters,
|
||||
pub has_degradation_preference: bool,
|
||||
pub degradation_preference: DegradationPreference,
|
||||
}
|
||||
|
||||
extern "C++" {
|
||||
include!("webrtc-sys/src/webrtc.rs.h");
|
||||
|
||||
type Priority = crate::webrtc::ffi::Priority;
|
||||
type MediaType = crate::webrtc::ffi::MediaType;
|
||||
type RtpTransceiverDirection = crate::webrtc::ffi::RtpTransceiverDirection;
|
||||
}
|
||||
}
|
||||
@@ -4,13 +4,48 @@
|
||||
|
||||
#include "livekit/rtp_receiver.h"
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
|
||||
namespace livekit {
|
||||
|
||||
RtpReceiver::RtpReceiver(
|
||||
rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver)
|
||||
: receiver_(std::move(receiver)) {}
|
||||
|
||||
std::unique_ptr<MediaStreamTrack> RtpReceiver::track() const {
|
||||
std::shared_ptr<MediaStreamTrack> RtpReceiver::track() const {
|
||||
return MediaStreamTrack::from(receiver_->track());
|
||||
}
|
||||
|
||||
} // namespace livekit
|
||||
rust::Vec<rust::String> RtpReceiver::stream_ids() const {
|
||||
rust::Vec<rust::String> rust;
|
||||
for (auto id : receiver_->stream_ids())
|
||||
rust.push_back(id);
|
||||
return rust;
|
||||
}
|
||||
|
||||
rust::Vec<MediaStreamPtr> RtpReceiver::streams() const {
|
||||
rust::Vec<MediaStreamPtr> rust;
|
||||
for (auto stream : receiver_->streams())
|
||||
rust.push_back(MediaStreamPtr{std::make_shared<MediaStream>(stream)});
|
||||
return rust;
|
||||
}
|
||||
|
||||
MediaType RtpReceiver::media_type() const {
|
||||
return static_cast<MediaType>(receiver_->media_type());
|
||||
}
|
||||
|
||||
rust::String RtpReceiver::id() const {
|
||||
return receiver_->id();
|
||||
}
|
||||
|
||||
RtpParameters RtpReceiver::get_parameters() const {
|
||||
return to_rust_rtp_parameters(receiver_->GetParameters());
|
||||
}
|
||||
|
||||
void RtpReceiver::set_jitter_buffer_minimum_delay(bool is_some,
|
||||
double delay_seconds) const {
|
||||
receiver_->SetJitterBufferMinimumDelay(
|
||||
is_some ? absl::make_optional(delay_seconds) : absl::nullopt);
|
||||
}
|
||||
|
||||
} // namespace livekit
|
||||
|
||||
@@ -1,18 +1,36 @@
|
||||
use crate::impl_thread_safety;
|
||||
|
||||
#[cxx::bridge(namespace = "livekit")]
|
||||
pub mod ffi {
|
||||
unsafe extern "C++" {
|
||||
include!("livekit/rtp_receiver.h");
|
||||
|
||||
extern "C++" {
|
||||
include!("livekit/webrtc.h");
|
||||
include!("livekit/rtp_parameters.h");
|
||||
include!("livekit/helper.h");
|
||||
include!("livekit/media_stream.h");
|
||||
|
||||
type MediaType = crate::webrtc::ffi::MediaType;
|
||||
type RtpParameters = crate::rtp_parameters::ffi::RtpParameters;
|
||||
type MediaStreamPtr = crate::helper::ffi::MediaStreamPtr;
|
||||
type MediaStreamTrack = crate::media_stream::ffi::MediaStreamTrack;
|
||||
type MediaStream = crate::media_stream::ffi::MediaStream;
|
||||
}
|
||||
|
||||
unsafe extern "C++" {
|
||||
include!("livekit/rtp_receiver.h");
|
||||
|
||||
type RtpReceiver;
|
||||
|
||||
fn track(self: &RtpReceiver) -> UniquePtr<MediaStreamTrack>;
|
||||
fn track(self: &RtpReceiver) -> SharedPtr<MediaStreamTrack>;
|
||||
fn stream_ids(self: &RtpReceiver) -> Vec<String>;
|
||||
fn streams(self: &RtpReceiver) -> Vec<MediaStreamPtr>;
|
||||
fn media_type(self: &RtpReceiver) -> MediaType;
|
||||
fn id(self: &RtpReceiver) -> String;
|
||||
fn get_parameters(self: &RtpReceiver) -> RtpParameters;
|
||||
fn set_jitter_buffer_minimum_delay(self: &RtpReceiver, is_some: bool, delay_seconds: f64);
|
||||
|
||||
fn _unique_rtp_receiver() -> UniquePtr<RtpReceiver>; // Ignore
|
||||
fn _shared_rtp_receiver() -> SharedPtr<RtpReceiver>;
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Sync for ffi::RtpReceiver {}
|
||||
|
||||
unsafe impl Send for ffi::RtpReceiver {}
|
||||
impl_thread_safety!(ffi::RtpReceiver, Send + Sync);
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
#include "livekit/rtp_sender.h"
|
||||
|
||||
namespace livekit {
|
||||
|
||||
RtpSender::RtpSender(rtc::scoped_refptr<webrtc::RtpSenderInterface> sender)
|
||||
: sender_(std::move(sender)) {}
|
||||
|
||||
bool RtpSender::set_track(std::shared_ptr<MediaStreamTrack> track) const {
|
||||
return sender_->SetTrack(track->get().get());
|
||||
}
|
||||
|
||||
std::shared_ptr<MediaStreamTrack> RtpSender::track() const {
|
||||
return MediaStreamTrack::from(sender_->track());
|
||||
}
|
||||
|
||||
uint32_t RtpSender::ssrc() const {
|
||||
return sender_->ssrc();
|
||||
}
|
||||
|
||||
MediaType RtpSender::media_type() const {
|
||||
return static_cast<MediaType>(sender_->media_type());
|
||||
}
|
||||
|
||||
rust::String RtpSender::id() const {
|
||||
return sender_->id();
|
||||
}
|
||||
|
||||
rust::Vec<rust::String> RtpSender::stream_ids() const {
|
||||
rust::Vec<rust::String> vec;
|
||||
for (auto str : sender_->stream_ids())
|
||||
vec.push_back(str);
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
void RtpSender::set_streams(const rust::Vec<rust::String>& stream_ids) const {
|
||||
std::vector<std::string> std_stream_ids(stream_ids.begin(), stream_ids.end());
|
||||
sender_->SetStreams(std_stream_ids);
|
||||
}
|
||||
|
||||
rust::Vec<RtpEncodingParameters> RtpSender::init_send_encodings() const {
|
||||
rust::Vec<RtpEncodingParameters> encodings;
|
||||
for (auto encoding : sender_->init_send_encodings())
|
||||
encodings.push_back(to_rust_rtp_encoding_parameters(encoding));
|
||||
return encodings;
|
||||
}
|
||||
|
||||
RtpParameters RtpSender::get_parameters() const {
|
||||
return to_rust_rtp_parameters(sender_->GetParameters());
|
||||
}
|
||||
|
||||
void RtpSender::set_parameters(RtpParameters params) const {
|
||||
auto error = sender_->SetParameters(to_native_rtp_parameters(params));
|
||||
if (!error.ok())
|
||||
throw std::runtime_error(serialize_error(to_error(error)));
|
||||
}
|
||||
|
||||
} // namespace livekit
|
||||
@@ -0,0 +1,33 @@
|
||||
#[cxx::bridge(namespace = "livekit")]
|
||||
pub mod ffi {
|
||||
|
||||
extern "C++" {
|
||||
include!("livekit/webrtc.h");
|
||||
include!("livekit/rtp_parameters.h");
|
||||
include!("livekit/media_stream.h");
|
||||
|
||||
type MediaType = crate::webrtc::ffi::MediaType;
|
||||
type RtpEncodingParameters = crate::rtp_parameters::ffi::RtpEncodingParameters;
|
||||
type RtpParameters = crate::rtp_parameters::ffi::RtpParameters;
|
||||
type MediaStreamTrack = crate::media_stream::ffi::MediaStreamTrack;
|
||||
}
|
||||
|
||||
unsafe extern "C++" {
|
||||
include!("livekit/rtp_sender.h");
|
||||
|
||||
type RtpSender;
|
||||
|
||||
fn set_track(self: &RtpSender, track: SharedPtr<MediaStreamTrack>) -> bool;
|
||||
fn track(self: &RtpSender) -> SharedPtr<MediaStreamTrack>;
|
||||
fn ssrc(self: &RtpSender) -> u32;
|
||||
fn media_type(self: &RtpSender) -> MediaType;
|
||||
fn id(self: &RtpSender) -> String;
|
||||
fn stream_ids(self: &RtpSender) -> Vec<String>;
|
||||
fn set_streams(self: &RtpSender, stream_ids: &Vec<String>);
|
||||
fn init_send_encodings(self: &RtpSender) -> Vec<RtpEncodingParameters>;
|
||||
fn get_parameters(self: &RtpSender) -> RtpParameters;
|
||||
fn set_parameters(self: &RtpSender, parameters: RtpParameters) -> Result<()>;
|
||||
|
||||
fn _shared_rtp_sender() -> SharedPtr<RtpSender>;
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,128 @@
|
||||
#include "livekit/rtp_transceiver.h"
|
||||
|
||||
namespace livekit {
|
||||
|
||||
webrtc::RtpTransceiverInit to_native_rtp_transceiver_init(
|
||||
RtpTransceiverInit init) {
|
||||
{
|
||||
webrtc::RtpTransceiverInit native;
|
||||
native.direction =
|
||||
static_cast<webrtc::RtpTransceiverDirection>(init.direction);
|
||||
native.stream_ids = std::vector<std::string>(init.stream_ids.begin(),
|
||||
init.stream_ids.end());
|
||||
for (auto encoding : init.send_encodings)
|
||||
native.send_encodings.push_back(
|
||||
to_native_rtp_encoding_paramters(encoding));
|
||||
return native;
|
||||
}
|
||||
}
|
||||
|
||||
RtpTransceiver::RtpTransceiver(
|
||||
rtc::scoped_refptr<webrtc::RtpTransceiverInterface> transceiver)
|
||||
: transceiver_(std::move(transceiver)) {}
|
||||
} // namespace livekit
|
||||
|
||||
MediaType RtpTransceiver::media_type() const {
|
||||
return static_cast<MediaType>(transceiver_->media_type());
|
||||
}
|
||||
|
||||
rust::String RtpTransceiver::mid() const {
|
||||
// The error/Result is converted into an Option in Rust (Wait for Option
|
||||
// suport in cxx.rs) (value throws an error if there's no value)
|
||||
return transceiver_->mid().value();
|
||||
}
|
||||
|
||||
std::shared_ptr<RtpSender> RtpTransceiver::sender() const {
|
||||
return std::make_shared<RtpSender>(transceiver_->sender());
|
||||
}
|
||||
|
||||
std::shared_ptr<RtpReceiver> RtpTransceiver::receiver() const {
|
||||
return std::make_shared<RtpReceiver>(transceiver_->receiver());
|
||||
}
|
||||
|
||||
bool RtpTransceiver::stopped() const {
|
||||
return transceiver_->stopped();
|
||||
}
|
||||
|
||||
bool RtpTransceiver::stopping() const {
|
||||
return transceiver_->stopping();
|
||||
}
|
||||
|
||||
RtpTransceiverDirection RtpTransceiver::direction() const {
|
||||
return static_cast<RtpTransceiverDirection>(transceiver_->direction());
|
||||
}
|
||||
|
||||
void RtpTransceiver::set_direction(RtpTransceiverDirection direction) const {
|
||||
auto error = transceiver_->SetDirectionWithError(
|
||||
static_cast<webrtc::RtpTransceiverDirection>(direction));
|
||||
|
||||
if (!error.ok()) {
|
||||
throw std::runtime_error(serialize_error(to_error(error)));
|
||||
}
|
||||
}
|
||||
|
||||
RtpTransceiverDirection RtpTransceiver::current_direction() const {
|
||||
return static_cast<RtpTransceiverDirection>(
|
||||
transceiver_->current_direction().value());
|
||||
}
|
||||
|
||||
RtpTransceiverDirection RtpTransceiver::fired_direction() const {
|
||||
return static_cast<RtpTransceiverDirection>(
|
||||
transceiver_->fired_direction().value());
|
||||
}
|
||||
|
||||
void RtpTransceiver::stop_standard() const {
|
||||
auto error = transceiver_->StopStandard();
|
||||
if (!error.ok())
|
||||
throw std::runtime_error(serialize_error(to_error(error)));
|
||||
}
|
||||
|
||||
void RtpTransceiver::set_codec_preferences(
|
||||
rust::Vec<RtpCodecCapability> codecs) const {
|
||||
std::vector<webrtc::RtpCodecCapability> std_codecs;
|
||||
for (auto codec : codecs)
|
||||
std_codecs.push_back(to_native_rtp_codec_capability(codec));
|
||||
|
||||
auto error = transceiver_->SetCodecPreferences(std_codecs);
|
||||
if (!error.ok())
|
||||
throw std::runtime_error(serialize_error(to_error(error)));
|
||||
}
|
||||
|
||||
rust::Vec<RtpCodecCapability> RtpTransceiver::codec_preferences() const {
|
||||
rust::Vec<RtpCodecCapability> rust;
|
||||
for (auto codec : transceiver_->codec_preferences())
|
||||
rust.push_back(to_rust_rtp_codec_capability(codec));
|
||||
|
||||
return rust;
|
||||
}
|
||||
|
||||
rust::Vec<RtpHeaderExtensionCapability>
|
||||
RtpTransceiver::header_extensions_to_offer() const {
|
||||
rust::Vec<RtpHeaderExtensionCapability> rust;
|
||||
for (auto header : transceiver_->HeaderExtensionsToOffer())
|
||||
rust.push_back(to_rust_rtp_header_extension_capability(header));
|
||||
|
||||
return rust;
|
||||
}
|
||||
|
||||
rust::Vec<RtpHeaderExtensionCapability>
|
||||
RtpTransceiver::header_extensions_negotiated() const {
|
||||
rust::Vec<RtpHeaderExtensionCapability> rust;
|
||||
for (auto header : transceiver_->HeaderExtensionsNegotiated())
|
||||
rust.push_back(to_rust_rtp_header_extension_capability(header));
|
||||
|
||||
return rust;
|
||||
}
|
||||
|
||||
void RtpTransceiver::set_offered_rtp_header_extensions(
|
||||
rust::Vec<RtpHeaderExtensionCapability> header_extensions_to_offer) const {
|
||||
std::vector<webrtc::RtpHeaderExtensionCapability> headers;
|
||||
|
||||
for (auto header : header_extensions_to_offer)
|
||||
headers.push_back(to_native_rtp_header_extension_capability(header));
|
||||
|
||||
auto error = transceiver_->SetOfferedRtpHeaderExtensions(headers);
|
||||
if (!error.ok())
|
||||
throw std::runtime_error(serialize_error(to_error(error)));
|
||||
}
|
||||
|
||||
} // namespace livekit
|
||||
|
||||
@@ -1,10 +1,62 @@
|
||||
use crate::impl_thread_safety;
|
||||
|
||||
#[cxx::bridge(namespace = "livekit")]
|
||||
pub mod ffi {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RtpTransceiverInit {
|
||||
pub direction: RtpTransceiverDirection,
|
||||
pub stream_ids: Vec<String>,
|
||||
pub send_encodings: Vec<RtpEncodingParameters>,
|
||||
}
|
||||
|
||||
extern "C++" {
|
||||
include!("livekit/webrtc.h");
|
||||
include!("livekit/rtp_parameters.h");
|
||||
include!("livekit/rtp_sender.h");
|
||||
include!("livekit/rtp_receiver.h");
|
||||
|
||||
type MediaType = crate::webrtc::ffi::MediaType;
|
||||
type RtpTransceiverDirection = crate::webrtc::ffi::RtpTransceiverDirection;
|
||||
type RtpEncodingParameters = crate::rtp_parameters::ffi::RtpEncodingParameters;
|
||||
type RtpCodecCapability = crate::rtp_parameters::ffi::RtpCodecCapability;
|
||||
type RtpHeaderExtensionCapability =
|
||||
crate::rtp_parameters::ffi::RtpHeaderExtensionCapability;
|
||||
type RtpSender = crate::rtp_sender::ffi::RtpSender;
|
||||
type RtpReceiver = crate::rtp_receiver::ffi::RtpReceiver;
|
||||
}
|
||||
|
||||
unsafe extern "C++" {
|
||||
include!("livekit/rtp_transceiver.h");
|
||||
|
||||
type RtpTransceiver;
|
||||
|
||||
fn _unique_rtp_transceiver() -> UniquePtr<RtpTransceiver>; // Ignore
|
||||
fn media_type(self: &RtpTransceiver) -> MediaType;
|
||||
fn mid(self: &RtpTransceiver) -> Result<String>;
|
||||
fn sender(self: &RtpTransceiver) -> SharedPtr<RtpSender>;
|
||||
fn receiver(self: &RtpTransceiver) -> SharedPtr<RtpReceiver>;
|
||||
fn stopped(self: &RtpTransceiver) -> bool;
|
||||
fn stopping(self: &RtpTransceiver) -> bool;
|
||||
fn direction(self: &RtpTransceiver) -> RtpTransceiverDirection;
|
||||
fn set_direction(self: &RtpTransceiver, direction: RtpTransceiverDirection) -> Result<()>;
|
||||
fn current_direction(self: &RtpTransceiver) -> Result<RtpTransceiverDirection>;
|
||||
fn fired_direction(self: &RtpTransceiver) -> Result<RtpTransceiverDirection>;
|
||||
fn stop_standard(self: &RtpTransceiver) -> Result<()>;
|
||||
fn set_codec_preferences(
|
||||
self: &RtpTransceiver,
|
||||
codecs: Vec<RtpCodecCapability>,
|
||||
) -> Result<()>;
|
||||
fn codec_preferences(self: &RtpTransceiver) -> Vec<RtpCodecCapability>;
|
||||
fn header_extensions_to_offer(self: &RtpTransceiver) -> Vec<RtpHeaderExtensionCapability>;
|
||||
fn header_extensions_negotiated(self: &RtpTransceiver)
|
||||
-> Vec<RtpHeaderExtensionCapability>;
|
||||
fn set_offered_rtp_header_extensions(
|
||||
self: &RtpTransceiver,
|
||||
headers: Vec<RtpHeaderExtensionCapability>,
|
||||
) -> Result<()>;
|
||||
|
||||
fn _shared_rtp_transceiver() -> SharedPtr<RtpTransceiver>;
|
||||
}
|
||||
}
|
||||
|
||||
impl_thread_safety!(ffi::RtpTransceiver, Send + Sync);
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
#include "livekit/video_frame.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "api/video/video_frame.h"
|
||||
|
||||
namespace livekit {
|
||||
VideoFrame::VideoFrame(const webrtc::VideoFrame& frame)
|
||||
: frame_(std::move(frame)) {}
|
||||
|
||||
int VideoFrame::width() const {
|
||||
return frame_.width();
|
||||
}
|
||||
int VideoFrame::height() const {
|
||||
return frame_.height();
|
||||
}
|
||||
uint32_t VideoFrame::size() const {
|
||||
return frame_.size();
|
||||
}
|
||||
uint16_t VideoFrame::id() const {
|
||||
return frame_.id();
|
||||
}
|
||||
int64_t VideoFrame::timestamp_us() const {
|
||||
return frame_.timestamp_us();
|
||||
}
|
||||
int64_t VideoFrame::ntp_time_ms() const {
|
||||
return frame_.ntp_time_ms();
|
||||
}
|
||||
uint32_t VideoFrame::transport_frame_id() const {
|
||||
return frame_.transport_frame_id();
|
||||
}
|
||||
uint32_t VideoFrame::timestamp() const {
|
||||
return frame_.timestamp();
|
||||
}
|
||||
|
||||
VideoRotation VideoFrame::rotation() const {
|
||||
return static_cast<VideoRotation>(frame_.rotation());
|
||||
}
|
||||
|
||||
// TODO(theomonnom) This shouldn't create a new shared_ptr at each call
|
||||
std::unique_ptr<VideoFrameBuffer> VideoFrame::video_frame_buffer() const {
|
||||
return std::make_unique<VideoFrameBuffer>(frame_.video_frame_buffer());
|
||||
}
|
||||
|
||||
webrtc::VideoFrame VideoFrame::get() const {
|
||||
return frame_;
|
||||
}
|
||||
|
||||
void VideoFrameBuilder::set_video_frame_buffer(
|
||||
std::unique_ptr<VideoFrameBuffer> buffer) {
|
||||
builder_.set_video_frame_buffer(buffer->get());
|
||||
}
|
||||
|
||||
void VideoFrameBuilder::set_timestamp_us(int64_t timestamp_us) {
|
||||
builder_.set_timestamp_us(timestamp_us);
|
||||
}
|
||||
|
||||
void VideoFrameBuilder::set_rotation(VideoRotation rotation) {
|
||||
builder_.set_rotation(static_cast<webrtc::VideoRotation>(rotation));
|
||||
}
|
||||
|
||||
void VideoFrameBuilder::set_id(uint16_t id) {
|
||||
builder_.set_id(id);
|
||||
}
|
||||
|
||||
std::unique_ptr<VideoFrame> VideoFrameBuilder::build() {
|
||||
return std::make_unique<VideoFrame>(builder_.build());
|
||||
}
|
||||
|
||||
std::unique_ptr<VideoFrameBuilder> create_video_frame_builder() {
|
||||
return std::make_unique<VideoFrameBuilder>();
|
||||
}
|
||||
|
||||
} // namespace livekit
|
||||
@@ -11,12 +11,17 @@ pub mod ffi {
|
||||
VideoRotation270 = 270,
|
||||
}
|
||||
|
||||
unsafe extern "C++" {
|
||||
include!("livekit/video_frame.h");
|
||||
extern "C++" {
|
||||
include!("livekit/video_frame_buffer.h");
|
||||
|
||||
type VideoFrame;
|
||||
type VideoFrameBuffer = crate::video_frame_buffer::ffi::VideoFrameBuffer;
|
||||
}
|
||||
|
||||
unsafe extern "C++" {
|
||||
include!("livekit/video_frame.h");
|
||||
|
||||
type VideoFrame;
|
||||
type VideoFrameBuilder;
|
||||
|
||||
fn width(self: &VideoFrame) -> i32;
|
||||
fn height(self: &VideoFrame) -> i32;
|
||||
@@ -29,7 +34,16 @@ pub mod ffi {
|
||||
fn rotation(self: &VideoFrame) -> VideoRotation;
|
||||
fn video_frame_buffer(self: &VideoFrame) -> UniquePtr<VideoFrameBuffer>;
|
||||
|
||||
fn _unique_video_frame() -> UniquePtr<VideoFrame>; // Ignore
|
||||
fn set_video_frame_buffer(
|
||||
self: Pin<&mut VideoFrameBuilder>,
|
||||
buffer: UniquePtr<VideoFrameBuffer>,
|
||||
);
|
||||
fn set_timestamp_us(self: Pin<&mut VideoFrameBuilder>, timestamp_us: i64);
|
||||
fn set_rotation(self: Pin<&mut VideoFrameBuilder>, rotation: VideoRotation);
|
||||
fn set_id(self: Pin<&mut VideoFrameBuilder>, id: u16);
|
||||
fn build(self: Pin<&mut VideoFrameBuilder>) -> UniquePtr<VideoFrame>;
|
||||
|
||||
fn create_video_frame_builder() -> UniquePtr<VideoFrameBuilder>;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,198 @@
|
||||
#include "livekit/video_frame_buffer.h"
|
||||
|
||||
namespace livekit {
|
||||
|
||||
VideoFrameBuffer::VideoFrameBuffer(
|
||||
rtc::scoped_refptr<webrtc::VideoFrameBuffer> buffer)
|
||||
: buffer_(std::move(buffer)) {}
|
||||
|
||||
VideoFrameBufferType VideoFrameBuffer::buffer_type() const {
|
||||
return static_cast<VideoFrameBufferType>(buffer_->type());
|
||||
}
|
||||
|
||||
int VideoFrameBuffer::width() const {
|
||||
return buffer_->width();
|
||||
}
|
||||
|
||||
int VideoFrameBuffer::height() const {
|
||||
return buffer_->height();
|
||||
}
|
||||
|
||||
std::unique_ptr<I420Buffer> VideoFrameBuffer::to_i420() {
|
||||
return std::make_unique<I420Buffer>(buffer_->ToI420());
|
||||
}
|
||||
|
||||
// const_cast is valid here because we take the ownership on the rust side
|
||||
std::unique_ptr<I420Buffer> VideoFrameBuffer::get_i420() {
|
||||
return std::make_unique<I420Buffer>(
|
||||
rtc::scoped_refptr<webrtc::I420BufferInterface>(
|
||||
const_cast<webrtc::I420BufferInterface*>(buffer_->GetI420())));
|
||||
}
|
||||
|
||||
std::unique_ptr<I420ABuffer> VideoFrameBuffer::get_i420a() {
|
||||
return std::make_unique<I420ABuffer>(
|
||||
rtc::scoped_refptr<webrtc::I420ABufferInterface>(
|
||||
const_cast<webrtc::I420ABufferInterface*>(buffer_->GetI420A())));
|
||||
}
|
||||
|
||||
std::unique_ptr<I422Buffer> VideoFrameBuffer::get_i422() {
|
||||
return std::make_unique<I422Buffer>(
|
||||
rtc::scoped_refptr<webrtc::I422BufferInterface>(
|
||||
const_cast<webrtc::I422BufferInterface*>(buffer_->GetI422())));
|
||||
}
|
||||
|
||||
std::unique_ptr<I444Buffer> VideoFrameBuffer::get_i444() {
|
||||
return std::make_unique<I444Buffer>(
|
||||
rtc::scoped_refptr<webrtc::I444BufferInterface>(
|
||||
const_cast<webrtc::I444BufferInterface*>(buffer_->GetI444())));
|
||||
}
|
||||
|
||||
std::unique_ptr<I010Buffer> VideoFrameBuffer::get_i010() {
|
||||
return std::make_unique<I010Buffer>(
|
||||
rtc::scoped_refptr<webrtc::I010BufferInterface>(
|
||||
const_cast<webrtc::I010BufferInterface*>(buffer_->GetI010())));
|
||||
}
|
||||
|
||||
std::unique_ptr<NV12Buffer> VideoFrameBuffer::get_nv12() {
|
||||
return std::make_unique<NV12Buffer>(
|
||||
rtc::scoped_refptr<webrtc::NV12BufferInterface>(
|
||||
const_cast<webrtc::NV12BufferInterface*>(buffer_->GetNV12())));
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<webrtc::VideoFrameBuffer> VideoFrameBuffer::get() const {
|
||||
return buffer_;
|
||||
}
|
||||
|
||||
PlanarYuvBuffer::PlanarYuvBuffer(
|
||||
rtc::scoped_refptr<webrtc::PlanarYuvBuffer> buffer)
|
||||
: VideoFrameBuffer(buffer) {}
|
||||
|
||||
int PlanarYuvBuffer::chroma_width() const {
|
||||
return buffer()->ChromaWidth();
|
||||
}
|
||||
|
||||
int PlanarYuvBuffer::chroma_height() const {
|
||||
return buffer()->ChromaHeight();
|
||||
}
|
||||
|
||||
int PlanarYuvBuffer::stride_y() const {
|
||||
return buffer()->StrideY();
|
||||
}
|
||||
|
||||
int PlanarYuvBuffer::stride_u() const {
|
||||
return buffer()->StrideU();
|
||||
}
|
||||
|
||||
int PlanarYuvBuffer::stride_v() const {
|
||||
return buffer()->StrideV();
|
||||
}
|
||||
|
||||
webrtc::PlanarYuvBuffer* PlanarYuvBuffer::buffer() const {
|
||||
return static_cast<webrtc::PlanarYuvBuffer*>(buffer_.get());
|
||||
}
|
||||
|
||||
PlanarYuv8Buffer::PlanarYuv8Buffer(
|
||||
rtc::scoped_refptr<webrtc::PlanarYuv8Buffer> buffer)
|
||||
: PlanarYuvBuffer(buffer) {}
|
||||
|
||||
const uint8_t* PlanarYuv8Buffer::data_y() const {
|
||||
return buffer()->DataY();
|
||||
}
|
||||
|
||||
const uint8_t* PlanarYuv8Buffer::data_u() const {
|
||||
return buffer()->DataU();
|
||||
}
|
||||
|
||||
const uint8_t* PlanarYuv8Buffer::data_v() const {
|
||||
return buffer()->DataV();
|
||||
}
|
||||
|
||||
webrtc::PlanarYuv8Buffer* PlanarYuv8Buffer::buffer() const {
|
||||
return static_cast<webrtc::PlanarYuv8Buffer*>(buffer_.get());
|
||||
}
|
||||
|
||||
PlanarYuv16BBuffer::PlanarYuv16BBuffer(
|
||||
rtc::scoped_refptr<webrtc::PlanarYuv16BBuffer> buffer)
|
||||
: PlanarYuvBuffer(buffer) {}
|
||||
|
||||
const uint16_t* PlanarYuv16BBuffer::data_y() const {
|
||||
return buffer()->DataY();
|
||||
}
|
||||
|
||||
const uint16_t* PlanarYuv16BBuffer::data_u() const {
|
||||
return buffer()->DataU();
|
||||
}
|
||||
|
||||
const uint16_t* PlanarYuv16BBuffer::data_v() const {
|
||||
return buffer()->DataV();
|
||||
}
|
||||
|
||||
webrtc::PlanarYuv16BBuffer* PlanarYuv16BBuffer::buffer() const {
|
||||
return static_cast<webrtc::PlanarYuv16BBuffer*>(buffer_.get());
|
||||
}
|
||||
|
||||
BiplanarYuvBuffer::BiplanarYuvBuffer(
|
||||
rtc::scoped_refptr<webrtc::BiplanarYuvBuffer> buffer)
|
||||
: VideoFrameBuffer(buffer) {}
|
||||
|
||||
int BiplanarYuvBuffer::chroma_width() const {
|
||||
return buffer()->ChromaWidth();
|
||||
}
|
||||
|
||||
int BiplanarYuvBuffer::chroma_height() const {
|
||||
return buffer()->ChromaHeight();
|
||||
}
|
||||
|
||||
int BiplanarYuvBuffer::stride_y() const {
|
||||
return buffer()->StrideY();
|
||||
}
|
||||
|
||||
int BiplanarYuvBuffer::stride_uv() const {
|
||||
return buffer()->StrideUV();
|
||||
}
|
||||
|
||||
webrtc::BiplanarYuvBuffer* BiplanarYuvBuffer::buffer() const {
|
||||
return static_cast<webrtc::BiplanarYuvBuffer*>(buffer_.get());
|
||||
}
|
||||
|
||||
BiplanarYuv8Buffer::BiplanarYuv8Buffer(
|
||||
rtc::scoped_refptr<webrtc::BiplanarYuv8Buffer> buffer)
|
||||
: BiplanarYuvBuffer(buffer) {}
|
||||
|
||||
const uint8_t* BiplanarYuv8Buffer::data_y() const {
|
||||
return buffer()->DataY();
|
||||
}
|
||||
|
||||
const uint8_t* BiplanarYuv8Buffer::data_uv() const {
|
||||
return buffer()->DataUV();
|
||||
}
|
||||
|
||||
webrtc::BiplanarYuv8Buffer* BiplanarYuv8Buffer::buffer() const {
|
||||
return static_cast<webrtc::BiplanarYuv8Buffer*>(buffer_.get());
|
||||
}
|
||||
|
||||
std::unique_ptr<I420Buffer> create_i420_buffer(int width, int height) {
|
||||
return std::make_unique<I420Buffer>(
|
||||
webrtc::I420Buffer::Create(width, height));
|
||||
}
|
||||
|
||||
I420Buffer::I420Buffer(rtc::scoped_refptr<webrtc::I420BufferInterface> buffer)
|
||||
: PlanarYuv8Buffer(buffer) {}
|
||||
|
||||
I420ABuffer::I420ABuffer(
|
||||
rtc::scoped_refptr<webrtc::I420ABufferInterface> buffer)
|
||||
: I420Buffer(buffer) {}
|
||||
|
||||
I422Buffer::I422Buffer(rtc::scoped_refptr<webrtc::I422BufferInterface> buffer)
|
||||
: PlanarYuv8Buffer(buffer) {}
|
||||
|
||||
I444Buffer::I444Buffer(rtc::scoped_refptr<webrtc::I444BufferInterface> buffer)
|
||||
: PlanarYuv8Buffer(buffer) {}
|
||||
|
||||
I010Buffer::I010Buffer(rtc::scoped_refptr<webrtc::I010BufferInterface> buffer)
|
||||
: PlanarYuv16BBuffer(buffer) {}
|
||||
|
||||
NV12Buffer::NV12Buffer(rtc::scoped_refptr<webrtc::NV12BufferInterface> buffer)
|
||||
: BiplanarYuv8Buffer(buffer) {}
|
||||
|
||||
} // namespace livekit
|
||||
@@ -66,6 +66,8 @@ pub mod ffi {
|
||||
fn data_y(self: &BiplanarYuv8Buffer) -> *const u8;
|
||||
fn data_uv(self: &BiplanarYuv8Buffer) -> *const u8;
|
||||
|
||||
fn create_i420_buffer(width: i32, height: i32) -> UniquePtr<I420Buffer>;
|
||||
|
||||
unsafe fn yuv_to_vfb(yuv: *const PlanarYuvBuffer) -> *const VideoFrameBuffer;
|
||||
unsafe fn biyuv_to_vfb(yuv: *const BiplanarYuvBuffer) -> *const VideoFrameBuffer;
|
||||
unsafe fn yuv8_to_yuv(yuv8: *const PlanarYuv8Buffer) -> *const PlanarYuvBuffer;
|
||||
|
||||
@@ -1,5 +1,36 @@
|
||||
use crate::impl_thread_safety;
|
||||
|
||||
#[cxx::bridge(namespace = "livekit")]
|
||||
pub mod ffi {
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(i32)]
|
||||
pub enum MediaType {
|
||||
Audio,
|
||||
Video,
|
||||
Data,
|
||||
Unsupported,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(i32)]
|
||||
pub enum Priority {
|
||||
VeryLow,
|
||||
Low,
|
||||
Medium,
|
||||
High,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(i32)]
|
||||
pub enum RtpTransceiverDirection {
|
||||
SendRecv,
|
||||
SendOnly,
|
||||
RecvOnly,
|
||||
Inactive,
|
||||
Stopped,
|
||||
}
|
||||
|
||||
unsafe extern "C++" {
|
||||
include!("livekit/webrtc.h");
|
||||
|
||||
@@ -9,6 +40,4 @@ pub mod ffi {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for ffi::RTCRuntime {}
|
||||
|
||||
unsafe impl Sync for ffi::RTCRuntime {}
|
||||
impl_thread_safety!(ffi::RTCRuntime, Send + Sync);
|
||||
|
||||
Reference in New Issue
Block a user