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
+1 -1
View File
@@ -5,6 +5,6 @@ pub mod ffi {
type Candidate; // cricket::Candidate
fn _unique_candidate() -> UniquePtr<Candidate>; // Ignore
fn _shared_candidate() -> SharedPtr<Candidate>;
}
}
+2 -4
View File
@@ -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();
}
+6 -9
View File
@@ -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
+54
View File
@@ -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>;
}
}
+3 -3
View File
@@ -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
View File
@@ -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
+3
View File
@@ -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
View File
@@ -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
+37 -25
View File
@@ -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>);
+76 -9
View File
@@ -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)); });
+86 -74
View File
@@ -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 {
+3 -3
View File
@@ -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);
+1 -1
View File
@@ -53,4 +53,4 @@ void throw_error() {
}
#endif
} // namespace livekit
} // namespace livekit
+446
View File
@@ -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
+194
View File
@@ -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;
}
}
+37 -2
View File
@@ -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
+25 -7
View File
@@ -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);
+58
View File
@@ -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
+33
View File
@@ -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>;
}
}
+122 -1
View File
@@ -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
+53 -1
View File
@@ -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);
+74
View File
@@ -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
+18 -4
View File
@@ -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>;
}
}
+198
View File
@@ -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
+2
View File
@@ -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;
+32 -3
View File
@@ -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);