feat: video publishing (#42)
- Prepare webrtc abstraction ( for future wasm support ) - Added track publish support for videos - Added LogoTrack example to simple_room demo - Lot of cleanup - There are compiler warnings I'll solve on our v1 release
This commit is contained in:
@@ -18,6 +18,8 @@
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "webrtc-sys/src/data_channel.rs.h"
|
||||
|
||||
namespace livekit {
|
||||
|
||||
DataChannel::DataChannel(
|
||||
@@ -26,8 +28,8 @@ DataChannel::DataChannel(
|
||||
: rtc_runtime_(std::move(rtc_runtime)),
|
||||
data_channel_(std::move(data_channel)) {}
|
||||
|
||||
void DataChannel::register_observer(NativeDataChannelObserver& observer) const {
|
||||
data_channel_->RegisterObserver(&observer);
|
||||
void DataChannel::register_observer(NativeDataChannelObserver* observer) const {
|
||||
data_channel_->RegisterObserver(observer);
|
||||
}
|
||||
|
||||
void DataChannel::unregister_observer() const {
|
||||
@@ -58,7 +60,6 @@ std::unique_ptr<NativeDataChannelInit> create_data_channel_init(
|
||||
rtc_init->negotiated = init.negotiated;
|
||||
rtc_init->ordered = init.ordered;
|
||||
rtc_init->protocol = init.protocol.c_str();
|
||||
rtc_init->reliable = init.reliable;
|
||||
|
||||
if (init.has_max_retransmit_time)
|
||||
rtc_init->maxRetransmitTime = init.max_retransmit_time;
|
||||
@@ -73,11 +74,16 @@ std::unique_ptr<NativeDataChannelInit> create_data_channel_init(
|
||||
}
|
||||
|
||||
NativeDataChannelObserver::NativeDataChannelObserver(
|
||||
rust::Box<DataChannelObserverWrapper> observer)
|
||||
: observer_(std::move(observer)) {}
|
||||
rust::Box<DataChannelObserverWrapper> observer,
|
||||
DataChannel* dc)
|
||||
: observer_(std::move(observer)), dc_(dc) {}
|
||||
|
||||
NativeDataChannelObserver::~NativeDataChannelObserver() {
|
||||
dc_->unregister_observer();
|
||||
}
|
||||
|
||||
void NativeDataChannelObserver::OnStateChange() {
|
||||
observer_->on_state_change();
|
||||
observer_->on_state_change(dc_->state());
|
||||
}
|
||||
|
||||
void NativeDataChannelObserver::OnMessage(const webrtc::DataBuffer& buffer) {
|
||||
@@ -93,8 +99,9 @@ void NativeDataChannelObserver::OnBufferedAmountChange(
|
||||
observer_->on_buffered_amount_change(sent_data_size);
|
||||
}
|
||||
|
||||
std::unique_ptr<NativeDataChannelObserver> create_native_data_channel_observer(
|
||||
rust::Box<DataChannelObserverWrapper> observer) {
|
||||
return std::make_unique<NativeDataChannelObserver>(std::move(observer));
|
||||
std::shared_ptr<NativeDataChannelObserver> create_native_data_channel_observer(
|
||||
rust::Box<DataChannelObserverWrapper> observer,
|
||||
DataChannel* dc) {
|
||||
return std::make_shared<NativeDataChannelObserver>(std::move(observer), dc);
|
||||
}
|
||||
} // namespace livekit
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::impl_thread_safety;
|
||||
use std::slice;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[cxx::bridge(namespace = "livekit")]
|
||||
pub mod ffi {
|
||||
@@ -14,9 +15,6 @@ pub mod ffi {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DataChannelInit {
|
||||
#[allow(deprecated)]
|
||||
#[deprecated]
|
||||
pub reliable: bool,
|
||||
pub ordered: bool,
|
||||
pub has_max_retransmit_time: bool,
|
||||
pub max_retransmit_time: i32,
|
||||
@@ -48,7 +46,7 @@ pub mod ffi {
|
||||
extern "Rust" {
|
||||
type DataChannelObserverWrapper;
|
||||
|
||||
fn on_state_change(self: &DataChannelObserverWrapper);
|
||||
fn on_state_change(self: &DataChannelObserverWrapper, state: DataState);
|
||||
fn on_message(self: &DataChannelObserverWrapper, buffer: DataBuffer);
|
||||
fn on_buffered_amount_change(self: &DataChannelObserverWrapper, sent_data_size: u64);
|
||||
}
|
||||
@@ -61,11 +59,8 @@ pub mod ffi {
|
||||
type NativeDataChannelObserver;
|
||||
|
||||
/// SAFETY
|
||||
/// The observer must live as the datachannel uses it
|
||||
unsafe fn register_observer(
|
||||
self: &DataChannel,
|
||||
observer: Pin<&mut NativeDataChannelObserver>,
|
||||
);
|
||||
/// The observer must live as long as the datachannel uses it
|
||||
unsafe fn register_observer(self: &DataChannel, observer: *mut NativeDataChannelObserver);
|
||||
|
||||
fn unregister_observer(self: &DataChannel);
|
||||
fn send(self: &DataChannel, data: &DataBuffer) -> bool;
|
||||
@@ -74,11 +69,12 @@ pub mod ffi {
|
||||
fn close(self: &DataChannel);
|
||||
|
||||
fn create_data_channel_init(init: DataChannelInit) -> UniquePtr<NativeDataChannelInit>;
|
||||
fn create_native_data_channel_observer(
|
||||
unsafe fn create_native_data_channel_observer(
|
||||
observer: Box<DataChannelObserverWrapper>,
|
||||
) -> UniquePtr<NativeDataChannelObserver>;
|
||||
dc: *mut DataChannel,
|
||||
) -> SharedPtr<NativeDataChannelObserver>;
|
||||
|
||||
fn _unique_data_channel() -> UniquePtr<DataChannel>; // Ignore
|
||||
fn _shared_data_channel() -> SharedPtr<DataChannel>; // Ignore
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,37 +83,33 @@ impl_thread_safety!(ffi::NativeDataChannelObserver, Send + Sync);
|
||||
|
||||
// DataChannelObserver
|
||||
|
||||
pub trait DataChannelObserver: Send {
|
||||
fn on_state_change(&self);
|
||||
pub trait DataChannelObserver: Send + Sync {
|
||||
fn on_state_change(&self, state: ffi::DataState);
|
||||
fn on_message(&self, data: &[u8], is_binary: bool);
|
||||
fn on_buffered_amount_change(&self, sent_data_size: u64);
|
||||
}
|
||||
|
||||
pub struct DataChannelObserverWrapper {
|
||||
observer: *mut dyn DataChannelObserver,
|
||||
observer: Arc<dyn DataChannelObserver>,
|
||||
}
|
||||
|
||||
impl DataChannelObserverWrapper {
|
||||
/// SAFETY
|
||||
/// DataChannelObserver must lives as long as DataChannelObserverWrapper does
|
||||
pub unsafe fn new(observer: *mut dyn DataChannelObserver) -> Self {
|
||||
pub fn new(observer: Arc<dyn DataChannelObserver>) -> Self {
|
||||
Self { observer }
|
||||
}
|
||||
|
||||
fn on_state_change(&self) {
|
||||
unsafe {
|
||||
(*self.observer).on_state_change();
|
||||
}
|
||||
fn on_state_change(&self, state: ffi::DataState) {
|
||||
self.observer.on_state_change(state);
|
||||
}
|
||||
|
||||
fn on_message(&self, buffer: ffi::DataBuffer) {
|
||||
unsafe {
|
||||
let data = slice::from_raw_parts(buffer.ptr, buffer.len);
|
||||
(*self.observer).on_message(data, buffer.binary);
|
||||
self.observer.on_message(data, buffer.binary);
|
||||
}
|
||||
}
|
||||
|
||||
fn on_buffered_amount_change(&self, sent_data_size: u64) {
|
||||
unsafe { (*self.observer).on_buffered_amount_change(sent_data_size) };
|
||||
self.observer.on_buffered_amount_change(sent_data_size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,6 +77,10 @@ SessionDescription::SessionDescription(
|
||||
std::unique_ptr<webrtc::SessionDescriptionInterface> session_description)
|
||||
: session_description_(std::move(session_description)) {}
|
||||
|
||||
SdpType SessionDescription::sdp_type() const {
|
||||
return static_cast<SdpType>(session_description_->GetType());
|
||||
}
|
||||
|
||||
rust::String SessionDescription::stringify() const {
|
||||
std::string str;
|
||||
session_description_->ToString(&str);
|
||||
|
||||
+1
-15
@@ -3,7 +3,6 @@ use cxx::UniquePtr;
|
||||
use std::error::Error;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::mem::ManuallyDrop;
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::rtc_error::ffi::RTCError;
|
||||
|
||||
@@ -59,6 +58,7 @@ pub mod ffi {
|
||||
fn candidate(self: &IceCandidate) -> String;
|
||||
fn stringify(self: &IceCandidate) -> String;
|
||||
|
||||
fn sdp_type(self: &SessionDescription) -> SdpType;
|
||||
fn stringify(self: &SessionDescription) -> String;
|
||||
fn clone(self: &SessionDescription) -> UniquePtr<SessionDescription>;
|
||||
|
||||
@@ -115,20 +115,6 @@ impl ffi::SdpParseError {
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for ffi::SdpType {
|
||||
type Err = ();
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"offer" => Ok(ffi::SdpType::Offer),
|
||||
"pranswer" => Ok(ffi::SdpType::PrAnswer),
|
||||
"answer" => Ok(ffi::SdpType::Answer),
|
||||
"rollback" => Ok(ffi::SdpType::Rollback),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CreateSdpObserver
|
||||
|
||||
pub struct CreateSdpObserverWrapper {
|
||||
|
||||
@@ -17,11 +17,15 @@
|
||||
#include "livekit/media_stream.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
#include "api/media_stream_interface.h"
|
||||
#include "api/video/video_frame.h"
|
||||
#include "api/video/video_rotation.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "rtc_base/ref_counted_object.h"
|
||||
#include "rtc_base/time_utils.h"
|
||||
|
||||
namespace livekit {
|
||||
|
||||
@@ -61,32 +65,28 @@ std::shared_ptr<VideoTrack> MediaStream::find_video_track(
|
||||
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_track(std::shared_ptr<MediaStreamTrack> track) const {
|
||||
if (track->kind() == webrtc::MediaStreamTrackInterface::kVideoKind) {
|
||||
return media_stream_->AddTrack(
|
||||
rtc::scoped_refptr<webrtc::VideoTrackInterface>(
|
||||
static_cast<webrtc::VideoTrackInterface*>(track->get().get())));
|
||||
} else {
|
||||
return media_stream_->AddTrack(
|
||||
rtc::scoped_refptr<webrtc::AudioTrackInterface>(
|
||||
static_cast<webrtc::AudioTrackInterface*>(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())));
|
||||
bool MediaStream::remove_track(std::shared_ptr<MediaStreamTrack> track) const {
|
||||
if (track->kind() == webrtc::MediaStreamTrackInterface::kVideoKind) {
|
||||
return media_stream_->RemoveTrack(
|
||||
rtc::scoped_refptr<webrtc::VideoTrackInterface>(
|
||||
static_cast<webrtc::VideoTrackInterface*>(track->get().get())));
|
||||
} else {
|
||||
return media_stream_->RemoveTrack(
|
||||
rtc::scoped_refptr<webrtc::AudioTrackInterface>(
|
||||
static_cast<webrtc::AudioTrackInterface*>(track->get().get())));
|
||||
}
|
||||
}
|
||||
|
||||
MediaStreamTrack::MediaStreamTrack(
|
||||
@@ -177,13 +177,13 @@ void NativeVideoFrameSink::OnConstraintsChanged(
|
||||
observer_->on_constraints_changed(cst);
|
||||
}
|
||||
|
||||
std::unique_ptr<NativeVideoFrameSink> create_native_video_frame_sink(
|
||||
std::unique_ptr<NativeVideoFrameSink> new_native_video_frame_sink(
|
||||
rust::Box<VideoFrameSinkWrapper> observer) {
|
||||
return std::make_unique<NativeVideoFrameSink>(std::move(observer));
|
||||
}
|
||||
|
||||
NativeVideoTrackSource::NativeVideoTrackSource()
|
||||
: rtc::AdaptedVideoTrackSource(1) {}
|
||||
: rtc::AdaptedVideoTrackSource(4) {}
|
||||
|
||||
NativeVideoTrackSource::~NativeVideoTrackSource() {}
|
||||
|
||||
@@ -197,7 +197,6 @@ absl::optional<bool> NativeVideoTrackSource::needs_denoising() const {
|
||||
|
||||
webrtc::MediaSourceInterface::SourceState NativeVideoTrackSource::state()
|
||||
const {
|
||||
// TODO(theomonnom): expose source state to Rust
|
||||
return SourceState::kLive;
|
||||
}
|
||||
|
||||
@@ -212,22 +211,23 @@ bool NativeVideoTrackSource::on_captured_frame(
|
||||
int64_t aligned_timestamp_us = timestamp_aligner_.TranslateTimestamp(
|
||||
frame.timestamp_us(), rtc::TimeMicros());
|
||||
|
||||
rtc::scoped_refptr<webrtc::VideoFrameBuffer> buffer =
|
||||
frame.video_frame_buffer();
|
||||
|
||||
int adapted_width, adapted_height, crop_width, crop_height, crop_x, crop_y;
|
||||
if (!AdaptFrame(frame.width(), frame.height(), frame.timestamp_us(),
|
||||
if (!AdaptFrame(buffer->width(), buffer->height(), aligned_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) {
|
||||
webrtc::VideoRotation rotation = frame.rotation();
|
||||
if (apply_rotation() && rotation != webrtc::kVideoRotation_0) {
|
||||
// If the buffer is I420, rtc::AdaptedVideoTrackSource will handle the
|
||||
// rotation for us.
|
||||
buffer = buffer->ToI420();
|
||||
@@ -235,7 +235,7 @@ bool NativeVideoTrackSource::on_captured_frame(
|
||||
|
||||
OnFrame(webrtc::VideoFrame::Builder()
|
||||
.set_video_frame_buffer(buffer)
|
||||
.set_rotation(frame.rotation())
|
||||
.set_rotation(rotation)
|
||||
.set_timestamp_us(aligned_timestamp_us)
|
||||
.build());
|
||||
|
||||
@@ -247,8 +247,15 @@ AdaptedVideoTrackSource::AdaptedVideoTrackSource(
|
||||
: source_(source) {}
|
||||
|
||||
bool AdaptedVideoTrackSource::on_captured_frame(
|
||||
std::unique_ptr<VideoFrame> frame) const {
|
||||
return source_->on_captured_frame(frame->get());
|
||||
const std::unique_ptr<VideoFrame>& frame) const {
|
||||
auto rtc_frame = frame->get();
|
||||
rtc_frame.set_timestamp_us(rtc::TimeMicros());
|
||||
|
||||
// auto buffer = webrtc::I420Buffer::Create(1280, 720);
|
||||
// webrtc::I420Buffer::SetBlack(buffer.get());
|
||||
// rtc_frame.set_video_frame_buffer(buffer);
|
||||
|
||||
return source_->on_captured_frame(rtc_frame);
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<NativeVideoTrackSource> AdaptedVideoTrackSource::get()
|
||||
@@ -256,8 +263,8 @@ rtc::scoped_refptr<NativeVideoTrackSource> AdaptedVideoTrackSource::get()
|
||||
return source_;
|
||||
}
|
||||
|
||||
std::unique_ptr<AdaptedVideoTrackSource> create_adapted_video_track_source() {
|
||||
return std::make_unique<AdaptedVideoTrackSource>(
|
||||
std::shared_ptr<AdaptedVideoTrackSource> new_adapted_video_track_source() {
|
||||
return std::make_shared<AdaptedVideoTrackSource>(
|
||||
rtc::make_ref_counted<NativeVideoTrackSource>());
|
||||
}
|
||||
|
||||
|
||||
@@ -52,10 +52,8 @@ pub mod ffi {
|
||||
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 add_track(self: &MediaStream, audio_track: SharedPtr<MediaStreamTrack>) -> bool;
|
||||
fn remove_track(self: &MediaStream, audio_track: SharedPtr<MediaStreamTrack>) -> bool;
|
||||
|
||||
fn kind(self: &MediaStreamTrack) -> String;
|
||||
fn id(self: &MediaStreamTrack) -> String;
|
||||
@@ -71,14 +69,19 @@ pub mod ffi {
|
||||
fn content_hint(self: &VideoTrack) -> ContentHint;
|
||||
fn set_content_hint(self: &VideoTrack, hint: ContentHint);
|
||||
|
||||
fn create_native_video_frame_sink(
|
||||
fn new_native_video_frame_sink(
|
||||
observer: Box<VideoFrameSinkWrapper>,
|
||||
) -> UniquePtr<NativeVideoFrameSink>;
|
||||
|
||||
fn on_captured_frame(self: &AdaptedVideoTrackSource, frame: UniquePtr<VideoFrame>) -> bool;
|
||||
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 new_adapted_video_track_source() -> SharedPtr<AdaptedVideoTrackSource>;
|
||||
|
||||
fn video_to_media(track: SharedPtr<VideoTrack>) -> SharedPtr<MediaStreamTrack>;
|
||||
fn audio_to_media(track: SharedPtr<AudioTrack>) -> SharedPtr<MediaStreamTrack>;
|
||||
fn media_to_video(track: SharedPtr<MediaStreamTrack>) -> SharedPtr<VideoTrack>;
|
||||
fn media_to_audio(track: SharedPtr<MediaStreamTrack>) -> SharedPtr<AudioTrack>;
|
||||
|
||||
fn _shared_media_stream_track() -> SharedPtr<MediaStreamTrack>;
|
||||
fn _shared_audio_track() -> SharedPtr<AudioTrack>;
|
||||
@@ -103,8 +106,9 @@ 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);
|
||||
impl_thread_safety!(ffi::AdaptedVideoTrackSource, Send + Sync);
|
||||
|
||||
pub trait VideoFrameSink: Send + Sync {
|
||||
pub trait VideoFrameSink: Send {
|
||||
fn on_frame(&self, frame: UniquePtr<VideoFrame>);
|
||||
fn on_discarded_frame(&self);
|
||||
fn on_constraints_changed(&self, constraints: ffi::VideoTrackSourceConstraints);
|
||||
|
||||
@@ -70,7 +70,7 @@ void PeerConnection::set_remote_description(
|
||||
observer.observer);
|
||||
}
|
||||
|
||||
std::unique_ptr<DataChannel> PeerConnection::create_data_channel(
|
||||
std::shared_ptr<DataChannel> PeerConnection::create_data_channel(
|
||||
rust::String label,
|
||||
std::unique_ptr<NativeDataChannelInit> init) const {
|
||||
auto result =
|
||||
@@ -80,7 +80,7 @@ std::unique_ptr<DataChannel> PeerConnection::create_data_channel(
|
||||
throw std::runtime_error(serialize_error(to_error(result.error())));
|
||||
}
|
||||
|
||||
return std::make_unique<DataChannel>(rtc_runtime_, result.value());
|
||||
return std::make_shared<DataChannel>(rtc_runtime_, result.value());
|
||||
}
|
||||
|
||||
std::shared_ptr<RtpSender> PeerConnection::add_track(
|
||||
@@ -106,7 +106,7 @@ std::shared_ptr<RtpTransceiver> PeerConnection::add_transceiver(
|
||||
RtpTransceiverInit init) const {
|
||||
auto result = peer_connection_->AddTransceiver(
|
||||
track->get(), to_native_rtp_transceiver_init(init));
|
||||
if (result.ok())
|
||||
if (!result.ok())
|
||||
throw std::runtime_error(serialize_error(to_error(result.error())));
|
||||
|
||||
return std::make_shared<RtpTransceiver>(result.value());
|
||||
@@ -119,7 +119,7 @@ std::shared_ptr<RtpTransceiver> PeerConnection::add_transceiver_for_media(
|
||||
static_cast<cricket::MediaType>(media_type),
|
||||
to_native_rtp_transceiver_init(init));
|
||||
|
||||
if (result.ok())
|
||||
if (!result.ok())
|
||||
throw std::runtime_error(serialize_error(to_error(result.error())));
|
||||
|
||||
return std::make_shared<RtpTransceiver>(result.value());
|
||||
@@ -158,12 +158,48 @@ void PeerConnection::add_ice_candidate(
|
||||
[&](const webrtc::RTCError& err) { observer.OnComplete(to_error(err)); });
|
||||
}
|
||||
|
||||
std::unique_ptr<SessionDescription> PeerConnection::current_local_description()
|
||||
const {
|
||||
auto local_description = peer_connection_->current_local_description();
|
||||
if (local_description)
|
||||
return std::make_unique<SessionDescription>(local_description->Clone());
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<SessionDescription> PeerConnection::current_remote_description()
|
||||
const {
|
||||
auto remote_description = peer_connection_->current_remote_description();
|
||||
if (remote_description)
|
||||
return std::make_unique<SessionDescription>(remote_description->Clone());
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<SessionDescription> PeerConnection::pending_local_description()
|
||||
const {
|
||||
auto local_description = peer_connection_->pending_local_description();
|
||||
if (local_description)
|
||||
return std::make_unique<SessionDescription>(local_description->Clone());
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<SessionDescription> PeerConnection::pending_remote_description()
|
||||
const {
|
||||
auto remote_description = peer_connection_->pending_remote_description();
|
||||
if (remote_description)
|
||||
return std::make_unique<SessionDescription>(remote_description->Clone());
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<SessionDescription> PeerConnection::local_description() const {
|
||||
auto local_description = peer_connection_->local_description();
|
||||
if (local_description)
|
||||
return std::make_unique<SessionDescription>(local_description->Clone());
|
||||
|
||||
return std::unique_ptr<SessionDescription>();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<SessionDescription> PeerConnection::remote_description() const {
|
||||
@@ -171,7 +207,12 @@ std::unique_ptr<SessionDescription> PeerConnection::remote_description() const {
|
||||
if (remote_description)
|
||||
return std::make_unique<SessionDescription>(remote_description->Clone());
|
||||
|
||||
return std::unique_ptr<SessionDescription>();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PeerConnectionState PeerConnection::connection_state() const {
|
||||
return static_cast<PeerConnectionState>(
|
||||
peer_connection_->peer_connection_state());
|
||||
}
|
||||
|
||||
SignalingState PeerConnection::signaling_state() const {
|
||||
@@ -188,7 +229,7 @@ IceConnectionState PeerConnection::ice_connection_state() const {
|
||||
peer_connection_->ice_connection_state());
|
||||
}
|
||||
|
||||
void PeerConnection::close() {
|
||||
void PeerConnection::close() const {
|
||||
peer_connection_->Close();
|
||||
}
|
||||
|
||||
@@ -213,7 +254,13 @@ create_native_add_ice_candidate_observer(
|
||||
NativePeerConnectionObserver::NativePeerConnectionObserver(
|
||||
std::shared_ptr<RTCRuntime> rtc_runtime,
|
||||
rust::Box<PeerConnectionObserverWrapper> observer)
|
||||
: rtc_runtime_(std::move(rtc_runtime)), observer_(std::move(observer)) {}
|
||||
: rtc_runtime_(std::move(rtc_runtime)), observer_(std::move(observer)) {
|
||||
RTC_LOG(LS_INFO) << "NativePeerConnectionObserver()";
|
||||
}
|
||||
|
||||
NativePeerConnectionObserver::~NativePeerConnectionObserver() {
|
||||
RTC_LOG(LS_INFO) << "~NativePeerConnectionObserver()";
|
||||
}
|
||||
|
||||
void NativePeerConnectionObserver::OnSignalingChange(
|
||||
webrtc::PeerConnectionInterface::SignalingState new_state) {
|
||||
@@ -233,7 +280,7 @@ void NativePeerConnectionObserver::OnRemoveStream(
|
||||
void NativePeerConnectionObserver::OnDataChannel(
|
||||
rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel) {
|
||||
observer_->on_data_channel(
|
||||
std::make_unique<DataChannel>(rtc_runtime_, data_channel));
|
||||
std::make_shared<DataChannel>(rtc_runtime_, data_channel));
|
||||
}
|
||||
|
||||
void NativePeerConnectionObserver::OnRenegotiationNeeded() {
|
||||
@@ -342,11 +389,11 @@ void NativePeerConnectionObserver::OnInterestingUsage(int usage_pattern) {
|
||||
observer_->on_interesting_usage(usage_pattern);
|
||||
}
|
||||
|
||||
std::unique_ptr<NativePeerConnectionObserver>
|
||||
std::shared_ptr<NativePeerConnectionObserver>
|
||||
create_native_peer_connection_observer(
|
||||
std::shared_ptr<RTCRuntime> rtc_runtime,
|
||||
rust::Box<PeerConnectionObserverWrapper> observer) {
|
||||
return std::make_unique<NativePeerConnectionObserver>(rtc_runtime,
|
||||
return std::make_shared<NativePeerConnectionObserver>(rtc_runtime,
|
||||
std::move(observer));
|
||||
}
|
||||
} // namespace livekit
|
||||
|
||||
@@ -6,8 +6,9 @@ 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 cxx::SharedPtr;
|
||||
use std::mem::ManuallyDrop;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[cxx::bridge(namespace = "livekit")]
|
||||
pub mod ffi {
|
||||
@@ -183,7 +184,7 @@ pub mod ffi {
|
||||
self: &PeerConnection,
|
||||
label: String,
|
||||
init: UniquePtr<NativeDataChannelInit>,
|
||||
) -> Result<UniquePtr<DataChannel>>;
|
||||
) -> Result<SharedPtr<DataChannel>>;
|
||||
|
||||
fn add_ice_candidate(
|
||||
self: &PeerConnection,
|
||||
@@ -191,9 +192,11 @@ pub mod ffi {
|
||||
observer: Pin<&mut NativeAddIceCandidateObserver>,
|
||||
);
|
||||
|
||||
fn local_description(self: &PeerConnection) -> UniquePtr<SessionDescription>;
|
||||
fn current_local_description(self: &PeerConnection) -> UniquePtr<SessionDescription>;
|
||||
|
||||
fn remote_description(self: &PeerConnection) -> UniquePtr<SessionDescription>;
|
||||
fn current_remote_description(self: &PeerConnection) -> UniquePtr<SessionDescription>;
|
||||
|
||||
fn connection_state(self: &PeerConnection) -> PeerConnectionState;
|
||||
|
||||
fn signaling_state(self: &PeerConnection) -> SignalingState;
|
||||
|
||||
@@ -201,18 +204,18 @@ pub mod ffi {
|
||||
|
||||
fn ice_connection_state(self: &PeerConnection) -> IceConnectionState;
|
||||
|
||||
fn close(self: Pin<&mut PeerConnection>);
|
||||
fn close(self: &PeerConnection);
|
||||
|
||||
fn create_native_peer_connection_observer(
|
||||
rtc_runtime: SharedPtr<RTCRuntime>,
|
||||
observer: Box<PeerConnectionObserverWrapper>,
|
||||
) -> UniquePtr<NativePeerConnectionObserver>;
|
||||
) -> SharedPtr<NativePeerConnectionObserver>;
|
||||
|
||||
fn create_native_add_ice_candidate_observer(
|
||||
observer: Box<AddIceCandidateObserverWrapper>,
|
||||
) -> UniquePtr<NativeAddIceCandidateObserver>;
|
||||
|
||||
fn _unique_peer_connection() -> UniquePtr<PeerConnection>; // Ignore
|
||||
fn _shared_peer_connection() -> SharedPtr<PeerConnection>; // Ignore
|
||||
}
|
||||
|
||||
extern "Rust" {
|
||||
@@ -227,7 +230,7 @@ pub mod ffi {
|
||||
fn on_remove_stream(self: &PeerConnectionObserverWrapper, stream: SharedPtr<MediaStream>);
|
||||
fn on_data_channel(
|
||||
self: &PeerConnectionObserverWrapper,
|
||||
data_channel: UniquePtr<DataChannel>,
|
||||
data_channel: SharedPtr<DataChannel>,
|
||||
);
|
||||
fn on_renegotiation_needed(self: &PeerConnectionObserverWrapper);
|
||||
fn on_negotiation_needed_event(self: &PeerConnectionObserverWrapper, event: u32);
|
||||
@@ -325,7 +328,7 @@ pub trait PeerConnectionObserver: Send + Sync {
|
||||
fn on_signaling_change(&self, new_state: ffi::SignalingState);
|
||||
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_data_channel(&self, data_channel: SharedPtr<DataChannel>);
|
||||
fn on_renegotiation_needed(&self);
|
||||
fn on_negotiation_needed_event(&self, event: u32);
|
||||
fn on_ice_connection_change(&self, new_state: ffi::IceConnectionState);
|
||||
@@ -352,80 +355,57 @@ pub trait PeerConnectionObserver: Send + Sync {
|
||||
|
||||
// Thread safety is handled inside PeerConnectionObserver
|
||||
pub struct PeerConnectionObserverWrapper {
|
||||
observer: *mut dyn PeerConnectionObserver,
|
||||
observer: Arc<dyn PeerConnectionObserver>,
|
||||
}
|
||||
|
||||
impl PeerConnectionObserverWrapper {
|
||||
/// # Safety
|
||||
/// PeerConnectionObserver must lives as long as PeerConnectionObserverWrapper does
|
||||
pub unsafe fn new(observer: *mut dyn PeerConnectionObserver) -> Self {
|
||||
pub fn new(observer: Arc<dyn PeerConnectionObserver>) -> Self {
|
||||
Self { observer }
|
||||
}
|
||||
|
||||
fn on_signaling_change(&self, new_state: ffi::SignalingState) {
|
||||
unsafe {
|
||||
(*self.observer).on_signaling_change(new_state);
|
||||
}
|
||||
self.observer.on_signaling_change(new_state);
|
||||
}
|
||||
|
||||
fn on_add_stream(&self, stream: SharedPtr<MediaStream>) {
|
||||
unsafe {
|
||||
(*self.observer).on_add_stream(stream);
|
||||
}
|
||||
self.observer.on_add_stream(stream);
|
||||
}
|
||||
|
||||
fn on_remove_stream(&self, stream: SharedPtr<MediaStream>) {
|
||||
unsafe {
|
||||
(*self.observer).on_remove_stream(stream);
|
||||
}
|
||||
self.observer.on_remove_stream(stream);
|
||||
}
|
||||
|
||||
fn on_data_channel(&self, data_channel: UniquePtr<DataChannel>) {
|
||||
unsafe {
|
||||
(*self.observer).on_data_channel(data_channel);
|
||||
}
|
||||
fn on_data_channel(&self, data_channel: SharedPtr<DataChannel>) {
|
||||
self.observer.on_data_channel(data_channel);
|
||||
}
|
||||
|
||||
fn on_renegotiation_needed(&self) {
|
||||
unsafe {
|
||||
(*self.observer).on_renegotiation_needed();
|
||||
}
|
||||
self.observer.on_renegotiation_needed();
|
||||
}
|
||||
|
||||
fn on_negotiation_needed_event(&self, event: u32) {
|
||||
unsafe {
|
||||
(*self.observer).on_negotiation_needed_event(event);
|
||||
}
|
||||
self.observer.on_negotiation_needed_event(event);
|
||||
}
|
||||
|
||||
fn on_ice_connection_change(&self, new_state: ffi::IceConnectionState) {
|
||||
unsafe {
|
||||
(*self.observer).on_ice_connection_change(new_state);
|
||||
}
|
||||
self.observer.on_ice_connection_change(new_state);
|
||||
}
|
||||
|
||||
fn on_standardized_ice_connection_change(&self, new_state: ffi::IceConnectionState) {
|
||||
unsafe {
|
||||
(*self.observer).on_standardized_ice_connection_change(new_state);
|
||||
}
|
||||
self.observer
|
||||
.on_standardized_ice_connection_change(new_state);
|
||||
}
|
||||
|
||||
fn on_connection_change(&self, new_state: ffi::PeerConnectionState) {
|
||||
unsafe {
|
||||
(*self.observer).on_connection_change(new_state);
|
||||
}
|
||||
self.observer.on_connection_change(new_state);
|
||||
}
|
||||
|
||||
fn on_ice_gathering_change(&self, new_state: ffi::IceGatheringState) {
|
||||
unsafe {
|
||||
(*self.observer).on_ice_gathering_change(new_state);
|
||||
}
|
||||
self.observer.on_ice_gathering_change(new_state);
|
||||
}
|
||||
|
||||
fn on_ice_candidate(&self, candidate: SharedPtr<IceCandidate>) {
|
||||
unsafe {
|
||||
(*self.observer).on_ice_candidate(candidate);
|
||||
}
|
||||
self.observer.on_ice_candidate(candidate);
|
||||
}
|
||||
|
||||
fn on_ice_candidate_error(
|
||||
@@ -436,9 +416,8 @@ impl PeerConnectionObserverWrapper {
|
||||
error_code: i32,
|
||||
error_text: String,
|
||||
) {
|
||||
unsafe {
|
||||
(*self.observer).on_ice_candidate_error(address, port, url, error_code, error_text);
|
||||
}
|
||||
self.observer
|
||||
.on_ice_candidate_error(address, port, url, error_code, error_text);
|
||||
}
|
||||
|
||||
fn on_ice_candidates_removed(&self, removed: Vec<ffi::CandidatePtr>) {
|
||||
@@ -448,21 +427,15 @@ impl PeerConnectionObserverWrapper {
|
||||
vec.push(v.ptr);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
(*self.observer).on_ice_candidates_removed(vec);
|
||||
}
|
||||
self.observer.on_ice_candidates_removed(vec);
|
||||
}
|
||||
|
||||
fn on_ice_connection_receiving_change(&self, receiving: bool) {
|
||||
unsafe {
|
||||
(*self.observer).on_ice_connection_receiving_change(receiving);
|
||||
}
|
||||
self.observer.on_ice_connection_receiving_change(receiving);
|
||||
}
|
||||
|
||||
fn on_ice_selected_candidate_pair_changed(&self, event: ffi::CandidatePairChangeEvent) {
|
||||
unsafe {
|
||||
(*self.observer).on_ice_selected_candidate_pair_changed(event);
|
||||
}
|
||||
self.observer.on_ice_selected_candidate_pair_changed(event);
|
||||
}
|
||||
|
||||
fn on_add_track(&self, receiver: SharedPtr<RtpReceiver>, streams: Vec<ffi::MediaStreamPtr>) {
|
||||
@@ -472,26 +445,18 @@ impl PeerConnectionObserverWrapper {
|
||||
vec.push(v.ptr);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
(*self.observer).on_add_track(receiver, vec);
|
||||
}
|
||||
self.observer.on_add_track(receiver, vec);
|
||||
}
|
||||
|
||||
fn on_track(&self, transceiver: SharedPtr<RtpTransceiver>) {
|
||||
unsafe {
|
||||
(*self.observer).on_track(transceiver);
|
||||
}
|
||||
self.observer.on_track(transceiver);
|
||||
}
|
||||
|
||||
fn on_remove_track(&self, receiver: SharedPtr<RtpReceiver>) {
|
||||
unsafe {
|
||||
(*self.observer).on_remove_track(receiver);
|
||||
}
|
||||
self.observer.on_remove_track(receiver);
|
||||
}
|
||||
|
||||
fn on_interesting_usage(&self, usage_pattern: i32) {
|
||||
unsafe {
|
||||
(*self.observer).on_interesting_usage(usage_pattern);
|
||||
}
|
||||
self.observer.on_interesting_usage(usage_pattern);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,11 +20,13 @@
|
||||
|
||||
#include "api/audio_codecs/builtin_audio_decoder_factory.h"
|
||||
#include "api/audio_codecs/builtin_audio_encoder_factory.h"
|
||||
#include "api/peer_connection_interface.h"
|
||||
#include "api/rtc_event_log/rtc_event_log_factory.h"
|
||||
#include "api/task_queue/default_task_queue_factory.h"
|
||||
#include "api/video_codecs/builtin_video_decoder_factory.h"
|
||||
#include "api/video_codecs/builtin_video_encoder_factory.h"
|
||||
#include "livekit/rtc_error.h"
|
||||
#include "livekit/rtp_parameters.h"
|
||||
#include "livekit/video_decoder_factory.h"
|
||||
#include "livekit/video_encoder_factory.h"
|
||||
#include "media/engine/webrtc_media_engine.h"
|
||||
@@ -73,10 +75,10 @@ PeerConnectionFactory::~PeerConnectionFactory() {
|
||||
RTC_LOG(LS_INFO) << "PeerConnectionFactory::~PeerConnectionFactory()";
|
||||
}
|
||||
|
||||
std::unique_ptr<PeerConnection> PeerConnectionFactory::create_peer_connection(
|
||||
std::shared_ptr<PeerConnection> PeerConnectionFactory::create_peer_connection(
|
||||
std::unique_ptr<webrtc::PeerConnectionInterface::RTCConfiguration> config,
|
||||
NativePeerConnectionObserver& observer) const {
|
||||
webrtc::PeerConnectionDependencies deps{&observer};
|
||||
NativePeerConnectionObserver* observer) const {
|
||||
webrtc::PeerConnectionDependencies deps{observer};
|
||||
auto result =
|
||||
peer_factory_->CreatePeerConnectionOrError(*config, std::move(deps));
|
||||
|
||||
@@ -84,12 +86,31 @@ std::unique_ptr<PeerConnection> PeerConnectionFactory::create_peer_connection(
|
||||
throw std::runtime_error(serialize_error(to_error(result.error())));
|
||||
}
|
||||
|
||||
return std::make_unique<PeerConnection>(rtc_runtime_, result.value());
|
||||
return std::make_shared<PeerConnection>(rtc_runtime_, result.value());
|
||||
}
|
||||
|
||||
std::unique_ptr<PeerConnectionFactory> create_peer_connection_factory(
|
||||
std::shared_ptr<VideoTrack> PeerConnectionFactory::create_video_track(
|
||||
rust::String label,
|
||||
std::shared_ptr<AdaptedVideoTrackSource> source) const {
|
||||
return std::make_shared<VideoTrack>(
|
||||
peer_factory_->CreateVideoTrack(label.c_str(), source->get().get()));
|
||||
}
|
||||
|
||||
RtpCapabilities PeerConnectionFactory::get_rtp_sender_capabilities(
|
||||
MediaType type) const {
|
||||
return to_rust_rtp_capabilities(peer_factory_->GetRtpSenderCapabilities(
|
||||
static_cast<cricket::MediaType>(type)));
|
||||
}
|
||||
|
||||
RtpCapabilities PeerConnectionFactory::get_rtp_receiver_capabilities(
|
||||
MediaType type) const {
|
||||
return to_rust_rtp_capabilities(peer_factory_->GetRtpReceiverCapabilities(
|
||||
static_cast<cricket::MediaType>(type)));
|
||||
}
|
||||
|
||||
std::shared_ptr<PeerConnectionFactory> create_peer_connection_factory(
|
||||
std::shared_ptr<RTCRuntime> rtc_runtime) {
|
||||
return std::make_unique<PeerConnectionFactory>(std::move(rtc_runtime));
|
||||
return std::make_shared<PeerConnectionFactory>(std::move(rtc_runtime));
|
||||
}
|
||||
|
||||
std::unique_ptr<NativeRTCConfiguration> create_rtc_configuration(
|
||||
|
||||
@@ -32,6 +32,17 @@ pub mod ffi {
|
||||
pub ice_transport_type: IceTransportsType,
|
||||
}
|
||||
|
||||
extern "C++" {
|
||||
include!("livekit/media_stream.h");
|
||||
include!("livekit/webrtc.h");
|
||||
include!("livekit/rtp_parameters.h");
|
||||
|
||||
type AdaptedVideoTrackSource = crate::media_stream::ffi::AdaptedVideoTrackSource;
|
||||
type VideoTrack = crate::media_stream::ffi::VideoTrack;
|
||||
type RtpCapabilities = crate::rtp_parameters::ffi::RtpCapabilities;
|
||||
type MediaType = crate::webrtc::ffi::MediaType;
|
||||
}
|
||||
|
||||
unsafe extern "C++" {
|
||||
include!("livekit/peer_connection_factory.h");
|
||||
|
||||
@@ -44,7 +55,7 @@ pub mod ffi {
|
||||
|
||||
fn create_peer_connection_factory(
|
||||
runtime: SharedPtr<RTCRuntime>,
|
||||
) -> UniquePtr<PeerConnectionFactory>;
|
||||
) -> SharedPtr<PeerConnectionFactory>;
|
||||
fn create_rtc_configuration(conf: RTCConfiguration) -> UniquePtr<NativeRTCConfiguration>;
|
||||
|
||||
/// # Safety
|
||||
@@ -52,8 +63,24 @@ pub mod ffi {
|
||||
unsafe fn create_peer_connection(
|
||||
self: &PeerConnectionFactory,
|
||||
config: UniquePtr<NativeRTCConfiguration>,
|
||||
observer: Pin<&mut NativePeerConnectionObserver>,
|
||||
) -> Result<UniquePtr<PeerConnection>>;
|
||||
observer: *mut NativePeerConnectionObserver,
|
||||
) -> Result<SharedPtr<PeerConnection>>;
|
||||
|
||||
fn create_video_track(
|
||||
self: &PeerConnectionFactory,
|
||||
label: String,
|
||||
source: SharedPtr<AdaptedVideoTrackSource>,
|
||||
) -> SharedPtr<VideoTrack>;
|
||||
|
||||
fn get_rtp_sender_capabilities(
|
||||
self: &PeerConnectionFactory,
|
||||
kind: MediaType,
|
||||
) -> RtpCapabilities;
|
||||
|
||||
fn get_rtp_receiver_capabilities(
|
||||
self: &PeerConnectionFactory,
|
||||
kind: MediaType,
|
||||
) -> RtpCapabilities;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
namespace livekit {
|
||||
|
||||
webrtc::RtcpFeedback to_native_rtcp_feedback(RtcpFeedback feedback) {
|
||||
webrtc::RtcpFeedback native;
|
||||
webrtc::RtcpFeedback native{};
|
||||
native.type = static_cast<webrtc::RtcpFeedbackType>(feedback.feedback_type);
|
||||
if (feedback.has_message_type)
|
||||
native.message_type =
|
||||
@@ -30,14 +30,14 @@ webrtc::RtcpFeedback to_native_rtcp_feedback(RtcpFeedback feedback) {
|
||||
|
||||
webrtc::RtpCodecCapability to_native_rtp_codec_capability(
|
||||
RtpCodecCapability capability) {
|
||||
webrtc::RtpCodecCapability native;
|
||||
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;
|
||||
native.clock_rate = capability.clock_rate;
|
||||
|
||||
if (capability.has_preferred_payload_type)
|
||||
native.preferred_payload_type = capability.preferred_payload_type;
|
||||
@@ -62,9 +62,7 @@ webrtc::RtpCodecCapability to_native_rtp_codec_capability(
|
||||
|
||||
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;
|
||||
@@ -72,7 +70,7 @@ webrtc::RtpCodecCapability to_native_rtp_codec_capability(
|
||||
|
||||
webrtc::RtpHeaderExtensionCapability to_native_rtp_header_extension_capability(
|
||||
RtpHeaderExtensionCapability header) {
|
||||
webrtc::RtpHeaderExtensionCapability native;
|
||||
webrtc::RtpHeaderExtensionCapability native{};
|
||||
native.uri = header.uri.c_str();
|
||||
|
||||
if (header.has_preferred_id)
|
||||
@@ -86,7 +84,7 @@ webrtc::RtpHeaderExtensionCapability to_native_rtp_header_extension_capability(
|
||||
}
|
||||
|
||||
webrtc::RtpExtension to_native_rtp_extension(RtpExtension ext) {
|
||||
webrtc::RtpExtension native;
|
||||
webrtc::RtpExtension native{};
|
||||
native.uri = ext.uri.c_str();
|
||||
native.id = ext.id;
|
||||
native.encrypt = ext.encrypt;
|
||||
@@ -94,7 +92,7 @@ webrtc::RtpExtension to_native_rtp_extension(RtpExtension ext) {
|
||||
}
|
||||
|
||||
webrtc::RtpFecParameters to_rtp_fec_parameters(RtpFecParameters fec) {
|
||||
webrtc::RtpFecParameters native;
|
||||
webrtc::RtpFecParameters native{};
|
||||
|
||||
if (fec.has_ssrc)
|
||||
native.ssrc = fec.ssrc;
|
||||
@@ -104,7 +102,7 @@ webrtc::RtpFecParameters to_rtp_fec_parameters(RtpFecParameters fec) {
|
||||
}
|
||||
|
||||
webrtc::RtpRtxParameters to_rtp_rtx_parameters(RtpRtxParameters rtx) {
|
||||
webrtc::RtpRtxParameters native;
|
||||
webrtc::RtpRtxParameters native{};
|
||||
|
||||
if (rtx.has_ssrc)
|
||||
native.ssrc = rtx.ssrc;
|
||||
@@ -113,7 +111,7 @@ webrtc::RtpRtxParameters to_rtp_rtx_parameters(RtpRtxParameters rtx) {
|
||||
|
||||
webrtc::RtpEncodingParameters to_native_rtp_encoding_paramters(
|
||||
RtpEncodingParameters parameters) {
|
||||
webrtc::RtpEncodingParameters native;
|
||||
webrtc::RtpEncodingParameters native{};
|
||||
native.rid = parameters.rid.c_str();
|
||||
|
||||
if (parameters.has_ssrc)
|
||||
@@ -147,7 +145,7 @@ webrtc::RtpEncodingParameters to_native_rtp_encoding_paramters(
|
||||
|
||||
webrtc::RtpCodecParameters to_native_rtp_codec_parameters(
|
||||
RtpCodecParameters params) {
|
||||
webrtc::RtpCodecParameters native;
|
||||
webrtc::RtpCodecParameters native{};
|
||||
native.name = params.name.c_str();
|
||||
native.kind = static_cast<cricket::MediaType>(params.kind);
|
||||
native.payload_type = params.payload_type;
|
||||
@@ -174,7 +172,7 @@ webrtc::RtpCodecParameters to_native_rtp_codec_parameters(
|
||||
}
|
||||
|
||||
webrtc::RtpCapabilities to_rtp_capabilities(RtpCapabilities capabilities) {
|
||||
webrtc::RtpCapabilities native;
|
||||
webrtc::RtpCapabilities native{};
|
||||
for (auto codec : capabilities.codecs)
|
||||
native.codecs.push_back(to_native_rtp_codec_capability(codec));
|
||||
|
||||
@@ -189,7 +187,7 @@ webrtc::RtpCapabilities to_rtp_capabilities(RtpCapabilities capabilities) {
|
||||
}
|
||||
|
||||
webrtc::RtcpParameters to_native_rtcp_paramaters(RtcpParameters params) {
|
||||
webrtc::RtcpParameters native;
|
||||
webrtc::RtcpParameters native{};
|
||||
if (params.has_ssrc)
|
||||
native.ssrc = params.ssrc;
|
||||
|
||||
@@ -200,7 +198,7 @@ webrtc::RtcpParameters to_native_rtcp_paramaters(RtcpParameters params) {
|
||||
}
|
||||
|
||||
webrtc::RtpParameters to_native_rtp_parameters(RtpParameters params) {
|
||||
webrtc::RtpParameters native;
|
||||
webrtc::RtpParameters native{};
|
||||
native.transaction_id = params.transaction_id.c_str();
|
||||
native.mid = params.mid.c_str();
|
||||
|
||||
@@ -223,7 +221,7 @@ webrtc::RtpParameters to_native_rtp_parameters(RtpParameters params) {
|
||||
}
|
||||
|
||||
RtcpFeedback to_rust_rtcp_feedback(webrtc::RtcpFeedback feedback) {
|
||||
RtcpFeedback rust;
|
||||
RtcpFeedback rust{};
|
||||
rust.feedback_type = static_cast<RtcpFeedbackType>(feedback.type);
|
||||
|
||||
if (feedback.message_type.has_value()) {
|
||||
@@ -237,7 +235,7 @@ RtcpFeedback to_rust_rtcp_feedback(webrtc::RtcpFeedback feedback) {
|
||||
|
||||
RtpCodecCapability to_rust_rtp_codec_capability(
|
||||
webrtc::RtpCodecCapability capability) {
|
||||
RtpCodecCapability rust;
|
||||
RtpCodecCapability rust{};
|
||||
rust.mime_type = capability.mime_type();
|
||||
rust.name = capability.name;
|
||||
rust.kind = static_cast<MediaType>(capability.kind);
|
||||
@@ -262,7 +260,7 @@ RtpCodecCapability to_rust_rtp_codec_capability(
|
||||
rust.ptime = capability.ptime.value();
|
||||
}
|
||||
|
||||
if (capability.num_channels.has_value()) {
|
||||
if (capability.num_channels) {
|
||||
rust.has_num_channels = true;
|
||||
rust.num_channels = capability.num_channels.value();
|
||||
}
|
||||
@@ -284,7 +282,7 @@ RtpCodecCapability to_rust_rtp_codec_capability(
|
||||
|
||||
RtpHeaderExtensionCapability to_rust_rtp_header_extension_capability(
|
||||
webrtc::RtpHeaderExtensionCapability header) {
|
||||
RtpHeaderExtensionCapability rust;
|
||||
RtpHeaderExtensionCapability rust{};
|
||||
rust.uri = header.uri;
|
||||
if (header.preferred_id.has_value()) {
|
||||
rust.has_preferred_id = true;
|
||||
@@ -297,7 +295,7 @@ RtpHeaderExtensionCapability to_rust_rtp_header_extension_capability(
|
||||
}
|
||||
|
||||
RtpExtension to_rust_rtp_extension(webrtc::RtpExtension ext) {
|
||||
RtpExtension rust;
|
||||
RtpExtension rust{};
|
||||
rust.uri = ext.uri;
|
||||
rust.id = ext.id;
|
||||
rust.encrypt = ext.encrypt;
|
||||
@@ -305,7 +303,7 @@ RtpExtension to_rust_rtp_extension(webrtc::RtpExtension ext) {
|
||||
}
|
||||
|
||||
RtpFecParameters to_rust_rtp_fec_parameters(webrtc::RtpFecParameters fec) {
|
||||
RtpFecParameters rust;
|
||||
RtpFecParameters rust{};
|
||||
if (fec.ssrc.has_value()) {
|
||||
rust.has_ssrc = true;
|
||||
rust.ssrc = fec.ssrc.value();
|
||||
@@ -316,7 +314,7 @@ RtpFecParameters to_rust_rtp_fec_parameters(webrtc::RtpFecParameters fec) {
|
||||
}
|
||||
|
||||
RtpRtxParameters to_rust_rtp_rtx_parameters(webrtc::RtpRtxParameters param) {
|
||||
RtpRtxParameters rust;
|
||||
RtpRtxParameters rust{};
|
||||
if (param.ssrc.has_value()) {
|
||||
rust.has_ssrc = param.ssrc.has_value();
|
||||
rust.ssrc = param.ssrc.value();
|
||||
@@ -326,7 +324,7 @@ RtpRtxParameters to_rust_rtp_rtx_parameters(webrtc::RtpRtxParameters param) {
|
||||
|
||||
RtpEncodingParameters to_rust_rtp_encoding_parameters(
|
||||
webrtc::RtpEncodingParameters params) {
|
||||
RtpEncodingParameters rust;
|
||||
RtpEncodingParameters rust{};
|
||||
if (params.ssrc.has_value()) {
|
||||
rust.has_ssrc = params.ssrc.has_value();
|
||||
rust.ssrc = params.ssrc.value();
|
||||
@@ -372,7 +370,7 @@ RtpEncodingParameters to_rust_rtp_encoding_parameters(
|
||||
|
||||
RtpCodecParameters to_rust_rtp_codec_parameters(
|
||||
webrtc::RtpCodecParameters params) {
|
||||
RtpCodecParameters rust;
|
||||
RtpCodecParameters rust{};
|
||||
rust.mime_type = params.mime_type();
|
||||
rust.name = params.name;
|
||||
rust.kind = static_cast<MediaType>(params.kind);
|
||||
@@ -407,7 +405,7 @@ RtpCodecParameters to_rust_rtp_codec_parameters(
|
||||
}
|
||||
|
||||
RtpCapabilities to_rust_rtp_capabilities(webrtc::RtpCapabilities capabilities) {
|
||||
RtpCapabilities rust;
|
||||
RtpCapabilities rust{};
|
||||
for (auto codec : capabilities.codecs)
|
||||
rust.codecs.push_back(to_rust_rtp_codec_capability(codec));
|
||||
|
||||
@@ -422,7 +420,7 @@ RtpCapabilities to_rust_rtp_capabilities(webrtc::RtpCapabilities capabilities) {
|
||||
}
|
||||
|
||||
RtcpParameters to_rust_rtcp_parameters(webrtc::RtcpParameters params) {
|
||||
RtcpParameters rust;
|
||||
RtcpParameters rust{};
|
||||
if (params.ssrc.has_value()) {
|
||||
rust.has_ssrc = true;
|
||||
rust.ssrc = params.ssrc.value();
|
||||
@@ -435,7 +433,7 @@ RtcpParameters to_rust_rtcp_parameters(webrtc::RtcpParameters params) {
|
||||
}
|
||||
|
||||
RtpParameters to_rust_rtp_parameters(webrtc::RtpParameters params) {
|
||||
RtpParameters rust;
|
||||
RtpParameters rust{};
|
||||
rust.transaction_id = params.transaction_id;
|
||||
rust.mid = params.mid;
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
use cxx::UniquePtr;
|
||||
|
||||
pub const DEFAULT_BITRATE_PRIORITY: f64 = 1.0;
|
||||
|
||||
#[cxx::bridge(namespace = "livekit")]
|
||||
@@ -12,34 +10,34 @@ pub mod ffi {
|
||||
pub value: String,
|
||||
}
|
||||
|
||||
#[repr(i32)]
|
||||
#[derive(Debug)]
|
||||
#[repr(i32)]
|
||||
pub enum FecMechanism {
|
||||
RED,
|
||||
REDAndULPFEC,
|
||||
FLEXFEC,
|
||||
Red,
|
||||
RedAndUlpfec,
|
||||
FlexFec,
|
||||
}
|
||||
|
||||
#[repr(i32)]
|
||||
#[derive(Debug)]
|
||||
#[repr(i32)]
|
||||
pub enum RtcpFeedbackType {
|
||||
CCM,
|
||||
LNTF,
|
||||
NACK,
|
||||
REMB,
|
||||
Ccm,
|
||||
Lntf,
|
||||
Nack,
|
||||
Remb,
|
||||
TransportCC,
|
||||
}
|
||||
|
||||
#[repr(i32)]
|
||||
#[derive(Debug)]
|
||||
#[repr(i32)]
|
||||
pub enum RtcpFeedbackMessageType {
|
||||
GenericNACK,
|
||||
PLI,
|
||||
FIR,
|
||||
GenericNack,
|
||||
Pli,
|
||||
Fir,
|
||||
}
|
||||
|
||||
#[repr(i32)]
|
||||
#[derive(Debug)]
|
||||
#[repr(i32)]
|
||||
pub enum DegradationPreference {
|
||||
Disabled,
|
||||
MaintainFramerate,
|
||||
@@ -86,8 +84,8 @@ pub mod ffi {
|
||||
pub direction: RtpTransceiverDirection,
|
||||
}
|
||||
|
||||
#[repr(i32)]
|
||||
#[derive(Debug)]
|
||||
#[repr(i32)]
|
||||
pub enum RtpExtensionFilter {
|
||||
DiscardEncryptedExtension,
|
||||
PreferEncryptedExtension,
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use crate::impl_thread_safety;
|
||||
|
||||
#[cxx::bridge(namespace = "livekit")]
|
||||
pub mod ffi {
|
||||
|
||||
@@ -31,3 +33,5 @@ pub mod ffi {
|
||||
fn _shared_rtp_sender() -> SharedPtr<RtpSender>;
|
||||
}
|
||||
}
|
||||
|
||||
impl_thread_safety!(ffi::RtpSender, Send + Sync);
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace livekit {
|
||||
webrtc::RtpTransceiverInit to_native_rtp_transceiver_init(
|
||||
RtpTransceiverInit init) {
|
||||
{
|
||||
webrtc::RtpTransceiverInit native;
|
||||
webrtc::RtpTransceiverInit native{};
|
||||
native.direction =
|
||||
static_cast<webrtc::RtpTransceiverDirection>(init.direction);
|
||||
native.stream_ids = std::vector<std::string>(init.stream_ids.begin(),
|
||||
@@ -95,6 +95,7 @@ void RtpTransceiver::stop_standard() const {
|
||||
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));
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ pub mod ffi {
|
||||
crate::rtp_parameters::ffi::RtpHeaderExtensionCapability;
|
||||
type RtpSender = crate::rtp_sender::ffi::RtpSender;
|
||||
type RtpReceiver = crate::rtp_receiver::ffi::RtpReceiver;
|
||||
type RTCError = crate::rtc_error::ffi::RTCError;
|
||||
}
|
||||
|
||||
unsafe extern "C++" {
|
||||
|
||||
@@ -62,9 +62,8 @@ 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_video_frame_buffer(const VideoFrameBuffer& buffer) {
|
||||
builder_.set_video_frame_buffer(buffer.get()); // const & ref_counted
|
||||
}
|
||||
|
||||
void VideoFrameBuilder::set_timestamp_us(int64_t timestamp_us) {
|
||||
@@ -83,7 +82,7 @@ std::unique_ptr<VideoFrame> VideoFrameBuilder::build() {
|
||||
return std::make_unique<VideoFrame>(builder_.build());
|
||||
}
|
||||
|
||||
std::unique_ptr<VideoFrameBuilder> create_video_frame_builder() {
|
||||
std::unique_ptr<VideoFrameBuilder> new_video_frame_builder() {
|
||||
return std::make_unique<VideoFrameBuilder>();
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@ pub mod ffi {
|
||||
include!("livekit/video_frame.h");
|
||||
|
||||
type VideoFrame;
|
||||
type VideoFrameBuilder;
|
||||
|
||||
fn width(self: &VideoFrame) -> i32;
|
||||
fn height(self: &VideoFrame) -> i32;
|
||||
@@ -32,18 +31,18 @@ pub mod ffi {
|
||||
fn transport_frame_id(self: &VideoFrame) -> u32;
|
||||
fn timestamp(self: &VideoFrame) -> u32;
|
||||
fn rotation(self: &VideoFrame) -> VideoRotation;
|
||||
fn video_frame_buffer(self: &VideoFrame) -> UniquePtr<VideoFrameBuffer>;
|
||||
unsafe fn video_frame_buffer(self: &VideoFrame) -> UniquePtr<VideoFrameBuffer>;
|
||||
|
||||
fn set_video_frame_buffer(
|
||||
self: Pin<&mut VideoFrameBuilder>,
|
||||
buffer: UniquePtr<VideoFrameBuffer>,
|
||||
);
|
||||
// VideoFrameBuilder
|
||||
type VideoFrameBuilder;
|
||||
fn new_video_frame_builder() -> UniquePtr<VideoFrameBuilder>;
|
||||
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 set_video_frame_buffer(self: Pin<&mut VideoFrameBuilder>, buffer: &VideoFrameBuffer);
|
||||
|
||||
fn build(self: Pin<&mut VideoFrameBuilder>) -> UniquePtr<VideoFrame>;
|
||||
|
||||
fn create_video_frame_builder() -> UniquePtr<VideoFrameBuilder>;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ int VideoFrameBuffer::height() const {
|
||||
return buffer_->height();
|
||||
}
|
||||
|
||||
std::unique_ptr<I420Buffer> VideoFrameBuffer::to_i420() {
|
||||
std::unique_ptr<I420Buffer> VideoFrameBuffer::to_i420() const {
|
||||
return std::make_unique<I420Buffer>(buffer_->ToI420());
|
||||
}
|
||||
|
||||
@@ -187,11 +187,16 @@ webrtc::BiplanarYuv8Buffer* BiplanarYuv8Buffer::buffer() const {
|
||||
return static_cast<webrtc::BiplanarYuv8Buffer*>(buffer_.get());
|
||||
}
|
||||
|
||||
std::unique_ptr<I420Buffer> create_i420_buffer(int width, int height) {
|
||||
std::unique_ptr<I420Buffer> new_i420_buffer(int width, int height) {
|
||||
return std::make_unique<I420Buffer>(
|
||||
webrtc::I420Buffer::Create(width, height));
|
||||
}
|
||||
|
||||
std::unique_ptr<I420Buffer> copy_i420_buffer(
|
||||
const std::unique_ptr<I420Buffer>& i420) {
|
||||
return std::make_unique<I420Buffer>(webrtc::I420Buffer::Copy(*i420->get()));
|
||||
}
|
||||
|
||||
I420Buffer::I420Buffer(rtc::scoped_refptr<webrtc::I420BufferInterface> buffer)
|
||||
: PlanarYuv8Buffer(buffer) {}
|
||||
|
||||
@@ -199,6 +204,18 @@ I420ABuffer::I420ABuffer(
|
||||
rtc::scoped_refptr<webrtc::I420ABufferInterface> buffer)
|
||||
: I420Buffer(buffer) {}
|
||||
|
||||
int I420ABuffer::stride_a() const {
|
||||
return buffer()->StrideA();
|
||||
}
|
||||
|
||||
const uint8_t* I420ABuffer::data_a() const {
|
||||
return buffer()->DataA();
|
||||
}
|
||||
|
||||
webrtc::I420ABufferInterface* I420ABuffer::buffer() const {
|
||||
return static_cast<webrtc::I420ABufferInterface*>(buffer_.get());
|
||||
}
|
||||
|
||||
I422Buffer::I422Buffer(rtc::scoped_refptr<webrtc::I422BufferInterface> buffer)
|
||||
: PlanarYuv8Buffer(buffer) {}
|
||||
|
||||
|
||||
@@ -34,9 +34,12 @@ pub mod ffi {
|
||||
fn width(self: &VideoFrameBuffer) -> i32;
|
||||
fn height(self: &VideoFrameBuffer) -> i32;
|
||||
|
||||
/// # SAFETY
|
||||
/// If the buffer type is I420, the buffer must be cloned before
|
||||
unsafe fn to_i420(self: &VideoFrameBuffer) -> UniquePtr<I420Buffer>;
|
||||
|
||||
/// # SAFETY
|
||||
/// The functions require ownership
|
||||
unsafe fn to_i420(self: Pin<&mut VideoFrameBuffer>) -> UniquePtr<I420Buffer>;
|
||||
unsafe fn get_i420(self: Pin<&mut VideoFrameBuffer>) -> UniquePtr<I420Buffer>;
|
||||
unsafe fn get_i420a(self: Pin<&mut VideoFrameBuffer>) -> UniquePtr<I420ABuffer>;
|
||||
unsafe fn get_i422(self: Pin<&mut VideoFrameBuffer>) -> UniquePtr<I422Buffer>;
|
||||
@@ -66,7 +69,11 @@ 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>;
|
||||
fn stride_a(self: &I420ABuffer) -> i32;
|
||||
fn data_a(self: &I420ABuffer) -> *const u8;
|
||||
|
||||
fn new_i420_buffer(width: i32, height: i32) -> UniquePtr<I420Buffer>;
|
||||
fn copy_i420_buffer(i420: &UniquePtr<I420Buffer>) -> UniquePtr<I420Buffer>;
|
||||
|
||||
unsafe fn yuv_to_vfb(yuv: *const PlanarYuvBuffer) -> *const VideoFrameBuffer;
|
||||
unsafe fn biyuv_to_vfb(yuv: *const BiplanarYuvBuffer) -> *const VideoFrameBuffer;
|
||||
|
||||
@@ -16,10 +16,12 @@
|
||||
|
||||
#include "livekit/webrtc.h"
|
||||
|
||||
#include "rtc_base/helpers.h"
|
||||
#include "rtc_base/logging.h"
|
||||
|
||||
namespace livekit {
|
||||
RTCRuntime::RTCRuntime() {
|
||||
// rtc::LogMessage::LogToDebug(rtc::LS_INFO);
|
||||
RTC_LOG(LS_INFO) << "RTCRuntime()";
|
||||
RTC_CHECK(rtc::InitializeSSL()) << "Failed to InitializeSSL()";
|
||||
|
||||
@@ -57,6 +59,10 @@ rtc::Thread* RTCRuntime::signaling_thread() const {
|
||||
return signaling_thread_.get();
|
||||
}
|
||||
|
||||
rust::String create_random_uuid() {
|
||||
return rtc::CreateRandomUuid();
|
||||
}
|
||||
|
||||
std::shared_ptr<RTCRuntime> create_rtc_runtime() {
|
||||
return std::make_shared<RTCRuntime>();
|
||||
}
|
||||
|
||||
@@ -33,9 +33,10 @@ pub mod ffi {
|
||||
|
||||
unsafe extern "C++" {
|
||||
include!("livekit/webrtc.h");
|
||||
|
||||
type RTCRuntime;
|
||||
|
||||
fn create_random_uuid() -> String;
|
||||
|
||||
fn create_rtc_runtime() -> SharedPtr<RTCRuntime>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ pub mod ffi {
|
||||
dst_stride_argb: i32,
|
||||
width: i32,
|
||||
height: i32,
|
||||
);
|
||||
) -> Result<()>;
|
||||
|
||||
unsafe fn i420_to_bgra(
|
||||
src_y: *const u8,
|
||||
@@ -27,7 +27,7 @@ pub mod ffi {
|
||||
dst_stride_bgra: i32,
|
||||
width: i32,
|
||||
height: i32,
|
||||
);
|
||||
) -> Result<()>;
|
||||
|
||||
unsafe fn i420_to_abgr(
|
||||
src_y: *const u8,
|
||||
@@ -40,7 +40,7 @@ pub mod ffi {
|
||||
dst_stride_abgr: i32,
|
||||
width: i32,
|
||||
height: i32,
|
||||
);
|
||||
) -> Result<()>;
|
||||
|
||||
unsafe fn i420_to_rgba(
|
||||
src_y: *const u8,
|
||||
@@ -53,6 +53,41 @@ pub mod ffi {
|
||||
dst_stride_rgba: i32,
|
||||
width: i32,
|
||||
height: i32,
|
||||
);
|
||||
) -> Result<()>;
|
||||
|
||||
unsafe fn argb_to_i420(
|
||||
src_argb: *const u8,
|
||||
src_stride_argb: i32,
|
||||
dst_y: *mut u8,
|
||||
dst_stride_y: i32,
|
||||
dst_u: *mut u8,
|
||||
dst_stride_u: i32,
|
||||
dst_v: *mut u8,
|
||||
dst_stride_v: i32,
|
||||
width: i32,
|
||||
height: i32,
|
||||
) -> Result<()>;
|
||||
|
||||
unsafe fn abgr_to_i420(
|
||||
src_abgr: *const u8,
|
||||
src_stride_abgr: i32,
|
||||
dst_y: *mut u8,
|
||||
dst_stride_y: i32,
|
||||
dst_u: *mut u8,
|
||||
dst_stride_u: i32,
|
||||
dst_v: *mut u8,
|
||||
dst_stride_v: i32,
|
||||
width: i32,
|
||||
height: i32,
|
||||
) -> Result<()>;
|
||||
|
||||
unsafe fn argb_to_rgb24(
|
||||
src_argb: *const u8,
|
||||
src_stride_argb: i32,
|
||||
dst_rgb24: *mut u8,
|
||||
dst_stride_rgb24: i32,
|
||||
width: i32,
|
||||
height: i32,
|
||||
) -> Result<()>;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user