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:
@@ -5,6 +5,6 @@ pub mod ffi {
|
||||
|
||||
type Candidate; // cricket::Candidate
|
||||
|
||||
fn _unique_candidate() -> UniquePtr<Candidate>; // Ignore
|
||||
fn _shared_candidate() -> SharedPtr<Candidate>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "webrtc-sys/src/data_channel.rs.h"
|
||||
|
||||
namespace livekit {
|
||||
|
||||
DataChannel::DataChannel(
|
||||
@@ -16,11 +14,11 @@ DataChannel::DataChannel(
|
||||
: rtc_runtime_(std::move(rtc_runtime)),
|
||||
data_channel_(std::move(data_channel)) {}
|
||||
|
||||
void DataChannel::register_observer(NativeDataChannelObserver& observer) {
|
||||
void DataChannel::register_observer(NativeDataChannelObserver& observer) const {
|
||||
data_channel_->RegisterObserver(&observer);
|
||||
}
|
||||
|
||||
void DataChannel::unregister_observer() {
|
||||
void DataChannel::unregister_observer() const {
|
||||
data_channel_->UnregisterObserver();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::fmt::Debug;
|
||||
use crate::impl_thread_safety;
|
||||
use std::slice;
|
||||
|
||||
#[cxx::bridge(namespace = "livekit")]
|
||||
@@ -63,12 +63,12 @@ pub mod ffi {
|
||||
/// SAFETY
|
||||
/// The observer must live as the datachannel uses it
|
||||
unsafe fn register_observer(
|
||||
self: Pin<&mut DataChannel>,
|
||||
self: &DataChannel,
|
||||
observer: Pin<&mut NativeDataChannelObserver>,
|
||||
);
|
||||
|
||||
fn unregister_observer(self: Pin<&mut DataChannel>);
|
||||
fn send(self: &DataChannel, data: &DataBuffer) -> bool;
|
||||
fn unregister_observer(self: &DataChannel);
|
||||
fn send(self: &DataChannel, data: &DataBuffer) -> bool;
|
||||
fn label(self: &DataChannel) -> String;
|
||||
fn state(self: &DataChannel) -> DataState;
|
||||
fn close(self: &DataChannel);
|
||||
@@ -82,11 +82,8 @@ pub mod ffi {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for ffi::DataChannel {}
|
||||
unsafe impl Sync for ffi::DataChannel {}
|
||||
|
||||
unsafe impl Send for ffi::NativeDataChannelObserver {}
|
||||
unsafe impl Sync for ffi::NativeDataChannelObserver {}
|
||||
impl_thread_safety!(ffi::DataChannel, Send + Sync);
|
||||
impl_thread_safety!(ffi::NativeDataChannelObserver, Send + Sync);
|
||||
|
||||
// DataChannelObserver
|
||||
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
#[cxx::bridge(namespace = "livekit")]
|
||||
pub mod ffi {
|
||||
|
||||
// Wrapper to opaque C++ objects
|
||||
// https://github.com/dtolnay/cxx/issues/741
|
||||
// Used to allow SharedPtr/UniquePtr type inside a rust::Vec
|
||||
pub struct MediaStreamPtr {
|
||||
pub ptr: SharedPtr<MediaStream>,
|
||||
}
|
||||
|
||||
pub struct CandidatePtr {
|
||||
pub ptr: SharedPtr<Candidate>,
|
||||
}
|
||||
|
||||
pub struct AudioTrackPtr {
|
||||
pub ptr: SharedPtr<AudioTrack>,
|
||||
}
|
||||
|
||||
pub struct VideoTrackPtr {
|
||||
pub ptr: SharedPtr<VideoTrack>,
|
||||
}
|
||||
|
||||
pub struct RtpSenderPtr {
|
||||
pub ptr: SharedPtr<RtpSender>,
|
||||
}
|
||||
|
||||
pub struct RtpReceiverPtr {
|
||||
pub ptr: SharedPtr<RtpReceiver>,
|
||||
}
|
||||
|
||||
pub struct RtpTransceiverPtr {
|
||||
pub ptr: SharedPtr<RtpTransceiver>,
|
||||
}
|
||||
|
||||
unsafe extern "C++" {
|
||||
include!("livekit/helper.h");
|
||||
|
||||
type MediaStream = crate::media_stream::ffi::MediaStream;
|
||||
type AudioTrack = crate::media_stream::ffi::AudioTrack;
|
||||
type VideoTrack = crate::media_stream::ffi::VideoTrack;
|
||||
type Candidate = crate::candidate::ffi::Candidate;
|
||||
type RtpSender = crate::rtp_sender::ffi::RtpSender;
|
||||
type RtpReceiver = crate::rtp_receiver::ffi::RtpReceiver;
|
||||
type RtpTransceiver = crate::rtp_transceiver::ffi::RtpTransceiver;
|
||||
|
||||
fn _vec_media_stream_ptr() -> Vec<MediaStreamPtr>;
|
||||
fn _vec_candidate_ptr() -> Vec<CandidatePtr>;
|
||||
fn _vec_audio_track_ptr() -> Vec<AudioTrackPtr>;
|
||||
fn _vec_video_track_ptr() -> Vec<VideoTrackPtr>;
|
||||
fn _vec_rtp_sender_ptr() -> Vec<RtpSenderPtr>;
|
||||
fn _vec_rtp_receiver_ptr() -> Vec<RtpReceiverPtr>;
|
||||
fn _vec_rtp_transceiver_ptr() -> Vec<RtpTransceiverPtr>;
|
||||
}
|
||||
}
|
||||
@@ -7,8 +7,8 @@
|
||||
#include <iomanip>
|
||||
#include <memory>
|
||||
|
||||
#include "webrtc-sys/src/jsep.rs.h"
|
||||
#include "livekit/rtc_error.h"
|
||||
#include "rtc_base/ref_counted_object.h"
|
||||
|
||||
namespace livekit {
|
||||
|
||||
@@ -47,7 +47,7 @@ std::unique_ptr<webrtc::IceCandidateInterface> IceCandidate::release() {
|
||||
return std::move(ice_candidate_);
|
||||
}
|
||||
|
||||
std::unique_ptr<IceCandidate> create_ice_candidate(rust::String sdp_mid,
|
||||
std::shared_ptr<IceCandidate> create_ice_candidate(rust::String sdp_mid,
|
||||
int sdp_mline_index,
|
||||
rust::String sdp) {
|
||||
webrtc::SdpParseError error;
|
||||
@@ -57,7 +57,7 @@ std::unique_ptr<IceCandidate> create_ice_candidate(rust::String sdp_mid,
|
||||
throw std::runtime_error(serialize_sdp_error(error));
|
||||
}
|
||||
|
||||
return std::make_unique<IceCandidate>(
|
||||
return std::make_shared<IceCandidate>(
|
||||
std::unique_ptr<webrtc::IceCandidateInterface>(ice_rtc));
|
||||
}
|
||||
|
||||
|
||||
+14
-15
@@ -1,10 +1,10 @@
|
||||
use crate::impl_thread_safety;
|
||||
use cxx::UniquePtr;
|
||||
use std::error::Error;
|
||||
use std::fmt::{Debug, Display, Formatter};
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::mem::ManuallyDrop;
|
||||
use std::str::FromStr;
|
||||
|
||||
use cxx::UniquePtr;
|
||||
|
||||
use crate::rtc_error::ffi::RTCError;
|
||||
|
||||
#[cxx::bridge(namespace = "livekit")]
|
||||
@@ -39,11 +39,15 @@ pub mod ffi {
|
||||
fn on_set_remote_description_complete(self: &SetRemoteSdpObserverWrapper, error: RTCError);
|
||||
}
|
||||
|
||||
unsafe extern "C++" {
|
||||
include!("webrtc-sys/src/rtc_error.rs.h");
|
||||
include!("livekit/jsep.h");
|
||||
extern "C++" {
|
||||
include!("livekit/rtc_error.h");
|
||||
|
||||
type RTCError = crate::rtc_error::ffi::RTCError;
|
||||
}
|
||||
|
||||
unsafe extern "C++" {
|
||||
include!("livekit/jsep.h");
|
||||
|
||||
type IceCandidate;
|
||||
type SessionDescription;
|
||||
type NativeCreateSdpObserverHandle;
|
||||
@@ -72,13 +76,13 @@ pub mod ffi {
|
||||
sdp_mid: String,
|
||||
sdp_mline_index: i32,
|
||||
sdp: String,
|
||||
) -> Result<UniquePtr<IceCandidate>>;
|
||||
) -> Result<SharedPtr<IceCandidate>>;
|
||||
fn create_session_description(
|
||||
sdp_type: SdpType,
|
||||
sdp: String,
|
||||
) -> Result<UniquePtr<SessionDescription>>;
|
||||
|
||||
fn _unique_ice_candidate() -> UniquePtr<IceCandidate>; // Ignore
|
||||
fn _shared_ice_candidate() -> SharedPtr<IceCandidate>; // Ignore
|
||||
fn _unique_session_description() -> UniquePtr<SessionDescription>; // Ignore
|
||||
}
|
||||
}
|
||||
@@ -95,13 +99,8 @@ impl Display for ffi::SdpParseError {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for ffi::SessionDescription {}
|
||||
|
||||
unsafe impl Sync for ffi::SessionDescription {}
|
||||
|
||||
unsafe impl Send for ffi::IceCandidate {}
|
||||
|
||||
unsafe impl Sync for ffi::IceCandidate {}
|
||||
impl_thread_safety!(ffi::SessionDescription, Send + Sync);
|
||||
impl_thread_safety!(ffi::IceCandidate, Send + Sync);
|
||||
|
||||
impl ffi::SdpParseError {
|
||||
/// # Safety
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
pub mod candidate;
|
||||
pub mod data_channel;
|
||||
pub mod helper;
|
||||
pub mod jsep;
|
||||
pub mod media_stream;
|
||||
pub mod peer_connection;
|
||||
pub mod peer_connection_factory;
|
||||
pub mod rtc_error;
|
||||
pub mod rtp_parameters;
|
||||
pub mod rtp_receiver;
|
||||
pub mod rtp_sender;
|
||||
pub mod rtp_transceiver;
|
||||
pub mod video_frame;
|
||||
pub mod video_frame_buffer;
|
||||
|
||||
+156
-17
@@ -4,23 +4,91 @@
|
||||
|
||||
#include "livekit/media_stream.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
||||
#include "api/media_stream_interface.h"
|
||||
#include "webrtc-sys/src/media_stream.rs.h"
|
||||
#include "api/video/video_frame.h"
|
||||
#include "rtc_base/ref_counted_object.h"
|
||||
|
||||
namespace livekit {
|
||||
|
||||
MediaStream::MediaStream(
|
||||
rtc::scoped_refptr<webrtc::MediaStreamInterface> stream)
|
||||
: media_stream_(std::move(stream)) {}
|
||||
|
||||
rust::String MediaStream::id() const {
|
||||
return media_stream_->id();
|
||||
}
|
||||
|
||||
rust::Vec<VideoTrackPtr> MediaStream::get_video_tracks() const {
|
||||
rust::Vec<VideoTrackPtr> rust;
|
||||
for (auto video : media_stream_->GetVideoTracks())
|
||||
rust.push_back(VideoTrackPtr{std::make_shared<VideoTrack>(video)});
|
||||
|
||||
return rust;
|
||||
}
|
||||
|
||||
rust::Vec<AudioTrackPtr> MediaStream::get_audio_tracks() const {
|
||||
rust::Vec<AudioTrackPtr> rust;
|
||||
for (auto audio : media_stream_->GetAudioTracks())
|
||||
rust.push_back(AudioTrackPtr{std::make_shared<AudioTrack>(audio)});
|
||||
|
||||
return rust;
|
||||
}
|
||||
|
||||
std::shared_ptr<AudioTrack> MediaStream::find_audio_track(
|
||||
rust::String track_id) const {
|
||||
return std::make_shared<AudioTrack>(
|
||||
media_stream_->FindAudioTrack(track_id.c_str()));
|
||||
}
|
||||
|
||||
std::shared_ptr<VideoTrack> MediaStream::find_video_track(
|
||||
rust::String track_id) const {
|
||||
return std::make_shared<VideoTrack>(
|
||||
media_stream_->FindVideoTrack(track_id.c_str()));
|
||||
}
|
||||
|
||||
bool MediaStream::add_audio_track(
|
||||
std::shared_ptr<AudioTrack> audio_track) const {
|
||||
return media_stream_->AddTrack(
|
||||
rtc::scoped_refptr<webrtc::AudioTrackInterface>(
|
||||
static_cast<webrtc::AudioTrackInterface*>(audio_track->get().get())));
|
||||
}
|
||||
|
||||
bool MediaStream::add_video_track(
|
||||
std::shared_ptr<VideoTrack> video_track) const {
|
||||
return media_stream_->AddTrack(
|
||||
rtc::scoped_refptr<webrtc::VideoTrackInterface>(
|
||||
static_cast<webrtc::VideoTrackInterface*>(video_track->get().get())));
|
||||
}
|
||||
|
||||
bool MediaStream::remove_audio_track(
|
||||
std::shared_ptr<AudioTrack> audio_track) const {
|
||||
return media_stream_->RemoveTrack(
|
||||
rtc::scoped_refptr<webrtc::AudioTrackInterface>(
|
||||
static_cast<webrtc::AudioTrackInterface*>(audio_track->get().get())));
|
||||
}
|
||||
|
||||
bool MediaStream::remove_video_track(
|
||||
std::shared_ptr<VideoTrack> video_track) const {
|
||||
return media_stream_->RemoveTrack(
|
||||
rtc::scoped_refptr<webrtc::VideoTrackInterface>(
|
||||
static_cast<webrtc::VideoTrackInterface*>(video_track->get().get())));
|
||||
}
|
||||
|
||||
MediaStreamTrack::MediaStreamTrack(
|
||||
rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track)
|
||||
: track_(std::move(track)) {}
|
||||
|
||||
std::unique_ptr<MediaStreamTrack> MediaStreamTrack::from(
|
||||
std::shared_ptr<MediaStreamTrack> MediaStreamTrack::from(
|
||||
rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track) {
|
||||
if (track->kind() == webrtc::MediaStreamTrackInterface::kVideoKind) {
|
||||
return std::make_unique<VideoTrack>(
|
||||
return std::make_shared<VideoTrack>(
|
||||
rtc::scoped_refptr<webrtc::VideoTrackInterface>(
|
||||
static_cast<webrtc::VideoTrackInterface*>(track.get())));
|
||||
} else {
|
||||
return std::make_unique<AudioTrack>(
|
||||
return std::make_shared<AudioTrack>(
|
||||
rtc::scoped_refptr<webrtc::AudioTrackInterface>(
|
||||
static_cast<webrtc::AudioTrackInterface*>(track.get())));
|
||||
}
|
||||
@@ -38,7 +106,7 @@ bool MediaStreamTrack::enabled() const {
|
||||
return track_->enabled();
|
||||
}
|
||||
|
||||
bool MediaStreamTrack::set_enabled(bool enable) {
|
||||
bool MediaStreamTrack::set_enabled(bool enable) const {
|
||||
return track_->set_enabled(enable);
|
||||
}
|
||||
|
||||
@@ -46,29 +114,21 @@ TrackState MediaStreamTrack::state() const {
|
||||
return static_cast<TrackState>(track_->state());
|
||||
}
|
||||
|
||||
MediaStream::MediaStream(
|
||||
rtc::scoped_refptr<webrtc::MediaStreamInterface> stream)
|
||||
: media_stream_(std::move(stream)) {}
|
||||
|
||||
rust::String MediaStream::id() const {
|
||||
return media_stream_->id();
|
||||
}
|
||||
|
||||
AudioTrack::AudioTrack(rtc::scoped_refptr<webrtc::AudioTrackInterface> track)
|
||||
: MediaStreamTrack(std::move(track)) {}
|
||||
|
||||
VideoTrack::VideoTrack(rtc::scoped_refptr<webrtc::VideoTrackInterface> track)
|
||||
: MediaStreamTrack(std::move(track)) {}
|
||||
|
||||
void VideoTrack::add_sink(NativeVideoFrameSink& sink) {
|
||||
void VideoTrack::add_sink(NativeVideoFrameSink& sink) const {
|
||||
track()->AddOrUpdateSink(&sink, rtc::VideoSinkWants());
|
||||
}
|
||||
|
||||
void VideoTrack::remove_sink(NativeVideoFrameSink& sink) {
|
||||
void VideoTrack::remove_sink(NativeVideoFrameSink& sink) const {
|
||||
track()->RemoveSink(&sink);
|
||||
}
|
||||
|
||||
void VideoTrack::set_should_receive(bool should_receive) {
|
||||
void VideoTrack::set_should_receive(bool should_receive) const {
|
||||
track()->set_should_receive(should_receive);
|
||||
}
|
||||
|
||||
@@ -80,7 +140,7 @@ ContentHint VideoTrack::content_hint() const {
|
||||
return static_cast<ContentHint>(track()->content_hint());
|
||||
}
|
||||
|
||||
void VideoTrack::set_content_hint(ContentHint hint) {
|
||||
void VideoTrack::set_content_hint(ContentHint hint) const {
|
||||
track()->set_content_hint(
|
||||
static_cast<webrtc::VideoTrackInterface::ContentHint>(hint));
|
||||
}
|
||||
@@ -110,4 +170,83 @@ std::unique_ptr<NativeVideoFrameSink> create_native_video_frame_sink(
|
||||
return std::make_unique<NativeVideoFrameSink>(std::move(observer));
|
||||
}
|
||||
|
||||
NativeVideoTrackSource::NativeVideoTrackSource()
|
||||
: rtc::AdaptedVideoTrackSource(1) {}
|
||||
|
||||
NativeVideoTrackSource::~NativeVideoTrackSource() {}
|
||||
|
||||
bool NativeVideoTrackSource::is_screencast() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
absl::optional<bool> NativeVideoTrackSource::needs_denoising() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
webrtc::MediaSourceInterface::SourceState NativeVideoTrackSource::state()
|
||||
const {
|
||||
// TODO(theomonnom): expose source state to Rust
|
||||
return SourceState::kLive;
|
||||
}
|
||||
|
||||
bool NativeVideoTrackSource::remote() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NativeVideoTrackSource::on_captured_frame(
|
||||
const webrtc::VideoFrame& frame) {
|
||||
webrtc::MutexLock lock(&mutex_);
|
||||
|
||||
int64_t aligned_timestamp_us = timestamp_aligner_.TranslateTimestamp(
|
||||
frame.timestamp_us(), rtc::TimeMicros());
|
||||
|
||||
int adapted_width, adapted_height, crop_width, crop_height, crop_x, crop_y;
|
||||
if (!AdaptFrame(frame.width(), frame.height(), frame.timestamp_us(),
|
||||
&adapted_width, &adapted_height, &crop_width, &crop_height,
|
||||
&crop_x, &crop_y)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO(theomonnom): Should this be handled by the users?
|
||||
rtc::scoped_refptr<webrtc::VideoFrameBuffer> buffer =
|
||||
frame.video_frame_buffer();
|
||||
if (adapted_width != frame.width() || adapted_height != frame.height()) {
|
||||
buffer = buffer->CropAndScale(crop_x, crop_y, crop_width, crop_height,
|
||||
adapted_width, adapted_height);
|
||||
}
|
||||
|
||||
if (apply_rotation() && frame.rotation() != webrtc::kVideoRotation_0) {
|
||||
// If the buffer is I420, rtc::AdaptedVideoTrackSource will handle the
|
||||
// rotation for us.
|
||||
buffer = buffer->ToI420();
|
||||
}
|
||||
|
||||
OnFrame(webrtc::VideoFrame::Builder()
|
||||
.set_video_frame_buffer(buffer)
|
||||
.set_rotation(frame.rotation())
|
||||
.set_timestamp_us(aligned_timestamp_us)
|
||||
.build());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
AdaptedVideoTrackSource::AdaptedVideoTrackSource(
|
||||
rtc::scoped_refptr<NativeVideoTrackSource> source)
|
||||
: source_(source) {}
|
||||
|
||||
bool AdaptedVideoTrackSource::on_captured_frame(
|
||||
std::unique_ptr<VideoFrame> frame) const {
|
||||
return source_->on_captured_frame(frame->get());
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<NativeVideoTrackSource> AdaptedVideoTrackSource::get()
|
||||
const {
|
||||
return source_;
|
||||
}
|
||||
|
||||
std::unique_ptr<AdaptedVideoTrackSource> create_adapted_video_track_source() {
|
||||
return std::make_unique<AdaptedVideoTrackSource>(
|
||||
rtc::make_ref_counted<NativeVideoTrackSource>());
|
||||
}
|
||||
|
||||
} // namespace livekit
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use cxx::UniquePtr;
|
||||
|
||||
use crate::impl_thread_safety;
|
||||
use crate::video_frame::ffi::VideoFrame;
|
||||
use cxx::UniquePtr;
|
||||
|
||||
#[cxx::bridge(namespace = "livekit")]
|
||||
pub mod ffi {
|
||||
@@ -22,51 +22,68 @@ pub mod ffi {
|
||||
}
|
||||
|
||||
// -1 = optional
|
||||
#[derive(Debug)]
|
||||
pub struct VideoTrackSourceConstraints {
|
||||
pub min_fps: f64,
|
||||
pub max_fps: f64,
|
||||
}
|
||||
|
||||
extern "C++" {
|
||||
include!("livekit/video_frame.h");
|
||||
include!("livekit/helper.h");
|
||||
|
||||
type VideoFrame = crate::video_frame::ffi::VideoFrame;
|
||||
type VideoTrackPtr = crate::helper::ffi::VideoTrackPtr;
|
||||
type AudioTrackPtr = crate::helper::ffi::AudioTrackPtr;
|
||||
}
|
||||
|
||||
unsafe extern "C++" {
|
||||
include!("livekit/media_stream.h");
|
||||
include!("livekit/video_frame.h");
|
||||
|
||||
type NativeVideoFrameSink;
|
||||
type MediaStreamTrack;
|
||||
type MediaStream;
|
||||
type AudioTrack;
|
||||
type VideoTrack;
|
||||
type VideoFrame = crate::video_frame::ffi::VideoFrame;
|
||||
type AdaptedVideoTrackSource;
|
||||
|
||||
fn id(self: &MediaStream) -> String;
|
||||
fn get_audio_tracks(self: &MediaStream) -> Vec<AudioTrackPtr>;
|
||||
fn get_video_tracks(self: &MediaStream) -> Vec<VideoTrackPtr>;
|
||||
fn find_audio_track(self: &MediaStream, track_id: String) -> SharedPtr<AudioTrack>;
|
||||
fn find_video_track(self: &MediaStream, track_id: String) -> SharedPtr<VideoTrack>;
|
||||
fn add_audio_track(self: &MediaStream, audio_track: SharedPtr<AudioTrack>) -> bool;
|
||||
fn add_video_track(self: &MediaStream, video_track: SharedPtr<VideoTrack>) -> bool;
|
||||
fn remove_audio_track(self: &MediaStream, audio_track: SharedPtr<AudioTrack>) -> bool;
|
||||
fn remove_video_track(self: &MediaStream, video_track: SharedPtr<VideoTrack>) -> bool;
|
||||
|
||||
fn kind(self: &MediaStreamTrack) -> String;
|
||||
fn id(self: &MediaStreamTrack) -> String;
|
||||
fn enabled(self: &MediaStreamTrack) -> bool;
|
||||
fn set_enabled(self: Pin<&mut MediaStreamTrack>, enable: bool) -> bool;
|
||||
fn set_enabled(self: &MediaStreamTrack, enable: bool) -> bool;
|
||||
fn state(self: &MediaStreamTrack) -> TrackState;
|
||||
|
||||
unsafe fn add_sink(self: Pin<&mut VideoTrack>, sink: Pin<&mut NativeVideoFrameSink>);
|
||||
unsafe fn remove_sink(self: Pin<&mut VideoTrack>, sink: Pin<&mut NativeVideoFrameSink>);
|
||||
unsafe fn add_sink(self: &VideoTrack, sink: Pin<&mut NativeVideoFrameSink>);
|
||||
unsafe fn remove_sink(self: &VideoTrack, sink: Pin<&mut NativeVideoFrameSink>);
|
||||
|
||||
fn set_should_receive(self: Pin<&mut VideoTrack>, should_receive: bool);
|
||||
fn set_should_receive(self: &VideoTrack, should_receive: bool);
|
||||
fn should_receive(self: &VideoTrack) -> bool;
|
||||
fn content_hint(self: &VideoTrack) -> ContentHint;
|
||||
fn set_content_hint(self: Pin<&mut VideoTrack>, hint: ContentHint);
|
||||
fn set_content_hint(self: &VideoTrack, hint: ContentHint);
|
||||
|
||||
fn create_native_video_frame_sink(
|
||||
observer: Box<VideoFrameSinkWrapper>,
|
||||
) -> UniquePtr<NativeVideoFrameSink>;
|
||||
|
||||
unsafe fn video_to_media(track: *const VideoTrack) -> *const MediaStreamTrack;
|
||||
unsafe fn audio_to_media(track: *const AudioTrack) -> *const MediaStreamTrack;
|
||||
fn on_captured_frame(self: &AdaptedVideoTrackSource, frame: UniquePtr<VideoFrame>) -> bool;
|
||||
|
||||
unsafe fn media_to_video(track: *const MediaStreamTrack) -> *const VideoTrack;
|
||||
unsafe fn media_to_audio(track: *const MediaStreamTrack) -> *const AudioTrack;
|
||||
|
||||
fn _unique_media_stream_track() -> UniquePtr<MediaStreamTrack>; // Ignore
|
||||
fn _unique_media_stream() -> UniquePtr<MediaStream>; // Ignore
|
||||
fn _unique_audio_track() -> UniquePtr<AudioTrack>; // Ignore
|
||||
fn _unique_video_track() -> UniquePtr<VideoTrack>; // Ignore
|
||||
fn _shared_media_stream_track() -> SharedPtr<MediaStreamTrack>;
|
||||
fn _shared_audio_track() -> SharedPtr<AudioTrack>;
|
||||
fn _shared_video_track() -> SharedPtr<VideoTrack>;
|
||||
fn _shared_media_stream() -> SharedPtr<MediaStream>;
|
||||
}
|
||||
|
||||
extern "Rust" {
|
||||
@@ -81,16 +98,11 @@ pub mod ffi {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Sync for ffi::MediaStreamTrack {}
|
||||
unsafe impl Send for ffi::MediaStreamTrack {}
|
||||
unsafe impl Sync for ffi::MediaStream {}
|
||||
unsafe impl Send for ffi::MediaStream {}
|
||||
unsafe impl Send for ffi::AudioTrack {}
|
||||
unsafe impl Sync for ffi::AudioTrack {}
|
||||
unsafe impl Send for ffi::VideoTrack {}
|
||||
unsafe impl Sync for ffi::VideoTrack {}
|
||||
unsafe impl Send for ffi::NativeVideoFrameSink {}
|
||||
unsafe impl Sync for ffi::NativeVideoFrameSink {}
|
||||
impl_thread_safety!(ffi::MediaStreamTrack, Send + Sync);
|
||||
impl_thread_safety!(ffi::MediaStream, Send + Sync);
|
||||
impl_thread_safety!(ffi::AudioTrack, Send + Sync);
|
||||
impl_thread_safety!(ffi::VideoTrack, Send + Sync);
|
||||
impl_thread_safety!(ffi::NativeVideoFrameSink, Send + Sync);
|
||||
|
||||
pub trait VideoFrameSink: Send + Sync {
|
||||
fn on_frame(&self, frame: UniquePtr<VideoFrame>);
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
//
|
||||
|
||||
#include "livekit/peer_connection.h"
|
||||
#include "livekit/media_stream.h"
|
||||
|
||||
#include "webrtc-sys/src/peer_connection.rs.h"
|
||||
#include "livekit/media_stream.h"
|
||||
#include "livekit/rtc_error.h"
|
||||
#include "livekit/rtp_transceiver.h"
|
||||
|
||||
namespace livekit {
|
||||
|
||||
@@ -32,35 +32,35 @@ PeerConnection::PeerConnection(
|
||||
|
||||
void PeerConnection::create_offer(
|
||||
NativeCreateSdpObserverHandle& observer_handle,
|
||||
RTCOfferAnswerOptions options) {
|
||||
RTCOfferAnswerOptions options) const {
|
||||
peer_connection_->CreateOffer(observer_handle.observer.get(),
|
||||
toNativeOfferAnswerOptions(options));
|
||||
}
|
||||
|
||||
void PeerConnection::create_answer(
|
||||
NativeCreateSdpObserverHandle& observer_handle,
|
||||
RTCOfferAnswerOptions options) {
|
||||
RTCOfferAnswerOptions options) const {
|
||||
peer_connection_->CreateAnswer(observer_handle.observer.get(),
|
||||
toNativeOfferAnswerOptions(options));
|
||||
}
|
||||
|
||||
void PeerConnection::set_local_description(
|
||||
std::unique_ptr<SessionDescription> desc,
|
||||
NativeSetLocalSdpObserverHandle& observer) {
|
||||
NativeSetLocalSdpObserverHandle& observer) const {
|
||||
peer_connection_->SetLocalDescription(desc->clone()->release(),
|
||||
observer.observer);
|
||||
}
|
||||
|
||||
void PeerConnection::set_remote_description(
|
||||
std::unique_ptr<SessionDescription> desc,
|
||||
NativeSetRemoteSdpObserverHandle& observer) {
|
||||
NativeSetRemoteSdpObserverHandle& observer) const {
|
||||
peer_connection_->SetRemoteDescription(desc->clone()->release(),
|
||||
observer.observer);
|
||||
}
|
||||
|
||||
std::unique_ptr<DataChannel> PeerConnection::create_data_channel(
|
||||
rust::String label,
|
||||
std::unique_ptr<NativeDataChannelInit> init) {
|
||||
std::unique_ptr<NativeDataChannelInit> init) const {
|
||||
auto result =
|
||||
peer_connection_->CreateDataChannelOrError(label.c_str(), init.get());
|
||||
|
||||
@@ -71,9 +71,76 @@ std::unique_ptr<DataChannel> PeerConnection::create_data_channel(
|
||||
return std::make_unique<DataChannel>(rtc_runtime_, result.value());
|
||||
}
|
||||
|
||||
std::shared_ptr<RtpSender> PeerConnection::add_track(
|
||||
std::shared_ptr<MediaStreamTrack> track,
|
||||
const rust::Vec<rust::String>& stream_ids) const {
|
||||
std::vector<std::string> std_stream_ids(stream_ids.begin(), stream_ids.end());
|
||||
auto result = peer_connection_->AddTrack(track->get(), std_stream_ids);
|
||||
if (!result.ok()) {
|
||||
throw std::runtime_error(serialize_error(to_error(result.error())));
|
||||
}
|
||||
|
||||
return std::make_shared<RtpSender>(result.value());
|
||||
}
|
||||
|
||||
void PeerConnection::remove_track(std::shared_ptr<RtpSender> sender) const {
|
||||
auto error = peer_connection_->RemoveTrackOrError(sender->get());
|
||||
if (!error.ok())
|
||||
throw std::runtime_error(serialize_error(to_error(error)));
|
||||
}
|
||||
|
||||
std::shared_ptr<RtpTransceiver> PeerConnection::add_transceiver(
|
||||
std::shared_ptr<MediaStreamTrack> track,
|
||||
RtpTransceiverInit init) const {
|
||||
auto result = peer_connection_->AddTransceiver(
|
||||
track->get(), to_native_rtp_transceiver_init(init));
|
||||
if (result.ok())
|
||||
throw std::runtime_error(serialize_error(to_error(result.error())));
|
||||
|
||||
return std::make_shared<RtpTransceiver>(result.value());
|
||||
}
|
||||
|
||||
std::shared_ptr<RtpTransceiver> PeerConnection::add_transceiver_for_media(
|
||||
MediaType media_type,
|
||||
RtpTransceiverInit init) const {
|
||||
auto result = peer_connection_->AddTransceiver(
|
||||
static_cast<cricket::MediaType>(media_type),
|
||||
to_native_rtp_transceiver_init(init));
|
||||
|
||||
if (result.ok())
|
||||
throw std::runtime_error(serialize_error(to_error(result.error())));
|
||||
|
||||
return std::make_shared<RtpTransceiver>(result.value());
|
||||
}
|
||||
|
||||
rust::Vec<RtpSenderPtr> PeerConnection::get_senders() const {
|
||||
rust::Vec<RtpSenderPtr> vec;
|
||||
for (auto sender : peer_connection_->GetSenders())
|
||||
vec.push_back(RtpSenderPtr{std::make_shared<RtpSender>(sender)});
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
rust::Vec<RtpReceiverPtr> PeerConnection::get_receivers() const {
|
||||
rust::Vec<RtpReceiverPtr> vec;
|
||||
for (auto receiver : peer_connection_->GetReceivers())
|
||||
vec.push_back(RtpReceiverPtr{std::make_shared<RtpReceiver>(receiver)});
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
rust::Vec<RtpTransceiverPtr> PeerConnection::get_transceivers() const {
|
||||
rust::Vec<RtpTransceiverPtr> vec;
|
||||
for (auto transceiver : peer_connection_->GetTransceivers())
|
||||
vec.push_back(
|
||||
RtpTransceiverPtr{std::make_shared<RtpTransceiver>(transceiver)});
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
void PeerConnection::add_ice_candidate(
|
||||
std::unique_ptr<IceCandidate> candidate,
|
||||
NativeAddIceCandidateObserver& observer) {
|
||||
std::shared_ptr<IceCandidate> candidate,
|
||||
NativeAddIceCandidateObserver& observer) const {
|
||||
peer_connection_->AddIceCandidate(
|
||||
candidate->release(),
|
||||
[&](const webrtc::RTCError& err) { observer.OnComplete(to_error(err)); });
|
||||
|
||||
@@ -1,21 +1,19 @@
|
||||
use std::fmt::Debug;
|
||||
use std::mem::ManuallyDrop;
|
||||
|
||||
use cxx::UniquePtr;
|
||||
|
||||
use crate::candidate::ffi::Candidate;
|
||||
use crate::data_channel::ffi::DataChannel;
|
||||
use crate::impl_thread_safety;
|
||||
use crate::jsep::ffi::IceCandidate;
|
||||
use crate::media_stream::ffi::MediaStream;
|
||||
use crate::rtc_error::ffi::RTCError;
|
||||
use crate::rtp_receiver::ffi::RtpReceiver;
|
||||
use crate::rtp_transceiver::ffi::RtpTransceiver;
|
||||
use cxx::{SharedPtr, UniquePtr};
|
||||
use std::mem::ManuallyDrop;
|
||||
|
||||
#[cxx::bridge(namespace = "livekit")]
|
||||
pub mod ffi {
|
||||
struct CandidatePair {
|
||||
local: UniquePtr<Candidate>,
|
||||
remote: UniquePtr<Candidate>,
|
||||
local: SharedPtr<Candidate>,
|
||||
remote: SharedPtr<Candidate>,
|
||||
}
|
||||
|
||||
struct CandidatePairChangeEvent {
|
||||
@@ -80,39 +78,44 @@ pub mod ffi {
|
||||
use_obsolete_sctp_sdp: bool,
|
||||
}
|
||||
|
||||
// Wrapper to opaque C++ objects
|
||||
// https://github.com/dtolnay/cxx/issues/741
|
||||
struct MediaStreamPtr {
|
||||
pub ptr: UniquePtr<MediaStream>,
|
||||
}
|
||||
|
||||
struct CandidatePtr {
|
||||
pub ptr: UniquePtr<Candidate>,
|
||||
}
|
||||
|
||||
unsafe extern "C++" {
|
||||
include!("livekit/peer_connection.h");
|
||||
include!("livekit/jsep.h");
|
||||
include!("livekit/data_channel.h");
|
||||
include!("livekit/rtp_receiver.h");
|
||||
include!("livekit/rtp_transceiver.h");
|
||||
include!("livekit/media_stream.h");
|
||||
extern "C++" {
|
||||
include!("livekit/rtc_error.h");
|
||||
include!("livekit/helper.h");
|
||||
include!("livekit/candidate.h");
|
||||
include!("webrtc-sys/src/rtc_error.rs.h");
|
||||
include!("livekit/media_stream.h");
|
||||
include!("livekit/rtp_transceiver.h");
|
||||
include!("livekit/rtp_sender.h");
|
||||
include!("livekit/rtp_receiver.h");
|
||||
include!("livekit/data_channel.h");
|
||||
include!("livekit/jsep.h");
|
||||
include!("livekit/webrtc.h");
|
||||
|
||||
type MediaStreamPtr = crate::helper::ffi::MediaStreamPtr;
|
||||
type CandidatePtr = crate::helper::ffi::CandidatePtr;
|
||||
type RtpSenderPtr = crate::helper::ffi::RtpSenderPtr;
|
||||
type RtpReceiverPtr = crate::helper::ffi::RtpReceiverPtr;
|
||||
type RtpTransceiverPtr = crate::helper::ffi::RtpTransceiverPtr;
|
||||
type RTCError = crate::rtc_error::ffi::RTCError;
|
||||
type Candidate = crate::candidate::ffi::Candidate;
|
||||
type IceCandidate = crate::jsep::ffi::IceCandidate;
|
||||
type DataChannel = crate::data_channel::ffi::DataChannel;
|
||||
type RtpSender = crate::rtp_sender::ffi::RtpSender;
|
||||
type RtpReceiver = crate::rtp_receiver::ffi::RtpReceiver;
|
||||
type RtpTransceiver = crate::rtp_transceiver::ffi::RtpTransceiver;
|
||||
type RtpTransceiverInit = crate::rtp_transceiver::ffi::RtpTransceiverInit;
|
||||
type MediaStream = crate::media_stream::ffi::MediaStream;
|
||||
type MediaStreamTrack = crate::media_stream::ffi::MediaStreamTrack;
|
||||
type NativeCreateSdpObserverHandle = crate::jsep::ffi::NativeCreateSdpObserverHandle;
|
||||
type NativeSetLocalSdpObserverHandle = crate::jsep::ffi::NativeSetLocalSdpObserverHandle;
|
||||
type NativeSetRemoteSdpObserverHandle = crate::jsep::ffi::NativeSetRemoteSdpObserverHandle;
|
||||
type NativeDataChannelInit = crate::data_channel::ffi::NativeDataChannelInit;
|
||||
type SessionDescription = crate::jsep::ffi::SessionDescription;
|
||||
type MediaType = crate::webrtc::ffi::MediaType;
|
||||
type RTCRuntime = crate::webrtc::ffi::RTCRuntime;
|
||||
}
|
||||
|
||||
unsafe extern "C++" {
|
||||
include!("livekit/peer_connection.h");
|
||||
|
||||
type NativeAddIceCandidateObserver;
|
||||
type NativePeerConnectionObserver;
|
||||
@@ -121,7 +124,7 @@ pub mod ffi {
|
||||
/// SAFETY
|
||||
/// The observer must live as long as the operation ends
|
||||
unsafe fn create_offer(
|
||||
self: Pin<&mut PeerConnection>,
|
||||
self: &PeerConnection,
|
||||
observer: Pin<&mut NativeCreateSdpObserverHandle>,
|
||||
options: RTCOfferAnswerOptions,
|
||||
);
|
||||
@@ -129,7 +132,7 @@ pub mod ffi {
|
||||
/// SAFETY
|
||||
/// The observer must live as long as the operation ends
|
||||
unsafe fn create_answer(
|
||||
self: Pin<&mut PeerConnection>,
|
||||
self: &PeerConnection,
|
||||
observer: Pin<&mut NativeCreateSdpObserverHandle>,
|
||||
options: RTCOfferAnswerOptions,
|
||||
);
|
||||
@@ -137,7 +140,7 @@ pub mod ffi {
|
||||
/// SAFETY
|
||||
/// The observer must live as long as the operation ends
|
||||
unsafe fn set_local_description(
|
||||
self: Pin<&mut PeerConnection>,
|
||||
self: &PeerConnection,
|
||||
desc: UniquePtr<SessionDescription>,
|
||||
observer: Pin<&mut NativeSetLocalSdpObserverHandle>,
|
||||
);
|
||||
@@ -145,20 +148,46 @@ pub mod ffi {
|
||||
/// SAFETY
|
||||
/// The observer must live as long as the operation ends
|
||||
unsafe fn set_remote_description(
|
||||
self: Pin<&mut PeerConnection>,
|
||||
self: &PeerConnection,
|
||||
desc: UniquePtr<SessionDescription>,
|
||||
observer: Pin<&mut NativeSetRemoteSdpObserverHandle>,
|
||||
);
|
||||
|
||||
fn add_track(
|
||||
self: &PeerConnection,
|
||||
track: SharedPtr<MediaStreamTrack>,
|
||||
stream_ids: &Vec<String>,
|
||||
) -> Result<SharedPtr<RtpSender>>;
|
||||
|
||||
fn remove_track(self: &PeerConnection, sender: SharedPtr<RtpSender>) -> Result<()>;
|
||||
|
||||
fn add_transceiver(
|
||||
self: &PeerConnection,
|
||||
track: SharedPtr<MediaStreamTrack>,
|
||||
init: RtpTransceiverInit,
|
||||
) -> Result<SharedPtr<RtpTransceiver>>;
|
||||
|
||||
fn add_transceiver_for_media(
|
||||
self: &PeerConnection,
|
||||
media_type: MediaType,
|
||||
init: RtpTransceiverInit,
|
||||
) -> Result<SharedPtr<RtpTransceiver>>;
|
||||
|
||||
fn get_senders(self: &PeerConnection) -> Vec<RtpSenderPtr>;
|
||||
|
||||
fn get_receivers(self: &PeerConnection) -> Vec<RtpReceiverPtr>;
|
||||
|
||||
fn get_transceivers(self: &PeerConnection) -> Vec<RtpTransceiverPtr>;
|
||||
|
||||
fn create_data_channel(
|
||||
self: Pin<&mut PeerConnection>,
|
||||
self: &PeerConnection,
|
||||
label: String,
|
||||
init: UniquePtr<NativeDataChannelInit>,
|
||||
) -> Result<UniquePtr<DataChannel>>;
|
||||
|
||||
fn add_ice_candidate(
|
||||
self: Pin<&mut PeerConnection>,
|
||||
candidate: UniquePtr<IceCandidate>,
|
||||
self: &PeerConnection,
|
||||
candidate: SharedPtr<IceCandidate>,
|
||||
observer: Pin<&mut NativeAddIceCandidateObserver>,
|
||||
);
|
||||
|
||||
@@ -194,8 +223,8 @@ pub mod ffi {
|
||||
type PeerConnectionObserverWrapper;
|
||||
|
||||
fn on_signaling_change(self: &PeerConnectionObserverWrapper, new_state: SignalingState);
|
||||
fn on_add_stream(self: &PeerConnectionObserverWrapper, stream: UniquePtr<MediaStream>);
|
||||
fn on_remove_stream(self: &PeerConnectionObserverWrapper, stream: UniquePtr<MediaStream>);
|
||||
fn on_add_stream(self: &PeerConnectionObserverWrapper, stream: SharedPtr<MediaStream>);
|
||||
fn on_remove_stream(self: &PeerConnectionObserverWrapper, stream: SharedPtr<MediaStream>);
|
||||
fn on_data_channel(
|
||||
self: &PeerConnectionObserverWrapper,
|
||||
data_channel: UniquePtr<DataChannel>,
|
||||
@@ -220,7 +249,7 @@ pub mod ffi {
|
||||
);
|
||||
fn on_ice_candidate(
|
||||
self: &PeerConnectionObserverWrapper,
|
||||
candidate: UniquePtr<IceCandidate>,
|
||||
candidate: SharedPtr<IceCandidate>,
|
||||
);
|
||||
fn on_ice_candidate_error(
|
||||
self: &PeerConnectionObserverWrapper,
|
||||
@@ -244,39 +273,22 @@ pub mod ffi {
|
||||
);
|
||||
fn on_add_track(
|
||||
self: &PeerConnectionObserverWrapper,
|
||||
receiver: UniquePtr<RtpReceiver>,
|
||||
receiver: SharedPtr<RtpReceiver>,
|
||||
streams: Vec<MediaStreamPtr>,
|
||||
);
|
||||
fn on_track(self: &PeerConnectionObserverWrapper, transceiver: UniquePtr<RtpTransceiver>);
|
||||
fn on_remove_track(self: &PeerConnectionObserverWrapper, receiver: UniquePtr<RtpReceiver>);
|
||||
fn on_track(self: &PeerConnectionObserverWrapper, transceiver: SharedPtr<RtpTransceiver>);
|
||||
fn on_remove_track(self: &PeerConnectionObserverWrapper, receiver: SharedPtr<RtpReceiver>);
|
||||
fn on_interesting_usage(self: &PeerConnectionObserverWrapper, usage_pattern: i32);
|
||||
}
|
||||
}
|
||||
|
||||
// https://webrtc.github.io/webrtc-org/native-code/native-apis/
|
||||
unsafe impl Send for ffi::PeerConnection {}
|
||||
|
||||
unsafe impl Sync for ffi::PeerConnection {}
|
||||
|
||||
unsafe impl Send for ffi::NativePeerConnectionObserver {}
|
||||
|
||||
unsafe impl Sync for ffi::NativePeerConnectionObserver {}
|
||||
|
||||
unsafe impl Sync for ffi::NativeAddIceCandidateObserver {}
|
||||
|
||||
unsafe impl Send for ffi::NativeAddIceCandidateObserver {}
|
||||
|
||||
unsafe impl Sync for ffi::NativeSetRemoteSdpObserverHandle {}
|
||||
|
||||
unsafe impl Send for ffi::NativeSetRemoteSdpObserverHandle {}
|
||||
|
||||
unsafe impl Sync for ffi::NativeSetLocalSdpObserverHandle {}
|
||||
|
||||
unsafe impl Send for ffi::NativeSetLocalSdpObserverHandle {}
|
||||
|
||||
unsafe impl Sync for ffi::NativeCreateSdpObserverHandle {}
|
||||
|
||||
unsafe impl Send for ffi::NativeCreateSdpObserverHandle {}
|
||||
impl_thread_safety!(ffi::PeerConnection, Send + Sync);
|
||||
impl_thread_safety!(ffi::NativePeerConnectionObserver, Send + Sync);
|
||||
impl_thread_safety!(ffi::NativeAddIceCandidateObserver, Send + Sync);
|
||||
impl_thread_safety!(ffi::NativeSetRemoteSdpObserverHandle, Send + Sync);
|
||||
impl_thread_safety!(ffi::NativeSetLocalSdpObserverHandle, Send + Sync);
|
||||
impl_thread_safety!(ffi::NativeCreateSdpObserverHandle, Send + Sync);
|
||||
|
||||
impl Default for ffi::RTCOfferAnswerOptions {
|
||||
/*
|
||||
@@ -311,8 +323,8 @@ impl AddIceCandidateObserverWrapper {
|
||||
|
||||
pub trait PeerConnectionObserver: Send + Sync {
|
||||
fn on_signaling_change(&self, new_state: ffi::SignalingState);
|
||||
fn on_add_stream(&self, stream: UniquePtr<MediaStream>);
|
||||
fn on_remove_stream(&self, stream: UniquePtr<MediaStream>);
|
||||
fn on_add_stream(&self, stream: SharedPtr<MediaStream>);
|
||||
fn on_remove_stream(&self, stream: SharedPtr<MediaStream>);
|
||||
fn on_data_channel(&self, data_channel: UniquePtr<DataChannel>);
|
||||
fn on_renegotiation_needed(&self);
|
||||
fn on_negotiation_needed_event(&self, event: u32);
|
||||
@@ -320,7 +332,7 @@ pub trait PeerConnectionObserver: Send + Sync {
|
||||
fn on_standardized_ice_connection_change(&self, new_state: ffi::IceConnectionState);
|
||||
fn on_connection_change(&self, new_state: ffi::PeerConnectionState);
|
||||
fn on_ice_gathering_change(&self, new_state: ffi::IceGatheringState);
|
||||
fn on_ice_candidate(&self, candidate: UniquePtr<IceCandidate>);
|
||||
fn on_ice_candidate(&self, candidate: SharedPtr<IceCandidate>);
|
||||
fn on_ice_candidate_error(
|
||||
&self,
|
||||
address: String,
|
||||
@@ -329,12 +341,12 @@ pub trait PeerConnectionObserver: Send + Sync {
|
||||
error_code: i32,
|
||||
error_text: String,
|
||||
);
|
||||
fn on_ice_candidates_removed(&self, removed: Vec<UniquePtr<Candidate>>);
|
||||
fn on_ice_candidates_removed(&self, removed: Vec<SharedPtr<Candidate>>);
|
||||
fn on_ice_connection_receiving_change(&self, receiving: bool);
|
||||
fn on_ice_selected_candidate_pair_changed(&self, event: ffi::CandidatePairChangeEvent);
|
||||
fn on_add_track(&self, receiver: UniquePtr<RtpReceiver>, streams: Vec<UniquePtr<MediaStream>>);
|
||||
fn on_track(&self, transceiver: UniquePtr<RtpTransceiver>);
|
||||
fn on_remove_track(&self, receiver: UniquePtr<RtpReceiver>);
|
||||
fn on_add_track(&self, receiver: SharedPtr<RtpReceiver>, streams: Vec<SharedPtr<MediaStream>>);
|
||||
fn on_track(&self, transceiver: SharedPtr<RtpTransceiver>);
|
||||
fn on_remove_track(&self, receiver: SharedPtr<RtpReceiver>);
|
||||
fn on_interesting_usage(&self, usage_pattern: i32);
|
||||
}
|
||||
|
||||
@@ -356,13 +368,13 @@ impl PeerConnectionObserverWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
fn on_add_stream(&self, stream: UniquePtr<MediaStream>) {
|
||||
fn on_add_stream(&self, stream: SharedPtr<MediaStream>) {
|
||||
unsafe {
|
||||
(*self.observer).on_add_stream(stream);
|
||||
}
|
||||
}
|
||||
|
||||
fn on_remove_stream(&self, stream: UniquePtr<MediaStream>) {
|
||||
fn on_remove_stream(&self, stream: SharedPtr<MediaStream>) {
|
||||
unsafe {
|
||||
(*self.observer).on_remove_stream(stream);
|
||||
}
|
||||
@@ -410,7 +422,7 @@ impl PeerConnectionObserverWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
fn on_ice_candidate(&self, candidate: UniquePtr<IceCandidate>) {
|
||||
fn on_ice_candidate(&self, candidate: SharedPtr<IceCandidate>) {
|
||||
unsafe {
|
||||
(*self.observer).on_ice_candidate(candidate);
|
||||
}
|
||||
@@ -453,7 +465,7 @@ impl PeerConnectionObserverWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
fn on_add_track(&self, receiver: UniquePtr<RtpReceiver>, streams: Vec<ffi::MediaStreamPtr>) {
|
||||
fn on_add_track(&self, receiver: SharedPtr<RtpReceiver>, streams: Vec<ffi::MediaStreamPtr>) {
|
||||
let mut vec = Vec::new();
|
||||
|
||||
for v in streams {
|
||||
@@ -465,13 +477,13 @@ impl PeerConnectionObserverWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
fn on_track(&self, transceiver: UniquePtr<RtpTransceiver>) {
|
||||
fn on_track(&self, transceiver: SharedPtr<RtpTransceiver>) {
|
||||
unsafe {
|
||||
(*self.observer).on_track(transceiver);
|
||||
}
|
||||
}
|
||||
|
||||
fn on_remove_track(&self, receiver: UniquePtr<RtpReceiver>) {
|
||||
fn on_remove_track(&self, receiver: SharedPtr<RtpReceiver>) {
|
||||
unsafe {
|
||||
(*self.observer).on_remove_track(receiver);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#include "livekit/video_decoder_factory.h"
|
||||
#include "livekit/video_encoder_factory.h"
|
||||
#include "media/engine/webrtc_media_engine.h"
|
||||
#include "webrtc-sys/src/peer_connection_factory.rs.h"
|
||||
|
||||
namespace livekit {
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use crate::impl_thread_safety;
|
||||
|
||||
#[cxx::bridge(namespace = "livekit")]
|
||||
pub mod ffi {
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -55,6 +57,4 @@ pub mod ffi {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for ffi::PeerConnectionFactory {}
|
||||
|
||||
unsafe impl Sync for ffi::PeerConnectionFactory {}
|
||||
impl_thread_safety!(ffi::PeerConnectionFactory, Send + Sync);
|
||||
|
||||
@@ -53,4 +53,4 @@ void throw_error() {
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace livekit
|
||||
} // namespace livekit
|
||||
|
||||
@@ -0,0 +1,446 @@
|
||||
#include "livekit/rtp_parameters.h"
|
||||
|
||||
namespace livekit {
|
||||
|
||||
webrtc::RtcpFeedback to_native_rtcp_feedback(RtcpFeedback feedback) {
|
||||
webrtc::RtcpFeedback native;
|
||||
native.type = static_cast<webrtc::RtcpFeedbackType>(feedback.feedback_type);
|
||||
if (feedback.has_message_type)
|
||||
native.message_type =
|
||||
static_cast<webrtc::RtcpFeedbackMessageType>(feedback.message_type);
|
||||
|
||||
return native;
|
||||
}
|
||||
|
||||
webrtc::RtpCodecCapability to_native_rtp_codec_capability(
|
||||
RtpCodecCapability capability) {
|
||||
webrtc::RtpCodecCapability native;
|
||||
// native.mime_type(); IGNORED
|
||||
|
||||
native.name = capability.name.c_str();
|
||||
native.kind = static_cast<cricket::MediaType>(capability.kind);
|
||||
|
||||
if (capability.has_clock_rate)
|
||||
native.clock_rate = native.clock_rate;
|
||||
|
||||
if (capability.has_preferred_payload_type)
|
||||
native.preferred_payload_type = capability.preferred_payload_type;
|
||||
|
||||
if (capability.has_max_ptime)
|
||||
native.max_ptime = capability.max_ptime;
|
||||
|
||||
if (capability.has_ptime)
|
||||
native.ptime = capability.ptime;
|
||||
|
||||
if (capability.has_num_channels)
|
||||
native.num_channels = capability.num_channels;
|
||||
|
||||
for (auto feedback : capability.rtcp_feedback)
|
||||
native.rtcp_feedback.push_back(to_native_rtcp_feedback(feedback));
|
||||
|
||||
for (auto pair : capability.parameters)
|
||||
native.parameters.insert(std::pair(pair.key, pair.value));
|
||||
|
||||
for (auto pair : capability.options)
|
||||
native.options.insert(std::pair(pair.key, pair.value));
|
||||
|
||||
native.max_temporal_layer_extensions =
|
||||
capability.max_temporal_layer_extensions;
|
||||
|
||||
native.max_spatial_layer_extensions = capability.max_spatial_layer_extensions;
|
||||
|
||||
native.svc_multi_stream_support = capability.svc_multi_stream_support;
|
||||
|
||||
return native;
|
||||
}
|
||||
|
||||
webrtc::RtpHeaderExtensionCapability to_native_rtp_header_extension_capability(
|
||||
RtpHeaderExtensionCapability header) {
|
||||
webrtc::RtpHeaderExtensionCapability native;
|
||||
native.uri = header.uri.c_str();
|
||||
|
||||
if (header.has_preferred_id)
|
||||
native.preferred_id = header.preferred_id;
|
||||
|
||||
native.preferred_encrypt = header.preferred_encrypt;
|
||||
native.direction =
|
||||
static_cast<webrtc::RtpTransceiverDirection>(header.direction);
|
||||
|
||||
return native;
|
||||
}
|
||||
|
||||
webrtc::RtpExtension to_native_rtp_extension(RtpExtension ext) {
|
||||
webrtc::RtpExtension native;
|
||||
native.uri = ext.uri.c_str();
|
||||
native.id = ext.id;
|
||||
native.encrypt = ext.encrypt;
|
||||
return native;
|
||||
}
|
||||
|
||||
webrtc::RtpFecParameters to_rtp_fec_parameters(RtpFecParameters fec) {
|
||||
webrtc::RtpFecParameters native;
|
||||
|
||||
if (fec.has_ssrc)
|
||||
native.ssrc = fec.ssrc;
|
||||
|
||||
native.mechanism = static_cast<webrtc::FecMechanism>(fec.mechanism);
|
||||
return native;
|
||||
}
|
||||
|
||||
webrtc::RtpRtxParameters to_rtp_rtx_parameters(RtpRtxParameters rtx) {
|
||||
webrtc::RtpRtxParameters native;
|
||||
|
||||
if (rtx.has_ssrc)
|
||||
native.ssrc = rtx.ssrc;
|
||||
return native;
|
||||
}
|
||||
|
||||
webrtc::RtpEncodingParameters to_native_rtp_encoding_paramters(
|
||||
RtpEncodingParameters parameters) {
|
||||
webrtc::RtpEncodingParameters native;
|
||||
native.rid = parameters.rid.c_str();
|
||||
|
||||
if (parameters.has_ssrc)
|
||||
native.ssrc = parameters.ssrc;
|
||||
|
||||
native.active = parameters.active;
|
||||
if (parameters.has_max_framerate)
|
||||
native.max_framerate = parameters.max_framerate;
|
||||
|
||||
native.adaptive_ptime = parameters.adaptive_ptime;
|
||||
if (parameters.has_max_bitrate_bps)
|
||||
native.max_bitrate_bps = parameters.max_bitrate_bps;
|
||||
|
||||
if (parameters.has_min_bitrate_bps)
|
||||
native.min_bitrate_bps = parameters.min_bitrate_bps;
|
||||
|
||||
native.bitrate_priority = parameters.bitrate_priority;
|
||||
native.network_priority =
|
||||
static_cast<webrtc::Priority>(parameters.network_priority);
|
||||
|
||||
if (parameters.has_scalability_mode)
|
||||
native.scalability_mode = parameters.scalability_mode.c_str();
|
||||
|
||||
if (parameters.has_num_temporal_layers)
|
||||
native.num_temporal_layers = parameters.num_temporal_layers;
|
||||
|
||||
if (parameters.has_scale_resolution_down_by)
|
||||
native.scale_resolution_down_by = parameters.scale_resolution_down_by;
|
||||
return native;
|
||||
}
|
||||
|
||||
webrtc::RtpCodecParameters to_native_rtp_codec_parameters(
|
||||
RtpCodecParameters params) {
|
||||
webrtc::RtpCodecParameters native;
|
||||
native.name = params.name.c_str();
|
||||
native.kind = static_cast<cricket::MediaType>(params.kind);
|
||||
native.payload_type = params.payload_type;
|
||||
|
||||
for (auto pair : params.parameters)
|
||||
native.parameters.insert(std::pair(pair.key, pair.value));
|
||||
|
||||
for (auto feedback : params.rtcp_feedback)
|
||||
native.rtcp_feedback.push_back(to_native_rtcp_feedback(feedback));
|
||||
|
||||
if (params.has_num_channels)
|
||||
native.num_channels = params.num_channels;
|
||||
|
||||
if (params.has_ptime)
|
||||
native.ptime = params.ptime;
|
||||
|
||||
if (params.has_max_ptime)
|
||||
native.max_ptime = params.max_ptime;
|
||||
|
||||
if (params.has_clock_rate)
|
||||
native.clock_rate = params.clock_rate;
|
||||
|
||||
return native;
|
||||
}
|
||||
|
||||
webrtc::RtpCapabilities to_rtp_capabilities(RtpCapabilities capabilities) {
|
||||
webrtc::RtpCapabilities native;
|
||||
for (auto codec : capabilities.codecs)
|
||||
native.codecs.push_back(to_native_rtp_codec_capability(codec));
|
||||
|
||||
for (auto header : capabilities.header_extensions)
|
||||
native.header_extensions.push_back(
|
||||
to_native_rtp_header_extension_capability(header));
|
||||
|
||||
for (auto fec : capabilities.fec)
|
||||
native.fec.push_back(static_cast<webrtc::FecMechanism>(fec));
|
||||
|
||||
return native;
|
||||
}
|
||||
|
||||
webrtc::RtcpParameters to_native_rtcp_paramaters(RtcpParameters params) {
|
||||
webrtc::RtcpParameters native;
|
||||
if (params.has_ssrc)
|
||||
native.ssrc = params.ssrc;
|
||||
|
||||
native.mux = params.mux;
|
||||
native.cname = params.cname.c_str();
|
||||
native.reduced_size = params.reduced_size;
|
||||
return native;
|
||||
}
|
||||
|
||||
webrtc::RtpParameters to_native_rtp_parameters(RtpParameters params) {
|
||||
webrtc::RtpParameters native;
|
||||
native.transaction_id = params.transaction_id.c_str();
|
||||
native.mid = params.mid.c_str();
|
||||
|
||||
for (auto codec : params.codecs)
|
||||
native.codecs.push_back(to_native_rtp_codec_parameters(codec));
|
||||
|
||||
for (auto header : params.header_extensions)
|
||||
native.header_extensions.push_back(to_native_rtp_extension(header));
|
||||
|
||||
for (auto encoding : params.encodings)
|
||||
native.encodings.push_back(to_native_rtp_encoding_paramters(encoding));
|
||||
|
||||
native.rtcp = to_native_rtcp_paramaters(params.rtcp);
|
||||
|
||||
if (params.has_degradation_preference)
|
||||
native.degradation_preference = static_cast<webrtc::DegradationPreference>(
|
||||
params.degradation_preference);
|
||||
|
||||
return native;
|
||||
}
|
||||
|
||||
RtcpFeedback to_rust_rtcp_feedback(webrtc::RtcpFeedback feedback) {
|
||||
RtcpFeedback rust;
|
||||
rust.feedback_type = static_cast<RtcpFeedbackType>(feedback.type);
|
||||
|
||||
if (feedback.message_type.has_value()) {
|
||||
rust.has_message_type = true;
|
||||
rust.message_type =
|
||||
static_cast<RtcpFeedbackMessageType>(feedback.message_type.value());
|
||||
}
|
||||
|
||||
return rust;
|
||||
}
|
||||
|
||||
RtpCodecCapability to_rust_rtp_codec_capability(
|
||||
webrtc::RtpCodecCapability capability) {
|
||||
RtpCodecCapability rust;
|
||||
rust.mime_type = capability.mime_type();
|
||||
rust.name = capability.name;
|
||||
rust.kind = static_cast<MediaType>(capability.kind);
|
||||
|
||||
if (capability.clock_rate.has_value()) {
|
||||
rust.has_clock_rate = true;
|
||||
rust.clock_rate = capability.clock_rate.value();
|
||||
}
|
||||
|
||||
if (capability.preferred_payload_type.has_value()) {
|
||||
rust.has_preferred_payload_type = true;
|
||||
rust.preferred_payload_type = capability.preferred_payload_type.value();
|
||||
}
|
||||
|
||||
if (capability.max_ptime.has_value()) {
|
||||
rust.has_max_ptime = true;
|
||||
rust.max_ptime = capability.max_ptime.value();
|
||||
}
|
||||
|
||||
if (capability.ptime.has_value()) {
|
||||
rust.has_ptime = true;
|
||||
rust.ptime = capability.ptime.value();
|
||||
}
|
||||
|
||||
if (capability.num_channels.has_value()) {
|
||||
rust.has_num_channels = true;
|
||||
rust.num_channels = capability.num_channels.value();
|
||||
}
|
||||
|
||||
for (auto feedback : capability.rtcp_feedback)
|
||||
rust.rtcp_feedback.push_back(to_rust_rtcp_feedback(feedback));
|
||||
|
||||
for (auto param : capability.parameters)
|
||||
rust.parameters.push_back(StringKeyValue{param.first, param.second});
|
||||
|
||||
for (auto option : capability.options)
|
||||
rust.options.push_back(StringKeyValue{option.first, option.second});
|
||||
|
||||
rust.max_temporal_layer_extensions = capability.max_temporal_layer_extensions;
|
||||
rust.max_spatial_layer_extensions = capability.max_spatial_layer_extensions;
|
||||
rust.svc_multi_stream_support = capability.svc_multi_stream_support;
|
||||
return rust;
|
||||
}
|
||||
|
||||
RtpHeaderExtensionCapability to_rust_rtp_header_extension_capability(
|
||||
webrtc::RtpHeaderExtensionCapability header) {
|
||||
RtpHeaderExtensionCapability rust;
|
||||
rust.uri = header.uri;
|
||||
if (header.preferred_id.has_value()) {
|
||||
rust.has_preferred_id = true;
|
||||
rust.preferred_id = header.preferred_id.value();
|
||||
}
|
||||
|
||||
rust.preferred_encrypt = header.preferred_encrypt;
|
||||
rust.direction = static_cast<RtpTransceiverDirection>(header.direction);
|
||||
return rust;
|
||||
}
|
||||
|
||||
RtpExtension to_rust_rtp_extension(webrtc::RtpExtension ext) {
|
||||
RtpExtension rust;
|
||||
rust.uri = ext.uri;
|
||||
rust.id = ext.id;
|
||||
rust.encrypt = ext.encrypt;
|
||||
return rust;
|
||||
}
|
||||
|
||||
RtpFecParameters to_rust_rtp_fec_parameters(webrtc::RtpFecParameters fec) {
|
||||
RtpFecParameters rust;
|
||||
if (fec.ssrc.has_value()) {
|
||||
rust.has_ssrc = true;
|
||||
rust.ssrc = fec.ssrc.value();
|
||||
}
|
||||
|
||||
rust.mechanism = static_cast<FecMechanism>(rust.mechanism);
|
||||
return rust;
|
||||
}
|
||||
|
||||
RtpRtxParameters to_rust_rtp_rtx_parameters(webrtc::RtpRtxParameters param) {
|
||||
RtpRtxParameters rust;
|
||||
if (param.ssrc.has_value()) {
|
||||
rust.has_ssrc = param.ssrc.has_value();
|
||||
rust.ssrc = param.ssrc.value();
|
||||
}
|
||||
return rust;
|
||||
}
|
||||
|
||||
RtpEncodingParameters to_rust_rtp_encoding_parameters(
|
||||
webrtc::RtpEncodingParameters params) {
|
||||
RtpEncodingParameters rust;
|
||||
if (params.ssrc.has_value()) {
|
||||
rust.has_ssrc = params.ssrc.has_value();
|
||||
rust.ssrc = params.ssrc.value();
|
||||
}
|
||||
|
||||
rust.bitrate_priority = params.bitrate_priority;
|
||||
rust.network_priority = static_cast<Priority>(params.network_priority);
|
||||
if (params.max_bitrate_bps.has_value()) {
|
||||
rust.has_max_bitrate_bps = true;
|
||||
rust.max_bitrate_bps = params.max_bitrate_bps.value();
|
||||
}
|
||||
|
||||
if (params.min_bitrate_bps.has_value()) {
|
||||
rust.has_min_bitrate_bps = true;
|
||||
rust.min_bitrate_bps = params.min_bitrate_bps.value();
|
||||
}
|
||||
|
||||
if (params.max_framerate.has_value()) {
|
||||
rust.has_max_framerate = true;
|
||||
rust.max_framerate = params.max_framerate.value();
|
||||
}
|
||||
|
||||
if (params.num_temporal_layers.has_value()) {
|
||||
rust.has_num_temporal_layers = true;
|
||||
rust.num_temporal_layers = params.num_temporal_layers.value();
|
||||
}
|
||||
|
||||
if (params.scale_resolution_down_by.has_value()) {
|
||||
rust.has_scale_resolution_down_by = true;
|
||||
rust.scale_resolution_down_by = params.scale_resolution_down_by.value();
|
||||
}
|
||||
|
||||
if (params.scalability_mode.has_value()) {
|
||||
rust.has_scalability_mode = true;
|
||||
rust.scalability_mode = params.scalability_mode.value();
|
||||
}
|
||||
|
||||
rust.active = params.active;
|
||||
rust.rid = params.rid;
|
||||
rust.adaptive_ptime = params.adaptive_ptime;
|
||||
return rust;
|
||||
}
|
||||
|
||||
RtpCodecParameters to_rust_rtp_codec_parameters(
|
||||
webrtc::RtpCodecParameters params) {
|
||||
RtpCodecParameters rust;
|
||||
rust.mime_type = params.mime_type();
|
||||
rust.name = params.name;
|
||||
rust.kind = static_cast<MediaType>(params.kind);
|
||||
rust.payload_type = params.payload_type;
|
||||
if (params.clock_rate.has_value()) {
|
||||
rust.has_clock_rate = true;
|
||||
rust.clock_rate = params.clock_rate.value();
|
||||
}
|
||||
|
||||
if (params.num_channels.has_value()) {
|
||||
rust.has_num_channels = true;
|
||||
rust.num_channels = params.num_channels.value();
|
||||
}
|
||||
|
||||
if (params.max_ptime.has_value()) {
|
||||
rust.has_max_ptime = true;
|
||||
rust.max_ptime = params.max_ptime.value();
|
||||
}
|
||||
|
||||
if (params.ptime.has_value()) {
|
||||
rust.has_ptime = true;
|
||||
rust.ptime = params.ptime.value();
|
||||
}
|
||||
|
||||
for (auto feedback : params.rtcp_feedback)
|
||||
rust.rtcp_feedback.push_back(to_rust_rtcp_feedback(feedback));
|
||||
|
||||
for (auto pair : params.parameters)
|
||||
rust.parameters.push_back(StringKeyValue{pair.first, pair.second});
|
||||
|
||||
return rust;
|
||||
}
|
||||
|
||||
RtpCapabilities to_rust_rtp_capabilities(webrtc::RtpCapabilities capabilities) {
|
||||
RtpCapabilities rust;
|
||||
for (auto codec : capabilities.codecs)
|
||||
rust.codecs.push_back(to_rust_rtp_codec_capability(codec));
|
||||
|
||||
for (auto header : capabilities.header_extensions)
|
||||
rust.header_extensions.push_back(
|
||||
to_rust_rtp_header_extension_capability(header));
|
||||
|
||||
for (auto fec : capabilities.fec)
|
||||
rust.fec.push_back(static_cast<FecMechanism>(fec));
|
||||
|
||||
return rust;
|
||||
}
|
||||
|
||||
RtcpParameters to_rust_rtcp_parameters(webrtc::RtcpParameters params) {
|
||||
RtcpParameters rust;
|
||||
if (params.ssrc.has_value()) {
|
||||
rust.has_ssrc = true;
|
||||
rust.ssrc = params.ssrc.value();
|
||||
}
|
||||
|
||||
rust.cname = params.cname;
|
||||
rust.reduced_size = params.reduced_size;
|
||||
rust.mux = params.mux;
|
||||
return rust;
|
||||
}
|
||||
|
||||
RtpParameters to_rust_rtp_parameters(webrtc::RtpParameters params) {
|
||||
RtpParameters rust;
|
||||
rust.transaction_id = params.transaction_id;
|
||||
rust.mid = params.mid;
|
||||
|
||||
for (auto codec : params.codecs)
|
||||
rust.codecs.push_back(to_rust_rtp_codec_parameters(codec));
|
||||
|
||||
for (auto header : params.header_extensions)
|
||||
rust.header_extensions.push_back(to_rust_rtp_extension(header));
|
||||
|
||||
for (auto encoding : params.encodings)
|
||||
rust.encodings.push_back(to_rust_rtp_encoding_parameters(encoding));
|
||||
|
||||
rust.rtcp = to_rust_rtcp_parameters(params.rtcp);
|
||||
|
||||
if (params.degradation_preference.has_value()) {
|
||||
rust.has_degradation_preference = true;
|
||||
rust.degradation_preference = static_cast<DegradationPreference>(
|
||||
params.degradation_preference.value());
|
||||
}
|
||||
|
||||
return rust;
|
||||
}
|
||||
|
||||
} // namespace livekit
|
||||
@@ -0,0 +1,194 @@
|
||||
use cxx::UniquePtr;
|
||||
|
||||
pub const DEFAULT_BITRATE_PRIORITY: f64 = 1.0;
|
||||
|
||||
#[cxx::bridge(namespace = "livekit")]
|
||||
pub mod ffi {
|
||||
|
||||
// Used to replace std::map
|
||||
#[derive(Debug)]
|
||||
pub struct StringKeyValue {
|
||||
pub key: String,
|
||||
pub value: String,
|
||||
}
|
||||
|
||||
#[repr(i32)]
|
||||
#[derive(Debug)]
|
||||
pub enum FecMechanism {
|
||||
RED,
|
||||
REDAndULPFEC,
|
||||
FLEXFEC,
|
||||
}
|
||||
|
||||
#[repr(i32)]
|
||||
#[derive(Debug)]
|
||||
pub enum RtcpFeedbackType {
|
||||
CCM,
|
||||
LNTF,
|
||||
NACK,
|
||||
REMB,
|
||||
TransportCC,
|
||||
}
|
||||
|
||||
#[repr(i32)]
|
||||
#[derive(Debug)]
|
||||
pub enum RtcpFeedbackMessageType {
|
||||
GenericNACK,
|
||||
PLI,
|
||||
FIR,
|
||||
}
|
||||
|
||||
#[repr(i32)]
|
||||
#[derive(Debug)]
|
||||
pub enum DegradationPreference {
|
||||
Disabled,
|
||||
MaintainFramerate,
|
||||
MaintainResolution,
|
||||
Balanced,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RtcpFeedback {
|
||||
pub feedback_type: RtcpFeedbackType,
|
||||
pub has_message_type: bool,
|
||||
pub message_type: RtcpFeedbackMessageType,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RtpCodecCapability {
|
||||
pub mime_type: String, // filled with mime_type fnc
|
||||
pub name: String,
|
||||
pub kind: MediaType,
|
||||
pub has_clock_rate: bool,
|
||||
pub clock_rate: i32,
|
||||
pub has_preferred_payload_type: bool,
|
||||
pub preferred_payload_type: i32,
|
||||
pub has_max_ptime: bool,
|
||||
pub max_ptime: i32,
|
||||
pub has_ptime: bool,
|
||||
pub ptime: i32,
|
||||
pub has_num_channels: bool,
|
||||
pub num_channels: i32,
|
||||
pub rtcp_feedback: Vec<RtcpFeedback>,
|
||||
pub parameters: Vec<StringKeyValue>,
|
||||
pub options: Vec<StringKeyValue>,
|
||||
pub max_temporal_layer_extensions: i32,
|
||||
pub max_spatial_layer_extensions: i32,
|
||||
pub svc_multi_stream_support: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RtpHeaderExtensionCapability {
|
||||
pub uri: String,
|
||||
pub has_preferred_id: bool,
|
||||
pub preferred_id: i32,
|
||||
pub preferred_encrypt: bool,
|
||||
pub direction: RtpTransceiverDirection,
|
||||
}
|
||||
|
||||
#[repr(i32)]
|
||||
#[derive(Debug)]
|
||||
pub enum RtpExtensionFilter {
|
||||
DiscardEncryptedExtension,
|
||||
PreferEncryptedExtension,
|
||||
RequireEncryptedExtension,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RtpExtension {
|
||||
// TODO(theomonnom): export available URI inside api/rtp_parameters.h
|
||||
pub uri: String,
|
||||
pub id: i32,
|
||||
pub encrypt: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RtpFecParameters {
|
||||
pub has_ssrc: bool,
|
||||
pub ssrc: u32,
|
||||
pub mechanism: FecMechanism,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RtpRtxParameters {
|
||||
pub has_ssrc: bool,
|
||||
pub ssrc: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RtpEncodingParameters {
|
||||
pub has_ssrc: bool,
|
||||
pub ssrc: u32,
|
||||
pub bitrate_priority: f64,
|
||||
pub network_priority: Priority, // Todo link type
|
||||
pub has_max_bitrate_bps: bool,
|
||||
pub max_bitrate_bps: i32,
|
||||
pub has_min_bitrate_bps: bool,
|
||||
pub min_bitrate_bps: i32,
|
||||
pub has_max_framerate: bool,
|
||||
pub max_framerate: f64,
|
||||
pub has_num_temporal_layers: bool,
|
||||
pub num_temporal_layers: i32,
|
||||
pub has_scale_resolution_down_by: bool,
|
||||
pub scale_resolution_down_by: f64,
|
||||
pub has_scalability_mode: bool,
|
||||
pub scalability_mode: String,
|
||||
pub active: bool,
|
||||
pub rid: String,
|
||||
pub adaptive_ptime: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RtpCodecParameters {
|
||||
pub mime_type: String, // filled with mime_type fnc
|
||||
pub name: String,
|
||||
pub kind: MediaType,
|
||||
pub payload_type: i32,
|
||||
pub has_clock_rate: bool,
|
||||
pub clock_rate: i32,
|
||||
pub has_num_channels: bool,
|
||||
pub num_channels: i32,
|
||||
pub has_max_ptime: bool,
|
||||
pub max_ptime: i32,
|
||||
pub has_ptime: bool,
|
||||
pub ptime: i32,
|
||||
pub rtcp_feedback: Vec<RtcpFeedback>,
|
||||
pub parameters: Vec<StringKeyValue>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RtpCapabilities {
|
||||
pub codecs: Vec<RtpCodecCapability>,
|
||||
pub header_extensions: Vec<RtpHeaderExtensionCapability>,
|
||||
pub fec: Vec<FecMechanism>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RtcpParameters {
|
||||
pub has_ssrc: bool,
|
||||
pub ssrc: u32,
|
||||
pub cname: String,
|
||||
pub reduced_size: bool,
|
||||
pub mux: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RtpParameters {
|
||||
pub transaction_id: String,
|
||||
pub mid: String,
|
||||
pub codecs: Vec<RtpCodecParameters>,
|
||||
pub header_extensions: Vec<RtpExtension>,
|
||||
pub encodings: Vec<RtpEncodingParameters>,
|
||||
pub rtcp: RtcpParameters,
|
||||
pub has_degradation_preference: bool,
|
||||
pub degradation_preference: DegradationPreference,
|
||||
}
|
||||
|
||||
extern "C++" {
|
||||
include!("webrtc-sys/src/webrtc.rs.h");
|
||||
|
||||
type Priority = crate::webrtc::ffi::Priority;
|
||||
type MediaType = crate::webrtc::ffi::MediaType;
|
||||
type RtpTransceiverDirection = crate::webrtc::ffi::RtpTransceiverDirection;
|
||||
}
|
||||
}
|
||||
@@ -4,13 +4,48 @@
|
||||
|
||||
#include "livekit/rtp_receiver.h"
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
|
||||
namespace livekit {
|
||||
|
||||
RtpReceiver::RtpReceiver(
|
||||
rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver)
|
||||
: receiver_(std::move(receiver)) {}
|
||||
|
||||
std::unique_ptr<MediaStreamTrack> RtpReceiver::track() const {
|
||||
std::shared_ptr<MediaStreamTrack> RtpReceiver::track() const {
|
||||
return MediaStreamTrack::from(receiver_->track());
|
||||
}
|
||||
|
||||
} // namespace livekit
|
||||
rust::Vec<rust::String> RtpReceiver::stream_ids() const {
|
||||
rust::Vec<rust::String> rust;
|
||||
for (auto id : receiver_->stream_ids())
|
||||
rust.push_back(id);
|
||||
return rust;
|
||||
}
|
||||
|
||||
rust::Vec<MediaStreamPtr> RtpReceiver::streams() const {
|
||||
rust::Vec<MediaStreamPtr> rust;
|
||||
for (auto stream : receiver_->streams())
|
||||
rust.push_back(MediaStreamPtr{std::make_shared<MediaStream>(stream)});
|
||||
return rust;
|
||||
}
|
||||
|
||||
MediaType RtpReceiver::media_type() const {
|
||||
return static_cast<MediaType>(receiver_->media_type());
|
||||
}
|
||||
|
||||
rust::String RtpReceiver::id() const {
|
||||
return receiver_->id();
|
||||
}
|
||||
|
||||
RtpParameters RtpReceiver::get_parameters() const {
|
||||
return to_rust_rtp_parameters(receiver_->GetParameters());
|
||||
}
|
||||
|
||||
void RtpReceiver::set_jitter_buffer_minimum_delay(bool is_some,
|
||||
double delay_seconds) const {
|
||||
receiver_->SetJitterBufferMinimumDelay(
|
||||
is_some ? absl::make_optional(delay_seconds) : absl::nullopt);
|
||||
}
|
||||
|
||||
} // namespace livekit
|
||||
|
||||
@@ -1,18 +1,36 @@
|
||||
use crate::impl_thread_safety;
|
||||
|
||||
#[cxx::bridge(namespace = "livekit")]
|
||||
pub mod ffi {
|
||||
unsafe extern "C++" {
|
||||
include!("livekit/rtp_receiver.h");
|
||||
|
||||
extern "C++" {
|
||||
include!("livekit/webrtc.h");
|
||||
include!("livekit/rtp_parameters.h");
|
||||
include!("livekit/helper.h");
|
||||
include!("livekit/media_stream.h");
|
||||
|
||||
type MediaType = crate::webrtc::ffi::MediaType;
|
||||
type RtpParameters = crate::rtp_parameters::ffi::RtpParameters;
|
||||
type MediaStreamPtr = crate::helper::ffi::MediaStreamPtr;
|
||||
type MediaStreamTrack = crate::media_stream::ffi::MediaStreamTrack;
|
||||
type MediaStream = crate::media_stream::ffi::MediaStream;
|
||||
}
|
||||
|
||||
unsafe extern "C++" {
|
||||
include!("livekit/rtp_receiver.h");
|
||||
|
||||
type RtpReceiver;
|
||||
|
||||
fn track(self: &RtpReceiver) -> UniquePtr<MediaStreamTrack>;
|
||||
fn track(self: &RtpReceiver) -> SharedPtr<MediaStreamTrack>;
|
||||
fn stream_ids(self: &RtpReceiver) -> Vec<String>;
|
||||
fn streams(self: &RtpReceiver) -> Vec<MediaStreamPtr>;
|
||||
fn media_type(self: &RtpReceiver) -> MediaType;
|
||||
fn id(self: &RtpReceiver) -> String;
|
||||
fn get_parameters(self: &RtpReceiver) -> RtpParameters;
|
||||
fn set_jitter_buffer_minimum_delay(self: &RtpReceiver, is_some: bool, delay_seconds: f64);
|
||||
|
||||
fn _unique_rtp_receiver() -> UniquePtr<RtpReceiver>; // Ignore
|
||||
fn _shared_rtp_receiver() -> SharedPtr<RtpReceiver>;
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Sync for ffi::RtpReceiver {}
|
||||
|
||||
unsafe impl Send for ffi::RtpReceiver {}
|
||||
impl_thread_safety!(ffi::RtpReceiver, Send + Sync);
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
#include "livekit/rtp_sender.h"
|
||||
|
||||
namespace livekit {
|
||||
|
||||
RtpSender::RtpSender(rtc::scoped_refptr<webrtc::RtpSenderInterface> sender)
|
||||
: sender_(std::move(sender)) {}
|
||||
|
||||
bool RtpSender::set_track(std::shared_ptr<MediaStreamTrack> track) const {
|
||||
return sender_->SetTrack(track->get().get());
|
||||
}
|
||||
|
||||
std::shared_ptr<MediaStreamTrack> RtpSender::track() const {
|
||||
return MediaStreamTrack::from(sender_->track());
|
||||
}
|
||||
|
||||
uint32_t RtpSender::ssrc() const {
|
||||
return sender_->ssrc();
|
||||
}
|
||||
|
||||
MediaType RtpSender::media_type() const {
|
||||
return static_cast<MediaType>(sender_->media_type());
|
||||
}
|
||||
|
||||
rust::String RtpSender::id() const {
|
||||
return sender_->id();
|
||||
}
|
||||
|
||||
rust::Vec<rust::String> RtpSender::stream_ids() const {
|
||||
rust::Vec<rust::String> vec;
|
||||
for (auto str : sender_->stream_ids())
|
||||
vec.push_back(str);
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
void RtpSender::set_streams(const rust::Vec<rust::String>& stream_ids) const {
|
||||
std::vector<std::string> std_stream_ids(stream_ids.begin(), stream_ids.end());
|
||||
sender_->SetStreams(std_stream_ids);
|
||||
}
|
||||
|
||||
rust::Vec<RtpEncodingParameters> RtpSender::init_send_encodings() const {
|
||||
rust::Vec<RtpEncodingParameters> encodings;
|
||||
for (auto encoding : sender_->init_send_encodings())
|
||||
encodings.push_back(to_rust_rtp_encoding_parameters(encoding));
|
||||
return encodings;
|
||||
}
|
||||
|
||||
RtpParameters RtpSender::get_parameters() const {
|
||||
return to_rust_rtp_parameters(sender_->GetParameters());
|
||||
}
|
||||
|
||||
void RtpSender::set_parameters(RtpParameters params) const {
|
||||
auto error = sender_->SetParameters(to_native_rtp_parameters(params));
|
||||
if (!error.ok())
|
||||
throw std::runtime_error(serialize_error(to_error(error)));
|
||||
}
|
||||
|
||||
} // namespace livekit
|
||||
@@ -0,0 +1,33 @@
|
||||
#[cxx::bridge(namespace = "livekit")]
|
||||
pub mod ffi {
|
||||
|
||||
extern "C++" {
|
||||
include!("livekit/webrtc.h");
|
||||
include!("livekit/rtp_parameters.h");
|
||||
include!("livekit/media_stream.h");
|
||||
|
||||
type MediaType = crate::webrtc::ffi::MediaType;
|
||||
type RtpEncodingParameters = crate::rtp_parameters::ffi::RtpEncodingParameters;
|
||||
type RtpParameters = crate::rtp_parameters::ffi::RtpParameters;
|
||||
type MediaStreamTrack = crate::media_stream::ffi::MediaStreamTrack;
|
||||
}
|
||||
|
||||
unsafe extern "C++" {
|
||||
include!("livekit/rtp_sender.h");
|
||||
|
||||
type RtpSender;
|
||||
|
||||
fn set_track(self: &RtpSender, track: SharedPtr<MediaStreamTrack>) -> bool;
|
||||
fn track(self: &RtpSender) -> SharedPtr<MediaStreamTrack>;
|
||||
fn ssrc(self: &RtpSender) -> u32;
|
||||
fn media_type(self: &RtpSender) -> MediaType;
|
||||
fn id(self: &RtpSender) -> String;
|
||||
fn stream_ids(self: &RtpSender) -> Vec<String>;
|
||||
fn set_streams(self: &RtpSender, stream_ids: &Vec<String>);
|
||||
fn init_send_encodings(self: &RtpSender) -> Vec<RtpEncodingParameters>;
|
||||
fn get_parameters(self: &RtpSender) -> RtpParameters;
|
||||
fn set_parameters(self: &RtpSender, parameters: RtpParameters) -> Result<()>;
|
||||
|
||||
fn _shared_rtp_sender() -> SharedPtr<RtpSender>;
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,128 @@
|
||||
#include "livekit/rtp_transceiver.h"
|
||||
|
||||
namespace livekit {
|
||||
|
||||
webrtc::RtpTransceiverInit to_native_rtp_transceiver_init(
|
||||
RtpTransceiverInit init) {
|
||||
{
|
||||
webrtc::RtpTransceiverInit native;
|
||||
native.direction =
|
||||
static_cast<webrtc::RtpTransceiverDirection>(init.direction);
|
||||
native.stream_ids = std::vector<std::string>(init.stream_ids.begin(),
|
||||
init.stream_ids.end());
|
||||
for (auto encoding : init.send_encodings)
|
||||
native.send_encodings.push_back(
|
||||
to_native_rtp_encoding_paramters(encoding));
|
||||
return native;
|
||||
}
|
||||
}
|
||||
|
||||
RtpTransceiver::RtpTransceiver(
|
||||
rtc::scoped_refptr<webrtc::RtpTransceiverInterface> transceiver)
|
||||
: transceiver_(std::move(transceiver)) {}
|
||||
} // namespace livekit
|
||||
|
||||
MediaType RtpTransceiver::media_type() const {
|
||||
return static_cast<MediaType>(transceiver_->media_type());
|
||||
}
|
||||
|
||||
rust::String RtpTransceiver::mid() const {
|
||||
// The error/Result is converted into an Option in Rust (Wait for Option
|
||||
// suport in cxx.rs) (value throws an error if there's no value)
|
||||
return transceiver_->mid().value();
|
||||
}
|
||||
|
||||
std::shared_ptr<RtpSender> RtpTransceiver::sender() const {
|
||||
return std::make_shared<RtpSender>(transceiver_->sender());
|
||||
}
|
||||
|
||||
std::shared_ptr<RtpReceiver> RtpTransceiver::receiver() const {
|
||||
return std::make_shared<RtpReceiver>(transceiver_->receiver());
|
||||
}
|
||||
|
||||
bool RtpTransceiver::stopped() const {
|
||||
return transceiver_->stopped();
|
||||
}
|
||||
|
||||
bool RtpTransceiver::stopping() const {
|
||||
return transceiver_->stopping();
|
||||
}
|
||||
|
||||
RtpTransceiverDirection RtpTransceiver::direction() const {
|
||||
return static_cast<RtpTransceiverDirection>(transceiver_->direction());
|
||||
}
|
||||
|
||||
void RtpTransceiver::set_direction(RtpTransceiverDirection direction) const {
|
||||
auto error = transceiver_->SetDirectionWithError(
|
||||
static_cast<webrtc::RtpTransceiverDirection>(direction));
|
||||
|
||||
if (!error.ok()) {
|
||||
throw std::runtime_error(serialize_error(to_error(error)));
|
||||
}
|
||||
}
|
||||
|
||||
RtpTransceiverDirection RtpTransceiver::current_direction() const {
|
||||
return static_cast<RtpTransceiverDirection>(
|
||||
transceiver_->current_direction().value());
|
||||
}
|
||||
|
||||
RtpTransceiverDirection RtpTransceiver::fired_direction() const {
|
||||
return static_cast<RtpTransceiverDirection>(
|
||||
transceiver_->fired_direction().value());
|
||||
}
|
||||
|
||||
void RtpTransceiver::stop_standard() const {
|
||||
auto error = transceiver_->StopStandard();
|
||||
if (!error.ok())
|
||||
throw std::runtime_error(serialize_error(to_error(error)));
|
||||
}
|
||||
|
||||
void RtpTransceiver::set_codec_preferences(
|
||||
rust::Vec<RtpCodecCapability> codecs) const {
|
||||
std::vector<webrtc::RtpCodecCapability> std_codecs;
|
||||
for (auto codec : codecs)
|
||||
std_codecs.push_back(to_native_rtp_codec_capability(codec));
|
||||
|
||||
auto error = transceiver_->SetCodecPreferences(std_codecs);
|
||||
if (!error.ok())
|
||||
throw std::runtime_error(serialize_error(to_error(error)));
|
||||
}
|
||||
|
||||
rust::Vec<RtpCodecCapability> RtpTransceiver::codec_preferences() const {
|
||||
rust::Vec<RtpCodecCapability> rust;
|
||||
for (auto codec : transceiver_->codec_preferences())
|
||||
rust.push_back(to_rust_rtp_codec_capability(codec));
|
||||
|
||||
return rust;
|
||||
}
|
||||
|
||||
rust::Vec<RtpHeaderExtensionCapability>
|
||||
RtpTransceiver::header_extensions_to_offer() const {
|
||||
rust::Vec<RtpHeaderExtensionCapability> rust;
|
||||
for (auto header : transceiver_->HeaderExtensionsToOffer())
|
||||
rust.push_back(to_rust_rtp_header_extension_capability(header));
|
||||
|
||||
return rust;
|
||||
}
|
||||
|
||||
rust::Vec<RtpHeaderExtensionCapability>
|
||||
RtpTransceiver::header_extensions_negotiated() const {
|
||||
rust::Vec<RtpHeaderExtensionCapability> rust;
|
||||
for (auto header : transceiver_->HeaderExtensionsNegotiated())
|
||||
rust.push_back(to_rust_rtp_header_extension_capability(header));
|
||||
|
||||
return rust;
|
||||
}
|
||||
|
||||
void RtpTransceiver::set_offered_rtp_header_extensions(
|
||||
rust::Vec<RtpHeaderExtensionCapability> header_extensions_to_offer) const {
|
||||
std::vector<webrtc::RtpHeaderExtensionCapability> headers;
|
||||
|
||||
for (auto header : header_extensions_to_offer)
|
||||
headers.push_back(to_native_rtp_header_extension_capability(header));
|
||||
|
||||
auto error = transceiver_->SetOfferedRtpHeaderExtensions(headers);
|
||||
if (!error.ok())
|
||||
throw std::runtime_error(serialize_error(to_error(error)));
|
||||
}
|
||||
|
||||
} // namespace livekit
|
||||
|
||||
@@ -1,10 +1,62 @@
|
||||
use crate::impl_thread_safety;
|
||||
|
||||
#[cxx::bridge(namespace = "livekit")]
|
||||
pub mod ffi {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RtpTransceiverInit {
|
||||
pub direction: RtpTransceiverDirection,
|
||||
pub stream_ids: Vec<String>,
|
||||
pub send_encodings: Vec<RtpEncodingParameters>,
|
||||
}
|
||||
|
||||
extern "C++" {
|
||||
include!("livekit/webrtc.h");
|
||||
include!("livekit/rtp_parameters.h");
|
||||
include!("livekit/rtp_sender.h");
|
||||
include!("livekit/rtp_receiver.h");
|
||||
|
||||
type MediaType = crate::webrtc::ffi::MediaType;
|
||||
type RtpTransceiverDirection = crate::webrtc::ffi::RtpTransceiverDirection;
|
||||
type RtpEncodingParameters = crate::rtp_parameters::ffi::RtpEncodingParameters;
|
||||
type RtpCodecCapability = crate::rtp_parameters::ffi::RtpCodecCapability;
|
||||
type RtpHeaderExtensionCapability =
|
||||
crate::rtp_parameters::ffi::RtpHeaderExtensionCapability;
|
||||
type RtpSender = crate::rtp_sender::ffi::RtpSender;
|
||||
type RtpReceiver = crate::rtp_receiver::ffi::RtpReceiver;
|
||||
}
|
||||
|
||||
unsafe extern "C++" {
|
||||
include!("livekit/rtp_transceiver.h");
|
||||
|
||||
type RtpTransceiver;
|
||||
|
||||
fn _unique_rtp_transceiver() -> UniquePtr<RtpTransceiver>; // Ignore
|
||||
fn media_type(self: &RtpTransceiver) -> MediaType;
|
||||
fn mid(self: &RtpTransceiver) -> Result<String>;
|
||||
fn sender(self: &RtpTransceiver) -> SharedPtr<RtpSender>;
|
||||
fn receiver(self: &RtpTransceiver) -> SharedPtr<RtpReceiver>;
|
||||
fn stopped(self: &RtpTransceiver) -> bool;
|
||||
fn stopping(self: &RtpTransceiver) -> bool;
|
||||
fn direction(self: &RtpTransceiver) -> RtpTransceiverDirection;
|
||||
fn set_direction(self: &RtpTransceiver, direction: RtpTransceiverDirection) -> Result<()>;
|
||||
fn current_direction(self: &RtpTransceiver) -> Result<RtpTransceiverDirection>;
|
||||
fn fired_direction(self: &RtpTransceiver) -> Result<RtpTransceiverDirection>;
|
||||
fn stop_standard(self: &RtpTransceiver) -> Result<()>;
|
||||
fn set_codec_preferences(
|
||||
self: &RtpTransceiver,
|
||||
codecs: Vec<RtpCodecCapability>,
|
||||
) -> Result<()>;
|
||||
fn codec_preferences(self: &RtpTransceiver) -> Vec<RtpCodecCapability>;
|
||||
fn header_extensions_to_offer(self: &RtpTransceiver) -> Vec<RtpHeaderExtensionCapability>;
|
||||
fn header_extensions_negotiated(self: &RtpTransceiver)
|
||||
-> Vec<RtpHeaderExtensionCapability>;
|
||||
fn set_offered_rtp_header_extensions(
|
||||
self: &RtpTransceiver,
|
||||
headers: Vec<RtpHeaderExtensionCapability>,
|
||||
) -> Result<()>;
|
||||
|
||||
fn _shared_rtp_transceiver() -> SharedPtr<RtpTransceiver>;
|
||||
}
|
||||
}
|
||||
|
||||
impl_thread_safety!(ffi::RtpTransceiver, Send + Sync);
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
#include "livekit/video_frame.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "api/video/video_frame.h"
|
||||
|
||||
namespace livekit {
|
||||
VideoFrame::VideoFrame(const webrtc::VideoFrame& frame)
|
||||
: frame_(std::move(frame)) {}
|
||||
|
||||
int VideoFrame::width() const {
|
||||
return frame_.width();
|
||||
}
|
||||
int VideoFrame::height() const {
|
||||
return frame_.height();
|
||||
}
|
||||
uint32_t VideoFrame::size() const {
|
||||
return frame_.size();
|
||||
}
|
||||
uint16_t VideoFrame::id() const {
|
||||
return frame_.id();
|
||||
}
|
||||
int64_t VideoFrame::timestamp_us() const {
|
||||
return frame_.timestamp_us();
|
||||
}
|
||||
int64_t VideoFrame::ntp_time_ms() const {
|
||||
return frame_.ntp_time_ms();
|
||||
}
|
||||
uint32_t VideoFrame::transport_frame_id() const {
|
||||
return frame_.transport_frame_id();
|
||||
}
|
||||
uint32_t VideoFrame::timestamp() const {
|
||||
return frame_.timestamp();
|
||||
}
|
||||
|
||||
VideoRotation VideoFrame::rotation() const {
|
||||
return static_cast<VideoRotation>(frame_.rotation());
|
||||
}
|
||||
|
||||
// TODO(theomonnom) This shouldn't create a new shared_ptr at each call
|
||||
std::unique_ptr<VideoFrameBuffer> VideoFrame::video_frame_buffer() const {
|
||||
return std::make_unique<VideoFrameBuffer>(frame_.video_frame_buffer());
|
||||
}
|
||||
|
||||
webrtc::VideoFrame VideoFrame::get() const {
|
||||
return frame_;
|
||||
}
|
||||
|
||||
void VideoFrameBuilder::set_video_frame_buffer(
|
||||
std::unique_ptr<VideoFrameBuffer> buffer) {
|
||||
builder_.set_video_frame_buffer(buffer->get());
|
||||
}
|
||||
|
||||
void VideoFrameBuilder::set_timestamp_us(int64_t timestamp_us) {
|
||||
builder_.set_timestamp_us(timestamp_us);
|
||||
}
|
||||
|
||||
void VideoFrameBuilder::set_rotation(VideoRotation rotation) {
|
||||
builder_.set_rotation(static_cast<webrtc::VideoRotation>(rotation));
|
||||
}
|
||||
|
||||
void VideoFrameBuilder::set_id(uint16_t id) {
|
||||
builder_.set_id(id);
|
||||
}
|
||||
|
||||
std::unique_ptr<VideoFrame> VideoFrameBuilder::build() {
|
||||
return std::make_unique<VideoFrame>(builder_.build());
|
||||
}
|
||||
|
||||
std::unique_ptr<VideoFrameBuilder> create_video_frame_builder() {
|
||||
return std::make_unique<VideoFrameBuilder>();
|
||||
}
|
||||
|
||||
} // namespace livekit
|
||||
@@ -11,12 +11,17 @@ pub mod ffi {
|
||||
VideoRotation270 = 270,
|
||||
}
|
||||
|
||||
unsafe extern "C++" {
|
||||
include!("livekit/video_frame.h");
|
||||
extern "C++" {
|
||||
include!("livekit/video_frame_buffer.h");
|
||||
|
||||
type VideoFrame;
|
||||
type VideoFrameBuffer = crate::video_frame_buffer::ffi::VideoFrameBuffer;
|
||||
}
|
||||
|
||||
unsafe extern "C++" {
|
||||
include!("livekit/video_frame.h");
|
||||
|
||||
type VideoFrame;
|
||||
type VideoFrameBuilder;
|
||||
|
||||
fn width(self: &VideoFrame) -> i32;
|
||||
fn height(self: &VideoFrame) -> i32;
|
||||
@@ -29,7 +34,16 @@ pub mod ffi {
|
||||
fn rotation(self: &VideoFrame) -> VideoRotation;
|
||||
fn video_frame_buffer(self: &VideoFrame) -> UniquePtr<VideoFrameBuffer>;
|
||||
|
||||
fn _unique_video_frame() -> UniquePtr<VideoFrame>; // Ignore
|
||||
fn set_video_frame_buffer(
|
||||
self: Pin<&mut VideoFrameBuilder>,
|
||||
buffer: UniquePtr<VideoFrameBuffer>,
|
||||
);
|
||||
fn set_timestamp_us(self: Pin<&mut VideoFrameBuilder>, timestamp_us: i64);
|
||||
fn set_rotation(self: Pin<&mut VideoFrameBuilder>, rotation: VideoRotation);
|
||||
fn set_id(self: Pin<&mut VideoFrameBuilder>, id: u16);
|
||||
fn build(self: Pin<&mut VideoFrameBuilder>) -> UniquePtr<VideoFrame>;
|
||||
|
||||
fn create_video_frame_builder() -> UniquePtr<VideoFrameBuilder>;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,198 @@
|
||||
#include "livekit/video_frame_buffer.h"
|
||||
|
||||
namespace livekit {
|
||||
|
||||
VideoFrameBuffer::VideoFrameBuffer(
|
||||
rtc::scoped_refptr<webrtc::VideoFrameBuffer> buffer)
|
||||
: buffer_(std::move(buffer)) {}
|
||||
|
||||
VideoFrameBufferType VideoFrameBuffer::buffer_type() const {
|
||||
return static_cast<VideoFrameBufferType>(buffer_->type());
|
||||
}
|
||||
|
||||
int VideoFrameBuffer::width() const {
|
||||
return buffer_->width();
|
||||
}
|
||||
|
||||
int VideoFrameBuffer::height() const {
|
||||
return buffer_->height();
|
||||
}
|
||||
|
||||
std::unique_ptr<I420Buffer> VideoFrameBuffer::to_i420() {
|
||||
return std::make_unique<I420Buffer>(buffer_->ToI420());
|
||||
}
|
||||
|
||||
// const_cast is valid here because we take the ownership on the rust side
|
||||
std::unique_ptr<I420Buffer> VideoFrameBuffer::get_i420() {
|
||||
return std::make_unique<I420Buffer>(
|
||||
rtc::scoped_refptr<webrtc::I420BufferInterface>(
|
||||
const_cast<webrtc::I420BufferInterface*>(buffer_->GetI420())));
|
||||
}
|
||||
|
||||
std::unique_ptr<I420ABuffer> VideoFrameBuffer::get_i420a() {
|
||||
return std::make_unique<I420ABuffer>(
|
||||
rtc::scoped_refptr<webrtc::I420ABufferInterface>(
|
||||
const_cast<webrtc::I420ABufferInterface*>(buffer_->GetI420A())));
|
||||
}
|
||||
|
||||
std::unique_ptr<I422Buffer> VideoFrameBuffer::get_i422() {
|
||||
return std::make_unique<I422Buffer>(
|
||||
rtc::scoped_refptr<webrtc::I422BufferInterface>(
|
||||
const_cast<webrtc::I422BufferInterface*>(buffer_->GetI422())));
|
||||
}
|
||||
|
||||
std::unique_ptr<I444Buffer> VideoFrameBuffer::get_i444() {
|
||||
return std::make_unique<I444Buffer>(
|
||||
rtc::scoped_refptr<webrtc::I444BufferInterface>(
|
||||
const_cast<webrtc::I444BufferInterface*>(buffer_->GetI444())));
|
||||
}
|
||||
|
||||
std::unique_ptr<I010Buffer> VideoFrameBuffer::get_i010() {
|
||||
return std::make_unique<I010Buffer>(
|
||||
rtc::scoped_refptr<webrtc::I010BufferInterface>(
|
||||
const_cast<webrtc::I010BufferInterface*>(buffer_->GetI010())));
|
||||
}
|
||||
|
||||
std::unique_ptr<NV12Buffer> VideoFrameBuffer::get_nv12() {
|
||||
return std::make_unique<NV12Buffer>(
|
||||
rtc::scoped_refptr<webrtc::NV12BufferInterface>(
|
||||
const_cast<webrtc::NV12BufferInterface*>(buffer_->GetNV12())));
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<webrtc::VideoFrameBuffer> VideoFrameBuffer::get() const {
|
||||
return buffer_;
|
||||
}
|
||||
|
||||
PlanarYuvBuffer::PlanarYuvBuffer(
|
||||
rtc::scoped_refptr<webrtc::PlanarYuvBuffer> buffer)
|
||||
: VideoFrameBuffer(buffer) {}
|
||||
|
||||
int PlanarYuvBuffer::chroma_width() const {
|
||||
return buffer()->ChromaWidth();
|
||||
}
|
||||
|
||||
int PlanarYuvBuffer::chroma_height() const {
|
||||
return buffer()->ChromaHeight();
|
||||
}
|
||||
|
||||
int PlanarYuvBuffer::stride_y() const {
|
||||
return buffer()->StrideY();
|
||||
}
|
||||
|
||||
int PlanarYuvBuffer::stride_u() const {
|
||||
return buffer()->StrideU();
|
||||
}
|
||||
|
||||
int PlanarYuvBuffer::stride_v() const {
|
||||
return buffer()->StrideV();
|
||||
}
|
||||
|
||||
webrtc::PlanarYuvBuffer* PlanarYuvBuffer::buffer() const {
|
||||
return static_cast<webrtc::PlanarYuvBuffer*>(buffer_.get());
|
||||
}
|
||||
|
||||
PlanarYuv8Buffer::PlanarYuv8Buffer(
|
||||
rtc::scoped_refptr<webrtc::PlanarYuv8Buffer> buffer)
|
||||
: PlanarYuvBuffer(buffer) {}
|
||||
|
||||
const uint8_t* PlanarYuv8Buffer::data_y() const {
|
||||
return buffer()->DataY();
|
||||
}
|
||||
|
||||
const uint8_t* PlanarYuv8Buffer::data_u() const {
|
||||
return buffer()->DataU();
|
||||
}
|
||||
|
||||
const uint8_t* PlanarYuv8Buffer::data_v() const {
|
||||
return buffer()->DataV();
|
||||
}
|
||||
|
||||
webrtc::PlanarYuv8Buffer* PlanarYuv8Buffer::buffer() const {
|
||||
return static_cast<webrtc::PlanarYuv8Buffer*>(buffer_.get());
|
||||
}
|
||||
|
||||
PlanarYuv16BBuffer::PlanarYuv16BBuffer(
|
||||
rtc::scoped_refptr<webrtc::PlanarYuv16BBuffer> buffer)
|
||||
: PlanarYuvBuffer(buffer) {}
|
||||
|
||||
const uint16_t* PlanarYuv16BBuffer::data_y() const {
|
||||
return buffer()->DataY();
|
||||
}
|
||||
|
||||
const uint16_t* PlanarYuv16BBuffer::data_u() const {
|
||||
return buffer()->DataU();
|
||||
}
|
||||
|
||||
const uint16_t* PlanarYuv16BBuffer::data_v() const {
|
||||
return buffer()->DataV();
|
||||
}
|
||||
|
||||
webrtc::PlanarYuv16BBuffer* PlanarYuv16BBuffer::buffer() const {
|
||||
return static_cast<webrtc::PlanarYuv16BBuffer*>(buffer_.get());
|
||||
}
|
||||
|
||||
BiplanarYuvBuffer::BiplanarYuvBuffer(
|
||||
rtc::scoped_refptr<webrtc::BiplanarYuvBuffer> buffer)
|
||||
: VideoFrameBuffer(buffer) {}
|
||||
|
||||
int BiplanarYuvBuffer::chroma_width() const {
|
||||
return buffer()->ChromaWidth();
|
||||
}
|
||||
|
||||
int BiplanarYuvBuffer::chroma_height() const {
|
||||
return buffer()->ChromaHeight();
|
||||
}
|
||||
|
||||
int BiplanarYuvBuffer::stride_y() const {
|
||||
return buffer()->StrideY();
|
||||
}
|
||||
|
||||
int BiplanarYuvBuffer::stride_uv() const {
|
||||
return buffer()->StrideUV();
|
||||
}
|
||||
|
||||
webrtc::BiplanarYuvBuffer* BiplanarYuvBuffer::buffer() const {
|
||||
return static_cast<webrtc::BiplanarYuvBuffer*>(buffer_.get());
|
||||
}
|
||||
|
||||
BiplanarYuv8Buffer::BiplanarYuv8Buffer(
|
||||
rtc::scoped_refptr<webrtc::BiplanarYuv8Buffer> buffer)
|
||||
: BiplanarYuvBuffer(buffer) {}
|
||||
|
||||
const uint8_t* BiplanarYuv8Buffer::data_y() const {
|
||||
return buffer()->DataY();
|
||||
}
|
||||
|
||||
const uint8_t* BiplanarYuv8Buffer::data_uv() const {
|
||||
return buffer()->DataUV();
|
||||
}
|
||||
|
||||
webrtc::BiplanarYuv8Buffer* BiplanarYuv8Buffer::buffer() const {
|
||||
return static_cast<webrtc::BiplanarYuv8Buffer*>(buffer_.get());
|
||||
}
|
||||
|
||||
std::unique_ptr<I420Buffer> create_i420_buffer(int width, int height) {
|
||||
return std::make_unique<I420Buffer>(
|
||||
webrtc::I420Buffer::Create(width, height));
|
||||
}
|
||||
|
||||
I420Buffer::I420Buffer(rtc::scoped_refptr<webrtc::I420BufferInterface> buffer)
|
||||
: PlanarYuv8Buffer(buffer) {}
|
||||
|
||||
I420ABuffer::I420ABuffer(
|
||||
rtc::scoped_refptr<webrtc::I420ABufferInterface> buffer)
|
||||
: I420Buffer(buffer) {}
|
||||
|
||||
I422Buffer::I422Buffer(rtc::scoped_refptr<webrtc::I422BufferInterface> buffer)
|
||||
: PlanarYuv8Buffer(buffer) {}
|
||||
|
||||
I444Buffer::I444Buffer(rtc::scoped_refptr<webrtc::I444BufferInterface> buffer)
|
||||
: PlanarYuv8Buffer(buffer) {}
|
||||
|
||||
I010Buffer::I010Buffer(rtc::scoped_refptr<webrtc::I010BufferInterface> buffer)
|
||||
: PlanarYuv16BBuffer(buffer) {}
|
||||
|
||||
NV12Buffer::NV12Buffer(rtc::scoped_refptr<webrtc::NV12BufferInterface> buffer)
|
||||
: BiplanarYuv8Buffer(buffer) {}
|
||||
|
||||
} // namespace livekit
|
||||
@@ -66,6 +66,8 @@ pub mod ffi {
|
||||
fn data_y(self: &BiplanarYuv8Buffer) -> *const u8;
|
||||
fn data_uv(self: &BiplanarYuv8Buffer) -> *const u8;
|
||||
|
||||
fn create_i420_buffer(width: i32, height: i32) -> UniquePtr<I420Buffer>;
|
||||
|
||||
unsafe fn yuv_to_vfb(yuv: *const PlanarYuvBuffer) -> *const VideoFrameBuffer;
|
||||
unsafe fn biyuv_to_vfb(yuv: *const BiplanarYuvBuffer) -> *const VideoFrameBuffer;
|
||||
unsafe fn yuv8_to_yuv(yuv8: *const PlanarYuv8Buffer) -> *const PlanarYuvBuffer;
|
||||
|
||||
@@ -1,5 +1,36 @@
|
||||
use crate::impl_thread_safety;
|
||||
|
||||
#[cxx::bridge(namespace = "livekit")]
|
||||
pub mod ffi {
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(i32)]
|
||||
pub enum MediaType {
|
||||
Audio,
|
||||
Video,
|
||||
Data,
|
||||
Unsupported,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(i32)]
|
||||
pub enum Priority {
|
||||
VeryLow,
|
||||
Low,
|
||||
Medium,
|
||||
High,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(i32)]
|
||||
pub enum RtpTransceiverDirection {
|
||||
SendRecv,
|
||||
SendOnly,
|
||||
RecvOnly,
|
||||
Inactive,
|
||||
Stopped,
|
||||
}
|
||||
|
||||
unsafe extern "C++" {
|
||||
include!("livekit/webrtc.h");
|
||||
|
||||
@@ -9,6 +40,4 @@ pub mod ffi {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for ffi::RTCRuntime {}
|
||||
|
||||
unsafe impl Sync for ffi::RTCRuntime {}
|
||||
impl_thread_safety!(ffi::RTCRuntime, Send + Sync);
|
||||
|
||||
Reference in New Issue
Block a user