cleanup: webrtc-sys & fix RtcRuntime disposing crashes (#81)

This commit is contained in:
Théo Monnom
2023-06-04 01:02:00 +02:00
committed by GitHub
parent 05ad1c95af
commit 55bda13069
80 changed files with 2209 additions and 1954 deletions
+134
View File
@@ -0,0 +1,134 @@
/*
* Copyright 2023 LiveKit
*
* Licensed under the Apache License, Version 2.0 (the “License”);
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an “AS IS” BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <memory>
#include "livekit/helper.h"
#include "livekit/media_stream_track.h"
#include "livekit/webrtc.h"
#include "pc/local_audio_source.h"
#include "rtc_base/synchronization/mutex.h"
#include "rust/cxx.h"
namespace livekit {
class AudioTrack;
class NativeAudioSink;
class AudioTrackSource;
} // namespace livekit
#include "webrtc-sys/src/audio_track.rs.h"
namespace livekit {
class AudioTrack : public MediaStreamTrack {
private:
friend RtcRuntime;
AudioTrack(std::shared_ptr<RtcRuntime> rtc_runtime,
rtc::scoped_refptr<webrtc::AudioTrackInterface> track);
public:
~AudioTrack();
void add_sink(const std::shared_ptr<NativeAudioSink>& sink) const;
void remove_sink(const std::shared_ptr<NativeAudioSink>& sink) const;
private:
webrtc::AudioTrackInterface* track() const {
return static_cast<webrtc::AudioTrackInterface*>(track_.get());
}
mutable webrtc::Mutex mutex_;
// Same for VideoTrack:
// Keep a strong reference to the added sinks, so we don't need to
// manage the lifetime safety on the Rust side
mutable std::vector<std::shared_ptr<NativeAudioSink>> sinks_;
};
class NativeAudioSink : public webrtc::AudioTrackSinkInterface {
public:
explicit NativeAudioSink(rust::Box<AudioSinkWrapper> observer);
void OnData(const void* audio_data,
int bits_per_sample,
int sample_rate,
size_t number_of_channels,
size_t number_of_frames) override;
private:
rust::Box<AudioSinkWrapper> observer_;
};
std::shared_ptr<NativeAudioSink> new_native_audio_sink(
rust::Box<AudioSinkWrapper> observer);
class AudioTrackSource {
class InternalSource : public webrtc::LocalAudioSource {
public:
InternalSource();
SourceState state() const override;
bool remote() const override;
const cricket::AudioOptions options() const override;
void AddSink(webrtc::AudioTrackSinkInterface* sink) override;
void RemoveSink(webrtc::AudioTrackSinkInterface* sink) override;
// AudioFrame should always contain 10 ms worth of data (see index.md of
// acm)
void on_captured_frame(rust::Slice<const int16_t> audio_data,
int sample_rate,
size_t number_of_channels,
size_t number_of_frames);
private:
webrtc::Mutex mutex_;
std::vector<webrtc::AudioTrackSinkInterface*> sinks_;
cricket::AudioOptions options_{};
};
public:
AudioTrackSource();
void on_captured_frame(rust::Slice<const int16_t> audio_data,
int sample_rate,
size_t number_of_channels,
size_t number_of_frames) const;
rtc::scoped_refptr<InternalSource> get() const;
private:
rtc::scoped_refptr<InternalSource> source_;
};
std::shared_ptr<AudioTrackSource> new_audio_track_source();
static std::shared_ptr<MediaStreamTrack> audio_to_media(
std::shared_ptr<AudioTrack> track) {
return track;
}
static std::shared_ptr<AudioTrack> media_to_audio(
std::shared_ptr<MediaStreamTrack> track) {
return std::static_pointer_cast<AudioTrack>(track);
}
static std::shared_ptr<AudioTrack> _shared_audio_track() {
return nullptr; // Ignore
}
} // namespace livekit
+14 -15
View File
@@ -17,27 +17,31 @@
#pragma once
#include <memory>
#include <mutex>
#include "api/data_channel_interface.h"
#include "livekit/webrtc.h"
#include "rtc_base/synchronization/mutex.h"
#include "rust/cxx.h"
namespace livekit {
class DataChannel;
using NativeDataChannelInit = webrtc::DataChannelInit;
class NativeDataChannelObserver;
} // namespace livekit
#include "webrtc-sys/src/data_channel.rs.h"
namespace livekit {
class NativeDataChannelObserver;
webrtc::DataChannelInit to_native_data_channel_init(DataChannelInit init);
class DataChannel {
public:
explicit DataChannel(
std::shared_ptr<RTCRuntime> rtc_runtime,
std::shared_ptr<RtcRuntime> rtc_runtime,
rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel);
void register_observer(NativeDataChannelObserver* observer) const;
void register_observer(rust::Box<DataChannelObserverWrapper> observer) const;
void unregister_observer() const;
bool send(const DataBuffer& buffer) const;
rust::String label() const;
@@ -45,22 +49,20 @@ class DataChannel {
void close() const;
private:
std::shared_ptr<RTCRuntime> rtc_runtime_;
mutable webrtc::Mutex mutex_;
std::shared_ptr<RtcRuntime> rtc_runtime_;
rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel_;
mutable std::unique_ptr<NativeDataChannelObserver> observer_;
};
std::unique_ptr<NativeDataChannelInit> create_data_channel_init(
DataChannelInit init);
static std::shared_ptr<DataChannel> _shared_data_channel() {
return nullptr; // Ignore
}
class NativeDataChannelObserver : public webrtc::DataChannelObserver {
public:
explicit NativeDataChannelObserver(
rust::Box<DataChannelObserverWrapper> observer,
DataChannel* dc);
NativeDataChannelObserver(rust::Box<DataChannelObserverWrapper> observer,
const DataChannel* dc);
~NativeDataChannelObserver();
@@ -70,10 +72,7 @@ class NativeDataChannelObserver : public webrtc::DataChannelObserver {
private:
rust::Box<DataChannelObserverWrapper> observer_;
DataChannel* dc_;
const DataChannel* dc_;
};
std::shared_ptr<NativeDataChannelObserver> create_native_data_channel_observer(
rust::Box<DataChannelObserverWrapper> observer,
DataChannel* dc);
} // namespace livekit
+22 -40
View File
@@ -22,19 +22,19 @@
#include "api/ref_counted_base.h"
#include "api/set_local_description_observer_interface.h"
#include "api/set_remote_description_observer_interface.h"
#include "livekit/rtc_error.h"
#include "rust/cxx.h"
namespace livekit {
class IceCandidate;
class SessionDescription;
struct NativeCreateSdpObserverHandle;
struct NativeSetLocalSdpObserverHandle;
struct NativeSetRemoteSdpObserverHandle;
}; // namespace livekit
#include "webrtc-sys/src/jsep.rs.h"
namespace livekit {
class AsyncContext;
class IceCandidate {
public:
explicit IceCandidate(
@@ -82,69 +82,51 @@ static std::unique_ptr<SessionDescription> _unique_session_description() {
return nullptr; // Ignore
}
// SetCreateSdpObserver
class NativeCreateSdpObserver
: public webrtc::CreateSessionDescriptionObserver {
public:
explicit NativeCreateSdpObserver(
rust::Box<CreateSdpObserverWrapper> observer);
NativeCreateSdpObserver(
rust::Box<AsyncContext> ctx,
rust::Fn<void(rust::Box<AsyncContext> ctx,
std::unique_ptr<SessionDescription>)> on_success,
rust::Fn<void(rust::Box<AsyncContext> ctx, RtcError)> on_error);
void OnSuccess(webrtc::SessionDescriptionInterface* desc) override;
void OnFailure(webrtc::RTCError error) override;
private:
rust::Box<CreateSdpObserverWrapper> observer_;
rust::Box<AsyncContext> ctx_;
rust::Fn<void(rust::Box<AsyncContext>, std::unique_ptr<SessionDescription>)>
on_success_;
rust::Fn<void(rust::Box<AsyncContext>, RtcError)> on_error_;
};
struct NativeCreateSdpObserverHandle {
rtc::scoped_refptr<NativeCreateSdpObserver> observer;
};
std::unique_ptr<NativeCreateSdpObserverHandle>
create_native_create_sdp_observer(rust::Box<CreateSdpObserverWrapper> observer);
// SetLocalSdpObserver
class NativeSetLocalSdpObserver
: public webrtc::SetLocalDescriptionObserverInterface {
public:
explicit NativeSetLocalSdpObserver(
rust::Box<SetLocalSdpObserverWrapper> observer);
NativeSetLocalSdpObserver(
rust::Box<AsyncContext> ctx,
rust::Fn<void(rust::Box<AsyncContext>, RtcError)> on_complete);
void OnSetLocalDescriptionComplete(webrtc::RTCError error) override;
private:
rust::Box<SetLocalSdpObserverWrapper> observer_;
rust::Box<AsyncContext> ctx_;
rust::Fn<void(rust::Box<AsyncContext>, RtcError)> on_complete_;
};
struct NativeSetLocalSdpObserverHandle {
rtc::scoped_refptr<NativeSetLocalSdpObserver> observer;
};
std::unique_ptr<NativeSetLocalSdpObserverHandle>
create_native_set_local_sdp_observer(
rust::Box<SetLocalSdpObserverWrapper> observer);
// SetRemoteSdpObserver
class NativeSetRemoteSdpObserver
: public webrtc::SetRemoteDescriptionObserverInterface {
public:
explicit NativeSetRemoteSdpObserver(
rust::Box<SetRemoteSdpObserverWrapper> observer);
NativeSetRemoteSdpObserver(
rust::Box<AsyncContext> ctx,
rust::Fn<void(rust::Box<AsyncContext>, RtcError)> on_complete);
void OnSetRemoteDescriptionComplete(webrtc::RTCError error) override;
private:
rust::Box<SetRemoteSdpObserverWrapper> observer_;
rust::Box<AsyncContext> ctx_;
rust::Fn<void(rust::Box<AsyncContext>, RtcError)> on_complete_;
};
struct NativeSetRemoteSdpObserverHandle {
rtc::scoped_refptr<NativeSetRemoteSdpObserver> observer;
};
std::unique_ptr<NativeSetRemoteSdpObserverHandle>
create_native_set_remote_sdp_observer(
rust::Box<SetRemoteSdpObserverWrapper> observer);
} // namespace livekit
-46
View File
@@ -1,46 +0,0 @@
/*
* Copyright 2023 LiveKit
*
* Licensed under the Apache License, Version 2.0 (the “License”);
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an “AS IS” BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "livekit/webrtc.h"
#include "rtc_base/logging.h"
#include "rust/cxx.h"
namespace livekit {
class LogSink;
} // namespace livekit
#include "webrtc-sys/src/logsink.rs.h"
namespace livekit {
class LogSink : public rtc::LogSink {
public:
LogSink(rust::Fn<void(rust::String message, LoggingSeverity severity)> fnc);
~LogSink();
void OnLogMessage(const std::string& message, rtc::LoggingSeverity severity) override;
void OnLogMessage(const std::string& message) override {}
private:
rust::Fn<void(rust::String message, LoggingSeverity severity)> fnc_;
};
std::unique_ptr<LogSink> new_log_sink(rust::Fn<void(rust::String, LoggingSeverity)> fnc);
} // namespace livekit
+4 -212
View File
@@ -19,27 +19,12 @@
#include <memory>
#include "api/media_stream_interface.h"
#include "api/video/video_frame.h"
#include "common_audio/resampler/include/push_resampler.h"
#include "common_audio/ring_buffer.h"
#include "livekit/helper.h"
#include "livekit/video_frame.h"
#include "media/base/adapted_video_track_source.h"
#include "pc/local_audio_source.h"
#include "rtc_base/synchronization/mutex.h"
#include "rtc_base/timestamp_aligner.h"
#include "livekit/webrtc.h"
#include "rust/cxx.h"
#include "system_wrappers/include/clock.h"
namespace livekit {
class MediaStream;
class MediaStreamTrack;
class VideoTrack;
class AudioTrack;
class NativeVideoFrameSink;
class NativeAudioSink;
class AudioTrackSource;
class AdaptedVideoTrackSource;
} // namespace livekit
#include "webrtc-sys/src/media_stream.rs.h"
@@ -47,7 +32,8 @@ namespace livekit {
class MediaStream {
public:
explicit MediaStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream);
MediaStream(std::shared_ptr<RtcRuntime> rtc_runtime,
rtc::scoped_refptr<webrtc::MediaStreamInterface> stream);
rust::String id() const;
rust::Vec<VideoTrackPtr> get_video_tracks() const;
@@ -60,204 +46,10 @@ class MediaStream {
bool remove_track(std::shared_ptr<MediaStreamTrack> track) const;
private:
std::shared_ptr<RtcRuntime> rtc_runtime_;
rtc::scoped_refptr<webrtc::MediaStreamInterface> media_stream_;
};
class MediaStreamTrack {
protected:
explicit MediaStreamTrack(
rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track);
public:
static std::shared_ptr<MediaStreamTrack> from(
rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track);
rust::String kind() const;
rust::String id() const;
bool enabled() const;
bool set_enabled(bool enable) const;
TrackState state() const;
rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> get() const {
return track_;
}
protected:
rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track_;
};
class AudioTrack : public MediaStreamTrack {
public:
explicit AudioTrack(rtc::scoped_refptr<webrtc::AudioTrackInterface> track);
void add_sink(NativeAudioSink& sink) const;
void remove_sink(NativeAudioSink& sink) const;
private:
webrtc::AudioTrackInterface* track() const {
return static_cast<webrtc::AudioTrackInterface*>(track_.get());
}
};
class NativeAudioSink : public webrtc::AudioTrackSinkInterface {
public:
explicit NativeAudioSink(rust::Box<AudioSinkWrapper> observer);
void OnData(const void* audio_data,
int bits_per_sample,
int sample_rate,
size_t number_of_channels,
size_t number_of_frames) override;
private:
rust::Box<AudioSinkWrapper> observer_;
};
std::unique_ptr<NativeAudioSink> new_native_audio_sink(
rust::Box<AudioSinkWrapper> observer);
class NativeAudioTrackSource : public webrtc::LocalAudioSource {
public:
NativeAudioTrackSource();
SourceState state() const override;
bool remote() const override;
const cricket::AudioOptions options() const override;
void AddSink(webrtc::AudioTrackSinkInterface* sink) override;
void RemoveSink(webrtc::AudioTrackSinkInterface* sink) override;
// AudioFrame should always contain 10 ms worth of data (see index.md of acm)
void on_captured_frame(const int16_t* audio_data,
int sample_rate,
size_t number_of_channels,
size_t number_of_frames);
private:
webrtc::Mutex mutex_;
std::vector<webrtc::AudioTrackSinkInterface*> sinks_;
cricket::AudioOptions options_{};
};
class AudioTrackSource {
public:
AudioTrackSource(rtc::scoped_refptr<NativeAudioTrackSource> source);
void on_captured_frame(const int16_t* audio_data,
int sample_rate,
size_t number_of_channels,
size_t number_of_frames) const;
rtc::scoped_refptr<NativeAudioTrackSource> get() const;
private:
rtc::scoped_refptr<NativeAudioTrackSource> source_;
};
std::shared_ptr<AudioTrackSource> new_audio_track_source();
class VideoTrack : public MediaStreamTrack {
public:
explicit VideoTrack(rtc::scoped_refptr<webrtc::VideoTrackInterface> track);
void add_sink(NativeVideoFrameSink& sink) const;
void remove_sink(NativeVideoFrameSink& sink) const;
void set_should_receive(bool should_receive) const;
bool should_receive() const;
ContentHint content_hint() const;
void set_content_hint(ContentHint hint) const;
private:
webrtc::VideoTrackInterface* track() const {
return static_cast<webrtc::VideoTrackInterface*>(track_.get());
}
};
class NativeVideoFrameSink
: public rtc::VideoSinkInterface<webrtc::VideoFrame> {
public:
explicit NativeVideoFrameSink(rust::Box<VideoFrameSinkWrapper> observer);
void OnFrame(const webrtc::VideoFrame& frame) override;
void OnDiscardedFrame() override;
void OnConstraintsChanged(
const webrtc::VideoTrackSourceConstraints& constraints) override;
private:
rust::Box<VideoFrameSinkWrapper> observer_;
};
std::unique_ptr<NativeVideoFrameSink> new_native_video_frame_sink(
rust::Box<VideoFrameSinkWrapper> observer);
// Native impl of the WebRTC interface
class NativeVideoTrackSource : public rtc::AdaptedVideoTrackSource {
public:
NativeVideoTrackSource();
~NativeVideoTrackSource() override;
bool is_screencast() const override;
absl::optional<bool> needs_denoising() const override;
SourceState state() const override;
bool remote() const override;
bool on_captured_frame(const webrtc::VideoFrame& frame);
private:
webrtc::Mutex mutex_;
rtc::TimestampAligner timestamp_aligner_;
};
class AdaptedVideoTrackSource {
public:
AdaptedVideoTrackSource(rtc::scoped_refptr<NativeVideoTrackSource> source);
bool on_captured_frame(const std::unique_ptr<VideoFrame>& frame)
const; // frames pushed from Rust (+interior mutability)
rtc::scoped_refptr<NativeVideoTrackSource> get() const;
private:
rtc::scoped_refptr<NativeVideoTrackSource> source_;
};
std::shared_ptr<AdaptedVideoTrackSource> new_adapted_video_track_source();
static std::shared_ptr<MediaStreamTrack> video_to_media(
std::shared_ptr<VideoTrack> track) {
return track;
}
static std::shared_ptr<MediaStreamTrack> audio_to_media(
std::shared_ptr<AudioTrack> track) {
return track;
}
static std::shared_ptr<VideoTrack> media_to_video(
std::shared_ptr<MediaStreamTrack> track) {
return std::static_pointer_cast<VideoTrack>(track);
}
static std::shared_ptr<AudioTrack> media_to_audio(
std::shared_ptr<MediaStreamTrack> track) {
return std::static_pointer_cast<AudioTrack>(track);
}
static std::shared_ptr<MediaStreamTrack> _shared_media_stream_track() {
return nullptr; // Ignore
}
static std::shared_ptr<AudioTrack> _shared_audio_track() {
return nullptr; // Ignore
}
static std::shared_ptr<VideoTrack> _shared_video_track() {
return nullptr; // Ignore
}
static std::shared_ptr<MediaStream> _shared_media_stream() {
return nullptr; // Ignore
}
@@ -0,0 +1,60 @@
/*
* Copyright 2023 LiveKit
*
* Licensed under the Apache License, Version 2.0 (the “License”);
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an “AS IS” BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <memory>
#include "api/media_stream_interface.h"
#include "livekit/helper.h"
#include "livekit/webrtc.h"
#include "rust/cxx.h"
namespace livekit {
class MediaStreamTrack;
} // namespace livekit
#include "webrtc-sys/src/media_stream_track.rs.h"
namespace livekit {
class MediaStreamTrack {
protected:
MediaStreamTrack(std::shared_ptr<RtcRuntime>,
rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track);
public:
rust::String kind() const;
rust::String id() const;
bool enabled() const;
bool set_enabled(bool enable) const;
TrackState state() const;
rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> rtc_track() const {
return track_;
}
protected:
std::shared_ptr<RtcRuntime> rtc_runtime_;
rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track_;
};
static std::shared_ptr<MediaStreamTrack> _shared_media_stream_track() {
return nullptr; // Ignore
}
} // namespace livekit
+42 -38
View File
@@ -23,46 +23,62 @@
#include "livekit/helper.h"
#include "livekit/jsep.h"
#include "livekit/media_stream.h"
#include "livekit/rtc_error.h"
#include "livekit/rtp_receiver.h"
#include "livekit/rtp_sender.h"
#include "livekit/rtp_transceiver.h"
#include "livekit/webrtc.h"
#include "rust/cxx.h"
#include "webrtc-sys/src/data_channel.rs.h"
namespace livekit {
class NativeAddIceCandidateObserver;
class PeerConnection;
class NativeAddIceCandidateObserver;
class NativePeerConnectionObserver;
} // namespace livekit
#include "webrtc-sys/src/peer_connection.rs.h"
namespace livekit {
class PeerConnectionFactory;
class PeerConnection {
public:
explicit PeerConnection(
std::shared_ptr<RTCRuntime> rtc_runtime,
PeerConnection(
std::shared_ptr<RtcRuntime> rtc_runtime,
std::unique_ptr<NativePeerConnectionObserver> observer,
rtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection);
void create_offer(NativeCreateSdpObserverHandle& observer,
RTCOfferAnswerOptions options) const;
void create_offer(
RtcOfferAnswerOptions options,
rust::Box<AsyncContext> ctx,
rust::Fn<void(rust::Box<AsyncContext>,
std::unique_ptr<SessionDescription>)> on_success,
rust::Fn<void(rust::Box<AsyncContext>, RtcError)> on_error) const;
void create_answer(NativeCreateSdpObserverHandle& observer,
RTCOfferAnswerOptions options) const;
void create_answer(
RtcOfferAnswerOptions options,
rust::Box<AsyncContext> ctx,
rust::Fn<void(rust::Box<AsyncContext>,
std::unique_ptr<SessionDescription>)> on_success,
rust::Fn<void(rust::Box<AsyncContext>, RtcError)> on_error) const;
void set_local_description(std::unique_ptr<SessionDescription> desc,
NativeSetLocalSdpObserverHandle& observer) const;
void set_local_description(
std::unique_ptr<SessionDescription> desc,
rust::Box<AsyncContext> ctx,
rust::Fn<void(rust::Box<AsyncContext>, RtcError)> on_complete) const;
void set_remote_description(std::unique_ptr<SessionDescription> desc,
NativeSetRemoteSdpObserverHandle& observer) const;
void set_remote_description(
std::unique_ptr<SessionDescription> desc,
rust::Box<AsyncContext> ctx,
rust::Fn<void(rust::Box<AsyncContext>, RtcError)> on_complete) const;
std::shared_ptr<DataChannel> create_data_channel(
rust::String label,
std::unique_ptr<NativeDataChannelInit> init) const;
std::shared_ptr<DataChannel> create_data_channel(rust::String label,
DataChannelInit init) const;
void add_ice_candidate(std::shared_ptr<IceCandidate> candidate,
NativeAddIceCandidateObserver& observer) const;
void add_ice_candidate(
std::shared_ptr<IceCandidate> candidate,
rust::Box<AsyncContext> ctx,
rust::Fn<void(rust::Box<AsyncContext>, RtcError)> on_complete) const;
std::shared_ptr<RtpSender> add_track(
std::shared_ptr<MediaStreamTrack> track,
@@ -107,7 +123,8 @@ class PeerConnection {
void close() const;
private:
std::shared_ptr<RTCRuntime> rtc_runtime_;
std::shared_ptr<RtcRuntime> rtc_runtime_;
std::unique_ptr<NativePeerConnectionObserver> observer_;
rtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection_;
};
@@ -115,25 +132,9 @@ static std::shared_ptr<PeerConnection> _shared_peer_connection() {
return nullptr; // Ignore
}
class NativeAddIceCandidateObserver {
public:
explicit NativeAddIceCandidateObserver(
rust::Box<AddIceCandidateObserverWrapper> observer);
void OnComplete(const RTCError& error);
private:
rust::Box<AddIceCandidateObserverWrapper> observer_;
};
std::unique_ptr<NativeAddIceCandidateObserver>
create_native_add_ice_candidate_observer(
rust::Box<AddIceCandidateObserverWrapper> observer);
class NativePeerConnectionObserver : public webrtc::PeerConnectionObserver {
public:
explicit NativePeerConnectionObserver(
std::shared_ptr<RTCRuntime> rtc_runtime,
NativePeerConnectionObserver(
rust::Box<PeerConnectionObserverWrapper> observer);
~NativePeerConnectionObserver();
@@ -196,12 +197,15 @@ class NativePeerConnectionObserver : public webrtc::PeerConnectionObserver {
void OnInterestingUsage(int usage_pattern) override;
private:
std::shared_ptr<RTCRuntime> rtc_runtime_;
friend PeerConnectionFactory;
// The RtcRuntime is set inside PeerConnectionFactory, we can simplify that
// once create_native_connection_observer is removed
std::shared_ptr<RtcRuntime> rtc_runtime_;
rust::Box<PeerConnectionObserverWrapper> observer_;
};
std::shared_ptr<NativePeerConnectionObserver>
std::unique_ptr<NativePeerConnectionObserver>
create_native_peer_connection_observer(
std::shared_ptr<RTCRuntime> rtc_runtime,
rust::Box<PeerConnectionObserverWrapper> observer);
} // namespace livekit
@@ -21,30 +21,31 @@
#include "peer_connection.h"
#include "rtp_parameters.h"
#include "rust/cxx.h"
#include "webrtc-sys/src/peer_connection.rs.h"
#include "webrtc.h"
namespace livekit {
using NativeRTCConfiguration =
webrtc::PeerConnectionInterface::RTCConfiguration;
class PeerConnectionFactory;
} // namespace livekit
#include "webrtc-sys/src/peer_connection_factory.rs.h"
namespace livekit {
webrtc::PeerConnectionInterface::RTCConfiguration to_native_rtc_configuration(
RtcConfiguration config);
class PeerConnectionFactory {
public:
explicit PeerConnectionFactory(std::shared_ptr<RTCRuntime> rtc_runtime);
explicit PeerConnectionFactory(std::shared_ptr<RtcRuntime> rtc_runtime);
~PeerConnectionFactory();
std::shared_ptr<PeerConnection> create_peer_connection(
std::unique_ptr<NativeRTCConfiguration> config,
NativePeerConnectionObserver* observer) const;
RtcConfiguration config,
std::unique_ptr<NativePeerConnectionObserver> observer) const;
std::shared_ptr<VideoTrack> create_video_track(
rust::String label,
std::shared_ptr<AdaptedVideoTrackSource> source) const;
std::shared_ptr<VideoTrackSource> source) const;
std::shared_ptr<AudioTrack> create_audio_track(
rust::String label,
@@ -55,12 +56,9 @@ class PeerConnectionFactory {
RtpCapabilities get_rtp_receiver_capabilities(MediaType type) const;
private:
std::shared_ptr<RTCRuntime> rtc_runtime_;
std::shared_ptr<RtcRuntime> rtc_runtime_;
rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> peer_factory_;
};
std::shared_ptr<PeerConnectionFactory> create_peer_connection_factory(
std::shared_ptr<RTCRuntime> rtc_runtime);
std::unique_ptr<NativeRTCConfiguration> create_rtc_configuration(
RTCConfiguration conf);
std::shared_ptr<PeerConnectionFactory> create_peer_connection_factory();
} // namespace livekit
+2 -2
View File
@@ -22,9 +22,9 @@
namespace livekit {
RTCError to_error(const webrtc::RTCError& error);
RtcError to_error(const webrtc::RTCError& error);
std::string serialize_error(
const RTCError& error); // to be used inside cxx::Exception msg
const RtcError& error); // to be used inside cxx::Exception msg
#ifdef LIVEKIT_TEST
rust::String serialize_deserialize();
+8 -2
View File
@@ -22,6 +22,7 @@
#include "livekit/helper.h"
#include "livekit/media_stream.h"
#include "livekit/rtp_parameters.h"
#include "livekit/webrtc.h"
#include "rust/cxx.h"
namespace livekit {
@@ -35,8 +36,8 @@ namespace livekit {
// TODO(theomonnom): FrameTransformer & FrameDecryptor interface
class RtpReceiver {
public:
explicit RtpReceiver(
rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver);
RtpReceiver(std::shared_ptr<RtcRuntime> rtc_runtime,
rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver);
std::shared_ptr<MediaStreamTrack> track() const;
@@ -53,7 +54,12 @@ class RtpReceiver {
void set_jitter_buffer_minimum_delay(bool is_some,
double delay_seconds) const;
rtc::scoped_refptr<webrtc::RtpReceiverInterface> rtc_receiver() const {
return receiver_;
}
private:
std::shared_ptr<RtcRuntime> rtc_runtime_;
rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver_;
};
+6 -2
View File
@@ -34,7 +34,8 @@ namespace livekit {
// TODO(theomonnom): FrameTransformer & FrameEncryptor interface
class RtpSender {
public:
explicit RtpSender(rtc::scoped_refptr<webrtc::RtpSenderInterface> sender);
RtpSender(std::shared_ptr<RtcRuntime> rtc_runtime,
rtc::scoped_refptr<webrtc::RtpSenderInterface> sender);
bool set_track(std::shared_ptr<MediaStreamTrack> track) const;
@@ -56,9 +57,12 @@ class RtpSender {
void set_parameters(RtpParameters params) const;
rtc::scoped_refptr<webrtc::RtpSenderInterface> get() const { return sender_; }
rtc::scoped_refptr<webrtc::RtpSenderInterface> rtc_sender() const {
return sender_;
}
private:
std::shared_ptr<RtcRuntime> rtc_runtime_;
rtc::scoped_refptr<webrtc::RtpSenderInterface> sender_;
};
+3 -1
View File
@@ -39,7 +39,8 @@ webrtc::RtpTransceiverInit to_native_rtp_transceiver_init(
class RtpTransceiver {
public:
explicit RtpTransceiver(
RtpTransceiver(
std::shared_ptr<RtcRuntime> rtc_runtime,
rtc::scoped_refptr<webrtc::RtpTransceiverInterface> transceiver);
MediaType media_type() const;
@@ -76,6 +77,7 @@ class RtpTransceiver {
rust::Vec<RtpHeaderExtensionCapability> header_extensions_to_offer) const;
private:
std::shared_ptr<RtcRuntime> rtc_runtime_;
rtc::scoped_refptr<webrtc::RtpTransceiverInterface> transceiver_;
};
+133
View File
@@ -0,0 +1,133 @@
/*
* Copyright 2023 LiveKit
*
* Licensed under the Apache License, Version 2.0 (the “License”);
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an “AS IS” BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <memory>
#include "api/media_stream_interface.h"
#include "api/video/video_frame.h"
#include "livekit/helper.h"
#include "livekit/media_stream_track.h"
#include "livekit/video_frame.h"
#include "livekit/webrtc.h"
#include "media/base/adapted_video_track_source.h"
#include "rtc_base/synchronization/mutex.h"
#include "rtc_base/timestamp_aligner.h"
#include "rust/cxx.h"
namespace livekit {
class VideoTrack;
class NativeVideoSink;
class VideoTrackSource;
} // namespace livekit
#include "webrtc-sys/src/video_track.rs.h"
namespace livekit {
class VideoTrack : public MediaStreamTrack {
private:
friend RtcRuntime;
VideoTrack(std::shared_ptr<RtcRuntime> rtc_runtime,
rtc::scoped_refptr<webrtc::VideoTrackInterface> track);
public:
~VideoTrack();
void add_sink(const std::shared_ptr<NativeVideoSink>& sink) const;
void remove_sink(const std::shared_ptr<NativeVideoSink>& sink) const;
void set_should_receive(bool should_receive) const;
bool should_receive() const;
ContentHint content_hint() const;
void set_content_hint(ContentHint hint) const;
private:
webrtc::VideoTrackInterface* track() const {
return static_cast<webrtc::VideoTrackInterface*>(track_.get());
}
mutable webrtc::Mutex mutex_;
// Same for AudioTrack:
// Keep a strong reference to the added sinks, so we don't need to
// manage the lifetime safety on the Rust side
mutable std::vector<std::shared_ptr<NativeVideoSink>> sinks_;
};
class NativeVideoSink : public rtc::VideoSinkInterface<webrtc::VideoFrame> {
public:
explicit NativeVideoSink(rust::Box<VideoSinkWrapper> observer);
void OnFrame(const webrtc::VideoFrame& frame) override;
void OnDiscardedFrame() override;
void OnConstraintsChanged(
const webrtc::VideoTrackSourceConstraints& constraints) override;
private:
rust::Box<VideoSinkWrapper> observer_;
};
std::shared_ptr<NativeVideoSink> new_native_video_sink(
rust::Box<VideoSinkWrapper> observer);
class VideoTrackSource {
class InternalSource : public rtc::AdaptedVideoTrackSource {
public:
InternalSource();
~InternalSource() override;
bool is_screencast() const override;
absl::optional<bool> needs_denoising() const override;
SourceState state() const override;
bool remote() const override;
bool on_captured_frame(const webrtc::VideoFrame& frame);
private:
webrtc::Mutex mutex_;
rtc::TimestampAligner timestamp_aligner_;
};
public:
VideoTrackSource();
bool on_captured_frame(const std::unique_ptr<VideoFrame>& frame)
const; // frames pushed from Rust (+interior mutability)
rtc::scoped_refptr<InternalSource> get() const;
private:
rtc::scoped_refptr<InternalSource> source_;
};
std::shared_ptr<VideoTrackSource> new_video_track_source();
static std::shared_ptr<MediaStreamTrack> video_to_media(
std::shared_ptr<VideoTrack> track) {
return track;
}
static std::shared_ptr<VideoTrack> media_to_video(
std::shared_ptr<MediaStreamTrack> track) {
return std::static_pointer_cast<VideoTrack>(track);
}
static std::shared_ptr<VideoTrack> _shared_video_track() {
return nullptr; // Ignore
}
} // namespace livekit
+62 -10
View File
@@ -16,6 +16,13 @@
#pragma once
#include <memory>
#include "api/media_stream_interface.h"
#include "api/rtp_receiver_interface.h"
#include "api/rtp_sender_interface.h"
#include "livekit/helper.h"
#include "rtc_base/logging.h"
#include "rtc_base/physical_socket_server.h"
#include "rtc_base/ssl_adapter.h"
#include "rust/cxx.h"
@@ -25,29 +32,60 @@
#endif
namespace livekit {
class RTCRuntime;
}
class RtcRuntime;
class LogSink;
} // namespace livekit
#include "webrtc-sys/src/webrtc.rs.h"
namespace livekit {
class RTCRuntime {
public:
RTCRuntime();
~RTCRuntime();
class MediaStreamTrack;
class RtpReceiver;
class RtpSender;
RTCRuntime(const RTCRuntime&) = delete;
RTCRuntime& operator=(const RTCRuntime&) = delete;
// Using a shared_ptr in RtcRuntime allows us to keep a strong reference to it
// on resources that depend on it. (e.g: AudioTrack, VideoTrack).
class RtcRuntime : public std::enable_shared_from_this<RtcRuntime> {
public:
[[nodiscard]] static std::shared_ptr<RtcRuntime> create() {
return std::shared_ptr<RtcRuntime>(new RtcRuntime());
}
RtcRuntime(const RtcRuntime&) = delete;
RtcRuntime& operator=(const RtcRuntime&) = delete;
~RtcRuntime();
rtc::Thread* network_thread() const;
rtc::Thread* worker_thread() const;
rtc::Thread* signaling_thread() const;
std::shared_ptr<MediaStreamTrack> get_or_create_media_stream_track(
rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track);
std::shared_ptr<AudioTrack> get_or_create_audio_track(
rtc::scoped_refptr<webrtc::AudioTrackInterface> track);
std::shared_ptr<VideoTrack> get_or_create_video_track(
rtc::scoped_refptr<webrtc::VideoTrackInterface> track);
private:
RtcRuntime();
std::unique_ptr<rtc::Thread> network_thread_;
std::unique_ptr<rtc::Thread> worker_thread_;
std::unique_ptr<rtc::Thread> signaling_thread_;
// Lists used to make sure we don't create multiple wrappers for one
// underlying webrtc object. (e.g: webrtc::VideoTrackInterface should only
// have one livekit::VideoTrack associated with it).
// The only reason we to do that is to allow to add states inside our
// wrappers (e.g: the sinks_ member inside AudioTrack)
webrtc::Mutex mutex_;
std::vector<std::weak_ptr<MediaStreamTrack>> media_stream_tracks_;
// We don't have additonal state in RtpReceiver and RtpSender atm..
// std::vector<std::weak_ptr<RtpReceiver>> rtp_receivers_;
// std::vector<std::weak_ptr<RtpSender>> rtp_senders_;
#ifdef WEBRTC_WIN
rtc::WinsockInitializer winsock_;
rtc::PhysicalSocketServer ss_;
@@ -55,8 +93,22 @@ class RTCRuntime {
#endif
};
class LogSink : public rtc::LogSink {
public:
LogSink(rust::Fn<void(rust::String message, LoggingSeverity severity)> fnc);
~LogSink();
void OnLogMessage(const std::string& message,
rtc::LoggingSeverity severity) override;
void OnLogMessage(const std::string& message) override {}
private:
rust::Fn<void(rust::String message, LoggingSeverity severity)> fnc_;
};
std::unique_ptr<LogSink> new_log_sink(
rust::Fn<void(rust::String, LoggingSeverity)> fnc);
rust::String create_random_uuid();
std::shared_ptr<RTCRuntime> create_rtc_runtime();
} // namespace livekit