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:
Théo Monnom
2023-02-12 19:44:04 +01:00
committed by GitHub
parent 4411f88b68
commit 16ea02075f
64 changed files with 3357 additions and 670 deletions
+5 -5
View File
@@ -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 -2
View File
@@ -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
View File
@@ -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 }
}
+98 -48
View File
@@ -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() {
+4 -2
View File
@@ -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;
+462
View File
@@ -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),
}
}
}
+45 -4
View File
@@ -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));
}
}
+81
View File
@@ -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()) })
}
}
+118 -1
View File
@@ -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()) })
}
}
+74
View File
@@ -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())
}
}
+107 -27
View File
@@ -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
}
}
+4
View File
@@ -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>,