From 8fbd62fc48c8b2fcac0279fb2d91991e3dd1d96f Mon Sep 17 00:00:00 2001 From: cloudwebrtc Date: Thu, 28 Aug 2025 10:21:25 +0800 Subject: [PATCH 01/52] chore: Upgrade libwebrtc to m137. --- webrtc-sys/build.rs | 1 + webrtc-sys/include/livekit/apm.h | 2 +- webrtc-sys/include/livekit/audio_device.h | 2 +- webrtc-sys/include/livekit/audio_track.h | 6 +-- webrtc-sys/include/livekit/data_channel.h | 4 +- webrtc-sys/include/livekit/frame_cryptor.h | 22 +++++----- webrtc-sys/include/livekit/jsep.h | 2 +- webrtc-sys/include/livekit/media_stream.h | 4 +- .../include/livekit/media_stream_track.h | 6 +-- webrtc-sys/include/livekit/peer_connection.h | 20 +++++----- .../include/livekit/peer_connection_factory.h | 4 +- webrtc-sys/include/livekit/rtp_receiver.h | 10 ++--- webrtc-sys/include/livekit/rtp_sender.h | 10 ++--- webrtc-sys/include/livekit/rtp_transceiver.h | 8 ++-- .../include/livekit/video_encoder_factory.h | 4 +- .../include/livekit/video_frame_buffer.h | 28 ++++++------- webrtc-sys/include/livekit/video_track.h | 14 +++---- webrtc-sys/include/livekit/webrtc.h | 30 +++++++------- webrtc-sys/libwebrtc/.gclient | 2 +- webrtc-sys/libwebrtc/build_android.sh | 2 +- webrtc-sys/libwebrtc/build_ios.sh | 2 +- webrtc-sys/libwebrtc/build_linux.sh | 2 +- webrtc-sys/libwebrtc/build_macos.sh | 6 ++- webrtc-sys/libwebrtc/build_windows.cmd | 2 +- webrtc-sys/src/apm.cpp | 6 ++- webrtc-sys/src/audio_device.cpp | 2 +- webrtc-sys/src/audio_resampler.cpp | 7 +++- webrtc-sys/src/audio_track.cpp | 12 +++--- webrtc-sys/src/data_channel.cpp | 6 +-- webrtc-sys/src/media_stream.cpp | 10 ++--- webrtc-sys/src/media_stream_track.cpp | 2 +- webrtc-sys/src/nvidia/h264_decoder_impl.cpp | 8 ++-- webrtc-sys/src/nvidia/h264_decoder_impl.h | 4 +- webrtc-sys/src/nvidia/h264_encoder_impl.cpp | 4 +- webrtc-sys/src/objc_video_frame_buffer.mm | 2 +- webrtc-sys/src/peer_connection.cpp | 36 ++++++++--------- webrtc-sys/src/peer_connection_factory.cpp | 12 ++++-- webrtc-sys/src/rtp_parameters.cpp | 4 +- webrtc-sys/src/rtp_receiver.cpp | 6 +-- webrtc-sys/src/rtp_sender.cpp | 6 +-- webrtc-sys/src/rtp_transceiver.cpp | 4 +- webrtc-sys/src/vaapi/h264_encoder_impl.cpp | 4 +- webrtc-sys/src/video_encoder_factory.cpp | 4 +- webrtc-sys/src/video_frame.cpp | 2 +- webrtc-sys/src/video_frame_buffer.cpp | 40 +++++++++---------- webrtc-sys/src/video_track.cpp | 18 ++++----- webrtc-sys/src/webrtc.cpp | 36 ++++++++--------- 47 files changed, 223 insertions(+), 205 deletions(-) diff --git a/webrtc-sys/build.rs b/webrtc-sys/build.rs index d95f519d0..691c966e8 100644 --- a/webrtc-sys/build.rs +++ b/webrtc-sys/build.rs @@ -204,6 +204,7 @@ fn main() { println!("cargo:rustc-link-lib=framework=QuartzCore"); println!("cargo:rustc-link-lib=framework=IOKit"); println!("cargo:rustc-link-lib=framework=IOSurface"); + println!("cargo:rustc-link-lib=framework=ScreenCaptureKit"); configure_darwin_sysroot(&mut builder); diff --git a/webrtc-sys/include/livekit/apm.h b/webrtc-sys/include/livekit/apm.h index 5f0e17eca..57cd6ea5c 100644 --- a/webrtc-sys/include/livekit/apm.h +++ b/webrtc-sys/include/livekit/apm.h @@ -63,7 +63,7 @@ class AudioProcessingModule { int set_stream_delay_ms(int delay_ms); private: - rtc::scoped_refptr apm_; + webrtc::scoped_refptr apm_; }; std::unique_ptr create_apm( diff --git a/webrtc-sys/include/livekit/audio_device.h b/webrtc-sys/include/livekit/audio_device.h index 74d76823a..d0ae2ded1 100644 --- a/webrtc-sys/include/livekit/audio_device.h +++ b/webrtc-sys/include/livekit/audio_device.h @@ -114,7 +114,7 @@ class AudioDevice : public webrtc::AudioDeviceModule { int GetRecordAudioParameters(webrtc::AudioParameters* params) const override; #endif // WEBRTC_IOS - int32_t SetAudioDeviceSink(webrtc::AudioDeviceSink* sink) const override; + int32_t SetObserver(webrtc::AudioDeviceObserver* sink) override; private: mutable webrtc::Mutex mutex_; diff --git a/webrtc-sys/include/livekit/audio_track.h b/webrtc-sys/include/livekit/audio_track.h index c780b7797..349bb7cea 100644 --- a/webrtc-sys/include/livekit/audio_track.h +++ b/webrtc-sys/include/livekit/audio_track.h @@ -48,7 +48,7 @@ class AudioTrack : public MediaStreamTrack { private: friend RtcRuntime; AudioTrack(std::shared_ptr rtc_runtime, - rtc::scoped_refptr track); + webrtc::scoped_refptr track); public: ~AudioTrack(); @@ -167,10 +167,10 @@ class AudioTrackSource { void clear_buffer() const; - rtc::scoped_refptr get() const; + webrtc::scoped_refptr get() const; private: - rtc::scoped_refptr source_; + webrtc::scoped_refptr source_; }; std::shared_ptr new_audio_track_source( diff --git a/webrtc-sys/include/livekit/data_channel.h b/webrtc-sys/include/livekit/data_channel.h index 33fea51b4..e511dc7e8 100644 --- a/webrtc-sys/include/livekit/data_channel.h +++ b/webrtc-sys/include/livekit/data_channel.h @@ -39,7 +39,7 @@ class DataChannel { public: explicit DataChannel( std::shared_ptr rtc_runtime, - rtc::scoped_refptr data_channel); + webrtc::scoped_refptr data_channel); ~DataChannel(); void register_observer(rust::Box observer) const; @@ -54,7 +54,7 @@ class DataChannel { private: mutable webrtc::Mutex mutex_; std::shared_ptr rtc_runtime_; - rtc::scoped_refptr data_channel_; + webrtc::scoped_refptr data_channel_; mutable std::unique_ptr observer_; }; diff --git a/webrtc-sys/include/livekit/frame_cryptor.h b/webrtc-sys/include/livekit/frame_cryptor.h index 43102d3cf..f7ba3584b 100644 --- a/webrtc-sys/include/livekit/frame_cryptor.h +++ b/webrtc-sys/include/livekit/frame_cryptor.h @@ -116,10 +116,10 @@ class KeyProvider { impl_->SetSifTrailer(trailer_vec); } - rtc::scoped_refptr rtc_key_provider() { return impl_; } + webrtc::scoped_refptr rtc_key_provider() { return impl_; } private: - rtc::scoped_refptr impl_; + webrtc::scoped_refptr impl_; }; class FrameCryptor { @@ -127,14 +127,14 @@ class FrameCryptor { FrameCryptor(std::shared_ptr rtc_runtime, const std::string participant_id, webrtc::FrameCryptorTransformer::Algorithm algorithm, - rtc::scoped_refptr key_provider, - rtc::scoped_refptr sender); + webrtc::scoped_refptr key_provider, + webrtc::scoped_refptr sender); FrameCryptor(std::shared_ptr rtc_runtime, const std::string participant_id, webrtc::FrameCryptorTransformer::Algorithm algorithm, - rtc::scoped_refptr key_provider, - rtc::scoped_refptr receiver); + webrtc::scoped_refptr key_provider, + webrtc::scoped_refptr receiver); ~FrameCryptor(); /// Enable/Disable frame crypto for the sender or receiver. @@ -161,11 +161,11 @@ class FrameCryptor { std::shared_ptr rtc_runtime_; const rust::String participant_id_; mutable webrtc::Mutex mutex_; - rtc::scoped_refptr e2ee_transformer_; - rtc::scoped_refptr key_provider_; - rtc::scoped_refptr sender_; - rtc::scoped_refptr receiver_; - mutable rtc::scoped_refptr observer_; + webrtc::scoped_refptr e2ee_transformer_; + webrtc::scoped_refptr key_provider_; + webrtc::scoped_refptr sender_; + webrtc::scoped_refptr receiver_; + mutable webrtc::scoped_refptr observer_; }; class NativeFrameCryptorObserver diff --git a/webrtc-sys/include/livekit/jsep.h b/webrtc-sys/include/livekit/jsep.h index 6f100f43e..62ec36669 100644 --- a/webrtc-sys/include/livekit/jsep.h +++ b/webrtc-sys/include/livekit/jsep.h @@ -139,7 +139,7 @@ class NativeRtcStatsCollector : public webrtc::RTCStatsCollectorCallback { : ctx_(std::move(ctx)), on_stats_(on_stats) {} void OnStatsDelivered( - const rtc::scoped_refptr& report) override { + const webrtc::scoped_refptr& report) override { on_stats_(std::move(ctx_), report->ToJson()); } diff --git a/webrtc-sys/include/livekit/media_stream.h b/webrtc-sys/include/livekit/media_stream.h index fe64dbe6a..fcfd09762 100644 --- a/webrtc-sys/include/livekit/media_stream.h +++ b/webrtc-sys/include/livekit/media_stream.h @@ -33,7 +33,7 @@ namespace livekit { class MediaStream { public: MediaStream(std::shared_ptr rtc_runtime, - rtc::scoped_refptr stream); + webrtc::scoped_refptr stream); rust::String id() const; rust::Vec get_video_tracks() const; @@ -47,7 +47,7 @@ class MediaStream { private: std::shared_ptr rtc_runtime_; - rtc::scoped_refptr media_stream_; + webrtc::scoped_refptr media_stream_; }; static std::shared_ptr _shared_media_stream() { diff --git a/webrtc-sys/include/livekit/media_stream_track.h b/webrtc-sys/include/livekit/media_stream_track.h index 6be69047a..1b86c6165 100644 --- a/webrtc-sys/include/livekit/media_stream_track.h +++ b/webrtc-sys/include/livekit/media_stream_track.h @@ -33,7 +33,7 @@ namespace livekit { class MediaStreamTrack { protected: MediaStreamTrack(std::shared_ptr, - rtc::scoped_refptr track); + webrtc::scoped_refptr track); public: rust::String kind() const; @@ -44,13 +44,13 @@ class MediaStreamTrack { TrackState state() const; - rtc::scoped_refptr rtc_track() const { + webrtc::scoped_refptr rtc_track() const { return track_; } protected: std::shared_ptr rtc_runtime_; - rtc::scoped_refptr track_; + webrtc::scoped_refptr track_; }; static std::shared_ptr _shared_media_stream_track() { diff --git a/webrtc-sys/include/livekit/peer_connection.h b/webrtc-sys/include/livekit/peer_connection.h index 32496ca00..6e7587b50 100644 --- a/webrtc-sys/include/livekit/peer_connection.h +++ b/webrtc-sys/include/livekit/peer_connection.h @@ -48,7 +48,7 @@ class PeerConnection : webrtc::PeerConnectionObserver { public: PeerConnection( std::shared_ptr rtc_runtime, - rtc::scoped_refptr pc_factory, + webrtc::scoped_refptr pc_factory, rust::Box observer); ~PeerConnection(); @@ -141,13 +141,13 @@ class PeerConnection : webrtc::PeerConnectionObserver { webrtc::PeerConnectionInterface::SignalingState new_state) override; void OnAddStream( - rtc::scoped_refptr stream) override; + webrtc::scoped_refptr stream) override; void OnRemoveStream( - rtc::scoped_refptr stream) override; + webrtc::scoped_refptr stream) override; void OnDataChannel( - rtc::scoped_refptr data_channel) override; + webrtc::scoped_refptr data_channel) override; void OnRenegotiationNeeded() override; @@ -182,23 +182,23 @@ class PeerConnection : webrtc::PeerConnectionObserver { const cricket::CandidatePairChangeEvent& event) override; void OnAddTrack( - rtc::scoped_refptr receiver, - const std::vector>& + webrtc::scoped_refptr receiver, + const std::vector>& streams) override; void OnTrack( - rtc::scoped_refptr transceiver) override; + webrtc::scoped_refptr transceiver) override; void OnRemoveTrack( - rtc::scoped_refptr receiver) override; + webrtc::scoped_refptr receiver) override; void OnInterestingUsage(int usage_pattern) override; private: std::shared_ptr rtc_runtime_; - rtc::scoped_refptr pc_factory_; + webrtc::scoped_refptr pc_factory_; rust::Box observer_; - rtc::scoped_refptr peer_connection_; + webrtc::scoped_refptr peer_connection_; }; static std::shared_ptr _shared_peer_connection() { diff --git a/webrtc-sys/include/livekit/peer_connection_factory.h b/webrtc-sys/include/livekit/peer_connection_factory.h index ae49842ba..2a4bf8539 100644 --- a/webrtc-sys/include/livekit/peer_connection_factory.h +++ b/webrtc-sys/include/livekit/peer_connection_factory.h @@ -64,8 +64,8 @@ class PeerConnectionFactory { private: std::shared_ptr rtc_runtime_; - rtc::scoped_refptr audio_device_; - rtc::scoped_refptr peer_factory_; + webrtc::scoped_refptr audio_device_; + webrtc::scoped_refptr peer_factory_; webrtc::TaskQueueFactory* task_queue_factory_; }; diff --git a/webrtc-sys/include/livekit/rtp_receiver.h b/webrtc-sys/include/livekit/rtp_receiver.h index 1bec92b8f..25181680d 100644 --- a/webrtc-sys/include/livekit/rtp_receiver.h +++ b/webrtc-sys/include/livekit/rtp_receiver.h @@ -40,8 +40,8 @@ class RtpReceiver { public: RtpReceiver( std::shared_ptr rtc_runtime, - rtc::scoped_refptr receiver, - rtc::scoped_refptr peer_connection); + webrtc::scoped_refptr receiver, + webrtc::scoped_refptr peer_connection); std::shared_ptr track() const; @@ -62,14 +62,14 @@ class RtpReceiver { void set_jitter_buffer_minimum_delay(bool is_some, double delay_seconds) const; - rtc::scoped_refptr rtc_receiver() const { + webrtc::scoped_refptr rtc_receiver() const { return receiver_; } private: std::shared_ptr rtc_runtime_; - rtc::scoped_refptr receiver_; - rtc::scoped_refptr peer_connection_; + webrtc::scoped_refptr receiver_; + webrtc::scoped_refptr peer_connection_; }; static std::shared_ptr _shared_rtp_receiver() { diff --git a/webrtc-sys/include/livekit/rtp_sender.h b/webrtc-sys/include/livekit/rtp_sender.h index b9ff44e29..80363942b 100644 --- a/webrtc-sys/include/livekit/rtp_sender.h +++ b/webrtc-sys/include/livekit/rtp_sender.h @@ -38,8 +38,8 @@ class RtpSender { public: RtpSender( std::shared_ptr rtc_runtime, - rtc::scoped_refptr sender, - rtc::scoped_refptr peer_connection); + webrtc::scoped_refptr sender, + webrtc::scoped_refptr peer_connection); bool set_track(std::shared_ptr track) const; @@ -65,14 +65,14 @@ class RtpSender { void set_parameters(RtpParameters params) const; - rtc::scoped_refptr rtc_sender() const { + webrtc::scoped_refptr rtc_sender() const { return sender_; } private: std::shared_ptr rtc_runtime_; - rtc::scoped_refptr sender_; - rtc::scoped_refptr peer_connection_; + webrtc::scoped_refptr sender_; + webrtc::scoped_refptr peer_connection_; }; static std::shared_ptr _shared_rtp_sender() { diff --git a/webrtc-sys/include/livekit/rtp_transceiver.h b/webrtc-sys/include/livekit/rtp_transceiver.h index 0eba06fb2..99a994ccc 100644 --- a/webrtc-sys/include/livekit/rtp_transceiver.h +++ b/webrtc-sys/include/livekit/rtp_transceiver.h @@ -43,8 +43,8 @@ class RtpTransceiver { public: RtpTransceiver( std::shared_ptr rtc_runtime, - rtc::scoped_refptr transceiver, - rtc::scoped_refptr peer_connection); + webrtc::scoped_refptr transceiver, + webrtc::scoped_refptr peer_connection); MediaType media_type() const; @@ -82,8 +82,8 @@ class RtpTransceiver { private: std::shared_ptr rtc_runtime_; - rtc::scoped_refptr transceiver_; - rtc::scoped_refptr peer_connection_; + webrtc::scoped_refptr transceiver_; + webrtc::scoped_refptr peer_connection_; }; static std::shared_ptr _shared_rtp_transceiver() { diff --git a/webrtc-sys/include/livekit/video_encoder_factory.h b/webrtc-sys/include/livekit/video_encoder_factory.h index f1e8bc84a..902049e3a 100644 --- a/webrtc-sys/include/livekit/video_encoder_factory.h +++ b/webrtc-sys/include/livekit/video_encoder_factory.h @@ -29,7 +29,7 @@ class VideoEncoderFactory : public webrtc::VideoEncoderFactory { CodecSupport QueryCodecSupport( const webrtc::SdpVideoFormat& format, - absl::optional scalability_mode) const override; + std::optional scalability_mode) const override; std::unique_ptr Create( const webrtc::Environment& env, const webrtc::SdpVideoFormat& format) override; @@ -45,7 +45,7 @@ class VideoEncoderFactory : public webrtc::VideoEncoderFactory { CodecSupport QueryCodecSupport( const webrtc::SdpVideoFormat& format, - absl::optional scalability_mode) const override; + std::optional scalability_mode) const override; std::unique_ptr Create( const webrtc::Environment& env, const webrtc::SdpVideoFormat& format) override; diff --git a/webrtc-sys/include/livekit/video_frame_buffer.h b/webrtc-sys/include/livekit/video_frame_buffer.h index a7e25fdf5..0a612b324 100644 --- a/webrtc-sys/include/livekit/video_frame_buffer.h +++ b/webrtc-sys/include/livekit/video_frame_buffer.h @@ -58,7 +58,7 @@ namespace livekit { class VideoFrameBuffer { public: explicit VideoFrameBuffer( - rtc::scoped_refptr buffer); + webrtc::scoped_refptr buffer); VideoFrameBufferType buffer_type() const; @@ -74,15 +74,15 @@ class VideoFrameBuffer { std::unique_ptr get_i444(); std::unique_ptr get_i010(); std::unique_ptr get_nv12(); - rtc::scoped_refptr get() const; + webrtc::scoped_refptr get() const; protected: - rtc::scoped_refptr buffer_; + webrtc::scoped_refptr buffer_; }; class PlanarYuvBuffer : public VideoFrameBuffer { public: - explicit PlanarYuvBuffer(rtc::scoped_refptr buffer); + explicit PlanarYuvBuffer(webrtc::scoped_refptr buffer); unsigned int chroma_width() const; unsigned int chroma_height() const; @@ -98,7 +98,7 @@ class PlanarYuvBuffer : public VideoFrameBuffer { class PlanarYuv8Buffer : public PlanarYuvBuffer { public: explicit PlanarYuv8Buffer( - rtc::scoped_refptr buffer); + webrtc::scoped_refptr buffer); const uint8_t* data_y() const; const uint8_t* data_u() const; @@ -111,7 +111,7 @@ class PlanarYuv8Buffer : public PlanarYuvBuffer { class PlanarYuv16BBuffer : public PlanarYuvBuffer { public: explicit PlanarYuv16BBuffer( - rtc::scoped_refptr buffer); + webrtc::scoped_refptr buffer); const uint16_t* data_y() const; const uint16_t* data_u() const; @@ -124,7 +124,7 @@ class PlanarYuv16BBuffer : public PlanarYuvBuffer { class BiplanarYuvBuffer : public VideoFrameBuffer { public: explicit BiplanarYuvBuffer( - rtc::scoped_refptr buffer); + webrtc::scoped_refptr buffer); unsigned int chroma_width() const; unsigned int chroma_height() const; @@ -139,7 +139,7 @@ class BiplanarYuvBuffer : public VideoFrameBuffer { class BiplanarYuv8Buffer : public BiplanarYuvBuffer { public: explicit BiplanarYuv8Buffer( - rtc::scoped_refptr buffer); + webrtc::scoped_refptr buffer); const uint8_t* data_y() const; const uint8_t* data_uv() const; @@ -150,12 +150,12 @@ class BiplanarYuv8Buffer : public BiplanarYuvBuffer { class I420Buffer : public PlanarYuv8Buffer { public: - explicit I420Buffer(rtc::scoped_refptr buffer); + explicit I420Buffer(webrtc::scoped_refptr buffer); }; class I420ABuffer : public I420Buffer { public: - explicit I420ABuffer(rtc::scoped_refptr buffer); + explicit I420ABuffer(webrtc::scoped_refptr buffer); unsigned int stride_a() const; const uint8_t* data_a() const; @@ -166,22 +166,22 @@ class I420ABuffer : public I420Buffer { class I422Buffer : public PlanarYuv8Buffer { public: - explicit I422Buffer(rtc::scoped_refptr buffer); + explicit I422Buffer(webrtc::scoped_refptr buffer); }; class I444Buffer : public PlanarYuv8Buffer { public: - explicit I444Buffer(rtc::scoped_refptr buffer); + explicit I444Buffer(webrtc::scoped_refptr buffer); }; class I010Buffer : public PlanarYuv16BBuffer { public: - explicit I010Buffer(rtc::scoped_refptr buffer); + explicit I010Buffer(webrtc::scoped_refptr buffer); }; class NV12Buffer : public BiplanarYuv8Buffer { public: - explicit NV12Buffer(rtc::scoped_refptr buffer); + explicit NV12Buffer(webrtc::scoped_refptr buffer); }; std::unique_ptr copy_i420_buffer( diff --git a/webrtc-sys/include/livekit/video_track.h b/webrtc-sys/include/livekit/video_track.h index f60c3dd91..ac74b79c9 100644 --- a/webrtc-sys/include/livekit/video_track.h +++ b/webrtc-sys/include/livekit/video_track.h @@ -42,7 +42,7 @@ class VideoTrack : public MediaStreamTrack { private: friend RtcRuntime; VideoTrack(std::shared_ptr rtc_runtime, - rtc::scoped_refptr track); + webrtc::scoped_refptr track); public: ~VideoTrack(); @@ -68,7 +68,7 @@ class VideoTrack : public MediaStreamTrack { mutable std::vector> sinks_; }; -class NativeVideoSink : public rtc::VideoSinkInterface { +class NativeVideoSink : public webrtc::VideoSinkInterface { public: explicit NativeVideoSink(rust::Box observer); @@ -85,7 +85,7 @@ std::shared_ptr new_native_video_sink( rust::Box observer); class VideoTrackSource { - class InternalSource : public rtc::AdaptedVideoTrackSource { + class InternalSource : public webrtc::AdaptedVideoTrackSource { public: InternalSource(const VideoResolution& resolution); // (0, 0) means no resolution/optional, the @@ -94,7 +94,7 @@ class VideoTrackSource { ~InternalSource() override; bool is_screencast() const override; - absl::optional needs_denoising() const override; + std::optional needs_denoising() const override; SourceState state() const override; bool remote() const override; VideoResolution video_resolution() const; @@ -102,7 +102,7 @@ class VideoTrackSource { private: mutable webrtc::Mutex mutex_; - rtc::TimestampAligner timestamp_aligner_; + webrtc::TimestampAligner timestamp_aligner_; VideoResolution resolution_; }; @@ -114,10 +114,10 @@ class VideoTrackSource { bool on_captured_frame(const std::unique_ptr& frame) const; // frames pushed from Rust (+interior mutability) - rtc::scoped_refptr get() const; + webrtc::scoped_refptr get() const; private: - rtc::scoped_refptr source_; + webrtc::scoped_refptr source_; }; std::shared_ptr new_video_track_source( diff --git a/webrtc-sys/include/livekit/webrtc.h b/webrtc-sys/include/livekit/webrtc.h index 88ad1027e..afa86e1fd 100644 --- a/webrtc-sys/include/livekit/webrtc.h +++ b/webrtc-sys/include/livekit/webrtc.h @@ -25,6 +25,7 @@ #include "rtc_base/logging.h" #include "rtc_base/physical_socket_server.h" #include "rtc_base/ssl_adapter.h" +#include "rtc_base/thread.h" #include "rust/cxx.h" #ifdef WEBRTC_WIN @@ -55,25 +56,25 @@ class RtcRuntime : public std::enable_shared_from_this { RtcRuntime& operator=(const RtcRuntime&) = delete; ~RtcRuntime(); - rtc::Thread* network_thread() const; - rtc::Thread* worker_thread() const; - rtc::Thread* signaling_thread() const; + webrtc::Thread* network_thread() const; + webrtc::Thread* worker_thread() const; + webrtc::Thread* signaling_thread() const; std::shared_ptr get_or_create_media_stream_track( - rtc::scoped_refptr track); + webrtc::scoped_refptr track); std::shared_ptr get_or_create_audio_track( - rtc::scoped_refptr track); + webrtc::scoped_refptr track); std::shared_ptr get_or_create_video_track( - rtc::scoped_refptr track); + webrtc::scoped_refptr track); private: RtcRuntime(); - std::unique_ptr network_thread_; - std::unique_ptr worker_thread_; - std::unique_ptr signaling_thread_; + std::unique_ptr network_thread_; + std::unique_ptr worker_thread_; + std::unique_ptr signaling_thread_; // Lists used to make sure we don't create multiple wrappers for one // underlying webrtc object. (e.g: webrtc::VideoTrackInterface should only @@ -89,19 +90,20 @@ class RtcRuntime : public std::enable_shared_from_this { // std::vector> rtp_senders_; #ifdef WEBRTC_WIN - // rtc::WinsockInitializer winsock_; - // rtc::PhysicalSocketServer ss_; - // rtc::AutoSocketServerThread main_thread_{&ss_}; + // webrtc::WinsockInitializer winsock_; + // webrtc::PhysicalSocketServer ss_; + // webrtc::AutoSocketServerThread main_thread_{&ss_}; #endif }; -class LogSink : public rtc::LogSink { +class LogSink : public webrtc::LogSink { public: LogSink(rust::Fn fnc); ~LogSink(); void OnLogMessage(const std::string& message, - rtc::LoggingSeverity severity) override; + webrtc::LoggingSeverity severity) override; + void OnLogMessage(const std::string& message) override {} private: diff --git a/webrtc-sys/libwebrtc/.gclient b/webrtc-sys/libwebrtc/.gclient index b4fbb1f00..2cdc191a5 100644 --- a/webrtc-sys/libwebrtc/.gclient +++ b/webrtc-sys/libwebrtc/.gclient @@ -1,7 +1,7 @@ solutions = [ { "name": 'src', - "url": 'https://github.com/webrtc-sdk/webrtc.git@m125_release', + "url": 'https://github.com/webrtc-sdk/webrtc.git@m137_release', "custom_deps": {}, "deps_file": "DEPS", "managed": False, diff --git a/webrtc-sys/libwebrtc/build_android.sh b/webrtc-sys/libwebrtc/build_android.sh index 0b7006fcc..692657d9d 100755 --- a/webrtc-sys/libwebrtc/build_android.sh +++ b/webrtc-sys/libwebrtc/build_android.sh @@ -134,4 +134,4 @@ cp "src/sdk/android/AndroidManifest.xml" "$ARTIFACTS_DIR" cd src find . -name "*.h" -print | cpio -pd "$ARTIFACTS_DIR/include" - +find . -name "*.inc" -print | cpio -pd "$ARTIFACTS_DIR/include" diff --git a/webrtc-sys/libwebrtc/build_ios.sh b/webrtc-sys/libwebrtc/build_ios.sh index 6db1ce21f..e60f8d411 100755 --- a/webrtc-sys/libwebrtc/build_ios.sh +++ b/webrtc-sys/libwebrtc/build_ios.sh @@ -142,4 +142,4 @@ cp "$OUTPUT_DIR/LICENSE.md" "$ARTIFACTS_DIR" cd src find . -name "*.h" -print | cpio -pd "$ARTIFACTS_DIR/include" - +find . -name "*.inc" -print | cpio -pd "$ARTIFACTS_DIR/include" diff --git a/webrtc-sys/libwebrtc/build_linux.sh b/webrtc-sys/libwebrtc/build_linux.sh index b08e29890..f17435d36 100755 --- a/webrtc-sys/libwebrtc/build_linux.sh +++ b/webrtc-sys/libwebrtc/build_linux.sh @@ -128,4 +128,4 @@ cp "$OUTPUT_DIR/LICENSE.md" "$ARTIFACTS_DIR" cd src find . -name "*.h" -print | cpio -pd "$ARTIFACTS_DIR/include" - +find . -name "*.inc" -print | cpio -pd "$ARTIFACTS_DIR/include" diff --git a/webrtc-sys/libwebrtc/build_macos.sh b/webrtc-sys/libwebrtc/build_macos.sh index c4ba72bd6..01e4e965c 100755 --- a/webrtc-sys/libwebrtc/build_macos.sh +++ b/webrtc-sys/libwebrtc/build_macos.sh @@ -104,6 +104,7 @@ gn gen "$OUTPUT_DIR" --root="src" \ rtc_enable_objc_symbol_export=false \ rtc_include_dav1d_in_internal_decoder_factory = true \ rtc_use_h264=true \ + rtc_use_h265=true \ use_custom_libcxx=false \ clang_use_chrome_plugins=false \ use_rtti=true \ @@ -117,7 +118,8 @@ ninja -C "$OUTPUT_DIR" :default \ sdk:default_codec_factory_objc \ pc:peer_connection \ sdk:videocapture_objc \ - sdk:mac_framework_objc + sdk:mac_framework_objc \ + desktop_capture_objc # make libwebrtc.a # don't include nasm @@ -132,4 +134,4 @@ cp "$OUTPUT_DIR/LICENSE.md" "$ARTIFACTS_DIR" cd src find . -name "*.h" -print | cpio -pd "$ARTIFACTS_DIR/include" - +find . -name "*.inc" -print | cpio -pd "$ARTIFACTS_DIR/include" diff --git a/webrtc-sys/libwebrtc/build_windows.cmd b/webrtc-sys/libwebrtc/build_windows.cmd index add24f4e9..edc84f84b 100644 --- a/webrtc-sys/libwebrtc/build_windows.cmd +++ b/webrtc-sys/libwebrtc/build_windows.cmd @@ -88,4 +88,4 @@ copy "%OUTPUT_DIR%\LICENSE.md" "%ARTIFACTS_DIR%" rem copy header xcopy src\*.h "%ARTIFACTS_DIR%\include" /C /S /I /F /H - +xcopy src\*.inc "%ARTIFACTS_DIR%\include" /C /S /I /F /H \ No newline at end of file diff --git a/webrtc-sys/src/apm.cpp b/webrtc-sys/src/apm.cpp index 0c6bcd1ec..4fe34d2be 100644 --- a/webrtc-sys/src/apm.cpp +++ b/webrtc-sys/src/apm.cpp @@ -1,5 +1,8 @@ #include "livekit/apm.h" +#include "api/audio/builtin_audio_processing_builder.h" +#include "api/environment/environment_factory.h" + #include #include @@ -7,7 +10,8 @@ namespace livekit { AudioProcessingModule::AudioProcessingModule( const AudioProcessingConfig& config) { - apm_ = webrtc::AudioProcessingBuilder().Create(); + apm_ = webrtc::BuiltinAudioProcessingBuilder() + .Build(webrtc::CreateEnvironment()); apm_->ApplyConfig(config.ToWebrtcConfig()); apm_->Initialize(); diff --git a/webrtc-sys/src/audio_device.cpp b/webrtc-sys/src/audio_device.cpp index d146a0c8a..364ca01f7 100644 --- a/webrtc-sys/src/audio_device.cpp +++ b/webrtc-sys/src/audio_device.cpp @@ -328,7 +328,7 @@ int AudioDevice::GetRecordAudioParameters( } #endif // WEBRTC_IOS -int32_t AudioDevice::SetAudioDeviceSink(webrtc::AudioDeviceSink* sink) const { +int32_t AudioDevice::SetObserver(webrtc::AudioDeviceObserver* observer) { return 0; } diff --git a/webrtc-sys/src/audio_resampler.cpp b/webrtc-sys/src/audio_resampler.cpp index cbb6060d4..8618018c8 100644 --- a/webrtc-sys/src/audio_resampler.cpp +++ b/webrtc-sys/src/audio_resampler.cpp @@ -19,6 +19,7 @@ #include #include "audio/remix_resample.h" +#include "api/audio/audio_view.h" namespace livekit { @@ -30,8 +31,10 @@ size_t AudioResampler::remix_and_resample(const int16_t* src, int dest_sample_rate) { frame_.num_channels_ = dest_num_channels; frame_.sample_rate_hz_ = dest_sample_rate; - webrtc::voe::RemixAndResample(src, samples_per_channel, num_channels, - sample_rate, &resampler_, &frame_); + webrtc::InterleavedView source(static_cast(src), + samples_per_channel, + num_channels); + webrtc::voe::RemixAndResample(source, sample_rate, &resampler_, &frame_); return frame_.num_channels() * frame_.samples_per_channel() * sizeof(int16_t); } diff --git a/webrtc-sys/src/audio_track.cpp b/webrtc-sys/src/audio_track.cpp index 8ca76e801..16e62f4c2 100644 --- a/webrtc-sys/src/audio_track.cpp +++ b/webrtc-sys/src/audio_track.cpp @@ -56,7 +56,7 @@ inline AudioSourceOptions to_rust_audio_options( } AudioTrack::AudioTrack(std::shared_ptr rtc_runtime, - rtc::scoped_refptr track) + webrtc::scoped_refptr track) : MediaStreamTrack(rtc_runtime, std::move(track)) {} AudioTrack::~AudioTrack() { @@ -99,9 +99,11 @@ void NativeAudioSink::OnData(const void* audio_data, const int16_t* data = static_cast(audio_data); if (sample_rate_ != sample_rate || num_channels_ != number_of_channels) { + webrtc::InterleavedView source(static_cast(data), + number_of_frames, + number_of_channels); // resample/remix before capturing - webrtc::voe::RemixAndResample(data, number_of_frames, number_of_channels, - sample_rate, &resampler_, &frame_); + webrtc::voe::RemixAndResample(source, sample_rate, &resampler_, &frame_); rust::Slice rust_slice( frame_.data(), frame_.num_channels() * frame_.samples_per_channel()); @@ -270,7 +272,7 @@ AudioTrackSource::AudioTrackSource(AudioSourceOptions options, int num_channels, int queue_size_ms, webrtc::TaskQueueFactory* task_queue_factory) - : source_(rtc::make_ref_counted( + : source_(webrtc::make_ref_counted( to_native_audio_options(options), sample_rate, num_channels, @@ -311,7 +313,7 @@ std::shared_ptr new_audio_track_source( GetGlobalTaskQueueFactory()); } -rtc::scoped_refptr AudioTrackSource::get() +webrtc::scoped_refptr AudioTrackSource::get() const { return source_; } diff --git a/webrtc-sys/src/data_channel.cpp b/webrtc-sys/src/data_channel.cpp index bec5cef4e..70d15122e 100644 --- a/webrtc-sys/src/data_channel.cpp +++ b/webrtc-sys/src/data_channel.cpp @@ -37,14 +37,14 @@ webrtc::DataChannelInit to_native_data_channel_init(DataChannelInit init) { rtc_init.maxRetransmits = init.max_retransmits; if (init.has_priority) - rtc_init.priority = static_cast(init.priority); + rtc_init.priority = webrtc::PriorityValue(static_cast(init.priority)); return rtc_init; } DataChannel::DataChannel( std::shared_ptr rtc_runtime, - rtc::scoped_refptr data_channel) + webrtc::scoped_refptr data_channel) : rtc_runtime_(rtc_runtime), data_channel_(std::move(data_channel)) { RTC_LOG(LS_VERBOSE) << "DataChannel::DataChannel()"; } @@ -73,7 +73,7 @@ void DataChannel::unregister_observer() const { bool DataChannel::send(const DataBuffer& buffer) const { return data_channel_->Send(webrtc::DataBuffer{ - rtc::CopyOnWriteBuffer(buffer.ptr, buffer.len), buffer.binary}); + webrtc::CopyOnWriteBuffer(buffer.ptr, buffer.len), buffer.binary}); } int DataChannel::id() const { diff --git a/webrtc-sys/src/media_stream.cpp b/webrtc-sys/src/media_stream.cpp index ed6f78e10..3a4ad1275 100644 --- a/webrtc-sys/src/media_stream.cpp +++ b/webrtc-sys/src/media_stream.cpp @@ -33,7 +33,7 @@ namespace livekit { MediaStream::MediaStream( std::shared_ptr rtc_runtime, - rtc::scoped_refptr stream) + webrtc::scoped_refptr stream) : rtc_runtime_(rtc_runtime), media_stream_(std::move(stream)) {} rust::String MediaStream::id() const { @@ -73,12 +73,12 @@ std::shared_ptr MediaStream::find_video_track( bool MediaStream::add_track(std::shared_ptr track) const { if (track->kind() == webrtc::MediaStreamTrackInterface::kVideoKind) { return media_stream_->AddTrack( - rtc::scoped_refptr( + webrtc::scoped_refptr( static_cast( track->rtc_track().get()))); } else { return media_stream_->AddTrack( - rtc::scoped_refptr( + webrtc::scoped_refptr( static_cast( track->rtc_track().get()))); } @@ -87,12 +87,12 @@ bool MediaStream::add_track(std::shared_ptr track) const { bool MediaStream::remove_track(std::shared_ptr track) const { if (track->kind() == webrtc::MediaStreamTrackInterface::kVideoKind) { return media_stream_->RemoveTrack( - rtc::scoped_refptr( + webrtc::scoped_refptr( static_cast( track->rtc_track().get()))); } else { return media_stream_->RemoveTrack( - rtc::scoped_refptr( + webrtc::scoped_refptr( static_cast( track->rtc_track().get()))); } diff --git a/webrtc-sys/src/media_stream_track.cpp b/webrtc-sys/src/media_stream_track.cpp index dafefca60..1f9fc1e3c 100644 --- a/webrtc-sys/src/media_stream_track.cpp +++ b/webrtc-sys/src/media_stream_track.cpp @@ -32,7 +32,7 @@ namespace livekit { MediaStreamTrack::MediaStreamTrack( std::shared_ptr rtc_runtime, - rtc::scoped_refptr track) + webrtc::scoped_refptr track) : rtc_runtime_(rtc_runtime), track_(std::move(track)) {} rust::String MediaStreamTrack::kind() const { diff --git a/webrtc-sys/src/nvidia/h264_decoder_impl.cpp b/webrtc-sys/src/nvidia/h264_decoder_impl.cpp index 3ba449b38..af716c503 100644 --- a/webrtc-sys/src/nvidia/h264_decoder_impl.cpp +++ b/webrtc-sys/src/nvidia/h264_decoder_impl.cpp @@ -110,8 +110,8 @@ int32_t NvidiaH264DecoderImpl::Decode(const EncodedImage& input_image, } h264_bitstream_parser_.ParseBitstream(input_image); - absl::optional qp = h264_bitstream_parser_.GetLastSliceQp(); - absl::optional sps = h264_bitstream_parser_.sps(); + std::optional qp = h264_bitstream_parser_.GetLastSliceQp(); + std::optional sps = h264_bitstream_parser_.sps(); if (is_configured_decoder_) { if (!sps || @@ -149,7 +149,7 @@ int32_t NvidiaH264DecoderImpl::Decode(const EncodedImage& input_image, int64_t timeStamp; uint8_t* pFrame = decoder_->GetFrame(&timeStamp); - rtc::scoped_refptr i420_buffer = + webrtc::scoped_refptr i420_buffer = buffer_pool_.CreateI420Buffer(decoder_->GetWidth(), decoder_->GetHeight()); @@ -176,7 +176,7 @@ int32_t NvidiaH264DecoderImpl::Decode(const EncodedImage& input_image, .build(); // todo: measurement decoding time - absl::optional decodetime; + std::optional decodetime; decoded_complete_callback_->Decoded(decoded_frame, decodetime, qp); } diff --git a/webrtc-sys/src/nvidia/h264_decoder_impl.h b/webrtc-sys/src/nvidia/h264_decoder_impl.h index 882f8f0f7..4674a3b5c 100644 --- a/webrtc-sys/src/nvidia/h264_decoder_impl.h +++ b/webrtc-sys/src/nvidia/h264_decoder_impl.h @@ -20,8 +20,8 @@ namespace webrtc { class H264BitstreamParserEx : public ::webrtc::H264BitstreamParser { public: - absl::optional sps() { return sps_; } - absl::optional pps() { return pps_; } + std::optional sps() { return sps_; } + std::optional pps() { return pps_; } }; class NvidiaH264DecoderImpl : public VideoDecoder { diff --git a/webrtc-sys/src/nvidia/h264_encoder_impl.cpp b/webrtc-sys/src/nvidia/h264_encoder_impl.cpp index 17ad27e92..4d2eee165 100644 --- a/webrtc-sys/src/nvidia/h264_encoder_impl.cpp +++ b/webrtc-sys/src/nvidia/h264_encoder_impl.cpp @@ -89,7 +89,7 @@ NvidiaH264EncoderImpl::NvidiaH264EncoderImpl( H264EncoderSettings::Parse(format).packetization_mode), format_(format) { std::string hexString = format_.parameters.at("profile-level-id"); - absl::optional profile_level_id = + std::optional profile_level_id = webrtc::ParseH264ProfileLevelId(hexString.c_str()); if (profile_level_id.has_value()) { profile_ = profile_level_id->profile; @@ -279,7 +279,7 @@ int32_t NvidiaH264EncoderImpl::Encode( return WEBRTC_VIDEO_CODEC_UNINITIALIZED; } - rtc::scoped_refptr frame_buffer = + webrtc::scoped_refptr frame_buffer = input_frame.video_frame_buffer()->ToI420(); if (!frame_buffer) { RTC_LOG(LS_ERROR) << "Failed to convert " diff --git a/webrtc-sys/src/objc_video_frame_buffer.mm b/webrtc-sys/src/objc_video_frame_buffer.mm index e8490beb1..6621b0f8e 100644 --- a/webrtc-sys/src/objc_video_frame_buffer.mm +++ b/webrtc-sys/src/objc_video_frame_buffer.mm @@ -26,7 +26,7 @@ CVPixelBufferRef pixelBuffer ) { RTCCVPixelBuffer *buffer = [[RTCCVPixelBuffer alloc] initWithPixelBuffer:pixelBuffer]; - rtc::scoped_refptr frame_buffer = webrtc::ObjCToNativeVideoFrameBuffer(buffer); + webrtc::scoped_refptr frame_buffer = webrtc::ObjCToNativeVideoFrameBuffer(buffer); [buffer release]; CVPixelBufferRelease(pixelBuffer); return std::make_unique(frame_buffer); diff --git a/webrtc-sys/src/peer_connection.cpp b/webrtc-sys/src/peer_connection.cpp index a3de766c6..17944ebf9 100644 --- a/webrtc-sys/src/peer_connection.cpp +++ b/webrtc-sys/src/peer_connection.cpp @@ -73,7 +73,7 @@ to_native_offer_answer_options(const RtcOfferAnswerOptions& options) { PeerConnection::PeerConnection( std::shared_ptr rtc_runtime, - rtc::scoped_refptr pc_factory, + webrtc::scoped_refptr pc_factory, rust::Box observer) : rtc_runtime_(std::move(rtc_runtime)), pc_factory_(std::move(pc_factory)), @@ -115,8 +115,8 @@ void PeerConnection::create_offer( rust::Fn, std::unique_ptr)> on_success, rust::Fn, RtcError)> on_error) const { - rtc::scoped_refptr observer = - rtc::make_ref_counted(std::move(ctx), on_success, + webrtc::scoped_refptr observer = + webrtc::make_ref_counted(std::move(ctx), on_success, on_error); peer_connection_->CreateOffer(observer.get(), @@ -129,8 +129,8 @@ void PeerConnection::create_answer( rust::Fn, std::unique_ptr)> on_success, rust::Fn, RtcError)> on_error) const { - rtc::scoped_refptr observer = - rtc::make_ref_counted(std::move(ctx), on_success, + webrtc::scoped_refptr observer = + webrtc::make_ref_counted(std::move(ctx), on_success, on_error); peer_connection_->CreateAnswer(observer.get(), @@ -141,8 +141,8 @@ void PeerConnection::set_local_description( std::unique_ptr desc, rust::Box ctx, rust::Fn, RtcError)> on_complete) const { - rtc::scoped_refptr observer = - rtc::make_ref_counted(std::move(ctx), + webrtc::scoped_refptr observer = + webrtc::make_ref_counted(std::move(ctx), on_complete); peer_connection_->SetLocalDescription(desc->clone()->release(), observer); @@ -152,8 +152,8 @@ void PeerConnection::set_remote_description( std::unique_ptr desc, rust::Box ctx, rust::Fn, RtcError)> on_complete) const { - rtc::scoped_refptr observer = - rtc::make_ref_counted(std::move(ctx), + webrtc::scoped_refptr observer = + webrtc::make_ref_counted(std::move(ctx), on_complete); peer_connection_->SetRemoteDescription(desc->clone()->release(), observer); @@ -209,7 +209,7 @@ void PeerConnection::remove_track(std::shared_ptr sender) const { void PeerConnection::get_stats( rust::Box ctx, rust::Fn, rust::String)> on_stats) const { - auto observer = rtc::make_ref_counted>( + auto observer = webrtc::make_ref_counted>( std::move(ctx), on_stats); peer_connection_->GetStats(observer.get()); } @@ -230,7 +230,7 @@ std::shared_ptr PeerConnection::add_transceiver_for_media( MediaType media_type, RtpTransceiverInit init) const { auto result = peer_connection_->AddTransceiver( - static_cast(media_type), + static_cast(media_type), to_native_rtp_transceiver_init(init)); if (!result.ok()) @@ -350,19 +350,19 @@ void PeerConnection::OnSignalingChange( } void PeerConnection::OnAddStream( - rtc::scoped_refptr stream) { + webrtc::scoped_refptr stream) { observer_->on_add_stream(std::make_unique(rtc_runtime_, stream)); } void PeerConnection::OnRemoveStream( - rtc::scoped_refptr stream) { + webrtc::scoped_refptr stream) { // Find current MediaStream // observer_->on_remove_stream(std::make_unique(rtc_runtime_, // stream)); } void PeerConnection::OnDataChannel( - rtc::scoped_refptr data_channel) { + webrtc::scoped_refptr data_channel) { observer_->on_data_channel( std::make_shared(rtc_runtime_, data_channel)); } @@ -444,8 +444,8 @@ void PeerConnection::OnIceSelectedCandidatePairChanged( } void PeerConnection::OnAddTrack( - rtc::scoped_refptr receiver, - const std::vector>& + webrtc::scoped_refptr receiver, + const std::vector>& streams) { rust::Vec vec; @@ -460,13 +460,13 @@ void PeerConnection::OnAddTrack( } void PeerConnection::OnTrack( - rtc::scoped_refptr transceiver) { + webrtc::scoped_refptr transceiver) { observer_->on_track(std::make_unique( rtc_runtime_, transceiver, peer_connection_)); } void PeerConnection::OnRemoveTrack( - rtc::scoped_refptr receiver) { + webrtc::scoped_refptr receiver) { observer_->on_remove_track( std::make_unique(rtc_runtime_, receiver, peer_connection_)); } diff --git a/webrtc-sys/src/peer_connection_factory.cpp b/webrtc-sys/src/peer_connection_factory.cpp index 31b32729e..2980a36e5 100644 --- a/webrtc-sys/src/peer_connection_factory.cpp +++ b/webrtc-sys/src/peer_connection_factory.cpp @@ -21,7 +21,10 @@ #include "api/audio_codecs/builtin_audio_decoder_factory.h" #include "api/audio_codecs/builtin_audio_encoder_factory.h" +#include "api/audio/builtin_audio_processing_builder.h" +#include "api/environment/environment_factory.h" #include "api/peer_connection_interface.h" +#include "api/transport/field_trial_based_config.h" #include "api/rtc_error.h" #include "api/enable_media.h" #include "api/rtc_event_log/rtc_event_log_factory.h" @@ -59,7 +62,7 @@ PeerConnectionFactory::PeerConnectionFactory( dependencies.trials = std::make_unique(); audio_device_ = rtc_runtime_->worker_thread()->BlockingCall([&] { - return rtc::make_ref_counted( + return webrtc::make_ref_counted( dependencies.task_queue_factory.get()); }); @@ -71,7 +74,8 @@ PeerConnectionFactory::PeerConnectionFactory( std::move(std::make_unique()); dependencies.audio_encoder_factory = webrtc::CreateBuiltinAudioEncoderFactory(); dependencies.audio_decoder_factory = webrtc::CreateBuiltinAudioDecoderFactory(); - dependencies.audio_processing = webrtc::AudioProcessingBuilder().Create(); + dependencies.audio_processing = webrtc::BuiltinAudioProcessingBuilder() + .Build(webrtc::CreateEnvironment()); webrtc::EnableMedia(dependencies); peer_factory_ = @@ -127,13 +131,13 @@ std::shared_ptr PeerConnectionFactory::create_audio_track( RtpCapabilities PeerConnectionFactory::rtp_sender_capabilities( MediaType type) const { return to_rust_rtp_capabilities(peer_factory_->GetRtpSenderCapabilities( - static_cast(type))); + static_cast(type))); } RtpCapabilities PeerConnectionFactory::rtp_receiver_capabilities( MediaType type) const { return to_rust_rtp_capabilities(peer_factory_->GetRtpReceiverCapabilities( - static_cast(type))); + static_cast(type))); } std::shared_ptr create_peer_connection_factory() { diff --git a/webrtc-sys/src/rtp_parameters.cpp b/webrtc-sys/src/rtp_parameters.cpp index 75bbcd4c9..66ffe0d99 100644 --- a/webrtc-sys/src/rtp_parameters.cpp +++ b/webrtc-sys/src/rtp_parameters.cpp @@ -34,7 +34,7 @@ webrtc::RtpCodecCapability to_native_rtp_codec_capability( // native.mime_type(); IGNORED native.name = capability.name.c_str(); - native.kind = static_cast(capability.kind); + native.kind = static_cast(capability.kind); if (capability.has_clock_rate) native.clock_rate = capability.clock_rate; @@ -133,7 +133,7 @@ webrtc::RtpCodecParameters to_native_rtp_codec_parameters( RtpCodecParameters params) { webrtc::RtpCodecParameters native{}; native.name = params.name.c_str(); - native.kind = static_cast(params.kind); + native.kind = static_cast(params.kind); native.payload_type = params.payload_type; for (auto pair : params.parameters) diff --git a/webrtc-sys/src/rtp_receiver.cpp b/webrtc-sys/src/rtp_receiver.cpp index 857f7a71a..04524c0c9 100644 --- a/webrtc-sys/src/rtp_receiver.cpp +++ b/webrtc-sys/src/rtp_receiver.cpp @@ -27,8 +27,8 @@ namespace livekit { RtpReceiver::RtpReceiver( std::shared_ptr rtc_runtime, - rtc::scoped_refptr receiver, - rtc::scoped_refptr peer_connection) + webrtc::scoped_refptr receiver, + webrtc::scoped_refptr peer_connection) : rtc_runtime_(rtc_runtime), receiver_(std::move(receiver)), peer_connection_(std::move(peer_connection)) {} @@ -48,7 +48,7 @@ void RtpReceiver::get_stats( rust::Box ctx, rust::Fn, rust::String)> on_stats) const { auto observer = - rtc::make_ref_counted>(std::move(ctx), on_stats); + webrtc::make_ref_counted>(std::move(ctx), on_stats); peer_connection_->GetStats(receiver_, observer); } diff --git a/webrtc-sys/src/rtp_sender.cpp b/webrtc-sys/src/rtp_sender.cpp index 8d5008f81..f56477466 100644 --- a/webrtc-sys/src/rtp_sender.cpp +++ b/webrtc-sys/src/rtp_sender.cpp @@ -26,8 +26,8 @@ namespace livekit { RtpSender::RtpSender( std::shared_ptr rtc_runtime, - rtc::scoped_refptr sender, - rtc::scoped_refptr peer_connection) + webrtc::scoped_refptr sender, + webrtc::scoped_refptr peer_connection) : rtc_runtime_(rtc_runtime), sender_(std::move(sender)), peer_connection_(std::move(peer_connection)) {} @@ -48,7 +48,7 @@ void RtpSender::get_stats( rust::Box ctx, rust::Fn, rust::String)> on_stats) const { auto observer = - rtc::make_ref_counted>(std::move(ctx), on_stats); + webrtc::make_ref_counted>(std::move(ctx), on_stats); peer_connection_->GetStats(sender_, observer); } diff --git a/webrtc-sys/src/rtp_transceiver.cpp b/webrtc-sys/src/rtp_transceiver.cpp index 82eb73b2f..62c20dcb2 100644 --- a/webrtc-sys/src/rtp_transceiver.cpp +++ b/webrtc-sys/src/rtp_transceiver.cpp @@ -38,8 +38,8 @@ webrtc::RtpTransceiverInit to_native_rtp_transceiver_init( RtpTransceiver::RtpTransceiver( std::shared_ptr rtc_runtime, - rtc::scoped_refptr transceiver, - rtc::scoped_refptr peer_connection) + webrtc::scoped_refptr transceiver, + webrtc::scoped_refptr peer_connection) : rtc_runtime_(rtc_runtime), transceiver_(std::move(transceiver)), peer_connection_(std::move(peer_connection)) {} diff --git a/webrtc-sys/src/vaapi/h264_encoder_impl.cpp b/webrtc-sys/src/vaapi/h264_encoder_impl.cpp index ec7965997..e740ebb7e 100644 --- a/webrtc-sys/src/vaapi/h264_encoder_impl.cpp +++ b/webrtc-sys/src/vaapi/h264_encoder_impl.cpp @@ -39,7 +39,7 @@ VAAPIH264EncoderWrapper::VAAPIH264EncoderWrapper(const webrtc::Environment& env, H264EncoderSettings::Parse(format).packetization_mode), format_(format) { std::string hexString = format_.parameters.at("profile-level-id"); - absl::optional profile_level_id = + std::optional profile_level_id = webrtc::ParseH264ProfileLevelId(hexString.c_str()); if (profile_level_id.has_value()) { profile_ = profile_level_id->profile; @@ -189,7 +189,7 @@ int32_t VAAPIH264EncoderWrapper::Encode( return WEBRTC_VIDEO_CODEC_UNINITIALIZED; } - rtc::scoped_refptr frame_buffer = + webrtc::scoped_refptr frame_buffer = input_frame.video_frame_buffer()->ToI420(); if (!frame_buffer) { RTC_LOG(LS_ERROR) << "Failed to convert " diff --git a/webrtc-sys/src/video_encoder_factory.cpp b/webrtc-sys/src/video_encoder_factory.cpp index 370a7d257..0ef5d524c 100644 --- a/webrtc-sys/src/video_encoder_factory.cpp +++ b/webrtc-sys/src/video_encoder_factory.cpp @@ -87,7 +87,7 @@ VideoEncoderFactory::InternalFactory::GetSupportedFormats() const { VideoEncoderFactory::CodecSupport VideoEncoderFactory::InternalFactory::QueryCodecSupport( const webrtc::SdpVideoFormat& format, - absl::optional scalability_mode) const { + std::optional scalability_mode) const { auto original_format = webrtc::FuzzyMatchSdpVideoFormat(Factory().GetSupportedFormats(), format); return original_format @@ -128,7 +128,7 @@ std::vector VideoEncoderFactory::GetSupportedFormats() VideoEncoderFactory::CodecSupport VideoEncoderFactory::QueryCodecSupport( const webrtc::SdpVideoFormat& format, - absl::optional scalability_mode) const { + std::optional scalability_mode) const { return internal_factory_->QueryCodecSupport(format, scalability_mode); } diff --git a/webrtc-sys/src/video_frame.cpp b/webrtc-sys/src/video_frame.cpp index ad082bdb8..e2dfc0a1c 100644 --- a/webrtc-sys/src/video_frame.cpp +++ b/webrtc-sys/src/video_frame.cpp @@ -43,7 +43,7 @@ int64_t VideoFrame::ntp_time_ms() const { return frame_.ntp_time_ms(); } uint32_t VideoFrame::timestamp() const { - return frame_.timestamp(); + return frame_.rtp_timestamp(); } VideoRotation VideoFrame::rotation() const { diff --git a/webrtc-sys/src/video_frame_buffer.cpp b/webrtc-sys/src/video_frame_buffer.cpp index b33ccf18a..32d5c0320 100644 --- a/webrtc-sys/src/video_frame_buffer.cpp +++ b/webrtc-sys/src/video_frame_buffer.cpp @@ -21,7 +21,7 @@ namespace livekit { VideoFrameBuffer::VideoFrameBuffer( - rtc::scoped_refptr buffer) + webrtc::scoped_refptr buffer) : buffer_(std::move(buffer)) {} VideoFrameBufferType VideoFrameBuffer::buffer_type() const { @@ -43,46 +43,46 @@ std::unique_ptr VideoFrameBuffer::to_i420() const { // const_cast is valid here because we take the ownership on the rust side std::unique_ptr VideoFrameBuffer::get_i420() { return std::make_unique( - rtc::scoped_refptr( + webrtc::scoped_refptr( const_cast(buffer_->GetI420()))); } std::unique_ptr VideoFrameBuffer::get_i420a() { return std::make_unique( - rtc::scoped_refptr( + webrtc::scoped_refptr( const_cast(buffer_->GetI420A()))); } std::unique_ptr VideoFrameBuffer::get_i422() { return std::make_unique( - rtc::scoped_refptr( + webrtc::scoped_refptr( const_cast(buffer_->GetI422()))); } std::unique_ptr VideoFrameBuffer::get_i444() { return std::make_unique( - rtc::scoped_refptr( + webrtc::scoped_refptr( const_cast(buffer_->GetI444()))); } std::unique_ptr VideoFrameBuffer::get_i010() { return std::make_unique( - rtc::scoped_refptr( + webrtc::scoped_refptr( const_cast(buffer_->GetI010()))); } std::unique_ptr VideoFrameBuffer::get_nv12() { return std::make_unique( - rtc::scoped_refptr( + webrtc::scoped_refptr( const_cast(buffer_->GetNV12()))); } -rtc::scoped_refptr VideoFrameBuffer::get() const { +webrtc::scoped_refptr VideoFrameBuffer::get() const { return buffer_; } PlanarYuvBuffer::PlanarYuvBuffer( - rtc::scoped_refptr buffer) + webrtc::scoped_refptr buffer) : VideoFrameBuffer(buffer) {} unsigned int PlanarYuvBuffer::chroma_width() const { @@ -110,7 +110,7 @@ webrtc::PlanarYuvBuffer* PlanarYuvBuffer::buffer() const { } PlanarYuv8Buffer::PlanarYuv8Buffer( - rtc::scoped_refptr buffer) + webrtc::scoped_refptr buffer) : PlanarYuvBuffer(buffer) {} const uint8_t* PlanarYuv8Buffer::data_y() const { @@ -130,7 +130,7 @@ webrtc::PlanarYuv8Buffer* PlanarYuv8Buffer::buffer() const { } PlanarYuv16BBuffer::PlanarYuv16BBuffer( - rtc::scoped_refptr buffer) + webrtc::scoped_refptr buffer) : PlanarYuvBuffer(buffer) {} const uint16_t* PlanarYuv16BBuffer::data_y() const { @@ -150,7 +150,7 @@ webrtc::PlanarYuv16BBuffer* PlanarYuv16BBuffer::buffer() const { } BiplanarYuvBuffer::BiplanarYuvBuffer( - rtc::scoped_refptr buffer) + webrtc::scoped_refptr buffer) : VideoFrameBuffer(buffer) {} unsigned int BiplanarYuvBuffer::chroma_width() const { @@ -174,7 +174,7 @@ webrtc::BiplanarYuvBuffer* BiplanarYuvBuffer::buffer() const { } BiplanarYuv8Buffer::BiplanarYuv8Buffer( - rtc::scoped_refptr buffer) + webrtc::scoped_refptr buffer) : BiplanarYuvBuffer(buffer) {} const uint8_t* BiplanarYuv8Buffer::data_y() const { @@ -189,11 +189,11 @@ webrtc::BiplanarYuv8Buffer* BiplanarYuv8Buffer::buffer() const { return static_cast(buffer_.get()); } -I420Buffer::I420Buffer(rtc::scoped_refptr buffer) +I420Buffer::I420Buffer(webrtc::scoped_refptr buffer) : PlanarYuv8Buffer(buffer) {} I420ABuffer::I420ABuffer( - rtc::scoped_refptr buffer) + webrtc::scoped_refptr buffer) : I420Buffer(buffer) {} unsigned int I420ABuffer::stride_a() const { @@ -208,16 +208,16 @@ webrtc::I420ABufferInterface* I420ABuffer::buffer() const { return static_cast(buffer_.get()); } -I422Buffer::I422Buffer(rtc::scoped_refptr buffer) +I422Buffer::I422Buffer(webrtc::scoped_refptr buffer) : PlanarYuv8Buffer(buffer) {} -I444Buffer::I444Buffer(rtc::scoped_refptr buffer) +I444Buffer::I444Buffer(webrtc::scoped_refptr buffer) : PlanarYuv8Buffer(buffer) {} -I010Buffer::I010Buffer(rtc::scoped_refptr buffer) +I010Buffer::I010Buffer(webrtc::scoped_refptr buffer) : PlanarYuv16BBuffer(buffer) {} -NV12Buffer::NV12Buffer(rtc::scoped_refptr buffer) +NV12Buffer::NV12Buffer(webrtc::scoped_refptr buffer) : BiplanarYuv8Buffer(buffer) {} std::unique_ptr copy_i420_buffer( @@ -257,7 +257,7 @@ std::unique_ptr new_i010_buffer(int width, int stride_y, int stride_u, int stride_v) { - return std::make_unique(rtc::make_ref_counted( + return std::make_unique(webrtc::make_ref_counted( width, height, stride_y, stride_u, stride_v)); } diff --git a/webrtc-sys/src/video_track.cpp b/webrtc-sys/src/video_track.cpp index 45e07dcae..cd83a1640 100644 --- a/webrtc-sys/src/video_track.cpp +++ b/webrtc-sys/src/video_track.cpp @@ -36,7 +36,7 @@ namespace livekit { VideoTrack::VideoTrack(std::shared_ptr rtc_runtime, - rtc::scoped_refptr track) + webrtc::scoped_refptr track) : MediaStreamTrack(rtc_runtime, std::move(track)) {} VideoTrack::~VideoTrack() { @@ -49,7 +49,7 @@ VideoTrack::~VideoTrack() { void VideoTrack::add_sink(const std::shared_ptr& sink) const { webrtc::MutexLock lock(&mutex_); track()->AddOrUpdateSink(sink.get(), - rtc::VideoSinkWants()); // TODO(theomonnom): Expose + webrtc::VideoSinkWants()); // TODO(theomonnom): Expose // VideoSinkWants to Rust? sinks_.push_back(sink); } @@ -106,7 +106,7 @@ std::shared_ptr new_native_video_sink( VideoTrackSource::InternalSource::InternalSource( const VideoResolution& resolution) - : rtc::AdaptedVideoTrackSource(4), resolution_(resolution) {} + : webrtc::AdaptedVideoTrackSource(4), resolution_(resolution) {} VideoTrackSource::InternalSource::~InternalSource() {} @@ -114,7 +114,7 @@ bool VideoTrackSource::InternalSource::is_screencast() const { return false; } -absl::optional VideoTrackSource::InternalSource::needs_denoising() const { +std::optional VideoTrackSource::InternalSource::needs_denoising() const { return false; } @@ -137,9 +137,9 @@ bool VideoTrackSource::InternalSource::on_captured_frame( webrtc::MutexLock lock(&mutex_); int64_t aligned_timestamp_us = timestamp_aligner_.TranslateTimestamp( - frame.timestamp_us(), rtc::TimeMicros()); + frame.timestamp_us(), webrtc::TimeMicros()); - rtc::scoped_refptr buffer = + webrtc::scoped_refptr buffer = frame.video_frame_buffer(); if (resolution_.height == 0 || resolution_.width == 0) { @@ -161,7 +161,7 @@ bool VideoTrackSource::InternalSource::on_captured_frame( webrtc::VideoRotation rotation = frame.rotation(); if (apply_rotation() && rotation != webrtc::kVideoRotation_0) { - // If the buffer is I420, rtc::AdaptedVideoTrackSource will handle the + // If the buffer is I420, webrtc::AdaptedVideoTrackSource will handle the // rotation for us. buffer = buffer->ToI420(); } @@ -176,7 +176,7 @@ bool VideoTrackSource::InternalSource::on_captured_frame( } VideoTrackSource::VideoTrackSource(const VideoResolution& resolution) { - source_ = rtc::make_ref_counted(resolution); + source_ = webrtc::make_ref_counted(resolution); } VideoResolution VideoTrackSource::video_resolution() const { @@ -189,7 +189,7 @@ bool VideoTrackSource::on_captured_frame( return source_->on_captured_frame(rtc_frame); } -rtc::scoped_refptr VideoTrackSource::get() +webrtc::scoped_refptr VideoTrackSource::get() const { return source_; } diff --git a/webrtc-sys/src/webrtc.cpp b/webrtc-sys/src/webrtc.cpp index 7305741c5..0b9491ff8 100644 --- a/webrtc-sys/src/webrtc.cpp +++ b/webrtc-sys/src/webrtc.cpp @@ -26,8 +26,8 @@ #include "livekit/rtp_receiver.h" #include "livekit/rtp_sender.h" #include "livekit/video_track.h" -#include "rtc_base/helpers.h" #include "rtc_base/logging.h" +#include "rtc_base/crypto_random.h" #include "rtc_base/synchronization/mutex.h" #ifdef WEBRTC_WIN @@ -48,7 +48,7 @@ RtcRuntime::RtcRuntime() { // Not the best way to do it... webrtc::MutexLock lock(&g_mutex); if (g_release_counter == 0) { - RTC_CHECK(rtc::InitializeSSL()) << "Failed to InitializeSSL()"; + RTC_CHECK(webrtc::InitializeSSL()) << "Failed to InitializeSSL()"; #ifdef WEBRTC_WIN WSADATA data; @@ -58,13 +58,13 @@ RtcRuntime::RtcRuntime() { g_release_counter++; } - network_thread_ = rtc::Thread::CreateWithSocketServer(); + network_thread_ = webrtc::Thread::CreateWithSocketServer(); network_thread_->SetName("network_thread", &network_thread_); network_thread_->Start(); - worker_thread_ = rtc::Thread::Create(); + worker_thread_ = webrtc::Thread::Create(); worker_thread_->SetName("worker_thread", &worker_thread_); worker_thread_->Start(); - signaling_thread_ = rtc::Thread::Create(); + signaling_thread_ = webrtc::Thread::Create(); signaling_thread_->SetName("signaling_thread", &signaling_thread_); signaling_thread_->Start(); } @@ -80,7 +80,7 @@ RtcRuntime::~RtcRuntime() { webrtc::MutexLock lock(&g_mutex); g_release_counter--; if (g_release_counter == 0) { - RTC_CHECK(rtc::CleanupSSL()) << "Failed to CleanupSSL()"; + RTC_CHECK(webrtc::CleanupSSL()) << "Failed to CleanupSSL()"; #ifdef WEBRTC_WIN WSACleanup(); @@ -89,20 +89,20 @@ RtcRuntime::~RtcRuntime() { } } -rtc::Thread* RtcRuntime::network_thread() const { +webrtc::Thread* RtcRuntime::network_thread() const { return network_thread_.get(); } -rtc::Thread* RtcRuntime::worker_thread() const { +webrtc::Thread* RtcRuntime::worker_thread() const { return worker_thread_.get(); } -rtc::Thread* RtcRuntime::signaling_thread() const { +webrtc::Thread* RtcRuntime::signaling_thread() const { return signaling_thread_.get(); } std::shared_ptr RtcRuntime::get_or_create_media_stream_track( - rtc::scoped_refptr rtc_track) { + webrtc::scoped_refptr rtc_track) { webrtc::MutexLock lock(&mutex_); for (std::weak_ptr weak_existing_track : media_stream_tracks_) { @@ -118,7 +118,7 @@ std::shared_ptr RtcRuntime::get_or_create_media_stream_track( std::shared_ptr video_track = std::shared_ptr(new VideoTrack( shared_from_this(), - rtc::scoped_refptr( + webrtc::scoped_refptr( static_cast(rtc_track.get())))); media_stream_tracks_.push_back( @@ -128,7 +128,7 @@ std::shared_ptr RtcRuntime::get_or_create_media_stream_track( std::shared_ptr audio_track = std::shared_ptr(new AudioTrack( shared_from_this(), - rtc::scoped_refptr( + webrtc::scoped_refptr( static_cast(rtc_track.get())))); media_stream_tracks_.push_back( @@ -138,13 +138,13 @@ std::shared_ptr RtcRuntime::get_or_create_media_stream_track( } std::shared_ptr RtcRuntime::get_or_create_audio_track( - rtc::scoped_refptr track) { + webrtc::scoped_refptr track) { return std::static_pointer_cast( get_or_create_media_stream_track(track)); } std::shared_ptr RtcRuntime::get_or_create_video_track( - rtc::scoped_refptr track) { + webrtc::scoped_refptr track) { return std::static_pointer_cast( get_or_create_media_stream_track(track)); } @@ -152,15 +152,15 @@ std::shared_ptr RtcRuntime::get_or_create_video_track( LogSink::LogSink( rust::Fn fnc) : fnc_(fnc) { - rtc::LogMessage::AddLogToStream(this, rtc::LoggingSeverity::LS_VERBOSE); + webrtc::LogMessage::AddLogToStream(this, rtc::LoggingSeverity::LS_VERBOSE); } LogSink::~LogSink() { - rtc::LogMessage::RemoveLogToStream(this); + webrtc::LogMessage::RemoveLogToStream(this); } void LogSink::OnLogMessage(const std::string& message, - rtc::LoggingSeverity severity) { + webrtc::LoggingSeverity severity) { fnc_(rust::String::lossy(message), static_cast(severity)); } @@ -170,7 +170,7 @@ std::unique_ptr new_log_sink( } rust::String create_random_uuid() { - return rtc::CreateRandomUuid(); + return webrtc::CreateRandomUuid(); } } // namespace livekit From ffd5ba9ded4640c2e4a638255401587d6a90735a Mon Sep 17 00:00:00 2001 From: cloudwebrtc Date: Thu, 28 Aug 2025 13:30:20 +0800 Subject: [PATCH 02/52] fix compile issue for linux. --- webrtc-sys/build.rs | 4 +++- webrtc-sys/libwebrtc/build_android.sh | 4 ---- webrtc-sys/libwebrtc/build_linux.sh | 8 ++----- .../patches/abseil_use_optional.patch | 13 ---------- webrtc-sys/libwebrtc/patches/add_deps.patch | 6 ++--- ...l_verify_callback_with_native_handle.patch | 24 +++++++++---------- webrtc-sys/src/nvidia/h264_encoder_impl.cpp | 9 +++---- webrtc-sys/src/nvidia/h264_encoder_impl.h | 1 + webrtc-sys/src/vaapi/h264_encoder_impl.cpp | 5 ++-- webrtc-sys/src/vaapi/h264_encoder_impl.h | 1 + 10 files changed, 30 insertions(+), 45 deletions(-) delete mode 100644 webrtc-sys/libwebrtc/patches/abseil_use_optional.patch diff --git a/webrtc-sys/build.rs b/webrtc-sys/build.rs index 691c966e8..3b2914d9a 100644 --- a/webrtc-sys/build.rs +++ b/webrtc-sys/build.rs @@ -186,7 +186,9 @@ fn main() { _ => {} } - builder.flag("-std=c++2a"); + builder + .flag("-Wno-changes-meaning") + .flag("-std=c++20"); } "macos" => { println!("cargo:rustc-link-lib=framework=Foundation"); diff --git a/webrtc-sys/libwebrtc/build_android.sh b/webrtc-sys/libwebrtc/build_android.sh index 692657d9d..7eb06ceb0 100755 --- a/webrtc-sys/libwebrtc/build_android.sh +++ b/webrtc-sys/libwebrtc/build_android.sh @@ -72,10 +72,6 @@ git apply "$COMMAND_DIR/patches/ssl_verify_callback_with_native_handle.patch" -v git apply "$COMMAND_DIR/patches/add_deps.patch" -v --ignore-space-change --ignore-whitespace --whitespace=nowarn git apply "$COMMAND_DIR/patches/android_use_libunwind.patch" -v --ignore-space-change --ignore-whitespace --whitespace=nowarn -cd third_party -git apply "$COMMAND_DIR/patches/abseil_use_optional.patch" -v --ignore-space-change --ignore-whitespace --whitespace=nowarn -cd .. - cd .. mkdir -p "$ARTIFACTS_DIR/lib" diff --git a/webrtc-sys/libwebrtc/build_linux.sh b/webrtc-sys/libwebrtc/build_linux.sh index f17435d36..482e847ef 100755 --- a/webrtc-sys/libwebrtc/build_linux.sh +++ b/webrtc-sys/libwebrtc/build_linux.sh @@ -71,10 +71,6 @@ git apply "$COMMAND_DIR/patches/add_licenses.patch" -v --ignore-space-change --i git apply "$COMMAND_DIR/patches/ssl_verify_callback_with_native_handle.patch" -v --ignore-space-change --ignore-whitespace --whitespace=nowarn git apply "$COMMAND_DIR/patches/add_deps.patch" -v --ignore-space-change --ignore-whitespace --whitespace=nowarn -cd third_party -git apply "$COMMAND_DIR/patches/abseil_use_optional.patch" -v --ignore-space-change --ignore-whitespace --whitespace=nowarn -cd .. - cd .. mkdir -p "$ARTIFACTS_DIR/lib" @@ -99,9 +95,9 @@ args="is_debug=$debug \ enable_libaom=true \ is_component_build=false \ enable_stripping=true \ - use_goma=false \ ffmpeg_branding=\"Chrome\" \ rtc_use_h264=true \ + rtc_use_h265=true \ rtc_use_pipewire=false \ symbol_level=0 \ enable_iterator_debugging=false \ @@ -117,7 +113,7 @@ ninja -C "$OUTPUT_DIR" :default # make libwebrtc.a # don't include nasm ar -rc "$ARTIFACTS_DIR/lib/libwebrtc.a" `find "$OUTPUT_DIR/obj" -name '*.o' -not -path "*/third_party/nasm/*"` -objcopy --redefine-syms="$COMMAND_DIR/boringssl_prefix_symbols.txt" "$ARTIFACTS_DIR/lib/libwebrtc.a" +objcopy --target=elf64-x86-64 --redefine-syms="$COMMAND_DIR/boringssl_prefix_symbols.txt" "$ARTIFACTS_DIR/lib/libwebrtc.a" python3 "./src/tools_webrtc/libs/generate_licenses.py" \ --target :default "$OUTPUT_DIR" "$OUTPUT_DIR" diff --git a/webrtc-sys/libwebrtc/patches/abseil_use_optional.patch b/webrtc-sys/libwebrtc/patches/abseil_use_optional.patch deleted file mode 100644 index 476ad2619..000000000 --- a/webrtc-sys/libwebrtc/patches/abseil_use_optional.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/abseil-cpp/absl/base/options.h b/abseil-cpp/absl/base/options.h -index bd43b6ef0..ab5917e75 100644 ---- a/abseil-cpp/absl/base/options.h -+++ b/abseil-cpp/absl/base/options.h -@@ -121,7 +121,7 @@ - // absl::optional is a typedef of std::optional, use the feature macro - // ABSL_USES_STD_OPTIONAL. - --#define ABSL_OPTION_USE_STD_OPTIONAL 2 -+#define ABSL_OPTION_USE_STD_OPTIONAL 0 - - - // ABSL_OPTION_USE_STD_STRING_VIEW diff --git a/webrtc-sys/libwebrtc/patches/add_deps.patch b/webrtc-sys/libwebrtc/patches/add_deps.patch index 1b383de4e..92ae3fa8f 100644 --- a/webrtc-sys/libwebrtc/patches/add_deps.patch +++ b/webrtc-sys/libwebrtc/patches/add_deps.patch @@ -1,5 +1,5 @@ diff --git a/BUILD.gn b/BUILD.gn -index d5289b85d7..76823f6cff 100644 +index ca8d8faa61..13e07a2f28 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -24,6 +24,9 @@ @@ -12,7 +12,7 @@ index d5289b85d7..76823f6cff 100644 if (rtc_enable_protobuf) { import("//third_party/protobuf/proto_library.gni") } -@@ -292,6 +295,10 @@ config("common_config") { +@@ -331,6 +334,10 @@ config("common_config") { defines += [ "WEBRTC_INCLUDE_INTERNAL_AUDIO_DEVICE" ] } @@ -23,7 +23,7 @@ index d5289b85d7..76823f6cff 100644 if (rtc_libvpx_build_vp9) { defines += [ "RTC_ENABLE_VP9" ] } -@@ -517,6 +524,10 @@ if (!build_with_chromium) { +@@ -565,6 +572,10 @@ if (!build_with_chromium) { "pc:rtc_pc", "sdk", "video", diff --git a/webrtc-sys/libwebrtc/patches/ssl_verify_callback_with_native_handle.patch b/webrtc-sys/libwebrtc/patches/ssl_verify_callback_with_native_handle.patch index ccfb138f7..df2a8ed69 100644 --- a/webrtc-sys/libwebrtc/patches/ssl_verify_callback_with_native_handle.patch +++ b/webrtc-sys/libwebrtc/patches/ssl_verify_callback_with_native_handle.patch @@ -1,8 +1,8 @@ diff --git a/rtc_base/boringssl_certificate.cc b/rtc_base/boringssl_certificate.cc -index 99b2ab3e24..c37d6d963f 100644 +index 016b4dabba..1a0c1b8d42 100644 --- a/rtc_base/boringssl_certificate.cc +++ b/rtc_base/boringssl_certificate.cc -@@ -253,6 +253,12 @@ BoringSSLCertificate::BoringSSLCertificate( +@@ -259,6 +259,12 @@ BoringSSLCertificate::BoringSSLCertificate( RTC_DCHECK(cert_buffer_ != nullptr); } @@ -16,10 +16,10 @@ index 99b2ab3e24..c37d6d963f 100644 OpenSSLKeyPair* key_pair, const SSLIdentityParams& params) { diff --git a/rtc_base/boringssl_certificate.h b/rtc_base/boringssl_certificate.h -index 8b4577a17c..e1fe26cba5 100644 +index 926dd332ec..5c62c63390 100644 --- a/rtc_base/boringssl_certificate.h +++ b/rtc_base/boringssl_certificate.h -@@ -33,6 +33,7 @@ class OpenSSLKeyPair; +@@ -34,6 +34,7 @@ namespace webrtc { class BoringSSLCertificate final : public SSLCertificate { public: explicit BoringSSLCertificate(bssl::UniquePtr cert_buffer); @@ -27,7 +27,7 @@ index 8b4577a17c..e1fe26cba5 100644 static std::unique_ptr Generate( OpenSSLKeyPair* key_pair, -@@ -74,6 +75,11 @@ class BoringSSLCertificate final : public SSLCertificate { +@@ -66,6 +67,11 @@ class BoringSSLCertificate final : public SSLCertificate { private: // A handle to the DER encoded certificate data. bssl::UniquePtr cert_buffer_; @@ -38,12 +38,12 @@ index 8b4577a17c..e1fe26cba5 100644 + SSL* ssl() const { return ssl_; } }; - } // namespace rtc + } // namespace webrtc diff --git a/rtc_base/openssl_adapter.cc b/rtc_base/openssl_adapter.cc -index bc10e619eb..836ef9ea18 100644 +index cb5dfc6a85..a2de51ee74 100644 --- a/rtc_base/openssl_adapter.cc +++ b/rtc_base/openssl_adapter.cc -@@ -822,7 +822,7 @@ enum ssl_verify_result_t OpenSSLAdapter::SSLVerifyInternal(SSL* ssl, +@@ -840,7 +840,7 @@ enum ssl_verify_result_t OpenSSLAdapter::SSLVerifyInternal(SSL* ssl, return ssl_verify_invalid; } @@ -52,20 +52,20 @@ index bc10e619eb..836ef9ea18 100644 if (!ssl_cert_verifier_->Verify(cert)) { RTC_LOG(LS_WARNING) << "Failed to verify certificate using custom callback"; return ssl_verify_invalid; -@@ -894,7 +894,7 @@ int OpenSSLAdapter::SSLVerifyInternal(int previous_status, +@@ -912,7 +912,7 @@ int OpenSSLAdapter::SSLVerifyInternal(int previous_status, RTC_LOG(LS_ERROR) << "Failed to allocate CRYPTO_BUFFER."; return previous_status; } - const BoringSSLCertificate cert(std::move(crypto_buffer)); + const BoringSSLCertificate cert(std::move(crypto_buffer), ssl); #else - const OpenSSLCertificate cert(X509_STORE_CTX_get_current_cert(store)); + const webrtc::OpenSSLCertificate cert(X509_STORE_CTX_get_current_cert(store)); #endif diff --git a/rtc_base/openssl_stream_adapter.cc b/rtc_base/openssl_stream_adapter.cc -index dd82e4f061..6d7e39c534 100644 +index b46faff911..537171b1f3 100644 --- a/rtc_base/openssl_stream_adapter.cc +++ b/rtc_base/openssl_stream_adapter.cc -@@ -1154,7 +1154,7 @@ enum ssl_verify_result_t OpenSSLStreamAdapter::SSLVerifyCallback( +@@ -1181,7 +1181,7 @@ enum ssl_verify_result_t OpenSSLStreamAdapter::SSLVerifyCallback( // Creates certificate chain. std::vector> cert_chain; for (CRYPTO_BUFFER* cert : chain) { diff --git a/webrtc-sys/src/nvidia/h264_encoder_impl.cpp b/webrtc-sys/src/nvidia/h264_encoder_impl.cpp index 4d2eee165..d48546499 100644 --- a/webrtc-sys/src/nvidia/h264_encoder_impl.cpp +++ b/webrtc-sys/src/nvidia/h264_encoder_impl.cpp @@ -80,7 +80,8 @@ NvidiaH264EncoderImpl::NvidiaH264EncoderImpl( CUmemorytype memory_type, NV_ENC_BUFFER_FORMAT nv_format, const SdpVideoFormat& format) - : encoder_(nullptr), + : env_(env), + encoder_(nullptr), cu_context_(context), cu_memory_type_(memory_type), cu_scaled_array_(nullptr), @@ -237,7 +238,7 @@ int32_t NvidiaH264EncoderImpl::InitEncode( return WEBRTC_VIDEO_CODEC_ERROR; } - SimulcastRateAllocator init_allocator(codec_); + SimulcastRateAllocator init_allocator(env_, codec_); VideoBitrateAllocation allocation = init_allocator.Allocate(VideoBitrateAllocationParameters( DataRate::KilobitsPerSec(codec_.startBitrate), codec_.maxFramerate)); @@ -361,7 +362,7 @@ int32_t NvidiaH264EncoderImpl::ProcessEncodedFrame( const ::webrtc::VideoFrame& inputFrame) { encoded_image_._encodedWidth = encoder_->GetEncodeWidth(); encoded_image_._encodedHeight = encoder_->GetEncodeHeight(); - encoded_image_.SetRtpTimestamp(inputFrame.timestamp()); + encoded_image_.SetRtpTimestamp(inputFrame.rtp_timestamp()); encoded_image_.SetSimulcastIndex(0); encoded_image_.ntp_time_ms_ = inputFrame.ntp_time_ms(); encoded_image_.capture_time_ms_ = inputFrame.render_time_ms(); @@ -371,7 +372,7 @@ int32_t NvidiaH264EncoderImpl::ProcessEncodedFrame( encoded_image_._frameType = VideoFrameType::kVideoFrameDelta; encoded_image_.SetColorSpace(inputFrame.color_space()); std::vector naluIndices = - H264::FindNaluIndices(packet.data(), packet.size()); + H264::FindNaluIndices(MakeArrayView(packet.data(), packet.size())); for (uint32_t i = 0; i < naluIndices.size(); i++) { const H264::NaluType naluType = H264::ParseNaluType(packet[naluIndices[i].payload_start_offset]); diff --git a/webrtc-sys/src/nvidia/h264_encoder_impl.h b/webrtc-sys/src/nvidia/h264_encoder_impl.h index d1009fbb1..b50a7e308 100644 --- a/webrtc-sys/src/nvidia/h264_encoder_impl.h +++ b/webrtc-sys/src/nvidia/h264_encoder_impl.h @@ -67,6 +67,7 @@ class NvidiaH264EncoderImpl : public VideoEncoder { int32_t ProcessEncodedFrame(std::vector& packet, const ::webrtc::VideoFrame& inputFrame); private: + const webrtc::Environment& env_; EncodedImageCallback* encoded_image_callback_ = nullptr; std::unique_ptr encoder_; diff --git a/webrtc-sys/src/vaapi/h264_encoder_impl.cpp b/webrtc-sys/src/vaapi/h264_encoder_impl.cpp index e740ebb7e..b2232bdcd 100644 --- a/webrtc-sys/src/vaapi/h264_encoder_impl.cpp +++ b/webrtc-sys/src/vaapi/h264_encoder_impl.cpp @@ -34,7 +34,8 @@ enum H264EncoderImplEvent { VAAPIH264EncoderWrapper::VAAPIH264EncoderWrapper(const webrtc::Environment& env, const SdpVideoFormat& format) - : encoder_(new livekit::VaapiH264EncoderWrapper()), + : env_(env), + encoder_(new livekit::VaapiH264EncoderWrapper()), packetization_mode_( H264EncoderSettings::Parse(format).packetization_mode), format_(format) { @@ -152,7 +153,7 @@ int32_t VAAPIH264EncoderWrapper::InitEncode( va_profile, VA_RC_CBR); } - SimulcastRateAllocator init_allocator(codec_); + SimulcastRateAllocator init_allocator(env_, codec_); VideoBitrateAllocation allocation = init_allocator.Allocate(VideoBitrateAllocationParameters( DataRate::KilobitsPerSec(codec_.startBitrate), codec_.maxFramerate)); diff --git a/webrtc-sys/src/vaapi/h264_encoder_impl.h b/webrtc-sys/src/vaapi/h264_encoder_impl.h index ad67e7fb5..be800a757 100644 --- a/webrtc-sys/src/vaapi/h264_encoder_impl.h +++ b/webrtc-sys/src/vaapi/h264_encoder_impl.h @@ -61,6 +61,7 @@ class VAAPIH264EncoderWrapper : public VideoEncoder { VAProfile GetVAProfile() const; private: + const webrtc::Environment& env_; EncodedImageCallback* encoded_image_callback_ = nullptr; std::unique_ptr encoder_; LayerConfig configuration_; From 1815e23046ead6636180d58db5f0ced1792e8a50 Mon Sep 17 00:00:00 2001 From: cloudwebrtc Date: Tue, 16 Sep 2025 13:30:06 +0800 Subject: [PATCH 03/52] fix. --- webrtc-sys/libwebrtc/build_linux.sh | 10 ++++++++-- webrtc-sys/libwebrtc/patches/force_gcc.patch | 13 +++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 webrtc-sys/libwebrtc/patches/force_gcc.patch diff --git a/webrtc-sys/libwebrtc/build_linux.sh b/webrtc-sys/libwebrtc/build_linux.sh index 482e847ef..30375c580 100755 --- a/webrtc-sys/libwebrtc/build_linux.sh +++ b/webrtc-sys/libwebrtc/build_linux.sh @@ -71,7 +71,12 @@ git apply "$COMMAND_DIR/patches/add_licenses.patch" -v --ignore-space-change --i git apply "$COMMAND_DIR/patches/ssl_verify_callback_with_native_handle.patch" -v --ignore-space-change --ignore-whitespace --whitespace=nowarn git apply "$COMMAND_DIR/patches/add_deps.patch" -v --ignore-space-change --ignore-whitespace --whitespace=nowarn -cd .. +cd build + +git apply "$COMMAND_DIR/patches/force_gcc.patch" -v --ignore-space-change --ignore-whitespace --whitespace=nowarn + +cd ../.. + mkdir -p "$ARTIFACTS_DIR/lib" @@ -102,6 +107,7 @@ args="is_debug=$debug \ symbol_level=0 \ enable_iterator_debugging=false \ use_rtti=true \ + is_clang=false \ rtc_use_x11=false" # generate ninja files @@ -113,7 +119,7 @@ ninja -C "$OUTPUT_DIR" :default # make libwebrtc.a # don't include nasm ar -rc "$ARTIFACTS_DIR/lib/libwebrtc.a" `find "$OUTPUT_DIR/obj" -name '*.o' -not -path "*/third_party/nasm/*"` -objcopy --target=elf64-x86-64 --redefine-syms="$COMMAND_DIR/boringssl_prefix_symbols.txt" "$ARTIFACTS_DIR/lib/libwebrtc.a" +objcopy --redefine-syms="$COMMAND_DIR/boringssl_prefix_symbols.txt" "$ARTIFACTS_DIR/lib/libwebrtc.a" python3 "./src/tools_webrtc/libs/generate_licenses.py" \ --target :default "$OUTPUT_DIR" "$OUTPUT_DIR" diff --git a/webrtc-sys/libwebrtc/patches/force_gcc.patch b/webrtc-sys/libwebrtc/patches/force_gcc.patch new file mode 100644 index 000000000..c004444c0 --- /dev/null +++ b/webrtc-sys/libwebrtc/patches/force_gcc.patch @@ -0,0 +1,13 @@ +diff --git a/config/c++/c++.gni b/config/c++/c++.gni +index c29d898fb..5ef014e51 100644 +--- a/config/c++/c++.gni ++++ b/config/c++/c++.gni +@@ -62,7 +62,7 @@ declare_args() { + # case. + # We disable that on LibFuzzer builds because it breaks the libfuzzer + # runtime. See crbug.com/411020147. +- use_llvm_libatomic = !is_apple && !is_nacl && !use_libfuzzer ++ use_llvm_libatomic = !is_apple && !is_nacl && !use_libfuzzer && !is_linux + } + + if (use_implicit_libcxx_modules) { From ed6063dff2b85ab0766a18591c090ab4d83c3352 Mon Sep 17 00:00:00 2001 From: CloudWebRTC Date: Tue, 16 Sep 2025 13:52:35 +0800 Subject: [PATCH 04/52] Add g++ for aarch64 to Ubuntu dependencies --- .github/workflows/webrtc-builds.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/webrtc-builds.yml b/.github/workflows/webrtc-builds.yml index def67d31d..a9a71b00c 100644 --- a/.github/workflows/webrtc-builds.yml +++ b/.github/workflows/webrtc-builds.yml @@ -119,7 +119,7 @@ jobs: if: ${{ matrix.target.os == 'ubuntu-latest' }} run: | sudo apt update -y - sudo apt install -y ninja-build pkg-config openjdk-11-jdk + sudo apt install -y ninja-build pkg-config openjdk-11-jdk g++-aarch64-linux-gnu - name: Install macos dependencies if: ${{ matrix.target.os == 'macos-latest' }} From 687edc52995fc1c2cddefcafa3197958f21b186d Mon Sep 17 00:00:00 2001 From: cloudwebrtc Date: Tue, 16 Sep 2025 14:47:02 +0800 Subject: [PATCH 05/52] fix build for linux arm64. --- webrtc-sys/libwebrtc/build_linux.sh | 3 +++ webrtc-sys/libwebrtc/patches/force_gcc.patch | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/webrtc-sys/libwebrtc/build_linux.sh b/webrtc-sys/libwebrtc/build_linux.sh index 30375c580..8baa7c6be 100755 --- a/webrtc-sys/libwebrtc/build_linux.sh +++ b/webrtc-sys/libwebrtc/build_linux.sh @@ -93,6 +93,9 @@ args="is_debug=$debug \ rtc_enable_protobuf=false \ treat_warnings_as_errors=false \ use_custom_libcxx=false \ + use_llvm_libatomic=false \ + use_libcxx_modules=false \ + use_custom_libcxx_for_host=false \ rtc_include_tests=false \ rtc_build_tools=false \ rtc_build_examples=false \ diff --git a/webrtc-sys/libwebrtc/patches/force_gcc.patch b/webrtc-sys/libwebrtc/patches/force_gcc.patch index c004444c0..c409737d3 100644 --- a/webrtc-sys/libwebrtc/patches/force_gcc.patch +++ b/webrtc-sys/libwebrtc/patches/force_gcc.patch @@ -11,3 +11,15 @@ index c29d898fb..5ef014e51 100644 } if (use_implicit_libcxx_modules) { +diff --git a/config/linux/BUILD.gn b/config/linux/BUILD.gn +index 131bb71d1..36c86c48e 100644 +--- a/config/linux/BUILD.gn ++++ b/config/linux/BUILD.gn +@@ -15,6 +15,7 @@ group("linux") { + # is applied to all targets. It is here to separate out the logic that is + # Linux-only. This is not applied to Android, but is applied to ChromeOS. + config("compiler") { ++ cflags_cc = [ "-Wno-changes-meaning" ] + if (current_cpu == "arm64") { + import("//build/config/arm.gni") + cflags = [] From f12118e6ed54f8caf45cef802cc43a38c125c1e0 Mon Sep 17 00:00:00 2001 From: CloudWebRTC Date: Tue, 16 Sep 2025 15:29:38 +0800 Subject: [PATCH 06/52] Remove goma usage and switch to autoninja --- webrtc-sys/libwebrtc/build_android.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/webrtc-sys/libwebrtc/build_android.sh b/webrtc-sys/libwebrtc/build_android.sh index 7eb06ceb0..1222cfdfb 100755 --- a/webrtc-sys/libwebrtc/build_android.sh +++ b/webrtc-sys/libwebrtc/build_android.sh @@ -94,7 +94,6 @@ args="is_debug=$debug \ rtc_libvpx_build_vp9=false \ is_component_build=false \ enable_stripping=true \ - use_goma=false \ rtc_use_h264=false \ rtc_use_pipewire=false \ symbol_level=0 \ @@ -109,7 +108,7 @@ fi gn gen "$OUTPUT_DIR" --root="src" --args="${args}" # build shared library -ninja -C "$OUTPUT_DIR" :default \ +autoninja -C "$OUTPUT_DIR" :default \ sdk/android:native_api \ sdk/android:libwebrtc \ sdk/android:libjingle_peerconnection_so From d6c8d68a1213163d108c66691a007a6bfbf541ab Mon Sep 17 00:00:00 2001 From: cloudwebrtc Date: Tue, 16 Sep 2025 15:42:37 +0800 Subject: [PATCH 07/52] fix android build. --- webrtc-sys/libwebrtc/patches/android_use_libunwind.patch | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/webrtc-sys/libwebrtc/patches/android_use_libunwind.patch b/webrtc-sys/libwebrtc/patches/android_use_libunwind.patch index 82512a2fc..1339b31d8 100644 --- a/webrtc-sys/libwebrtc/patches/android_use_libunwind.patch +++ b/webrtc-sys/libwebrtc/patches/android_use_libunwind.patch @@ -2,7 +2,7 @@ +++ src/buildtools/third_party/libunwind/BUILD.gn 2023-07-10 10:19:23 @@ -21,7 +21,7 @@ config("libunwind_config") { - # TODO(crbug.com/1458042): Move this build file to third_party/libc++/BUILD.gn once submodule migration is done + # TODO(crbug.com/40273848): Move this build file to third_party/libc++/BUILD.gn once submodule migration is done source_set("libunwind") { - visibility = [ "//buildtools/third_party/libc++abi" ] + visibility = [ "//buildtools/third_party/libc++abi", "//build/config:common_deps" ] @@ -11,7 +11,7 @@ } --- src/build/config/BUILD.gn 2023-07-10 10:23:49 +++ src/build/config/BUILD.gn 2023-07-10 10:23:54 -@@ -246,6 +246,8 @@ group("common_deps") { +@@ -296,6 +296,8 @@ group("common_deps") { if (use_custom_libcxx) { public_deps += [ "//buildtools/third_party/libc++" ] @@ -19,4 +19,4 @@ + public_deps += [ "//buildtools/third_party/libunwind" ] } - if (use_afl) { + if (use_llvm_libatomic) { From 770f172c05058cabe0cb04075ba20ee1433cd156 Mon Sep 17 00:00:00 2001 From: cloudwebrtc Date: Tue, 16 Sep 2025 16:02:37 +0800 Subject: [PATCH 08/52] fix build on linux arm64 for gcc. --- webrtc-sys/libwebrtc/build_linux.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/webrtc-sys/libwebrtc/build_linux.sh b/webrtc-sys/libwebrtc/build_linux.sh index 8baa7c6be..813c552c7 100755 --- a/webrtc-sys/libwebrtc/build_linux.sh +++ b/webrtc-sys/libwebrtc/build_linux.sh @@ -108,6 +108,7 @@ args="is_debug=$debug \ rtc_use_h265=true \ rtc_use_pipewire=false \ symbol_level=0 \ + libyuv_use_sme=false \ enable_iterator_debugging=false \ use_rtti=true \ is_clang=false \ From 996a20294c7c5f166bfbc20e3c05922575c3f0d4 Mon Sep 17 00:00:00 2001 From: CloudWebRTC Date: Tue, 16 Sep 2025 16:23:25 +0800 Subject: [PATCH 09/52] Update Windows OS version in workflow configuration --- .github/workflows/webrtc-builds.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/webrtc-builds.yml b/.github/workflows/webrtc-builds.yml index a9a71b00c..67b4640bc 100644 --- a/.github/workflows/webrtc-builds.yml +++ b/.github/workflows/webrtc-builds.yml @@ -31,7 +31,7 @@ jobs: arch: x64 - name: win - os: windows-latest + os: windows-2025 cmd: .\build_windows.cmd arch: arm64 From 2b90351ea276743fecea2f56e14bcc918a5fa1d5 Mon Sep 17 00:00:00 2001 From: CloudWebRTC Date: Tue, 16 Sep 2025 18:07:58 +0800 Subject: [PATCH 10/52] Add GCC 14 installation steps for Ubuntu --- .github/workflows/webrtc-builds.yml | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/.github/workflows/webrtc-builds.yml b/.github/workflows/webrtc-builds.yml index 67b4640bc..c89fcfff6 100644 --- a/.github/workflows/webrtc-builds.yml +++ b/.github/workflows/webrtc-builds.yml @@ -115,11 +115,31 @@ jobs: run: | pip3 install setuptools # pkg_resources is sometimes not found? + - name: Add GCC PPA and install GCC 14 + if: ${{ matrix.target.os == 'ubuntu-latest' }} + run: | + sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y + sudo apt update + sudo apt install gcc-14 g++-14 -y + + - name: Verify GCC 14 installation + if: ${{ matrix.target.os == 'ubuntu-latest' }} + run: | + gcc-14 --version + g++-14 --version + + - name: Set GCC 14 as default (optional) + if: ${{ matrix.target.os == 'ubuntu-latest' }} + run: | + update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-14 140 --slave /usr/bin/g++ g++ /usr/bin/g++-14 + sudo update-alternatives --config gcc + gcc --version + - name: Install linux dependencies if: ${{ matrix.target.os == 'ubuntu-latest' }} run: | sudo apt update -y - sudo apt install -y ninja-build pkg-config openjdk-11-jdk g++-aarch64-linux-gnu + sudo apt install -y ninja-build pkg-config openjdk-11-jdk g++-14-aarch64-linux-gnu - name: Install macos dependencies if: ${{ matrix.target.os == 'macos-latest' }} From 79872adaba896ae2d128b868f92a641553346437 Mon Sep 17 00:00:00 2001 From: CloudWebRTC Date: Tue, 16 Sep 2025 18:11:30 +0800 Subject: [PATCH 11/52] Update webrtc-builds.yml --- .github/workflows/webrtc-builds.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/webrtc-builds.yml b/.github/workflows/webrtc-builds.yml index c89fcfff6..5d841548a 100644 --- a/.github/workflows/webrtc-builds.yml +++ b/.github/workflows/webrtc-builds.yml @@ -131,7 +131,7 @@ jobs: - name: Set GCC 14 as default (optional) if: ${{ matrix.target.os == 'ubuntu-latest' }} run: | - update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-14 140 --slave /usr/bin/g++ g++ /usr/bin/g++-14 + sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-14 140 --slave /usr/bin/g++ g++ /usr/bin/g++-14 sudo update-alternatives --config gcc gcc --version From b698d1af2de2f24572033ce6eb23151f2f3da087 Mon Sep 17 00:00:00 2001 From: CloudWebRTC Date: Tue, 16 Sep 2025 18:39:16 +0800 Subject: [PATCH 12/52] Change Windows OS to latest and add SDK installation --- .github/workflows/webrtc-builds.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/webrtc-builds.yml b/.github/workflows/webrtc-builds.yml index 5d841548a..50f50aae1 100644 --- a/.github/workflows/webrtc-builds.yml +++ b/.github/workflows/webrtc-builds.yml @@ -31,7 +31,7 @@ jobs: arch: x64 - name: win - os: windows-2025 + os: windows-latest cmd: .\build_windows.cmd arch: arm64 @@ -151,6 +151,8 @@ jobs: Invoke-WebRequest -Uri "https://github.com/ninja-build/ninja/releases/latest/download/ninja-win.zip" -OutFile ninja.zip Expand-Archive -Path ninja.zip -DestinationPath ${{ github.workspace }}\ninja echo "${{ github.workspace }}\ninja" | Out-File -Append -Encoding utf8 -FilePath $Env:GITHUB_PATH + powershell -c "Invoke-WebRequest -Uri 'https://go.microsoft.com/fwlink/?linkid=2120843' -OutFile winsdksetup.exe -UseBasicParsing ;" + winsdksetup.exe /features + /q /norestart - name: Print ninja version run: ninja --version From 03921f36d4c43d8685b6dc353f8ae2b4bb7faa95 Mon Sep 17 00:00:00 2001 From: CloudWebRTC Date: Tue, 16 Sep 2025 18:44:11 +0800 Subject: [PATCH 13/52] Update webrtc-builds.yml --- .github/workflows/webrtc-builds.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/webrtc-builds.yml b/.github/workflows/webrtc-builds.yml index 50f50aae1..a283b29ea 100644 --- a/.github/workflows/webrtc-builds.yml +++ b/.github/workflows/webrtc-builds.yml @@ -151,8 +151,8 @@ jobs: Invoke-WebRequest -Uri "https://github.com/ninja-build/ninja/releases/latest/download/ninja-win.zip" -OutFile ninja.zip Expand-Archive -Path ninja.zip -DestinationPath ${{ github.workspace }}\ninja echo "${{ github.workspace }}\ninja" | Out-File -Append -Encoding utf8 -FilePath $Env:GITHUB_PATH - powershell -c "Invoke-WebRequest -Uri 'https://go.microsoft.com/fwlink/?linkid=2120843' -OutFile winsdksetup.exe -UseBasicParsing ;" - winsdksetup.exe /features + /q /norestart + Invoke-WebRequest -Uri "https://go.microsoft.com/fwlink/?linkid=2120843" -OutFile ${{ github.workspace }}\winsdksetup.exe + ${{ github.workspace }}\winsdksetup.exe /features OptionId.WindowsDesktopDebuggers /q /norestart - name: Print ninja version run: ninja --version From 3d304de1d28fa5711f08cf1498af19915710436a Mon Sep 17 00:00:00 2001 From: CloudWebRTC Date: Tue, 16 Sep 2025 19:10:28 +0800 Subject: [PATCH 14/52] Update webrtc-builds.yml --- .github/workflows/webrtc-builds.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/webrtc-builds.yml b/.github/workflows/webrtc-builds.yml index a283b29ea..6fe6cee85 100644 --- a/.github/workflows/webrtc-builds.yml +++ b/.github/workflows/webrtc-builds.yml @@ -120,13 +120,14 @@ jobs: run: | sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y sudo apt update - sudo apt install gcc-14 g++-14 -y + sudo apt install gcc-14 g++-14 g++-14-aarch64-linux-gnu -y - name: Verify GCC 14 installation if: ${{ matrix.target.os == 'ubuntu-latest' }} run: | gcc-14 --version g++-14 --version + aarch64-linux-gnu-g++-14 --version - name: Set GCC 14 as default (optional) if: ${{ matrix.target.os == 'ubuntu-latest' }} @@ -134,12 +135,15 @@ jobs: sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-14 140 --slave /usr/bin/g++ g++ /usr/bin/g++-14 sudo update-alternatives --config gcc gcc --version + sudo update-alternatives --install /usr/bin/aarch64-linux-gnu-gcc aarch64-linux-gnu-gcc /usr/bin/aarch64-linux-gnu-gcc-14 140 --slave /usr/bin/aarch64-linux-gnu-g++ aarch64-linux-gnu-g++ /usr/bin/aarch64-linux-gnu-g++-14 + sudo update-alternatives --config aarch64-linux-gnu-gcc + aarch64-linux-gnu-gcc --version - name: Install linux dependencies if: ${{ matrix.target.os == 'ubuntu-latest' }} run: | sudo apt update -y - sudo apt install -y ninja-build pkg-config openjdk-11-jdk g++-14-aarch64-linux-gnu + sudo apt install -y ninja-build pkg-config openjdk-11-jdk - name: Install macos dependencies if: ${{ matrix.target.os == 'macos-latest' }} From 016bdef4e74535071cd1c1079285d3898b580b22 Mon Sep 17 00:00:00 2001 From: CloudWebRTC Date: Tue, 16 Sep 2025 19:15:21 +0800 Subject: [PATCH 15/52] Update webrtc-builds.yml --- .github/workflows/webrtc-builds.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/webrtc-builds.yml b/.github/workflows/webrtc-builds.yml index 6fe6cee85..bdd4748ec 100644 --- a/.github/workflows/webrtc-builds.yml +++ b/.github/workflows/webrtc-builds.yml @@ -156,7 +156,7 @@ jobs: Expand-Archive -Path ninja.zip -DestinationPath ${{ github.workspace }}\ninja echo "${{ github.workspace }}\ninja" | Out-File -Append -Encoding utf8 -FilePath $Env:GITHUB_PATH Invoke-WebRequest -Uri "https://go.microsoft.com/fwlink/?linkid=2120843" -OutFile ${{ github.workspace }}\winsdksetup.exe - ${{ github.workspace }}\winsdksetup.exe /features OptionId.WindowsDesktopDebuggers /q /norestart + ${{ github.workspace }}\winsdksetup.exe /features + /q /norestart - name: Print ninja version run: ninja --version From 5edf00e8c3aa8a871313ed348cd0d1e1ac4724c9 Mon Sep 17 00:00:00 2001 From: CloudWebRTC Date: Tue, 16 Sep 2025 19:42:06 +0800 Subject: [PATCH 16/52] Update webrtc-builds.yml --- .github/workflows/webrtc-builds.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/webrtc-builds.yml b/.github/workflows/webrtc-builds.yml index bdd4748ec..b8e4786db 100644 --- a/.github/workflows/webrtc-builds.yml +++ b/.github/workflows/webrtc-builds.yml @@ -155,8 +155,8 @@ jobs: Invoke-WebRequest -Uri "https://github.com/ninja-build/ninja/releases/latest/download/ninja-win.zip" -OutFile ninja.zip Expand-Archive -Path ninja.zip -DestinationPath ${{ github.workspace }}\ninja echo "${{ github.workspace }}\ninja" | Out-File -Append -Encoding utf8 -FilePath $Env:GITHUB_PATH - Invoke-WebRequest -Uri "https://go.microsoft.com/fwlink/?linkid=2120843" -OutFile ${{ github.workspace }}\winsdksetup.exe - ${{ github.workspace }}\winsdksetup.exe /features + /q /norestart + Invoke-WebRequest -Uri "https://go.microsoft.com/fwlink/?linkid=2317808" -OutFile ${{ github.workspace }}\winsdksetup.exe + ${{ github.workspace }}\winsdksetup.exe /features OptionId.WindowsDesktopDebuggers /q /norestart - name: Print ninja version run: ninja --version From 48f658721fc4a57d32a3abee1ecab75d1ab54f00 Mon Sep 17 00:00:00 2001 From: CloudWebRTC Date: Tue, 16 Sep 2025 19:43:56 +0800 Subject: [PATCH 17/52] Update build_linux.sh --- webrtc-sys/libwebrtc/build_linux.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/webrtc-sys/libwebrtc/build_linux.sh b/webrtc-sys/libwebrtc/build_linux.sh index 813c552c7..8baa7c6be 100755 --- a/webrtc-sys/libwebrtc/build_linux.sh +++ b/webrtc-sys/libwebrtc/build_linux.sh @@ -108,7 +108,6 @@ args="is_debug=$debug \ rtc_use_h265=true \ rtc_use_pipewire=false \ symbol_level=0 \ - libyuv_use_sme=false \ enable_iterator_debugging=false \ use_rtti=true \ is_clang=false \ From 10848d6711221ff9992969c56ebeb3982540a2c1 Mon Sep 17 00:00:00 2001 From: CloudWebRTC Date: Tue, 16 Sep 2025 19:55:38 +0800 Subject: [PATCH 18/52] Update webrtc-builds.yml --- .github/workflows/webrtc-builds.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/webrtc-builds.yml b/.github/workflows/webrtc-builds.yml index b8e4786db..fee484dea 100644 --- a/.github/workflows/webrtc-builds.yml +++ b/.github/workflows/webrtc-builds.yml @@ -31,7 +31,7 @@ jobs: arch: x64 - name: win - os: windows-latest + os: windows-2019 cmd: .\build_windows.cmd arch: arm64 From 756d71ab6b3f1fbc1843b9210ee79839eafa3198 Mon Sep 17 00:00:00 2001 From: CloudWebRTC Date: Tue, 16 Sep 2025 20:25:33 +0800 Subject: [PATCH 19/52] Update webrtc-builds.yml --- .github/workflows/webrtc-builds.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/webrtc-builds.yml b/.github/workflows/webrtc-builds.yml index fee484dea..618094050 100644 --- a/.github/workflows/webrtc-builds.yml +++ b/.github/workflows/webrtc-builds.yml @@ -31,7 +31,7 @@ jobs: arch: x64 - name: win - os: windows-2019 + os: windows-latest cmd: .\build_windows.cmd arch: arm64 @@ -155,8 +155,6 @@ jobs: Invoke-WebRequest -Uri "https://github.com/ninja-build/ninja/releases/latest/download/ninja-win.zip" -OutFile ninja.zip Expand-Archive -Path ninja.zip -DestinationPath ${{ github.workspace }}\ninja echo "${{ github.workspace }}\ninja" | Out-File -Append -Encoding utf8 -FilePath $Env:GITHUB_PATH - Invoke-WebRequest -Uri "https://go.microsoft.com/fwlink/?linkid=2317808" -OutFile ${{ github.workspace }}\winsdksetup.exe - ${{ github.workspace }}\winsdksetup.exe /features OptionId.WindowsDesktopDebuggers /q /norestart - name: Print ninja version run: ninja --version From 2e92f57be76aee27b8f558abcfc54a0fa0c2436e Mon Sep 17 00:00:00 2001 From: CloudWebRTC Date: Tue, 16 Sep 2025 20:51:24 +0800 Subject: [PATCH 20/52] Update build_windows.cmd --- webrtc-sys/libwebrtc/build_windows.cmd | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/webrtc-sys/libwebrtc/build_windows.cmd b/webrtc-sys/libwebrtc/build_windows.cmd index edc84f84b..1b2cd5f73 100644 --- a/webrtc-sys/libwebrtc/build_windows.cmd +++ b/webrtc-sys/libwebrtc/build_windows.cmd @@ -40,10 +40,10 @@ set COMMAND_DIR=%~dp0 set PATH=%cd%\depot_tools;%PATH% set DEPOT_TOOLS_WIN_TOOLCHAIN=0 set GYP_GENERATORS=ninja,msvs-ninja -set GYP_MSVS_VERSION=2019 +set GYP_MSVS_VERSION=2022 set OUTPUT_DIR=src\out-!arch!-!profile! set ARTIFACTS_DIR=%cd%\win-!arch!-!profile! -set vs2019_install=C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional +set vs2019_install=C:\Program Files\Microsoft Visual Studio\2022\Enterprise if not exist src ( call gclient.bat sync -D --with_branch_heads --with_tags @@ -88,4 +88,4 @@ copy "%OUTPUT_DIR%\LICENSE.md" "%ARTIFACTS_DIR%" rem copy header xcopy src\*.h "%ARTIFACTS_DIR%\include" /C /S /I /F /H -xcopy src\*.inc "%ARTIFACTS_DIR%\include" /C /S /I /F /H \ No newline at end of file +xcopy src\*.inc "%ARTIFACTS_DIR%\include" /C /S /I /F /H From 41531eddb134409c1e5a91298735170dbf85044a Mon Sep 17 00:00:00 2001 From: cloudwebrtc Date: Tue, 16 Sep 2025 21:47:44 +0800 Subject: [PATCH 21/52] cargo fmt. --- webrtc-sys/build.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/webrtc-sys/build.rs b/webrtc-sys/build.rs index 3b2914d9a..8e00f2b2a 100644 --- a/webrtc-sys/build.rs +++ b/webrtc-sys/build.rs @@ -186,9 +186,7 @@ fn main() { _ => {} } - builder - .flag("-Wno-changes-meaning") - .flag("-std=c++20"); + builder.flag("-Wno-changes-meaning").flag("-std=c++20"); } "macos" => { println!("cargo:rustc-link-lib=framework=Foundation"); From c7695c434e7bef2bbb97b84eba8bffd1bf0b2c53 Mon Sep 17 00:00:00 2001 From: CloudWebRTC Date: Tue, 16 Sep 2025 22:13:18 +0800 Subject: [PATCH 22/52] Update build_windows.cmd --- webrtc-sys/libwebrtc/build_windows.cmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webrtc-sys/libwebrtc/build_windows.cmd b/webrtc-sys/libwebrtc/build_windows.cmd index 1b2cd5f73..92127ecea 100644 --- a/webrtc-sys/libwebrtc/build_windows.cmd +++ b/webrtc-sys/libwebrtc/build_windows.cmd @@ -70,7 +70,7 @@ if "!profile!" == "debug" ( rem generate ninja for release call gn.bat gen %OUTPUT_DIR% --root="src" ^ - --args="is_debug=!debug! is_clang=true target_cpu=\"!arch!\" use_custom_libcxx=false rtc_libvpx_build_vp9=true enable_libaom=true rtc_include_tests=false rtc_build_examples=false rtc_build_tools=false is_component_build=false rtc_enable_protobuf=false rtc_use_h264=true ffmpeg_branding=\"Chrome\" symbol_level=0 enable_iterator_debugging=false" + --args="is_debug=!debug! is_clang=true target_cpu=\"!arch!\" use_custom_libcxx=false use_custom_libcxx_for_host=false rtc_libvpx_build_vp9=true enable_libaom=true rtc_include_tests=false rtc_build_examples=false rtc_build_tools=false is_component_build=false rtc_enable_protobuf=false rtc_use_h264=true ffmpeg_branding=\"Chrome\" symbol_level=0 enable_iterator_debugging=false" rem build ninja.exe -C %OUTPUT_DIR% :default From 9069b80e94eb9d5332c0db36f991077cb8902043 Mon Sep 17 00:00:00 2001 From: lukasIO Date: Tue, 16 Sep 2025 17:09:04 +0200 Subject: [PATCH 23/52] Add new encryption room options field and forward to e2ee_manager --- livekit/src/room/e2ee/manager.rs | 4 +++- livekit/src/room/mod.rs | 7 ++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/livekit/src/room/e2ee/manager.rs b/livekit/src/room/e2ee/manager.rs index bab97e0a4..358bb6b60 100644 --- a/livekit/src/room/e2ee/manager.rs +++ b/livekit/src/room/e2ee/manager.rs @@ -35,6 +35,7 @@ type StateChangedHandler = Box, // If Some, it means the e2ee was initialized enabled: bool, // Used to enable/disable e2ee + dc_encryption: bool, frame_cryptors: HashMap<(ParticipantIdentity, TrackSid), FrameCryptor>, } @@ -47,10 +48,11 @@ pub struct E2eeManager { impl E2eeManager { /// E2eeOptions is an optional parameter. We may support to reconfigure e2ee after connect in /// the future. - pub(crate) fn new(options: Option) -> Self { + pub(crate) fn new(options: Option, with_dc_encryption: bool) -> Self { Self { inner: Arc::new(Mutex::new(ManagerInner { enabled: options.is_some(), // Enabled by default if options is provided + dc_encryption: options.is_some() && with_dc_encryption, options, frame_cryptors: HashMap::new(), })), diff --git a/livekit/src/room/mod.rs b/livekit/src/room/mod.rs index de72cb808..8400b46ae 100644 --- a/livekit/src/room/mod.rs +++ b/livekit/src/room/mod.rs @@ -350,7 +350,9 @@ pub struct RoomOptions { pub auto_subscribe: bool, pub adaptive_stream: bool, pub dynacast: bool, + #[deprecated = "use encryption field instead, see x for a detailed explanation of the implications"] pub e2ee: Option, + pub encryption: Option, pub rtc_config: RtcConfiguration, pub join_retries: u32, pub sdk_options: RoomSdkOptions, @@ -363,6 +365,7 @@ impl Default for RoomOptions { adaptive_stream: false, dynacast: false, e2ee: None, + encryption: None, // Explicitly set the default values rtc_config: RtcConfiguration { @@ -459,7 +462,9 @@ impl Room { options: RoomOptions, ) -> RoomResult<(Self, mpsc::UnboundedReceiver)> { // TODO(theomonnom): move connection logic to the RoomSession - let e2ee_manager = E2eeManager::new(options.e2ee.clone()); + let with_dc_encryption = options.encryption.is_some(); + let encryption_options = options.encryption.clone().or(options.e2ee.clone()); + let e2ee_manager = E2eeManager::new(encryption_options, with_dc_encryption); let mut signal_options = SignalOptions::default(); signal_options.sdk_options = options.sdk_options.clone().into(); signal_options.auto_subscribe = options.auto_subscribe; From d29e7f8292f5cb06ba204a0ec5fa0c6e4bf99f01 Mon Sep 17 00:00:00 2001 From: lukasIO Date: Thu, 18 Sep 2025 11:54:30 +0200 Subject: [PATCH 24/52] libwebrtc ffi --- webrtc-sys/include/livekit/frame_cryptor.h | 23 ++++++ webrtc-sys/src/frame_cryptor.cpp | 80 +++++++++++++++++++ webrtc-sys/src/frame_cryptor.rs | 91 ++++++++++++++++++++++ 3 files changed, 194 insertions(+) diff --git a/webrtc-sys/include/livekit/frame_cryptor.h b/webrtc-sys/include/livekit/frame_cryptor.h index f7ba3584b..4664a40d5 100644 --- a/webrtc-sys/include/livekit/frame_cryptor.h +++ b/webrtc-sys/include/livekit/frame_cryptor.h @@ -35,6 +35,7 @@ namespace livekit { struct KeyProviderOptions; +struct EncryptedPacket; enum class Algorithm : ::std::int32_t; class RtcFrameCryptorObserverWrapper; class NativeFrameCryptorObserver; @@ -183,6 +184,24 @@ class NativeFrameCryptorObserver const FrameCryptor* fc_; }; +class DataPacketCryptor { + public: + DataPacketCryptor(webrtc::FrameCryptorTransformer::Algorithm algorithm, + webrtc::scoped_refptr key_provider); + + EncryptedPacket encrypt_data_packet( + const ::rust::String participant_id, + uint32_t key_index, + rust::Vec<::std::uint8_t> data) const; + + rust::Vec<::std::uint8_t> decrypt_data_packet( + const ::rust::String participant_id, + const EncryptedPacket& encrypted_packet) const; + + private: + webrtc::scoped_refptr data_packet_cryptor_; +}; + std::shared_ptr new_frame_cryptor_for_rtp_sender( std::shared_ptr peer_factory, const ::rust::String participant_id, @@ -199,4 +218,8 @@ std::shared_ptr new_frame_cryptor_for_rtp_receiver( std::shared_ptr new_key_provider(KeyProviderOptions options); +std::shared_ptr new_data_packet_cryptor( + Algorithm algorithm, + std::shared_ptr key_provider); + } // namespace livekit diff --git a/webrtc-sys/src/frame_cryptor.cpp b/webrtc-sys/src/frame_cryptor.cpp index eca5ec8ad..9e9ee07a4 100644 --- a/webrtc-sys/src/frame_cryptor.cpp +++ b/webrtc-sys/src/frame_cryptor.cpp @@ -20,6 +20,7 @@ #include "absl/types/optional.h" #include "api/make_ref_counted.h" +#include "api/crypto/data_packet_cryptor.h" #include "livekit/peer_connection.h" #include "livekit/peer_connection_factory.h" #include "livekit/webrtc.h" @@ -154,6 +155,77 @@ int32_t FrameCryptor::key_index() const { return e2ee_transformer_->key_index(); } +class DataPacketCryptor { + public: + DataPacketCryptor(webrtc::FrameCryptorTransformer::Algorithm algorithm, + webrtc::scoped_refptr key_provider) + : data_packet_cryptor_( + webrtc::make_ref_counted(algorithm, key_provider)) {} + + EncryptedPacket encrypt_data_packet( + const ::rust::String participant_id, + uint32_t key_index, + rust::Vec<::std::uint8_t> data) const { + std::vector data_vec; + std::copy(data.begin(), data.end(), std::back_inserter(data_vec)); + + auto result = data_packet_cryptor_->Encrypt( + std::string(participant_id.data(), participant_id.size()), + key_index, + data_vec); + + if (!result.ok()) { + throw std::runtime_error("Failed to encrypt data packet: " + result.error().message()); + } + + auto& packet = result.value(); + + EncryptedPacket encrypted_packet; + encrypted_packet.data = rust::Vec(); + std::copy(packet->data.begin(), packet->data.end(), + std::back_inserter(encrypted_packet.data)); + + encrypted_packet.iv = rust::Vec(); + std::copy(packet->iv.begin(), packet->iv.end(), + std::back_inserter(encrypted_packet.iv)); + + encrypted_packet.key_index = packet->key_index; + + return encrypted_packet; + } + + rust::Vec<::std::uint8_t> decrypt_data_packet( + const ::rust::String participant_id, + const EncryptedPacket& encrypted_packet) const { + std::vector data_vec; + std::copy(encrypted_packet.data.begin(), encrypted_packet.data.end(), + std::back_inserter(data_vec)); + + std::vector iv_vec; + std::copy(encrypted_packet.iv.begin(), encrypted_packet.iv.end(), + std::back_inserter(iv_vec)); + + auto native_encrypted_packet = webrtc::make_ref_counted( + std::move(data_vec), std::move(iv_vec), encrypted_packet.key_index); + + auto result = data_packet_cryptor_->Decrypt( + std::string(participant_id.data(), participant_id.size()), + native_encrypted_packet); + + if (!result.ok()) { + throw std::runtime_error("Failed to decrypt data packet: " + result.error().message()); + } + + rust::Vec decrypted_data; + auto& decrypted = result.value(); + std::copy(decrypted.begin(), decrypted.end(), std::back_inserter(decrypted_data)); + return decrypted_data; + } + + private: + webrtc::scoped_refptr data_packet_cryptor_; +}; + std::shared_ptr new_key_provider(KeyProviderOptions options) { return std::make_shared(options); } @@ -184,4 +256,12 @@ std::shared_ptr new_frame_cryptor_for_rtp_receiver( key_provider->rtc_key_provider(), receiver->rtc_receiver()); } +std::shared_ptr new_data_packet_cryptor( + Algorithm algorithm, + std::shared_ptr key_provider) { + return std::make_shared( + AlgorithmToFrameCryptorAlgorithm(algorithm), + key_provider->rtc_key_provider()); +} + } // namespace livekit diff --git a/webrtc-sys/src/frame_cryptor.rs b/webrtc-sys/src/frame_cryptor.rs index e46e1052f..5579e6119 100644 --- a/webrtc-sys/src/frame_cryptor.rs +++ b/webrtc-sys/src/frame_cryptor.rs @@ -46,6 +46,13 @@ pub mod ffi { InternalError, } + #[derive(Debug)] + pub struct EncryptedPacket { + pub data: Vec, + pub iv: Vec, + pub key_index: u32, + } + unsafe extern "C++" { include!("livekit/frame_cryptor.h"); @@ -127,6 +134,30 @@ pub mod ffi { pub fn unregister_observer(self: &FrameCryptor); } + unsafe extern "C++" { + include!("livekit/frame_cryptor.h"); + + pub type DataPacketCryptor; + + pub fn new_data_packet_cryptor( + algorithm: Algorithm, + key_provider: SharedPtr, + ) -> SharedPtr; + + pub fn encrypt_data_packet( + self: &DataPacketCryptor, + participant_id: String, + key_index: u32, + data: Vec, + ) -> Result; + + pub fn decrypt_data_packet( + self: &DataPacketCryptor, + participant_id: String, + encrypted_packet: &EncryptedPacket, + ) -> Result>; + } + extern "Rust" { type RtcFrameCryptorObserverWrapper; @@ -140,9 +171,13 @@ pub mod ffi { impl_thread_safety!(ffi::FrameCryptor, Send + Sync); impl_thread_safety!(ffi::KeyProvider, Send + Sync); +impl_thread_safety!(ffi::DataPacketCryptor, Send + Sync); use ffi::FrameCryptionState; +// Re-export the EncryptedPacket for convenience +pub use ffi::EncryptedPacket; + pub trait RtcFrameCryptorObserver: Send + Sync { fn on_frame_cryption_state_change(&self, participant_id: String, state: FrameCryptionState); } @@ -164,3 +199,59 @@ impl RtcFrameCryptorObserverWrapper { self.observer.on_frame_cryption_state_change(participant_id, state); } } + +/// High-level Rust wrapper for data packet cryptor functionality +pub struct DataPacketCryptor { + inner: cxx::SharedPtr, +} + +impl DataPacketCryptor { + /// Create a new data packet cryptor with the specified algorithm and key provider + pub fn new(algorithm: ffi::Algorithm, key_provider: cxx::SharedPtr) -> Self { + Self { inner: ffi::new_data_packet_cryptor(algorithm, key_provider) } + } + + /// Encrypt data for a specific participant + pub fn encrypt( + &self, + participant_id: &str, + key_index: u32, + data: &[u8], + ) -> Result> { + let data_vec: Vec = data.to_vec(); + match self.inner.encrypt_data_packet(participant_id.to_string(), key_index, data_vec) { + Ok(packet) => Ok(packet), + Err(e) => Err(format!("Encryption failed: {}", e).into()), + } + } + + /// Decrypt an encrypted packet for a specific participant + pub fn decrypt( + &self, + participant_id: &str, + encrypted_packet: &ffi::EncryptedPacket, + ) -> Result, Box> { + match self.inner.decrypt_data_packet(participant_id.to_string(), encrypted_packet) { + Ok(data) => Ok(data.into_iter().collect()), + Err(e) => Err(format!("Decryption failed: {}", e).into()), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_data_packet_cryptor_creation() { + let options = ffi::KeyProviderOptions { + shared_key: true, + ratchet_window_size: 16, + ratchet_salt: vec![], + failure_tolerance: -1, + }; + + let key_provider = ffi::new_key_provider(options); + let _cryptor = DataPacketCryptor::new(ffi::Algorithm::AesGcm, key_provider); + } +} From ee519e43399dbb02e1ac8765038ef52ac447cec1 Mon Sep 17 00:00:00 2001 From: lukasIO Date: Thu, 18 Sep 2025 12:40:22 +0200 Subject: [PATCH 25/52] fix ffi --- webrtc-sys/src/frame_cryptor.cpp | 127 +++++++++++++++---------------- 1 file changed, 60 insertions(+), 67 deletions(-) diff --git a/webrtc-sys/src/frame_cryptor.cpp b/webrtc-sys/src/frame_cryptor.cpp index 9e9ee07a4..6e43212e2 100644 --- a/webrtc-sys/src/frame_cryptor.cpp +++ b/webrtc-sys/src/frame_cryptor.cpp @@ -20,7 +20,6 @@ #include "absl/types/optional.h" #include "api/make_ref_counted.h" -#include "api/crypto/data_packet_cryptor.h" #include "livekit/peer_connection.h" #include "livekit/peer_connection_factory.h" #include "livekit/webrtc.h" @@ -155,76 +154,70 @@ int32_t FrameCryptor::key_index() const { return e2ee_transformer_->key_index(); } -class DataPacketCryptor { - public: - DataPacketCryptor(webrtc::FrameCryptorTransformer::Algorithm algorithm, - webrtc::scoped_refptr key_provider) - : data_packet_cryptor_( - webrtc::make_ref_counted(algorithm, key_provider)) {} - - EncryptedPacket encrypt_data_packet( - const ::rust::String participant_id, - uint32_t key_index, - rust::Vec<::std::uint8_t> data) const { - std::vector data_vec; - std::copy(data.begin(), data.end(), std::back_inserter(data_vec)); - - auto result = data_packet_cryptor_->Encrypt( - std::string(participant_id.data(), participant_id.size()), - key_index, - data_vec); - - if (!result.ok()) { - throw std::runtime_error("Failed to encrypt data packet: " + result.error().message()); - } - - auto& packet = result.value(); - - EncryptedPacket encrypted_packet; - encrypted_packet.data = rust::Vec(); - std::copy(packet->data.begin(), packet->data.end(), - std::back_inserter(encrypted_packet.data)); - - encrypted_packet.iv = rust::Vec(); - std::copy(packet->iv.begin(), packet->iv.end(), - std::back_inserter(encrypted_packet.iv)); - - encrypted_packet.key_index = packet->key_index; - - return encrypted_packet; +DataPacketCryptor::DataPacketCryptor(webrtc::FrameCryptorTransformer::Algorithm algorithm, + webrtc::scoped_refptr key_provider) + : data_packet_cryptor_( + webrtc::make_ref_counted(algorithm, key_provider)) {} + +EncryptedPacket DataPacketCryptor::encrypt_data_packet( + const ::rust::String participant_id, + uint32_t key_index, + rust::Vec<::std::uint8_t> data) const { + std::vector data_vec; + std::copy(data.begin(), data.end(), std::back_inserter(data_vec)); + + auto result = data_packet_cryptor_->Encrypt( + std::string(participant_id.data(), participant_id.size()), + key_index, + data_vec); + + if (!result.ok()) { + throw std::runtime_error(std::string("Failed to encrypt data packet: ") + result.error().message()); } - rust::Vec<::std::uint8_t> decrypt_data_packet( - const ::rust::String participant_id, - const EncryptedPacket& encrypted_packet) const { - std::vector data_vec; - std::copy(encrypted_packet.data.begin(), encrypted_packet.data.end(), - std::back_inserter(data_vec)); - - std::vector iv_vec; - std::copy(encrypted_packet.iv.begin(), encrypted_packet.iv.end(), - std::back_inserter(iv_vec)); - - auto native_encrypted_packet = webrtc::make_ref_counted( - std::move(data_vec), std::move(iv_vec), encrypted_packet.key_index); - - auto result = data_packet_cryptor_->Decrypt( - std::string(participant_id.data(), participant_id.size()), - native_encrypted_packet); - - if (!result.ok()) { - throw std::runtime_error("Failed to decrypt data packet: " + result.error().message()); - } - - rust::Vec decrypted_data; - auto& decrypted = result.value(); - std::copy(decrypted.begin(), decrypted.end(), std::back_inserter(decrypted_data)); - return decrypted_data; + auto& packet = result.value(); + + EncryptedPacket encrypted_packet; + encrypted_packet.data = rust::Vec(); + std::copy(packet->data.begin(), packet->data.end(), + std::back_inserter(encrypted_packet.data)); + + encrypted_packet.iv = rust::Vec(); + std::copy(packet->iv.begin(), packet->iv.end(), + std::back_inserter(encrypted_packet.iv)); + + encrypted_packet.key_index = packet->key_index; + + return encrypted_packet; +} + +rust::Vec<::std::uint8_t> DataPacketCryptor::decrypt_data_packet( + const ::rust::String participant_id, + const EncryptedPacket& encrypted_packet) const { + std::vector data_vec; + std::copy(encrypted_packet.data.begin(), encrypted_packet.data.end(), + std::back_inserter(data_vec)); + + std::vector iv_vec; + std::copy(encrypted_packet.iv.begin(), encrypted_packet.iv.end(), + std::back_inserter(iv_vec)); + + auto native_encrypted_packet = webrtc::make_ref_counted( + std::move(data_vec), std::move(iv_vec), encrypted_packet.key_index); + + auto result = data_packet_cryptor_->Decrypt( + std::string(participant_id.data(), participant_id.size()), + native_encrypted_packet); + + if (!result.ok()) { + throw std::runtime_error(std::string("Failed to decrypt data packet: ") + result.error().message()); } - private: - webrtc::scoped_refptr data_packet_cryptor_; -}; + rust::Vec decrypted_data; + auto& decrypted = result.value(); + std::copy(decrypted.begin(), decrypted.end(), std::back_inserter(decrypted_data)); + return decrypted_data; +} std::shared_ptr new_key_provider(KeyProviderOptions options) { return std::make_shared(options); From 3c00272157ae09cb3e2522db32207ef54bff4519 Mon Sep 17 00:00:00 2001 From: lukasIO Date: Thu, 18 Sep 2025 12:41:32 +0200 Subject: [PATCH 26/52] add data packet cryptor to webrtc crate --- libwebrtc/src/native/frame_cryptor.rs | 66 +++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/libwebrtc/src/native/frame_cryptor.rs b/libwebrtc/src/native/frame_cryptor.rs index 8f64e7711..4fd0eed06 100644 --- a/libwebrtc/src/native/frame_cryptor.rs +++ b/libwebrtc/src/native/frame_cryptor.rs @@ -36,6 +36,13 @@ pub enum EncryptionState { InternalError, } +#[derive(Debug, Clone)] +pub struct EncryptedPacket { + pub data: Vec, + pub iv: Vec, + pub key_index: u32, +} + #[derive(Clone)] pub struct KeyProvider { pub(crate) sys_handle: SharedPtr, @@ -149,6 +156,49 @@ impl FrameCryptor { } } +#[derive(Clone)] +pub struct DataPacketCryptor { + pub(crate) sys_handle: SharedPtr, +} + +impl DataPacketCryptor { + pub fn new(algorithm: EncryptionAlgorithm, key_provider: KeyProvider) -> Self { + Self { + sys_handle: sys_fc::ffi::new_data_packet_cryptor( + algorithm.into(), + key_provider.sys_handle, + ), + } + } + + pub fn encrypt( + &self, + participant_id: &str, + key_index: u32, + data: &[u8], + ) -> Result> { + let data_vec: Vec = data.to_vec(); + match self.sys_handle.encrypt_data_packet(participant_id.to_string(), key_index, data_vec) { + Ok(packet) => Ok(packet.into()), + Err(e) => Err(format!("Encryption failed: {}", e).into()), + } + } + + pub fn decrypt( + &self, + participant_id: &str, + encrypted_packet: &EncryptedPacket, + ) -> Result, Box> { + match self + .sys_handle + .decrypt_data_packet(participant_id.to_string(), &encrypted_packet.clone().into()) + { + Ok(data) => Ok(data.into_iter().collect()), + Err(e) => Err(format!("Decryption failed: {}", e).into()), + } + } +} + #[derive(Default)] struct RtcFrameCryptorObserver { state_change_handler: Mutex>, @@ -211,3 +261,19 @@ impl From for sys_fc::ffi::KeyProviderOptions { } } } + +impl From for EncryptedPacket { + fn from(value: sys_fc::ffi::EncryptedPacket) -> Self { + Self { + data: value.data.into_iter().collect(), + iv: value.iv.into_iter().collect(), + key_index: value.key_index, + } + } +} + +impl From for sys_fc::ffi::EncryptedPacket { + fn from(value: EncryptedPacket) -> Self { + Self { data: value.data, iv: value.iv, key_index: value.key_index } + } +} From bf20551d679ba9336345b47aed7723307a43fd75 Mon Sep 17 00:00:00 2001 From: lukasIO Date: Thu, 18 Sep 2025 14:42:12 +0200 Subject: [PATCH 27/52] add data frame cryptor handling on rtc session --- livekit/src/proto.rs | 10 ++ livekit/src/room/e2ee/manager.rs | 56 +++++++++- livekit/src/rtc_engine/rtc_session.rs | 154 +++++++++++++++++++++++++- 3 files changed, 217 insertions(+), 3 deletions(-) diff --git a/livekit/src/proto.rs b/livekit/src/proto.rs index ef833a95a..cd274f1ab 100644 --- a/livekit/src/proto.rs +++ b/livekit/src/proto.rs @@ -136,6 +136,16 @@ impl From for encryption::Type { } } +impl From for i32 { + fn from(value: EncryptionType) -> Self { + match value { + EncryptionType::None => 0, + EncryptionType::Gcm => 1, + EncryptionType::Custom => 2, + } + } +} + impl From for participant::ParticipantKind { fn from(value: participant_info::Kind) -> Self { match value { diff --git a/livekit/src/room/e2ee/manager.rs b/livekit/src/room/e2ee/manager.rs index 358bb6b60..ab4b956c1 100644 --- a/livekit/src/room/e2ee/manager.rs +++ b/livekit/src/room/e2ee/manager.rs @@ -15,7 +15,9 @@ use std::{collections::HashMap, sync::Arc}; use libwebrtc::{ - native::frame_cryptor::{EncryptionAlgorithm, EncryptionState, FrameCryptor}, + native::frame_cryptor::{ + DataPacketCryptor, EncryptedPacket, EncryptionAlgorithm, EncryptionState, FrameCryptor, + }, rtp_receiver::RtpReceiver, rtp_sender::RtpSender, }; @@ -37,6 +39,7 @@ struct ManagerInner { enabled: bool, // Used to enable/disable e2ee dc_encryption: bool, frame_cryptors: HashMap<(ParticipantIdentity, TrackSid), FrameCryptor>, + data_packet_cryptor: Option, } #[derive(Clone)] @@ -49,12 +52,19 @@ impl E2eeManager { /// E2eeOptions is an optional parameter. We may support to reconfigure e2ee after connect in /// the future. pub(crate) fn new(options: Option, with_dc_encryption: bool) -> Self { + // Create DataPacketCryptor whenever E2EE options are available + // This allows for decryption even if we're not encrypting our own data + let data_packet_cryptor = options.as_ref().map(|opts| { + DataPacketCryptor::new(EncryptionAlgorithm::AesGcm, opts.key_provider.handle.clone()) + }); + Self { inner: Arc::new(Mutex::new(ManagerInner { enabled: options.is_some(), // Enabled by default if options is provided dc_encryption: options.is_some() && with_dc_encryption, options, frame_cryptors: HashMap::new(), + data_packet_cryptor, })), state_changed: Default::default(), } @@ -230,4 +240,48 @@ impl E2eeManager { let mut inner = self.inner.lock(); inner.frame_cryptors.remove(&(participant_identity, track_sid)); } + + /// Decrypt data received from a data channel + pub fn handle_encrypted_data( + &self, + data: &[u8], + iv: &[u8], + participant_identity: &str, + key_index: u32, + ) -> Option> { + let inner = self.inner.lock(); + + let data_packet_cryptor = inner.data_packet_cryptor.as_ref()?; + + let encrypted_packet = EncryptedPacket { data: data.to_vec(), iv: iv.to_vec(), key_index }; + + match data_packet_cryptor.decrypt(participant_identity, &encrypted_packet) { + Ok(decrypted_data) => Some(decrypted_data), + Err(e) => { + log::warn!("handle_encrypted_data error: {}", e); + None + } + } + } + + /// Encrypt data for transmission over a data channel + pub fn encrypt_data( + &self, + data: &[u8], + participant_identity: &str, + key_index: u32, + ) -> Result> { + let inner = self.inner.lock(); + + let data_packet_cryptor = + inner.data_packet_cryptor.as_ref().ok_or("DataPacketCryptor is not initialized")?; + + let key_provider = + inner.options.as_ref().ok_or("E2EE options not available")?.key_provider.clone(); + + // Get the latest key index for this participant + let key_index = key_provider.get_key(participant_identity); + + data_packet_cryptor.encrypt(participant_identity, key_index as u32, data) + } } diff --git a/livekit/src/rtc_engine/rtc_session.rs b/livekit/src/rtc_engine/rtc_session.rs index a95c3aa27..d01e497fc 100644 --- a/livekit/src/rtc_engine/rtc_session.rs +++ b/livekit/src/rtc_engine/rtc_session.rs @@ -25,7 +25,7 @@ use std::{ use libwebrtc::{prelude::*, stats::RtcStats}; use livekit_api::signal_client::{SignalClient, SignalEvent, SignalEvents}; -use livekit_protocol as proto; +use livekit_protocol::{self as proto, encryption}; use livekit_runtime::{sleep, JoinHandle}; use parking_lot::Mutex; use prost::Message; @@ -49,7 +49,7 @@ use crate::{ id::ParticipantSid, options::TrackPublishOptions, prelude::TrackKind, - room::DisconnectReason, + room::{e2ee::manager::E2eeManager, DisconnectReason}, rtc_engine::{ lk_runtime::LkRuntime, peer_transport::PeerTransport, @@ -301,6 +301,8 @@ struct SessionInner { negotiation_queue: NegotiationQueue, pending_requests: Mutex>>, + + e2ee_manager: Option, } /// Information about the local participant needed for outgoing @@ -348,6 +350,7 @@ impl RtcSession { url: &str, token: &str, options: EngineOptions, + e2ee_manager: Option, ) -> EngineResult<(Self, proto::JoinResponse, SessionEvents)> { let (emitter, session_events) = mpsc::unbounded_channel(); @@ -425,6 +428,7 @@ impl RtcSession { negotiation_debouncer: Default::default(), negotiation_queue: NegotiationQueue::new(), pending_requests: Default::default(), + e2ee_manager, }); // Start session tasks @@ -1133,6 +1137,54 @@ impl SessionInner { participant_identity.map_or("".into(), |identity| identity.0); self.emitter.send(SessionEvent::DataStreamTrailer { trailer, participant_identity }) } + proto::data_packet::Value::EncryptedPacket(encrypted_packet) => { + // Handle encrypted data packets + if let Some(e2ee_manager) = &self.e2ee_manager { + let participant_identity_str = + participant_identity.as_ref().map(|p| p.0.as_str()).unwrap_or(""); + + match e2ee_manager.handle_encrypted_data( + &encrypted_packet.encrypted_value, + &encrypted_packet.iv, + participant_identity_str, + encrypted_packet.key_index, + ) { + Some(decrypted_payload) => { + // Parse the decrypted payload as EncryptedPacketPayload + match proto::EncryptedPacketPayload::decode(&*decrypted_payload) { + Ok(encrypted_payload) => { + if let Some(value) = encrypted_payload.value { + // Forward the decrypted payload based on its type + self.handle_decrypted_payload( + kind, + participant_sid, + participant_identity, + value, + ) + } else { + log::warn!("Decrypted payload has no value"); + Ok(()) + } + } + Err(e) => { + log::warn!("Failed to decode decrypted payload: {}", e); + Ok(()) + } + } + } + None => { + log::warn!( + "Failed to decrypt data packet from {}", + participant_identity_str + ); + Ok(()) // Don't emit the event if decryption fails + } + } + } else { + log::warn!("Received encrypted data packet but E2EE is not enabled"); + Ok(()) // Don't emit the event if E2EE is not available + } + } _ => Ok(()), }; if let Err(err) = send_result { @@ -1140,6 +1192,75 @@ impl SessionInner { } } + fn handle_decrypted_payload( + &self, + kind: DataPacketKind, + participant_sid: Option, + participant_identity: Option, + value: proto::encrypted_packet_payload::Value, + ) -> Result<(), mpsc::error::SendError> { + match value { + proto::encrypted_packet_payload::Value::User(user) => { + self.emitter.send(SessionEvent::Data { + kind, + participant_sid, + participant_identity, + payload: user.payload, + topic: user.topic, + }) + } + proto::encrypted_packet_payload::Value::ChatMessage(message) => { + self.emitter.send(SessionEvent::ChatMessage { + participant_identity: participant_identity + .unwrap_or(ParticipantIdentity("".into())), + message: ChatMessage::from(message), + }) + } + + proto::encrypted_packet_payload::Value::RpcRequest(rpc_request) => { + let caller_identity = participant_identity; + self.emitter.send(SessionEvent::RpcRequest { + caller_identity, + request_id: rpc_request.id, + method: rpc_request.method, + payload: rpc_request.payload, + response_timeout: Duration::from_millis(rpc_request.response_timeout_ms as u64), + version: rpc_request.version, + }) + } + proto::encrypted_packet_payload::Value::RpcResponse(rpc_response) => { + let (payload, error) = match rpc_response.value { + None => (None, None), + Some(proto::rpc_response::Value::Payload(payload)) => (Some(payload), None), + Some(proto::rpc_response::Value::Error(err)) => (None, Some(err)), + }; + self.emitter.send(SessionEvent::RpcResponse { + request_id: rpc_response.request_id, + payload, + error, + }) + } + proto::encrypted_packet_payload::Value::RpcAck(rpc_ack) => { + self.emitter.send(SessionEvent::RpcAck { request_id: rpc_ack.request_id }) + } + proto::encrypted_packet_payload::Value::StreamHeader(header) => { + let participant_identity = + participant_identity.map_or("".into(), |identity| identity.0); + self.emitter.send(SessionEvent::DataStreamHeader { header, participant_identity }) + } + proto::encrypted_packet_payload::Value::StreamChunk(chunk) => { + let participant_identity = + participant_identity.map_or("".into(), |identity| identity.0); + self.emitter.send(SessionEvent::DataStreamChunk { chunk, participant_identity }) + } + proto::encrypted_packet_payload::Value::StreamTrailer(trailer) => { + let participant_identity = + participant_identity.map_or("".into(), |identity| identity.0); + self.emitter.send(SessionEvent::DataStreamTrailer { trailer, participant_identity }) + } + } + } + async fn add_track(&self, req: proto::AddTrackRequest) -> EngineResult { let (tx, rx) = oneshot::channel(); let cid = req.cid.clone(); @@ -1351,6 +1472,35 @@ impl SessionInner { packet.participant_identity = self.participant_info.identity.to_string(); packet.participant_sid = self.participant_info.sid.to_string(); + // Handle encryption for user data packets + if let Some(proto::data_packet::Value::User(user)) = packet.value.take() { + if let Some(e2ee_manager) = &self.e2ee_manager { + match e2ee_manager.encrypt_data(&user.payload, &self.participant_info.identity.0, 0) + { + Ok(encrypted_packet) => { + let encryption_type = e2ee_manager.encryption_type().clone(); + // Replace with EncryptedPacket variant + packet.value = Some(proto::data_packet::Value::EncryptedPacket( + proto::EncryptedPacket { + encrypted_value: encrypted_packet.data, + iv: encrypted_packet.iv, + key_index: encrypted_packet.key_index, + encryption_type: encryption_type.into(), + }, + )); + } + Err(e) => { + log::warn!("Failed to encrypt data packet: {}", e); + // Restore original user packet if encryption fails + packet.value = Some(proto::data_packet::Value::User(user)); + } + } + } else { + // Restore user packet if no E2EE manager + packet.value = Some(proto::data_packet::Value::User(user)); + } + } + let (completion_tx, completion_rx) = oneshot::channel(); let ev = DataChannelEvent { kind, From 34284cbd46015facdeaaffbec21b40b1c17a56b5 Mon Sep 17 00:00:00 2001 From: lukasIO Date: Thu, 18 Sep 2025 15:22:38 +0200 Subject: [PATCH 28/52] data packet type encryption handling --- livekit/src/room/e2ee/manager.rs | 9 +++ livekit/src/rtc_engine/mod.rs | 26 +++++--- livekit/src/rtc_engine/rtc_session.rs | 91 ++++++++++++++++++++------- 3 files changed, 97 insertions(+), 29 deletions(-) diff --git a/livekit/src/room/e2ee/manager.rs b/livekit/src/room/e2ee/manager.rs index ab4b956c1..a35395e3b 100644 --- a/livekit/src/room/e2ee/manager.rs +++ b/livekit/src/room/e2ee/manager.rs @@ -175,6 +175,10 @@ impl E2eeManager { self.inner.lock().enabled && self.initialized() } + pub fn is_dc_encryption_enabled(&self) -> bool { + self.inner.lock().dc_encryption + } + pub fn set_enabled(&self, enabled: bool) { let inner = self.inner.lock(); if inner.enabled == enabled { @@ -196,6 +200,11 @@ impl E2eeManager { inner.options.as_ref().map(|opts| opts.encryption_type).unwrap_or(EncryptionType::None) } + pub fn is_dc_encryption_enabled(&self) -> bool { + let inner = self.inner.lock(); + inner.dc_encryption + } + fn setup_rtp_sender( &self, participant_identity: &ParticipantIdentity, diff --git a/livekit/src/rtc_engine/mod.rs b/livekit/src/rtc_engine/mod.rs index 363bd6eb2..1b5a1332e 100644 --- a/livekit/src/rtc_engine/mod.rs +++ b/livekit/src/rtc_engine/mod.rs @@ -38,7 +38,7 @@ use crate::{ }, DataPacketKind, }; -use crate::{ChatMessage, TranscriptionSegment}; +use crate::{ChatMessage, E2eeManager, TranscriptionSegment}; pub mod lk_runtime; mod peer_transport; @@ -232,9 +232,10 @@ impl RtcEngine { url: &str, token: &str, options: EngineOptions, + e2ee_manager: Option, ) -> EngineResult<(Self, proto::JoinResponse, EngineEvents)> { let (inner, join_response, engine_events) = - EngineInner::connect(url, token, options).await?; + EngineInner::connect(url, token, options, e2ee_manager).await?; Ok((Self { inner }, join_response, engine_events)) } @@ -340,6 +341,7 @@ impl EngineInner { url: &str, token: &str, options: EngineOptions, + e2ee_manager: Option, ) -> EngineResult<(Arc, proto::JoinResponse, EngineEvents)> { let lk_runtime = LkRuntime::instance(); let max_retries = options.join_retries; @@ -348,9 +350,10 @@ impl EngineInner { move || { let options = options.clone(); let lk_runtime = lk_runtime.clone(); + let e2ee_manager = e2ee_manager.clone(); async move { let (session, join_response, session_events) = - RtcSession::connect(url, token, options.clone()).await?; + RtcSession::connect(url, token, options.clone(), e2ee_manager).await?; session.wait_pc_connection().await?; let (engine_tx, engine_rx) = mpsc::unbounded_channel(); @@ -682,12 +685,14 @@ impl EngineInner { async fn reconnect_task(self: &Arc) -> EngineResult<()> { // Get the latest connection info from the signal_client (including the refreshed token // because the initial join token may have expired) - let (url, token) = { + let (url, token, e2ee_manager) = { let running_handle = self.running_handle.read(); let signal_client = running_handle.session.signal_client(); + let e2ee_manager = running_handle.session.e2ee_manager(); ( signal_client.url(), signal_client.token(), // Refreshed token + e2ee_manager.clone(), ) }; @@ -709,8 +714,14 @@ impl EngineInner { } log::error!("restarting connection... attempt: {}", i); - if let Err(err) = - self.try_restart_connection(&url, &token, self.options.clone()).await + if let Err(err) = self + .try_restart_connection( + &url, + &token, + self.options.clone(), + e2ee_manager.clone(), + ) + .await { log::error!("restarting connection failed: {}", err); } else { @@ -757,6 +768,7 @@ impl EngineInner { url: &str, token: &str, options: EngineOptions, + e2ee_manager: Option, ) -> EngineResult<()> { // Close the current RtcSession and the current tasks let (session, engine_task) = { @@ -773,7 +785,7 @@ impl EngineInner { } let (new_session, join_response, session_events) = - RtcSession::connect(url, token, options).await?; + RtcSession::connect(url, token, options, e2ee_manager).await?; // On SignalRestarted, the room will try to unpublish the local tracks // NOTE: Doing operations that use rtc_session will not use the new one diff --git a/livekit/src/rtc_engine/rtc_session.rs b/livekit/src/rtc_engine/rtc_session.rs index d01e497fc..78ec3d6bd 100644 --- a/livekit/src/rtc_engine/rtc_session.rs +++ b/livekit/src/rtc_engine/rtc_session.rs @@ -536,6 +536,10 @@ impl RtcSession { self.inner.data_channel(target, kind) } + pub fn e2ee_manager(&self) -> Option { + self.inner.e2ee_manager.clone() + } + pub fn data_channel_buffered_amount_low_threshold(&self, kind: DataPacketKind) -> u64 { match kind { DataPacketKind::Lossy => { @@ -1472,32 +1476,75 @@ impl SessionInner { packet.participant_identity = self.participant_info.identity.to_string(); packet.participant_sid = self.participant_info.sid.to_string(); - // Handle encryption for user data packets - if let Some(proto::data_packet::Value::User(user)) = packet.value.take() { - if let Some(e2ee_manager) = &self.e2ee_manager { - match e2ee_manager.encrypt_data(&user.payload, &self.participant_info.identity.0, 0) - { - Ok(encrypted_packet) => { - let encryption_type = e2ee_manager.encryption_type().clone(); - // Replace with EncryptedPacket variant - packet.value = Some(proto::data_packet::Value::EncryptedPacket( - proto::EncryptedPacket { - encrypted_value: encrypted_packet.data, - iv: encrypted_packet.iv, - key_index: encrypted_packet.key_index, - encryption_type: encryption_type.into(), - }, - )); + let packet_value = packet.value.take(); + + // Handle encryption for all data packet types when DC encryption is enabled + if let (Some(e2ee_manager), Some(value)) = (&self.e2ee_manager, packet_value.clone()) { + if e2ee_manager.is_dc_encryption_enabled() { + // Create EncryptedPacketPayload from the original value if it's an encryptable type + let encrypted_payload_value = match value { + proto::data_packet::Value::User(user) => { + Some(proto::encrypted_packet_payload::Value::User(user)) + } + proto::data_packet::Value::ChatMessage(msg) => { + Some(proto::encrypted_packet_payload::Value::ChatMessage(msg)) + } + proto::data_packet::Value::RpcRequest(req) => { + Some(proto::encrypted_packet_payload::Value::RpcRequest(req)) + } + proto::data_packet::Value::RpcResponse(resp) => { + Some(proto::encrypted_packet_payload::Value::RpcResponse(resp)) + } + proto::data_packet::Value::RpcAck(ack) => { + Some(proto::encrypted_packet_payload::Value::RpcAck(ack)) + } + proto::data_packet::Value::StreamHeader(header) => { + Some(proto::encrypted_packet_payload::Value::StreamHeader(header)) } - Err(e) => { - log::warn!("Failed to encrypt data packet: {}", e); - // Restore original user packet if encryption fails - packet.value = Some(proto::data_packet::Value::User(user)); + proto::data_packet::Value::StreamChunk(chunk) => { + Some(proto::encrypted_packet_payload::Value::StreamChunk(chunk)) } + proto::data_packet::Value::StreamTrailer(trailer) => { + Some(proto::encrypted_packet_payload::Value::StreamTrailer(trailer)) + } + // Non-encryptable types return None + _ => None, + }; + + if let Some(encrypted_payload_value) = encrypted_payload_value { + // Create EncryptedPacketPayload and encrypt it + let encrypted_payload = + proto::EncryptedPacketPayload { value: Some(encrypted_payload_value) }; + + // Encode the payload and encrypt it + let payload_bytes = encrypted_payload.encode_to_vec(); + match e2ee_manager.encrypt_data( + &payload_bytes, + &self.participant_info.identity.0, + 0, // FIXME - we need to get the current key index of the keyprovider here + ) { + Ok(encrypted_data) => { + // Replace with EncryptedPacket variant + packet.value = Some(proto::data_packet::Value::EncryptedPacket( + proto::EncryptedPacket { + encrypted_value: encrypted_data.data, + iv: encrypted_data.iv, + key_index: encrypted_data.key_index, + encryption_type: e2ee_manager.encryption_type().into(), + }, + )); + } + Err(e) => { + log::warn!("Failed to encrypt data packet: {}", e); + } + } + } else { + // Packet type shouldn't be encrypted, restore original + packet.value = packet_value; } } else { - // Restore user packet if no E2EE manager - packet.value = Some(proto::data_packet::Value::User(user)); + // DC encryption not enabled, restore original packet + packet.value = packet_value; } } From 8800bf7d9f210d00e38953e6a4c84361c13e4a99 Mon Sep 17 00:00:00 2001 From: lukasIO Date: Thu, 18 Sep 2025 16:08:15 +0200 Subject: [PATCH 29/52] cleanup --- livekit/src/room/e2ee/manager.rs | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/livekit/src/room/e2ee/manager.rs b/livekit/src/room/e2ee/manager.rs index a35395e3b..8432ec343 100644 --- a/livekit/src/room/e2ee/manager.rs +++ b/livekit/src/room/e2ee/manager.rs @@ -200,11 +200,6 @@ impl E2eeManager { inner.options.as_ref().map(|opts| opts.encryption_type).unwrap_or(EncryptionType::None) } - pub fn is_dc_encryption_enabled(&self) -> bool { - let inner = self.inner.lock(); - inner.dc_encryption - } - fn setup_rtp_sender( &self, participant_identity: &ParticipantIdentity, @@ -285,12 +280,6 @@ impl E2eeManager { let data_packet_cryptor = inner.data_packet_cryptor.as_ref().ok_or("DataPacketCryptor is not initialized")?; - let key_provider = - inner.options.as_ref().ok_or("E2EE options not available")?.key_provider.clone(); - - // Get the latest key index for this participant - let key_index = key_provider.get_key(participant_identity); - - data_packet_cryptor.encrypt(participant_identity, key_index as u32, data) + data_packet_cryptor.encrypt(participant_identity, key_index, data) } } From 9407cb627c46b17f18693a8e313b108e470a1ef5 Mon Sep 17 00:00:00 2001 From: lukasIO Date: Thu, 18 Sep 2025 16:20:05 +0200 Subject: [PATCH 30/52] ffi encryption option --- livekit-ffi/protocol/room.proto | 5 +++-- livekit-ffi/src/conversion/room.rs | 16 ++++++++++++++++ livekit-ffi/src/livekit.proto.rs | 3 +++ livekit/src/room/mod.rs | 2 +- 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/livekit-ffi/protocol/room.proto b/livekit-ffi/protocol/room.proto index f1f1da372..56996731b 100644 --- a/livekit-ffi/protocol/room.proto +++ b/livekit-ffi/protocol/room.proto @@ -291,9 +291,10 @@ message RoomOptions { optional bool auto_subscribe = 1; optional bool adaptive_stream = 2; optional bool dynacast = 3; - optional E2eeOptions e2ee = 4; + optional E2eeOptions e2ee = 4 [deprecated=true]; optional RtcConfig rtc_config = 5; // allow to setup a custom RtcConfiguration optional uint32 join_retries = 6; + optional E2eeOptions encryption = 7; } // @@ -697,4 +698,4 @@ message ByteStreamOpened { message TextStreamOpened { required OwnedTextStreamReader reader = 1; required string participant_identity = 2; -} \ No newline at end of file +} diff --git a/livekit-ffi/src/conversion/room.rs b/livekit-ffi/src/conversion/room.rs index b5001649e..fa1e3d55e 100644 --- a/livekit-ffi/src/conversion/room.rs +++ b/livekit-ffi/src/conversion/room.rs @@ -179,6 +179,21 @@ impl From for RoomOptions { }) }); + let encryption = value.encryption.and_then(|opts| { + let encryption_type = opts.encryption_type(); + let provider_opts = opts.key_provider_options; + + Some(E2eeOptions { + encryption_type: encryption_type.into(), + key_provider: if provider_opts.shared_key.is_some() { + let shared_key = provider_opts.shared_key.clone().unwrap(); + KeyProvider::with_shared_key(provider_opts.into(), shared_key) + } else { + KeyProvider::new(provider_opts.into()) + }, + }) + }); + let rtc_config = value.rtc_config.map(Into::into).unwrap_or(RoomOptions::default().rtc_config); @@ -189,6 +204,7 @@ impl From for RoomOptions { options.rtc_config = rtc_config; options.join_retries = value.join_retries.unwrap_or(options.join_retries); options.e2ee = e2ee; + options.encryption = encryption; options } } diff --git a/livekit-ffi/src/livekit.proto.rs b/livekit-ffi/src/livekit.proto.rs index 48bf8dda6..5657c7e08 100644 --- a/livekit-ffi/src/livekit.proto.rs +++ b/livekit-ffi/src/livekit.proto.rs @@ -3289,6 +3289,7 @@ pub struct RoomOptions { pub adaptive_stream: ::core::option::Option, #[prost(bool, optional, tag="3")] pub dynacast: ::core::option::Option, + #[deprecated] #[prost(message, optional, tag="4")] pub e2ee: ::core::option::Option, /// allow to setup a custom RtcConfiguration @@ -3296,6 +3297,8 @@ pub struct RoomOptions { pub rtc_config: ::core::option::Option, #[prost(uint32, optional, tag="6")] pub join_retries: ::core::option::Option, + #[prost(message, optional, tag="7")] + pub encryption: ::core::option::Option, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] diff --git a/livekit/src/room/mod.rs b/livekit/src/room/mod.rs index 8400b46ae..4e7d58cb9 100644 --- a/livekit/src/room/mod.rs +++ b/livekit/src/room/mod.rs @@ -350,7 +350,7 @@ pub struct RoomOptions { pub auto_subscribe: bool, pub adaptive_stream: bool, pub dynacast: bool, - #[deprecated = "use encryption field instead, see x for a detailed explanation of the implications"] + #[deprecated(note = "Use `encryption` field instead, see x for a detailed explanation")] pub e2ee: Option, pub encryption: Option, pub rtc_config: RtcConfiguration, From dcea938908a3128ae9089991658eedbd39acf62b Mon Sep 17 00:00:00 2001 From: lukasIO Date: Fri, 19 Sep 2025 10:18:08 +0200 Subject: [PATCH 31/52] add way to retrieve latest key index --- livekit/src/room/e2ee/key_provider.rs | 11 ++++++++++- livekit/src/room/e2ee/manager.rs | 6 +++--- livekit/src/rtc_engine/rtc_session.rs | 6 +++++- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/livekit/src/room/e2ee/key_provider.rs b/livekit/src/room/e2ee/key_provider.rs index 4d9fb0d08..c4b4ff37d 100644 --- a/livekit/src/room/e2ee/key_provider.rs +++ b/livekit/src/room/e2ee/key_provider.rs @@ -13,6 +13,7 @@ // limitations under the License. use libwebrtc::native::frame_cryptor as fc; +use std::cell::Cell; use crate::id::ParticipantIdentity; @@ -40,6 +41,7 @@ impl Default for KeyProviderOptions { #[derive(Clone)] pub struct KeyProvider { pub(crate) handle: fc::KeyProvider, + latest_key_index: Cell, } impl KeyProvider { @@ -52,6 +54,7 @@ impl KeyProvider { ratchet_salt: options.ratchet_salt, failure_tolerance: options.failure_tolerance, }), + latest_key_index: Cell::new(0), } } @@ -63,10 +66,11 @@ impl KeyProvider { failure_tolerance: options.failure_tolerance, }); handle.set_shared_key(0, shared_key); - Self { handle } + Self { handle, latest_key_index: Cell::new(0) } } pub fn set_shared_key(&self, shared_key: Vec, key_index: i32) { + self.latest_key_index.set(key_index); self.handle.set_shared_key(key_index, shared_key); } @@ -79,6 +83,7 @@ impl KeyProvider { } pub fn set_key(&self, identity: &ParticipantIdentity, key_index: i32, key: Vec) -> bool { + self.latest_key_index.set(key_index); self.handle.set_key(identity.to_string(), key_index, key) } @@ -93,4 +98,8 @@ impl KeyProvider { pub fn set_sif_trailer(&self, trailer: Vec) { self.handle.set_sif_trailer(trailer); } + + pub fn get_latest_key_index(&self) -> i32 { + self.latest_key_index.get() + } } diff --git a/livekit/src/room/e2ee/manager.rs b/livekit/src/room/e2ee/manager.rs index 8432ec343..ae7ec1bab 100644 --- a/livekit/src/room/e2ee/manager.rs +++ b/livekit/src/room/e2ee/manager.rs @@ -37,7 +37,7 @@ type StateChangedHandler = Box, // If Some, it means the e2ee was initialized enabled: bool, // Used to enable/disable e2ee - dc_encryption: bool, + dc_encryption_enabled: bool, frame_cryptors: HashMap<(ParticipantIdentity, TrackSid), FrameCryptor>, data_packet_cryptor: Option, } @@ -61,7 +61,7 @@ impl E2eeManager { Self { inner: Arc::new(Mutex::new(ManagerInner { enabled: options.is_some(), // Enabled by default if options is provided - dc_encryption: options.is_some() && with_dc_encryption, + dc_encryption_enabled: options.is_some() && with_dc_encryption, options, frame_cryptors: HashMap::new(), data_packet_cryptor, @@ -176,7 +176,7 @@ impl E2eeManager { } pub fn is_dc_encryption_enabled(&self) -> bool { - self.inner.lock().dc_encryption + self.inner.lock().dc_encryption_enabled } pub fn set_enabled(&self, enabled: bool) { diff --git a/livekit/src/rtc_engine/rtc_session.rs b/livekit/src/rtc_engine/rtc_session.rs index 78ec3d6bd..cac757a17 100644 --- a/livekit/src/rtc_engine/rtc_session.rs +++ b/livekit/src/rtc_engine/rtc_session.rs @@ -1518,10 +1518,14 @@ impl SessionInner { // Encode the payload and encrypt it let payload_bytes = encrypted_payload.encode_to_vec(); + let key_index = e2ee_manager + .key_provider() + .map(|kp| kp.get_latest_key_index() as u32) + .unwrap_or(0); match e2ee_manager.encrypt_data( &payload_bytes, &self.participant_info.identity.0, - 0, // FIXME - we need to get the current key index of the keyprovider here + key_index, ) { Ok(encrypted_data) => { // Replace with EncryptedPacket variant From a09b685e3ac800ac1225097148dd7093bc1f125c Mon Sep 17 00:00:00 2001 From: lukasIO Date: Fri, 19 Sep 2025 11:22:43 +0200 Subject: [PATCH 32/52] fix key provider last index --- livekit/src/room/e2ee/key_provider.rs | 17 ++++++++++------- livekit/src/room/mod.rs | 1 + livekit/src/rtc_engine/rtc_session.rs | 5 ++++- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/livekit/src/room/e2ee/key_provider.rs b/livekit/src/room/e2ee/key_provider.rs index c4b4ff37d..f472c4ad9 100644 --- a/livekit/src/room/e2ee/key_provider.rs +++ b/livekit/src/room/e2ee/key_provider.rs @@ -13,7 +13,10 @@ // limitations under the License. use libwebrtc::native::frame_cryptor as fc; -use std::cell::Cell; +use std::sync::{ + atomic::{AtomicI32, Ordering}, + Arc, +}; use crate::id::ParticipantIdentity; @@ -41,7 +44,7 @@ impl Default for KeyProviderOptions { #[derive(Clone)] pub struct KeyProvider { pub(crate) handle: fc::KeyProvider, - latest_key_index: Cell, + latest_key_index: Arc, } impl KeyProvider { @@ -54,7 +57,7 @@ impl KeyProvider { ratchet_salt: options.ratchet_salt, failure_tolerance: options.failure_tolerance, }), - latest_key_index: Cell::new(0), + latest_key_index: Arc::new(AtomicI32::new(0)), } } @@ -66,11 +69,11 @@ impl KeyProvider { failure_tolerance: options.failure_tolerance, }); handle.set_shared_key(0, shared_key); - Self { handle, latest_key_index: Cell::new(0) } + Self { handle, latest_key_index: Arc::new(AtomicI32::new(0)) } } pub fn set_shared_key(&self, shared_key: Vec, key_index: i32) { - self.latest_key_index.set(key_index); + self.latest_key_index.store(key_index, Ordering::Relaxed); self.handle.set_shared_key(key_index, shared_key); } @@ -83,7 +86,7 @@ impl KeyProvider { } pub fn set_key(&self, identity: &ParticipantIdentity, key_index: i32, key: Vec) -> bool { - self.latest_key_index.set(key_index); + self.latest_key_index.store(key_index, Ordering::Relaxed); self.handle.set_key(identity.to_string(), key_index, key) } @@ -100,6 +103,6 @@ impl KeyProvider { } pub fn get_latest_key_index(&self) -> i32 { - self.latest_key_index.get() + self.latest_key_index.load(Ordering::Relaxed) } } diff --git a/livekit/src/room/mod.rs b/livekit/src/room/mod.rs index 4e7d58cb9..5b9a55987 100644 --- a/livekit/src/room/mod.rs +++ b/livekit/src/room/mod.rs @@ -477,6 +477,7 @@ impl Room { signal_options, join_retries: options.join_retries, }, + Some(e2ee_manager.clone()), ) .await?; let rtc_engine = Arc::new(rtc_engine); diff --git a/livekit/src/rtc_engine/rtc_session.rs b/livekit/src/rtc_engine/rtc_session.rs index cac757a17..e8e3daa40 100644 --- a/livekit/src/rtc_engine/rtc_session.rs +++ b/livekit/src/rtc_engine/rtc_session.rs @@ -25,7 +25,7 @@ use std::{ use libwebrtc::{prelude::*, stats::RtcStats}; use livekit_api::signal_client::{SignalClient, SignalEvent, SignalEvents}; -use livekit_protocol::{self as proto, encryption}; +use livekit_protocol::{self as proto}; use livekit_runtime::{sleep, JoinHandle}; use parking_lot::Mutex; use prost::Message; @@ -1537,6 +1537,7 @@ impl SessionInner { encryption_type: e2ee_manager.encryption_type().into(), }, )); + log::info!("Successfully encrypted data packet"); } Err(e) => { log::warn!("Failed to encrypt data packet: {}", e); @@ -1544,10 +1545,12 @@ impl SessionInner { } } else { // Packet type shouldn't be encrypted, restore original + log::info!("Packet type shouldn't be encrypted, restore original"); packet.value = packet_value; } } else { // DC encryption not enabled, restore original packet + log::info!("DC encryption not enabled, restore original packet"); packet.value = packet_value; } } From 2c2c5335436a2544a80a0ac77e5f5448e3fdf205 Mon Sep 17 00:00:00 2001 From: Jacob Gelman <3182119+ladvoc@users.noreply.github.com> Date: Fri, 19 Sep 2025 19:10:53 +1000 Subject: [PATCH 33/52] Allow passing test room options --- livekit/tests/common/e2e.rs | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/livekit/tests/common/e2e.rs b/livekit/tests/common/e2e.rs index 676c758c4..5a71f0fe2 100644 --- a/livekit/tests/common/e2e.rs +++ b/livekit/tests/common/e2e.rs @@ -26,31 +26,39 @@ impl TestEnvironment { /// Creates the specified number of connections to a shared room for testing. pub async fn test_rooms(count: usize) -> Result)>> { + test_rooms_with_options((0..count).map(|_| RoomOptions::default())).await +} + +/// Creates multiple connections to a shared room for testing, one for each configuration. +pub async fn test_rooms_with_options( + options: impl IntoIterator, +) -> Result)>> { let test_env = TestEnvironment::from_env_or_defaults(); let room_name = format!("test_room_{}", create_random_uuid()); - let tokens = (0..count) + let tokens = options .into_iter() - .map(|id| -> Result { + .enumerate() + .map(|(id, options)| -> Result<(String, RoomOptions)> { let grants = VideoGrants { room_join: true, room: room_name.clone(), ..Default::default() }; - Ok(AccessToken::with_api_key(&test_env.api_key, &test_env.api_secret) + let token = AccessToken::with_api_key(&test_env.api_key, &test_env.api_secret) .with_ttl(Duration::from_secs(30 * 60)) // 30 minutes .with_grants(grants) .with_identity(&format!("p{}", id)) .to_jwt() - .context("Failed to generate JWT")?) + .context("Failed to generate JWT")?; + Ok((token, options)) }) .collect::>>()?; - let rooms = try_join_all(tokens.into_iter().map(|token| { + let rooms = try_join_all(tokens.into_iter().map(|(token, options)| { let server_url = test_env.server_url.clone(); async move { - let options = RoomOptions::default(); Room::connect(&server_url, &token, options).await.context("Failed to connect to room") } })) .await?; Ok(rooms) -} +} \ No newline at end of file From e4fdfa6e6d829f1062e910bc26be9ce89cd505c5 Mon Sep 17 00:00:00 2001 From: lukasIO Date: Fri, 19 Sep 2025 11:38:14 +0200 Subject: [PATCH 34/52] add dc e2ee test --- livekit/tests/data_channel_encryption.rs | 77 ++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 livekit/tests/data_channel_encryption.rs diff --git a/livekit/tests/data_channel_encryption.rs b/livekit/tests/data_channel_encryption.rs new file mode 100644 index 000000000..bed64d859 --- /dev/null +++ b/livekit/tests/data_channel_encryption.rs @@ -0,0 +1,77 @@ +#[cfg(feature = "__lk-e2e-test")] +use { + crate::common::test_rooms_with_options, + anyhow::{anyhow, Result}, + livekit::{ + e2ee::key_provider::{KeyProvider, KeyProviderOptions}, + DataPacket, E2eeOptions, RoomEvent, RoomOptions, SimulateScenario, + }, + std::{sync::Arc, time::Duration}, + tokio::{sync::oneshot, time}, +}; + +mod common; + +// These tests depend on a LiveKit server, and thus are not enabled by default; +// to run them, start a local LiveKit server in development mode, and enable the +// E2E test feature: +// +// > livekit-server --dev +// > cargo test --features __lk-e2e-test +// +#[cfg(feature = "__lk-e2e-test")] +#[tokio::test] +async fn test_reliable_retry_e2ee() -> Result<()> { + const ITERATIONS: usize = 128; + const PAYLOAD_SIZE: usize = 4096; + + let key_provider_1 = KeyProvider::new(KeyProviderOptions::default()); + let key_provider_2 = KeyProvider::new(KeyProviderOptions::default()); + + key_provider_1.set_shared_key("password".as_bytes().to_vec(), 0); + key_provider_2.set_shared_key("password".as_bytes().to_vec(), 0); + + // Set up test rooms + let mut options1 = RoomOptions::default(); + options1.encryption = Some(E2eeOptions { + key_provider: key_provider_1, + encryption_type: livekit::e2ee::EncryptionType::Gcm, + }); + + let mut options2 = RoomOptions::default(); + options2.encryption = Some(E2eeOptions { + key_provider: key_provider_2, + encryption_type: livekit::e2ee::EncryptionType::Gcm, + }); + + let options = vec![options1, options2]; + let mut rooms = test_rooms_with_options(options).await?; + let (sending_room, _) = rooms.pop().unwrap(); + let (receiving_room, mut receiving_event_rx) = rooms.pop().unwrap(); + + sending_room.e2ee_manager().set_enabled(true); + receiving_room.e2ee_manager().set_enabled(true); + + let sending_room = Arc::new(sending_room); + let receiving_room = Arc::new(receiving_room); + + let receiving_identity = receiving_room.local_participant().identity(); + let (fulfill, expectation) = oneshot::channel(); + + for _ in 0..ITERATIONS { + let packet = DataPacket { + reliable: true, + payload: [0xFA; PAYLOAD_SIZE].to_vec(), + destination_identities: vec![receiving_identity.clone()], + ..Default::default() + }; + sending_room.local_participant().publish_data(packet).await?; + time::sleep(Duration::from_millis(10)).await; + } + + match time::timeout(Duration::from_secs(15), expectation).await { + Ok(Ok(())) => Ok(()), + Ok(Err(_)) => Err(anyhow!("Not all packets were received")), + Err(_) => Err(anyhow!("Timed out waiting for packets")), + } +} From ae48346d1ec03e8fe885d0755518e063220db356 Mon Sep 17 00:00:00 2001 From: lukasIO Date: Fri, 19 Sep 2025 11:58:59 +0200 Subject: [PATCH 35/52] use shared key --- livekit/tests/data_channel_encryption.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/livekit/tests/data_channel_encryption.rs b/livekit/tests/data_channel_encryption.rs index bed64d859..933a16b76 100644 --- a/livekit/tests/data_channel_encryption.rs +++ b/livekit/tests/data_channel_encryption.rs @@ -22,14 +22,15 @@ mod common; #[cfg(feature = "__lk-e2e-test")] #[tokio::test] async fn test_reliable_retry_e2ee() -> Result<()> { + use livekit::e2ee::key_provider::KeyProvider; + const ITERATIONS: usize = 128; const PAYLOAD_SIZE: usize = 4096; - let key_provider_1 = KeyProvider::new(KeyProviderOptions::default()); - let key_provider_2 = KeyProvider::new(KeyProviderOptions::default()); - - key_provider_1.set_shared_key("password".as_bytes().to_vec(), 0); - key_provider_2.set_shared_key("password".as_bytes().to_vec(), 0); + let key_provider_1 = + KeyProvider::with_shared_key(KeyProviderOptions::default(), "password".as_bytes().to_vec()); + let key_provider_2 = + KeyProvider::with_shared_key(KeyProviderOptions::default(), "password".as_bytes().to_vec()); // Set up test rooms let mut options1 = RoomOptions::default(); From 7ee92bf8b8d2750835e92ada5b95fd56b4774d01 Mon Sep 17 00:00:00 2001 From: Jacob Gelman <3182119+ladvoc@users.noreply.github.com> Date: Fri, 19 Sep 2025 20:33:01 +1000 Subject: [PATCH 36/52] Implement encryption test receiver side --- livekit/tests/data_channel_encryption.rs | 91 +++++++++++------------- 1 file changed, 41 insertions(+), 50 deletions(-) diff --git a/livekit/tests/data_channel_encryption.rs b/livekit/tests/data_channel_encryption.rs index 933a16b76..b73102ac6 100644 --- a/livekit/tests/data_channel_encryption.rs +++ b/livekit/tests/data_channel_encryption.rs @@ -1,78 +1,69 @@ #[cfg(feature = "__lk-e2e-test")] use { crate::common::test_rooms_with_options, - anyhow::{anyhow, Result}, + anyhow::{Ok, Result}, livekit::{ - e2ee::key_provider::{KeyProvider, KeyProviderOptions}, - DataPacket, E2eeOptions, RoomEvent, RoomOptions, SimulateScenario, + e2ee::{ + key_provider::{KeyProvider, KeyProviderOptions}, + EncryptionType, + }, + DataPacket, E2eeOptions, RoomEvent, RoomOptions, }, - std::{sync::Arc, time::Duration}, - tokio::{sync::oneshot, time}, + std::time::Duration, + tokio::{time::timeout, try_join}, }; mod common; -// These tests depend on a LiveKit server, and thus are not enabled by default; -// to run them, start a local LiveKit server in development mode, and enable the -// E2E test feature: -// -// > livekit-server --dev -// > cargo test --features __lk-e2e-test -// #[cfg(feature = "__lk-e2e-test")] #[tokio::test] async fn test_reliable_retry_e2ee() -> Result<()> { - use livekit::e2ee::key_provider::KeyProvider; - const ITERATIONS: usize = 128; const PAYLOAD_SIZE: usize = 4096; - let key_provider_1 = - KeyProvider::with_shared_key(KeyProviderOptions::default(), "password".as_bytes().to_vec()); - let key_provider_2 = + let key_provider = KeyProvider::with_shared_key(KeyProviderOptions::default(), "password".as_bytes().to_vec()); - // Set up test rooms - let mut options1 = RoomOptions::default(); - options1.encryption = Some(E2eeOptions { - key_provider: key_provider_1, - encryption_type: livekit::e2ee::EncryptionType::Gcm, - }); + let mut options = RoomOptions::default(); + options.encryption = Some(E2eeOptions { key_provider, encryption_type: EncryptionType::Gcm }); - let mut options2 = RoomOptions::default(); - options2.encryption = Some(E2eeOptions { - key_provider: key_provider_2, - encryption_type: livekit::e2ee::EncryptionType::Gcm, - }); + let mut rooms = test_rooms_with_options([options.clone(), options]).await?; - let options = vec![options1, options2]; - let mut rooms = test_rooms_with_options(options).await?; let (sending_room, _) = rooms.pop().unwrap(); let (receiving_room, mut receiving_event_rx) = rooms.pop().unwrap(); sending_room.e2ee_manager().set_enabled(true); receiving_room.e2ee_manager().set_enabled(true); - let sending_room = Arc::new(sending_room); - let receiving_room = Arc::new(receiving_room); - - let receiving_identity = receiving_room.local_participant().identity(); - let (fulfill, expectation) = oneshot::channel(); + let send_packets = async move { + for iteration in 0..ITERATIONS { + let packet = DataPacket { + reliable: true, + // Set all the bytes in the payload equal to the iteration number + // to verify on the receiver side. + payload: [iteration as u8; PAYLOAD_SIZE].to_vec(), + ..Default::default() + }; + sending_room.local_participant().publish_data(packet).await?; + } + Ok(()) + }; - for _ in 0..ITERATIONS { - let packet = DataPacket { - reliable: true, - payload: [0xFA; PAYLOAD_SIZE].to_vec(), - destination_identities: vec![receiving_identity.clone()], - ..Default::default() - }; - sending_room.local_participant().publish_data(packet).await?; - time::sleep(Duration::from_millis(10)).await; - } + let receive_packets = async move { + let mut recv_idx = 0; + while let Some(event) = receiving_event_rx.recv().await { + let RoomEvent::DataReceived { payload, .. } = event else { + continue; + }; + assert!(payload.iter().all(|byte| *byte == recv_idx as u8)); + recv_idx += 1; + if recv_idx >= ITERATIONS { + break; + } + } + Ok(()) + }; - match time::timeout(Duration::from_secs(15), expectation).await { - Ok(Ok(())) => Ok(()), - Ok(Err(_)) => Err(anyhow!("Not all packets were received")), - Err(_) => Err(anyhow!("Timed out waiting for packets")), - } + timeout(Duration::from_secs(5), async { try_join!(send_packets, receive_packets) }).await??; + Ok(()) } From 1b5a14e30c6f0ae6d40e837688dd0b71f3827c02 Mon Sep 17 00:00:00 2001 From: lukasIO Date: Fri, 19 Sep 2025 13:57:29 +0200 Subject: [PATCH 37/52] rename test --- livekit/tests/data_channel_encryption.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/livekit/tests/data_channel_encryption.rs b/livekit/tests/data_channel_encryption.rs index b73102ac6..7b84a4bf8 100644 --- a/livekit/tests/data_channel_encryption.rs +++ b/livekit/tests/data_channel_encryption.rs @@ -17,7 +17,7 @@ mod common; #[cfg(feature = "__lk-e2e-test")] #[tokio::test] -async fn test_reliable_retry_e2ee() -> Result<()> { +async fn test_data_channel_encryption() -> Result<()> { const ITERATIONS: usize = 128; const PAYLOAD_SIZE: usize = 4096; From 08e5ff547068a32542aa0f21308834de0e57f83f Mon Sep 17 00:00:00 2001 From: lukasIO Date: Fri, 19 Sep 2025 14:27:30 +0200 Subject: [PATCH 38/52] Add encrypted text stream example --- examples/encrypted_text_stream/Cargo.lock | 3440 ++++++++++++++++++++ examples/encrypted_text_stream/Cargo.toml | 14 + examples/encrypted_text_stream/src/main.rs | 172 + 3 files changed, 3626 insertions(+) create mode 100644 examples/encrypted_text_stream/Cargo.lock create mode 100644 examples/encrypted_text_stream/Cargo.toml create mode 100644 examples/encrypted_text_stream/src/main.rs diff --git a/examples/encrypted_text_stream/Cargo.lock b/examples/encrypted_text_stream/Cargo.lock new file mode 100644 index 000000000..f0300e268 --- /dev/null +++ b/examples/encrypted_text_stream/Cargo.lock @@ -0,0 +1,3440 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anstream" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" + +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" +dependencies = [ + "windows-sys 0.60.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.60.2", +] + +[[package]] +name = "anyhow" +version = "1.0.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" + +[[package]] +name = "async-channel" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener 2.5.3", + "futures-core", +] + +[[package]] +name = "async-channel" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-executor" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497c00e0fd83a72a79a39fcbd8e3e2f055d6f6c7e025f3b3d91f4f8e76527fb8" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "pin-project-lite", + "slab", +] + +[[package]] +name = "async-global-executor" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" +dependencies = [ + "async-channel 2.5.0", + "async-executor", + "async-io", + "async-lock", + "blocking", + "futures-lite", + "once_cell", +] + +[[package]] +name = "async-io" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc" +dependencies = [ + "autocfg", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite", + "parking", + "polling", + "rustix", + "slab", + "windows-sys 0.61.0", +] + +[[package]] +name = "async-lock" +version = "3.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc" +dependencies = [ + "event-listener 5.4.1", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-native-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9343dc5acf07e79ff82d0c37899f079db3534d99f189a1837c8e549c99405bec" +dependencies = [ + "futures-util", + "native-tls", + "thiserror", + "url", +] + +[[package]] +name = "async-std" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c8e079a4ab67ae52b7403632e4618815d6db36d2a010cfe41b02c1b1578f93b" +dependencies = [ + "async-channel 1.9.0", + "async-global-executor", + "async-io", + "async-lock", + "crossbeam-utils", + "futures-channel", + "futures-core", + "futures-io", + "futures-lite", + "gloo-timers", + "kv-log-macro", + "log", + "memchr", + "once_cell", + "pin-project-lite", + "pin-utils", + "slab", + "wasm-bindgen-futures", +] + +[[package]] +name = "async-task" +version = "4.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" + +[[package]] +name = "async-tungstenite" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cca750b12e02c389c1694d35c16539f88b8bbaa5945934fdc1b41a776688589" +dependencies = [ + "async-native-tls", + "async-std", + "futures-io", + "futures-util", + "log", + "pin-project-lite", + "tungstenite 0.21.0", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "backtrace" +version = "0.3.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets 0.52.6", +] + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "blocking" +version = "1.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" +dependencies = [ + "async-channel 2.5.0", + "async-task", + "futures-io", + "futures-lite", + "piper", +] + +[[package]] +name = "bmrng" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54df9073108f1558f90ae6c5bf5ab9c917c4185f5527b280c87a993cbead0ac" +dependencies = [ + "futures-core", + "tokio", +] + +[[package]] +name = "bumpalo" +version = "3.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" + +[[package]] +name = "bzip2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" +dependencies = [ + "bzip2-sys", + "libc", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.13+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14" +dependencies = [ + "cc", + "pkg-config", +] + +[[package]] +name = "cc" +version = "1.2.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80f41ae168f955c12fb8960b057d70d0ca153fb83182b57d86380443527be7e9" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cfg-if" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" + +[[package]] +name = "chrono" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-link 0.2.0", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "clap" +version = "4.5.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eac00902d9d136acd712710d71823fb8ac8004ca445a89e73a41d45aa712931" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.5.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ad9bbf750e73b5884fb8a211a9424a1906c1e156724260fdae972f31d70e1d6" +dependencies = [ + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_lex" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" + +[[package]] +name = "codespan-reporting" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe6d2e5af09e8c8ad56c969f2157a3d4238cebc7c55f0a517728c38f7b200f81" +dependencies = [ + "serde", + "termcolor", + "unicode-width", +] + +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "cxx" +version = "1.0.185" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f81de88da10862f22b5b3a60f18f6f42bbe7cb8faa24845dd7b1e4e22190e77" +dependencies = [ + "cc", + "cxx-build", + "cxxbridge-cmd", + "cxxbridge-flags", + "cxxbridge-macro", + "foldhash", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.185" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5edd58bf75c3fdfc80d79806403af626570662f7b6cc782a7fabe156166bd6d6" +dependencies = [ + "cc", + "codespan-reporting", + "indexmap", + "proc-macro2", + "quote", + "scratch", + "syn", +] + +[[package]] +name = "cxxbridge-cmd" +version = "1.0.185" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd46bf2b541a4e0c2d5abba76607379ee05d68e714868e3cb406dc8d591ce2d2" +dependencies = [ + "clap", + "codespan-reporting", + "indexmap", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.185" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c79b68f6a3a8f809d39b38ae8af61305a6113819b19b262643b9c21353b92d9" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.185" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "862b7fdb048ff9ef0779a0d0a03affd09746c4c875543746b640756be9cff2af" +dependencies = [ + "indexmap", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + +[[package]] +name = "data-encoding" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" + +[[package]] +name = "deranged" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d630bccd429a5bb5a64b5e94f693bfc48c9f8566418fda4c494cc94f911f87cc" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "encrypted_text_stream" +version = "0.1.0" +dependencies = [ + "env_logger", + "futures-util", + "livekit", + "livekit-api", + "log", + "tokio", +] + +[[package]] +name = "env_filter" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "jiff", + "log", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.0", +] + +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "event-listener" +version = "5.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener 5.4.1", + "pin-project-lite", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "find-msvc-tools" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959" + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "flate2" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fs2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-lite" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi 0.14.7+wasi-0.2.4", +] + +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + +[[package]] +name = "gloo-timers" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "h2" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 0.2.12", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http 0.2.12", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "0.14.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http 0.2.12", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2 0.5.10", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http 0.2.12", + "hyper", + "rustls", + "tokio", + "tokio-rustls", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" + +[[package]] +name = "icu_properties" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "potential_utf", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" + +[[package]] +name = "icu_provider" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +dependencies = [ + "displaydoc", + "icu_locale_core", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array", +] + +[[package]] +name = "io-uring" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" +dependencies = [ + "bitflags 2.9.4", + "cfg-if", + "libc", +] + +[[package]] +name = "ipnet" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "jiff" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49" +dependencies = [ + "jiff-static", + "log", + "portable-atomic", + "portable-atomic-util", + "serde", +] + +[[package]] +name = "jiff-static" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.3", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852f13bec5eba4ba9afbeb93fd7c13fe56147f055939ae21c43a29a0ecb2702e" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "jsonwebtoken" +version = "9.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a87cc7a48537badeae96744432de36f4be2b4a34a05a5ef32e9dd8a1c169dde" +dependencies = [ + "base64 0.22.1", + "js-sys", + "ring", + "serde", + "serde_json", +] + +[[package]] +name = "kv-log-macro" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" +dependencies = [ + "log", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.175" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" + +[[package]] +name = "libloading" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" +dependencies = [ + "cfg-if", + "windows-targets 0.53.3", +] + +[[package]] +name = "libwebrtc" +version = "0.3.14" +dependencies = [ + "cxx", + "jni", + "js-sys", + "lazy_static", + "livekit-protocol", + "livekit-runtime", + "log", + "parking_lot", + "serde", + "serde_json", + "thiserror", + "tokio", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webrtc-sys", +] + +[[package]] +name = "link-cplusplus" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f78c730aaa7d0b9336a299029ea49f9ee53b0ed06e9202e8cb7db9bae7b8c82" +dependencies = [ + "cc", +] + +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + +[[package]] +name = "litemap" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" + +[[package]] +name = "livekit" +version = "0.7.18" +dependencies = [ + "bmrng", + "bytes", + "chrono", + "futures-util", + "lazy_static", + "libloading", + "libwebrtc", + "livekit-api", + "livekit-protocol", + "livekit-runtime", + "log", + "parking_lot", + "prost", + "semver", + "serde", + "serde_json", + "thiserror", + "tokio", +] + +[[package]] +name = "livekit-api" +version = "0.4.6" +dependencies = [ + "async-tungstenite", + "base64 0.21.7", + "futures-util", + "http 0.2.12", + "jsonwebtoken", + "livekit-protocol", + "livekit-runtime", + "log", + "parking_lot", + "pbjson-types", + "prost", + "rand 0.9.2", + "reqwest", + "scopeguard", + "serde", + "serde_json", + "sha2", + "thiserror", + "tokio", + "tokio-tungstenite", + "url", +] + +[[package]] +name = "livekit-protocol" +version = "0.4.0" +dependencies = [ + "futures-util", + "livekit-runtime", + "parking_lot", + "pbjson", + "pbjson-types", + "prost", + "prost-types", + "serde", + "thiserror", + "tokio", +] + +[[package]] +name = "livekit-runtime" +version = "0.4.0" +dependencies = [ + "tokio", + "tokio-stream", +] + +[[package]] +name = "lock_api" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" +dependencies = [ + "value-bag", +] + +[[package]] +name = "memchr" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +dependencies = [ + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.59.0", +] + +[[package]] +name = "multimap" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084" + +[[package]] +name = "native-tls" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "object" +version = "0.36.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" + +[[package]] +name = "openssl" +version = "0.10.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" +dependencies = [ + "bitflags 2.9.4", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-sys" +version = "0.9.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] + +[[package]] +name = "password-hash" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" +dependencies = [ + "base64ct", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "pbjson" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1030c719b0ec2a2d25a5df729d6cff1acf3cc230bf766f4f97833591f7577b90" +dependencies = [ + "base64 0.21.7", + "serde", +] + +[[package]] +name = "pbjson-build" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2580e33f2292d34be285c5bc3dba5259542b083cfad6037b6d70345f24dcb735" +dependencies = [ + "heck 0.4.1", + "itertools 0.11.0", + "prost", + "prost-types", +] + +[[package]] +name = "pbjson-types" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18f596653ba4ac51bdecbb4ef6773bc7f56042dc13927910de1684ad3d32aa12" +dependencies = [ + "bytes", + "chrono", + "pbjson", + "pbjson-build", + "prost", + "prost-build", + "serde", +] + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest", + "hmac", + "password-hash", + "sha2", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "petgraph" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" +dependencies = [ + "fixedbitset", + "indexmap", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "piper" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" +dependencies = [ + "atomic-waker", + "fastrand", + "futures-io", +] + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "polling" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi", + "pin-project-lite", + "rustix", + "windows-sys 0.61.0", +] + +[[package]] +name = "portable-atomic" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" + +[[package]] +name = "portable-atomic-util" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "potential_utf" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "prost" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-build" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22505a5c94da8e3b7c2996394d1c933236c4d743e81a410bcca4e6989fc066a4" +dependencies = [ + "bytes", + "heck 0.5.0", + "itertools 0.12.1", + "log", + "multimap", + "once_cell", + "petgraph", + "prettyplease", + "prost", + "prost-types", + "regex", + "syn", + "tempfile", +] + +[[package]] +name = "prost-derive" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" +dependencies = [ + "anyhow", + "itertools 0.12.1", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "prost-types" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9091c90b0a32608e984ff2fa4091273cbdd755d54935c51d520887f4a1dbd5b0" +dependencies = [ + "prost", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.16", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.3", +] + +[[package]] +name = "redox_syscall" +version = "0.5.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" +dependencies = [ + "bitflags 2.9.4", +] + +[[package]] +name = "regex" +version = "1.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" + +[[package]] +name = "reqwest" +version = "0.11.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +dependencies = [ + "base64 0.21.7", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http 0.2.12", + "http-body", + "hyper", + "hyper-rustls", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls", + "rustls-native-certs", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "system-configuration", + "tokio", + "tokio-native-tls", + "tokio-rustls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.16", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" + +[[package]] +name = "rustix" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +dependencies = [ + "bitflags 2.9.4", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.0", +] + +[[package]] +name = "rustls" +version = "0.21.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +dependencies = [ + "log", + "ring", + "rustls-webpki", + "sct", +] + +[[package]] +name = "rustls-native-certs" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" +dependencies = [ + "openssl-probe", + "rustls-pemfile", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" +dependencies = [ + "windows-sys 0.61.0", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "scratch" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d68f2ec51b097e4c1a75b681a8bec621909b5e91f15bb7b840c4f2f7b01148b2" + +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags 2.9.4", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + +[[package]] +name = "serde" +version = "1.0.225" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6c24dee235d0da097043389623fb913daddf92c76e9f5a1db88607a0bcbd1d" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.225" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "659356f9a0cb1e529b24c01e43ad2bdf520ec4ceaf83047b83ddcc2251f96383" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.225" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ea936adf78b1f766949a4977b91d2f5595825bd6ec079aa9543ad2685fc4516" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", + "serde_core", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" +dependencies = [ + "libc", +] + +[[package]] +name = "slab" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "socket2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "socket2" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tempfile" +version = "3.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84fa4d11fadde498443cca10fd3ac23c951f0dc59e080e9f4b93d4df4e4eea53" +dependencies = [ + "fastrand", + "getrandom 0.3.3", + "once_cell", + "rustix", + "windows-sys 0.61.0", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "time" +version = "0.3.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde", + "time-core", +] + +[[package]] +name = "time-core" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" + +[[package]] +name = "tinystr" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tokio" +version = "1.47.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" +dependencies = [ + "backtrace", + "bytes", + "io-uring", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "slab", + "socket2 0.6.0", + "tokio-macros", + "windows-sys 0.59.0", +] + +[[package]] +name = "tokio-macros" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" +dependencies = [ + "futures-util", + "log", + "native-tls", + "tokio", + "tokio-native-tls", + "tungstenite 0.20.1", +] + +[[package]] +name = "tokio-util" +version = "0.7.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "tungstenite" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http 0.2.12", + "httparse", + "log", + "native-tls", + "rand 0.8.5", + "sha1", + "thiserror", + "url", + "utf-8", +] + +[[package]] +name = "tungstenite" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http 1.3.1", + "httparse", + "log", + "native-tls", + "rand 0.8.5", + "sha1", + "thiserror", + "url", + "utf-8", +] + +[[package]] +name = "typenum" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" + +[[package]] +name = "unicode-ident" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" + +[[package]] +name = "unicode-width" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "value-bag" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "943ce29a8a743eb10d6082545d861b24f9d1b160b7d741e0f2cdf726bec909c5" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasi" +version = "0.14.7+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" +dependencies = [ + "wasip2", +] + +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab10a69fbd0a177f5f649ad4d8d3305499c42bab9aef2f7ff592d0ec8f833819" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bb702423545a6007bbc368fde243ba47ca275e549c8a28617f56f6ba53b1d1c" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0b221ff421256839509adbb55998214a70d829d3a28c69b4a6672e9d2a42f67" +dependencies = [ + "cfg-if", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc65f4f411d91494355917b605e1480033152658d71f722a90647f56a70c88a0" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffc003a991398a8ee604a401e194b6b3a39677b3173d6e74495eb51b82e99a32" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "293c37f4efa430ca14db3721dfbe48d8c33308096bd44d80ebaa775ab71ba1cf" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbe734895e869dc429d78c4b433f8d17d95f8d05317440b4fad5ab2d33e596dc" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webrtc-sys" +version = "0.3.11" +dependencies = [ + "cc", + "cxx", + "cxx-build", + "glob", + "log", + "webrtc-sys-build", +] + +[[package]] +name = "webrtc-sys-build" +version = "0.3.7" +dependencies = [ + "anyhow", + "fs2", + "regex", + "reqwest", + "scratch", + "semver", + "zip", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.0", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-core" +version = "0.62.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57fe7168f7de578d2d8a05b07fd61870d2e73b4020e9f49aa00da8471723497c" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link 0.2.0", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-link" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" + +[[package]] +name = "windows-result" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7084dcc306f89883455a206237404d3eaf961e5bd7e0f312f7c91f57eb44167f" +dependencies = [ + "windows-link 0.2.0", +] + +[[package]] +name = "windows-strings" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7218c655a553b0bed4426cf54b20d7ba363ef543b52d515b3e48d7fd55318dda" +dependencies = [ + "windows-link 0.2.0", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.3", +] + +[[package]] +name = "windows-sys" +version = "0.61.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa" +dependencies = [ + "windows-link 0.2.0", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" +dependencies = [ + "windows-link 0.1.3", + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "wit-bindgen" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" + +[[package]] +name = "writeable" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" + +[[package]] +name = "yoke" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zip" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" +dependencies = [ + "aes", + "byteorder", + "bzip2", + "constant_time_eq", + "crc32fast", + "crossbeam-utils", + "flate2", + "hmac", + "pbkdf2", + "sha1", + "time", + "zstd", +] + +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.16+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/examples/encrypted_text_stream/Cargo.toml b/examples/encrypted_text_stream/Cargo.toml new file mode 100644 index 000000000..963f2c797 --- /dev/null +++ b/examples/encrypted_text_stream/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "encrypted_text_stream" +version = "0.1.0" +edition = "2021" + +[dependencies] +tokio = { version = "1", features = ["full"] } +futures-util = { version = "0.3", default-features = false, features = ["sink"] } +livekit = { path = "../../livekit", features = ["native-tls"] } +livekit-api = { path = "../../livekit-api" } +log = "0.4.26" +env_logger = "0.11.7" + +[workspace] diff --git a/examples/encrypted_text_stream/src/main.rs b/examples/encrypted_text_stream/src/main.rs new file mode 100644 index 000000000..971dbb0ea --- /dev/null +++ b/examples/encrypted_text_stream/src/main.rs @@ -0,0 +1,172 @@ +use futures_util::TryStreamExt; +use livekit::{ + e2ee::{ + key_provider::{KeyProvider, KeyProviderOptions}, + E2eeOptions, EncryptionType, + }, + prelude::*, + SimulateScenario, StreamReader, StreamTextOptions, TextStreamReader, +}; +use livekit_api::access_token; +use std::{env, error::Error, io::Write}; +use tokio::{ + io::{self, AsyncBufReadExt, BufReader}, + sync::mpsc::UnboundedReceiver, +}; + +#[tokio::main] +async fn main() -> Result<(), Box> { + env_logger::init(); + + let url = env::var("LIVEKIT_URL").unwrap_or_else(|_| "ws://localhost:7880".to_string()); + let api_key = env::var("LIVEKIT_API_KEY").unwrap_or_else(|_| "devkey".to_string()); + let api_secret = env::var("LIVEKIT_API_SECRET").unwrap_or_else(|_| "secret".to_string()); + let room_name = env::var("LIVEKIT_ROOM").unwrap_or_else(|_| "dev".to_string()); + let identity = env::var("LIVEKIT_IDENTITY").unwrap_or_else(|_| "rust-participant".to_string()); + + // Prompt for encryption password + print!("Enter encryption password: "); + std::io::stdout().flush()?; + let mut password = String::new(); + std::io::stdin().read_line(&mut password)?; + let password = password.trim().to_string(); + + // Create access token + let token = access_token::AccessToken::with_api_key(&api_key, &api_secret) + .with_identity(&identity) + .with_name(&format!("{} (Encrypted)", identity)) + .with_grants(access_token::VideoGrants { + room_join: true, + room: room_name.clone(), + ..Default::default() + }) + .to_jwt()?; + + // Set up E2EE key provider + let key_provider = + KeyProvider::with_shared_key(KeyProviderOptions::default(), password.as_bytes().to_vec()); + + // Configure room options with encryption + let mut room_options = RoomOptions::default(); + room_options.encryption = + Some(E2eeOptions { key_provider, encryption_type: livekit::e2ee::EncryptionType::Gcm }); + + // Connect to room + let (room, rx) = Room::connect(&url, &token, room_options).await?; + println!("Connected to encrypted room: {} - {}", room.name(), room.sid().await); + + // Enable E2EE + room.e2ee_manager().set_enabled(true); + println!("End-to-end encryption enabled!"); + + // Run the interactive chat + run_interactive_chat(room, rx).await +} + +async fn run_interactive_chat( + room: Room, + mut rx: UnboundedReceiver, +) -> Result<(), Box> { + println!("\n=== Encrypted Text Chat ==="); + println!("Type messages to send (press Enter). Type 'quit' to exit."); + println!("Incoming messages will be displayed below:\n"); + + let stdin = io::stdin(); + let mut stdin_reader = BufReader::new(stdin); + + loop { + tokio::select! { + // Handle user input + input_result = read_user_input(&mut stdin_reader) => { + match input_result { + Ok(Some(input)) => { + if input == "quit" { + println!("Goodbye!"); + break; + } + + // Send the message + let options = StreamTextOptions { + topic: "lk.chat".to_string(), + ..Default::default() + }; + + match room.local_participant().send_text(&input, options).await { + Ok(_) => { + println!("✓ Sent (encrypted): {}", input); + } + Err(e) => { + println!("✗ Failed to send: {}", e); + } + } + } + Ok(None) => { + // Empty input, continue + continue; + } + Err(e) => { + eprintln!("Error reading input: {}", e); + break; + } + } + } + + // Handle incoming room events + event = rx.recv() => { + match event { + Some(RoomEvent::TextStreamOpened { reader, topic, participant_identity }) => { + if topic == "lk.chat" { + if let Some(mut reader) = reader.take() { + match reader.read_all().await { + Ok(message) => { + println!("📨 {} (decrypted): {}", participant_identity, message); + } + Err(e) => { + println!("✗ Failed to read message from {}: {}", participant_identity, e); + } + } + } + } + } + Some(RoomEvent::ParticipantConnected( participant )) => { + println!("👋 {} joined the room", participant.identity()); + } + Some(RoomEvent::ParticipantDisconnected ( participant )) => { + println!("👋 {} left the room", participant.identity()); + } + Some(RoomEvent::Disconnected { reason }) => { + println!("Disconnected from room: {:?}", reason); + break; + } + Some(_) => { + // Ignore other events + } + None => { + println!("Room event stream ended"); + break; + } + } + } + } + } + + Ok(()) +} + +async fn read_user_input( + stdin_reader: &mut BufReader, +) -> Result, Box> { + let mut input = String::new(); + let bytes_read = stdin_reader.read_line(&mut input).await?; + + if bytes_read == 0 { + return Ok(None); // EOF + } + + let input = input.trim().to_string(); + if input.is_empty() { + return Ok(None); + } + + Ok(Some(input)) +} From e9e46a4162e86d4b08ac38ca3f1d959eeede3ef5 Mon Sep 17 00:00:00 2001 From: lukasIO Date: Fri, 19 Sep 2025 14:39:17 +0200 Subject: [PATCH 39/52] revert merge artifacts --- webrtc-sys/libwebrtc/build_windows.cmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webrtc-sys/libwebrtc/build_windows.cmd b/webrtc-sys/libwebrtc/build_windows.cmd index d5e9839a5..ef772538e 100644 --- a/webrtc-sys/libwebrtc/build_windows.cmd +++ b/webrtc-sys/libwebrtc/build_windows.cmd @@ -66,7 +66,7 @@ if "!profile!" == "debug" ( rem generate ninja for release call gn.bat gen %OUTPUT_DIR% --root="src" ^ - --args="is_debug=!debug! is_clang=true target_cpu=\"!arch!\" use_custom_libcxx=false use_custom_libcxx_for_host=false rtc_libvpx_build_vp9=true enable_libaom=true rtc_include_tests=false rtc_build_examples=false rtc_build_tools=false is_component_build=false rtc_enable_protobuf=false rtc_use_h264=true ffmpeg_branding=\"Chrome\" symbol_level=0 enable_iterator_debugging=false" +--args="is_debug=!debug! is_clang=true target_cpu=\"!arch!\" use_custom_libcxx=false rtc_libvpx_build_vp9=true enable_libaom=true rtc_include_tests=false rtc_build_examples=false rtc_build_tools=false is_component_build=false rtc_enable_protobuf=false rtc_use_h264=true ffmpeg_branding=\"Chrome\" symbol_level=0 enable_iterator_debugging=false" rem build ninja.exe -C %OUTPUT_DIR% :default From b8758647d4c13e42b34a17fd1fe0485caa085665 Mon Sep 17 00:00:00 2001 From: lukasIO Date: Fri, 19 Sep 2025 14:39:49 +0200 Subject: [PATCH 40/52] whitespace --- webrtc-sys/libwebrtc/build_windows.cmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webrtc-sys/libwebrtc/build_windows.cmd b/webrtc-sys/libwebrtc/build_windows.cmd index ef772538e..2dda7e870 100644 --- a/webrtc-sys/libwebrtc/build_windows.cmd +++ b/webrtc-sys/libwebrtc/build_windows.cmd @@ -66,7 +66,7 @@ if "!profile!" == "debug" ( rem generate ninja for release call gn.bat gen %OUTPUT_DIR% --root="src" ^ ---args="is_debug=!debug! is_clang=true target_cpu=\"!arch!\" use_custom_libcxx=false rtc_libvpx_build_vp9=true enable_libaom=true rtc_include_tests=false rtc_build_examples=false rtc_build_tools=false is_component_build=false rtc_enable_protobuf=false rtc_use_h264=true ffmpeg_branding=\"Chrome\" symbol_level=0 enable_iterator_debugging=false" + --args="is_debug=!debug! is_clang=true target_cpu=\"!arch!\" use_custom_libcxx=false rtc_libvpx_build_vp9=true enable_libaom=true rtc_include_tests=false rtc_build_examples=false rtc_build_tools=false is_component_build=false rtc_enable_protobuf=false rtc_use_h264=true ffmpeg_branding=\"Chrome\" symbol_level=0 enable_iterator_debugging=false" rem build ninja.exe -C %OUTPUT_DIR% :default From 802e24d887f413e1885bf2bbf8c5acd45a2cabe5 Mon Sep 17 00:00:00 2001 From: lukasIO Date: Fri, 19 Sep 2025 14:40:17 +0200 Subject: [PATCH 41/52] whitespace --- webrtc-sys/libwebrtc/build_windows.cmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webrtc-sys/libwebrtc/build_windows.cmd b/webrtc-sys/libwebrtc/build_windows.cmd index 2dda7e870..1de0d83a1 100644 --- a/webrtc-sys/libwebrtc/build_windows.cmd +++ b/webrtc-sys/libwebrtc/build_windows.cmd @@ -66,7 +66,7 @@ if "!profile!" == "debug" ( rem generate ninja for release call gn.bat gen %OUTPUT_DIR% --root="src" ^ - --args="is_debug=!debug! is_clang=true target_cpu=\"!arch!\" use_custom_libcxx=false rtc_libvpx_build_vp9=true enable_libaom=true rtc_include_tests=false rtc_build_examples=false rtc_build_tools=false is_component_build=false rtc_enable_protobuf=false rtc_use_h264=true ffmpeg_branding=\"Chrome\" symbol_level=0 enable_iterator_debugging=false" + --args="is_debug=!debug! is_clang=true target_cpu=\"!arch!\" use_custom_libcxx=false rtc_libvpx_build_vp9=true enable_libaom=true rtc_include_tests=false rtc_build_examples=false rtc_build_tools=false is_component_build=false rtc_enable_protobuf=false rtc_use_h264=true ffmpeg_branding=\"Chrome\" symbol_level=0 enable_iterator_debugging=false" rem build ninja.exe -C %OUTPUT_DIR% :default From ce09de001b090ca8ac3c4bf5b73778b6bda3a090 Mon Sep 17 00:00:00 2001 From: lukasIO Date: Fri, 19 Sep 2025 14:46:17 +0200 Subject: [PATCH 42/52] format --- livekit/tests/common/e2e.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/livekit/tests/common/e2e.rs b/livekit/tests/common/e2e.rs index 5a71f0fe2..4f55a7cb4 100644 --- a/livekit/tests/common/e2e.rs +++ b/livekit/tests/common/e2e.rs @@ -61,4 +61,4 @@ pub async fn test_rooms_with_options( .await?; Ok(rooms) -} \ No newline at end of file +} From ef627dcce7986edf605e864cec16be964379eb75 Mon Sep 17 00:00:00 2001 From: lukasIO Date: Mon, 22 Sep 2025 12:09:29 +0200 Subject: [PATCH 43/52] cleanup --- livekit/src/rtc_engine/rtc_session.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/livekit/src/rtc_engine/rtc_session.rs b/livekit/src/rtc_engine/rtc_session.rs index 7440344f3..c463a62f2 100644 --- a/livekit/src/rtc_engine/rtc_session.rs +++ b/livekit/src/rtc_engine/rtc_session.rs @@ -1532,7 +1532,6 @@ impl SessionInner { encryption_type: e2ee_manager.encryption_type().into(), }, )); - log::info!("Successfully encrypted data packet"); } Err(e) => { log::warn!("Failed to encrypt data packet: {}", e); @@ -1540,12 +1539,10 @@ impl SessionInner { } } else { // Packet type shouldn't be encrypted, restore original - log::info!("Packet type shouldn't be encrypted, restore original"); packet.value = packet_value; } } else { // DC encryption not enabled, restore original packet - log::info!("DC encryption not enabled, restore original packet"); packet.value = packet_value; } } From d082698830fc75f1056dad5b2c152f54383ab0ad Mon Sep 17 00:00:00 2001 From: lukasIO Date: Tue, 23 Sep 2025 14:01:15 +0200 Subject: [PATCH 44/52] address comments --- livekit/src/room/mod.rs | 4 ++-- livekit/src/rtc_engine/rtc_session.rs | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/livekit/src/room/mod.rs b/livekit/src/room/mod.rs index 5b9a55987..6650c71dc 100644 --- a/livekit/src/room/mod.rs +++ b/livekit/src/room/mod.rs @@ -459,11 +459,11 @@ impl Room { pub async fn connect( url: &str, token: &str, - options: RoomOptions, + mut options: RoomOptions, ) -> RoomResult<(Self, mpsc::UnboundedReceiver)> { // TODO(theomonnom): move connection logic to the RoomSession let with_dc_encryption = options.encryption.is_some(); - let encryption_options = options.encryption.clone().or(options.e2ee.clone()); + let encryption_options = options.encryption.take().or(options.e2ee.take()); let e2ee_manager = E2eeManager::new(encryption_options, with_dc_encryption); let mut signal_options = SignalOptions::default(); signal_options.sdk_options = options.sdk_options.clone().into(); diff --git a/livekit/src/rtc_engine/rtc_session.rs b/livekit/src/rtc_engine/rtc_session.rs index c463a62f2..8c8df3c6d 100644 --- a/livekit/src/rtc_engine/rtc_session.rs +++ b/livekit/src/rtc_engine/rtc_session.rs @@ -1534,7 +1534,9 @@ impl SessionInner { )); } Err(e) => { - log::warn!("Failed to encrypt data packet: {}", e); + return Err(EngineError::Internal( + format!("Failed to encrypt data packet: {}", e).into(), + )); } } } else { From 7a93560ed98f32d572a6fd96fca42e2ba13c76b5 Mon Sep 17 00:00:00 2001 From: lukasIO Date: Tue, 23 Sep 2025 14:17:07 +0200 Subject: [PATCH 45/52] simplify conversion and recursive data handling --- livekit/src/rtc_engine/rtc_session.rs | 134 +++++++++----------------- 1 file changed, 47 insertions(+), 87 deletions(-) diff --git a/livekit/src/rtc_engine/rtc_session.rs b/livekit/src/rtc_engine/rtc_session.rs index 8c8df3c6d..ed7ff0abc 100644 --- a/livekit/src/rtc_engine/rtc_session.rs +++ b/livekit/src/rtc_engine/rtc_session.rs @@ -240,9 +240,38 @@ struct EncodedPacket { sequence: u32, } -impl Into for proto::DataPacket { - fn into(self) -> EncodedPacket { - EncodedPacket { data: self.encode_to_vec(), sequence: self.sequence } +impl From for EncodedPacket { + fn from(packet: proto::DataPacket) -> Self { + Self { data: packet.encode_to_vec(), sequence: packet.sequence } + } +} + +fn convert_encrypted_to_data_packet_value( + encrypted_value: proto::encrypted_packet_payload::Value, +) -> proto::data_packet::Value { + match encrypted_value { + proto::encrypted_packet_payload::Value::User(user) => proto::data_packet::Value::User(user), + proto::encrypted_packet_payload::Value::ChatMessage(msg) => { + proto::data_packet::Value::ChatMessage(msg) + } + proto::encrypted_packet_payload::Value::RpcRequest(req) => { + proto::data_packet::Value::RpcRequest(req) + } + proto::encrypted_packet_payload::Value::RpcResponse(resp) => { + proto::data_packet::Value::RpcResponse(resp) + } + proto::encrypted_packet_payload::Value::RpcAck(ack) => { + proto::data_packet::Value::RpcAck(ack) + } + proto::encrypted_packet_payload::Value::StreamHeader(header) => { + proto::data_packet::Value::StreamHeader(header) + } + proto::encrypted_packet_payload::Value::StreamChunk(chunk) => { + proto::data_packet::Value::StreamChunk(chunk) + } + proto::encrypted_packet_payload::Value::StreamTrailer(trailer) => { + proto::data_packet::Value::StreamTrailer(trailer) + } } } @@ -1016,7 +1045,11 @@ impl SessionInner { self.update_packet_rx_state(&packet); } if let Some(detail) = packet.value.take() { - self.emit_incoming_packet(kind, packet, detail); + let participant_sid: Option = + packet.participant_sid.try_into().ok(); + let participant_identity: Option = + packet.participant_identity.try_into().ok(); + self.emit_incoming_packet(kind, participant_sid, participant_identity, detail); } } RtcEvent::DataChannelBufferedAmountChange { sent, amount: _, kind } => { @@ -1036,15 +1069,10 @@ impl SessionInner { fn emit_incoming_packet( &self, kind: DataPacketKind, - packet: proto::DataPacket, + participant_sid: Option, + participant_identity: Option, value: proto::data_packet::Value, ) { - // TODO: Standardize how participant identity is emitted in events; - // Option, ParticipantIdentity, and String are all used. - let participant_sid: Option = packet.participant_sid.try_into().ok(); - let participant_identity: Option = - packet.participant_identity.try_into().ok(); - let send_result = match value { proto::data_packet::Value::User(user) => { // Participant SID and identity used to be defined on user packet, but @@ -1152,16 +1180,17 @@ impl SessionInner { // Parse the decrypted payload as EncryptedPacketPayload match proto::EncryptedPacketPayload::decode(&*decrypted_payload) { Ok(encrypted_payload) => { - if let Some(value) = encrypted_payload.value { - // Forward the decrypted payload based on its type - self.handle_decrypted_payload( + if let Some(decrypted_value) = encrypted_payload.value { + // Recursively call emit_incoming_packet with the decrypted value + self.emit_incoming_packet( kind, participant_sid, participant_identity, - value, - ) + convert_encrypted_to_data_packet_value(decrypted_value), + ); + Ok(()) } else { - log::warn!("Decrypted payload has no value"); + log::warn!("Failed to decrypt encrypted payload"); Ok(()) } } @@ -1176,7 +1205,7 @@ impl SessionInner { "Failed to decrypt data packet from {}", participant_identity_str ); - Ok(()) // Don't emit the event if decryption fails + Ok(()) } } } else { @@ -1191,75 +1220,6 @@ impl SessionInner { } } - fn handle_decrypted_payload( - &self, - kind: DataPacketKind, - participant_sid: Option, - participant_identity: Option, - value: proto::encrypted_packet_payload::Value, - ) -> Result<(), mpsc::error::SendError> { - match value { - proto::encrypted_packet_payload::Value::User(user) => { - self.emitter.send(SessionEvent::Data { - kind, - participant_sid, - participant_identity, - payload: user.payload, - topic: user.topic, - }) - } - proto::encrypted_packet_payload::Value::ChatMessage(message) => { - self.emitter.send(SessionEvent::ChatMessage { - participant_identity: participant_identity - .unwrap_or(ParticipantIdentity("".into())), - message: ChatMessage::from(message), - }) - } - - proto::encrypted_packet_payload::Value::RpcRequest(rpc_request) => { - let caller_identity = participant_identity; - self.emitter.send(SessionEvent::RpcRequest { - caller_identity, - request_id: rpc_request.id, - method: rpc_request.method, - payload: rpc_request.payload, - response_timeout: Duration::from_millis(rpc_request.response_timeout_ms as u64), - version: rpc_request.version, - }) - } - proto::encrypted_packet_payload::Value::RpcResponse(rpc_response) => { - let (payload, error) = match rpc_response.value { - None => (None, None), - Some(proto::rpc_response::Value::Payload(payload)) => (Some(payload), None), - Some(proto::rpc_response::Value::Error(err)) => (None, Some(err)), - }; - self.emitter.send(SessionEvent::RpcResponse { - request_id: rpc_response.request_id, - payload, - error, - }) - } - proto::encrypted_packet_payload::Value::RpcAck(rpc_ack) => { - self.emitter.send(SessionEvent::RpcAck { request_id: rpc_ack.request_id }) - } - proto::encrypted_packet_payload::Value::StreamHeader(header) => { - let participant_identity = - participant_identity.map_or("".into(), |identity| identity.0); - self.emitter.send(SessionEvent::DataStreamHeader { header, participant_identity }) - } - proto::encrypted_packet_payload::Value::StreamChunk(chunk) => { - let participant_identity = - participant_identity.map_or("".into(), |identity| identity.0); - self.emitter.send(SessionEvent::DataStreamChunk { chunk, participant_identity }) - } - proto::encrypted_packet_payload::Value::StreamTrailer(trailer) => { - let participant_identity = - participant_identity.map_or("".into(), |identity| identity.0); - self.emitter.send(SessionEvent::DataStreamTrailer { trailer, participant_identity }) - } - } - } - async fn add_track(&self, req: proto::AddTrackRequest) -> EngineResult { let (tx, rx) = oneshot::channel(); let cid = req.cid.clone(); From 22f9d4226922c319f0c4aabfb30587980d53892d Mon Sep 17 00:00:00 2001 From: lukasIO Date: Tue, 23 Sep 2025 14:19:05 +0200 Subject: [PATCH 46/52] cleanup --- livekit/src/rtc_engine/rtc_session.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/livekit/src/rtc_engine/rtc_session.rs b/livekit/src/rtc_engine/rtc_session.rs index ed7ff0abc..1f17dc1ee 100644 --- a/livekit/src/rtc_engine/rtc_session.rs +++ b/livekit/src/rtc_engine/rtc_session.rs @@ -240,9 +240,9 @@ struct EncodedPacket { sequence: u32, } -impl From for EncodedPacket { - fn from(packet: proto::DataPacket) -> Self { - Self { data: packet.encode_to_vec(), sequence: packet.sequence } +impl Into for proto::DataPacket { + fn into(self) -> EncodedPacket { + EncodedPacket { data: self.encode_to_vec(), sequence: self.sequence } } } From 4f29df1b1f35393e432c9cd9e850038db0d8938b Mon Sep 17 00:00:00 2001 From: lukasIO Date: Tue, 23 Sep 2025 14:27:20 +0200 Subject: [PATCH 47/52] more explicit conversion --- livekit/src/rtc_engine/rtc_session.rs | 61 +++++++++++++++------------ 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/livekit/src/rtc_engine/rtc_session.rs b/livekit/src/rtc_engine/rtc_session.rs index 1f17dc1ee..ceb2b0005 100644 --- a/livekit/src/rtc_engine/rtc_session.rs +++ b/livekit/src/rtc_engine/rtc_session.rs @@ -275,6 +275,38 @@ fn convert_encrypted_to_data_packet_value( } } +fn convert_data_packet_to_encrypted_value( + value: proto::data_packet::Value, +) -> Option { + match value { + proto::data_packet::Value::User(user) => { + Some(proto::encrypted_packet_payload::Value::User(user)) + } + proto::data_packet::Value::ChatMessage(msg) => { + Some(proto::encrypted_packet_payload::Value::ChatMessage(msg)) + } + proto::data_packet::Value::RpcRequest(req) => { + Some(proto::encrypted_packet_payload::Value::RpcRequest(req)) + } + proto::data_packet::Value::RpcResponse(resp) => { + Some(proto::encrypted_packet_payload::Value::RpcResponse(resp)) + } + proto::data_packet::Value::RpcAck(ack) => { + Some(proto::encrypted_packet_payload::Value::RpcAck(ack)) + } + proto::data_packet::Value::StreamHeader(header) => { + Some(proto::encrypted_packet_payload::Value::StreamHeader(header)) + } + proto::data_packet::Value::StreamChunk(chunk) => { + Some(proto::encrypted_packet_payload::Value::StreamChunk(chunk)) + } + proto::data_packet::Value::StreamTrailer(trailer) => { + Some(proto::encrypted_packet_payload::Value::StreamTrailer(trailer)) + } + _ => None, + } +} + impl TxQueueItem for EncodedPacket { fn buffered_size(&self) -> usize { self.data.len() @@ -1437,34 +1469,7 @@ impl SessionInner { if let (Some(e2ee_manager), Some(value)) = (&self.e2ee_manager, packet_value.clone()) { if e2ee_manager.is_dc_encryption_enabled() { // Create EncryptedPacketPayload from the original value if it's an encryptable type - let encrypted_payload_value = match value { - proto::data_packet::Value::User(user) => { - Some(proto::encrypted_packet_payload::Value::User(user)) - } - proto::data_packet::Value::ChatMessage(msg) => { - Some(proto::encrypted_packet_payload::Value::ChatMessage(msg)) - } - proto::data_packet::Value::RpcRequest(req) => { - Some(proto::encrypted_packet_payload::Value::RpcRequest(req)) - } - proto::data_packet::Value::RpcResponse(resp) => { - Some(proto::encrypted_packet_payload::Value::RpcResponse(resp)) - } - proto::data_packet::Value::RpcAck(ack) => { - Some(proto::encrypted_packet_payload::Value::RpcAck(ack)) - } - proto::data_packet::Value::StreamHeader(header) => { - Some(proto::encrypted_packet_payload::Value::StreamHeader(header)) - } - proto::data_packet::Value::StreamChunk(chunk) => { - Some(proto::encrypted_packet_payload::Value::StreamChunk(chunk)) - } - proto::data_packet::Value::StreamTrailer(trailer) => { - Some(proto::encrypted_packet_payload::Value::StreamTrailer(trailer)) - } - // Non-encryptable types return None - _ => None, - }; + let encrypted_payload_value = convert_data_packet_to_encrypted_value(value); if let Some(encrypted_payload_value) = encrypted_payload_value { // Create EncryptedPacketPayload and encrypt it From a6e9236bb3f5e19f90c53872ed53c6dc3a018b76 Mon Sep 17 00:00:00 2001 From: lukasIO Date: Tue, 23 Sep 2025 14:42:04 +0200 Subject: [PATCH 48/52] Update test case --- livekit/tests/data_channel_encryption.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/livekit/tests/data_channel_encryption.rs b/livekit/tests/data_channel_encryption.rs index 7b84a4bf8..7fe46a4f5 100644 --- a/livekit/tests/data_channel_encryption.rs +++ b/livekit/tests/data_channel_encryption.rs @@ -21,13 +21,21 @@ async fn test_data_channel_encryption() -> Result<()> { const ITERATIONS: usize = 128; const PAYLOAD_SIZE: usize = 4096; - let key_provider = + let key_provider1 = KeyProvider::with_shared_key(KeyProviderOptions::default(), "password".as_bytes().to_vec()); - let mut options = RoomOptions::default(); - options.encryption = Some(E2eeOptions { key_provider, encryption_type: EncryptionType::Gcm }); + let mut options1 = RoomOptions::default(); + options1.encryption = + Some(E2eeOptions { key_provider: key_provider1, encryption_type: EncryptionType::Gcm }); - let mut rooms = test_rooms_with_options([options.clone(), options]).await?; + let key_provider2 = + KeyProvider::with_shared_key(KeyProviderOptions::default(), "password".as_bytes().to_vec()); + + let mut options2 = RoomOptions::default(); + options2.encryption = + Some(E2eeOptions { key_provider: key_provider2, encryption_type: EncryptionType::Gcm }); + + let mut rooms = test_rooms_with_options([options1, options2]).await?; let (sending_room, _) = rooms.pop().unwrap(); let (receiving_room, mut receiving_event_rx) = rooms.pop().unwrap(); From 3b382bfb35deae9a7c0812d267cc48f791462d55 Mon Sep 17 00:00:00 2001 From: lukasIO Date: Mon, 29 Sep 2025 12:12:37 +0200 Subject: [PATCH 49/52] wip expose encryption_type --- livekit-ffi/protocol/data_stream.proto | 3 +++ livekit-ffi/protocol/room.proto | 1 + livekit/Cargo.toml | 1 + livekit/src/room/data_stream/incoming.rs | 11 ++++++-- livekit/src/room/data_stream/mod.rs | 10 +++++++ livekit/src/room/mod.rs | 15 +++++++---- livekit/src/rtc_engine/mod.rs | 33 +++++++++++++++++------- livekit/src/rtc_engine/rtc_session.rs | 26 ++++++++++++++++--- 8 files changed, 81 insertions(+), 19 deletions(-) diff --git a/livekit-ffi/protocol/data_stream.proto b/livekit-ffi/protocol/data_stream.proto index bc1076ec4..d9d98b3e9 100644 --- a/livekit-ffi/protocol/data_stream.proto +++ b/livekit-ffi/protocol/data_stream.proto @@ -18,6 +18,7 @@ package livekit.proto; option csharp_namespace = "LiveKit.Proto"; import "handle.proto"; +import "e2ee.proto"; // MARK: - Text stream reader @@ -329,6 +330,7 @@ message TextStreamInfo { optional string reply_to_stream_id = 9; // Optional: Reply to specific message repeated string attached_stream_ids = 10; // file attachments for text streams optional bool generated = 11; // true if the text has been generated by an agent from a participant's audio transcription + required EncryptionType encryption_type = 12; } message ByteStreamInfo { required string stream_id = 1; // unique identifier for this data stream @@ -339,6 +341,7 @@ message ByteStreamInfo { map attributes = 6; // user defined attributes map that can carry additional info required string name = 7; + required EncryptionType encryption_type = 8; } message StreamTextOptions { diff --git a/livekit-ffi/protocol/room.proto b/livekit-ffi/protocol/room.proto index 56996731b..57293e485 100644 --- a/livekit-ffi/protocol/room.proto +++ b/livekit-ffi/protocol/room.proto @@ -510,6 +510,7 @@ message ConnectionQualityChanged { message UserPacket { required OwnedBuffer data = 1; optional string topic = 2; + required EncryptionType encryption_type = 3; } message ChatMessage { diff --git a/livekit/Cargo.toml b/livekit/Cargo.toml index bbaae8e33..8d02251fb 100644 --- a/livekit/Cargo.toml +++ b/livekit/Cargo.toml @@ -44,6 +44,7 @@ semver = "1.0" libloading = { version = "0.8.6" } bytes = "1.10.1" bmrng = "0.5.2" +test-log = "0.2.18" [dev-dependencies] anyhow = "1.0.99" diff --git a/livekit/src/room/data_stream/incoming.rs b/livekit/src/room/data_stream/incoming.rs index 93bfad39b..e5215a169 100644 --- a/livekit/src/room/data_stream/incoming.rs +++ b/livekit/src/room/data_stream/incoming.rs @@ -15,7 +15,7 @@ use super::{ AnyStreamInfo, ByteStreamInfo, StreamError, StreamProgress, StreamResult, TextStreamInfo, }; -use crate::TakeCell; +use crate::{e2ee::EncryptionType, TakeCell}; use bytes::{Bytes, BytesMut}; use futures_util::{Stream, StreamExt}; use livekit_protocol::data_stream as proto; @@ -246,13 +246,20 @@ impl IncomingStreamManager { } /// Handles an incoming header packet. - pub fn handle_header(&self, header: proto::Header, identity: String) { + pub fn handle_header( + &self, + header: proto::Header, + identity: String, + encryption_type: livekit_protocol::encryption::Type, + ) { let Ok(info) = AnyStreamInfo::try_from(header).inspect_err(|e| log::error!("Invalid header: {}", e)) else { return; }; + info.encryption_type = encryption_type.into(); + let id = info.id().to_owned(); let bytes_total = info.total_length(); diff --git a/livekit/src/room/data_stream/mod.rs b/livekit/src/room/data_stream/mod.rs index d71a88719..e83ee037f 100644 --- a/livekit/src/room/data_stream/mod.rs +++ b/livekit/src/room/data_stream/mod.rs @@ -23,6 +23,8 @@ mod outgoing; pub use incoming::*; pub use outgoing::*; +use crate::e2ee::EncryptionType; + /// Result type for data stream operations. pub type StreamResult = Result; @@ -96,6 +98,8 @@ pub struct ByteStreamInfo { pub mime_type: String, /// The name of the file being sent. pub name: String, + /// The encryption used + pub encryption_type: EncryptionType, } /// Information about a text data stream. @@ -118,6 +122,8 @@ pub struct TextStreamInfo { pub reply_to_stream_id: Option, pub attached_stream_ids: Vec, pub generated: bool, + /// The encryption used + pub encryption_type: EncryptionType, } /// Operation type for text streams. @@ -162,6 +168,7 @@ impl ByteStreamInfo { attributes: header.attributes, mime_type: header.mime_type, name: byte_header.name, + encryption_type: EncryptionType::None, } } } @@ -182,6 +189,7 @@ impl TextStreamInfo { .then_some(text_header.reply_to_stream_id), attached_stream_ids: text_header.attached_stream_ids, generated: text_header.generated, + encryption_type: EncryptionType::None, } } } @@ -209,6 +217,7 @@ impl AnyStreamInfo { [Byte, Text]; pub fn id(self: &Self) -> &str; pub fn total_length(self: &Self) -> Option; + pub fn encryption_type(self: &Self) -> EncryptionType; ); } @@ -217,6 +226,7 @@ macro_rules! stream_info { () => { fn id(&self) -> &str { &self.id } fn total_length(&self) -> Option { self.total_length } + fn encryption_type(&self) -> EncryptionType { self.encryption_type } }; } diff --git a/livekit/src/room/mod.rs b/livekit/src/room/mod.rs index 6650c71dc..812e1afd5 100644 --- a/livekit/src/room/mod.rs +++ b/livekit/src/room/mod.rs @@ -876,11 +876,11 @@ impl RoomSession { EngineEvent::LocalTrackSubscribed { track_sid } => { self.handle_track_subscribed(track_sid) } - EngineEvent::DataStreamHeader { header, participant_identity } => { - self.handle_data_stream_header(header, participant_identity); + EngineEvent::DataStreamHeader { header, participant_identity, encryption_type } => { + self.handle_data_stream_header(header, participant_identity, encryption_type); } - EngineEvent::DataStreamChunk { chunk, participant_identity } => { - self.handle_data_stream_chunk(chunk, participant_identity); + EngineEvent::DataStreamChunk { chunk, participant_identity, encryption_type } => { + self.handle_data_stream_chunk(chunk, participant_identity, encryption_type); } EngineEvent::DataStreamTrailer { trailer, participant_identity } => { self.handle_data_stream_trailer(trailer, participant_identity); @@ -1485,8 +1485,13 @@ impl RoomSession { &self, header: proto::data_stream::Header, participant_identity: String, + encryption_type: proto::encryption::Type, ) { - self.incoming_stream_manager.handle_header(header.clone(), participant_identity.clone()); + self.incoming_stream_manager.handle_header( + header.clone(), + participant_identity.clone(), + encryption_type, + ); // For backwards compatibly let event = RoomEvent::StreamHeaderReceived { header, participant_identity }; diff --git a/livekit/src/rtc_engine/mod.rs b/livekit/src/rtc_engine/mod.rs index 1b5a1332e..3bb937d4f 100644 --- a/livekit/src/rtc_engine/mod.rs +++ b/livekit/src/rtc_engine/mod.rs @@ -98,6 +98,7 @@ pub enum EngineEvent { payload: Vec, topic: Option, kind: DataPacketKind, + encryption_type: proto::encryption::Type, }, ChatMessage { participant_identity: ParticipantIdentity, @@ -165,10 +166,12 @@ pub enum EngineEvent { DataStreamHeader { header: proto::data_stream::Header, participant_identity: String, + encryption_type: proto::encryption::Type, }, DataStreamChunk { chunk: proto::data_stream::Chunk, participant_identity: String, + encryption_type: proto::encryption::Type, }, DataStreamTrailer { trailer: proto::data_stream::Trailer, @@ -480,13 +483,21 @@ impl EngineInner { } } } - SessionEvent::Data { participant_sid, participant_identity, payload, topic, kind } => { + SessionEvent::Data { + participant_sid, + participant_identity, + payload, + topic, + kind, + encryption_type, + } => { let _ = self.engine_tx.send(EngineEvent::Data { participant_sid, participant_identity, payload, topic, kind, + encryption_type, }); } SessionEvent::ChatMessage { participant_identity, message } => { @@ -553,15 +564,19 @@ impl EngineInner { SessionEvent::LocalTrackSubscribed { track_sid } => { let _ = self.engine_tx.send(EngineEvent::LocalTrackSubscribed { track_sid }); } - SessionEvent::DataStreamHeader { header, participant_identity } => { - let _ = self - .engine_tx - .send(EngineEvent::DataStreamHeader { header, participant_identity }); + SessionEvent::DataStreamHeader { header, participant_identity, encryption_type } => { + let _ = self.engine_tx.send(EngineEvent::DataStreamHeader { + header, + participant_identity, + encryption_type, + }); } - SessionEvent::DataStreamChunk { chunk, participant_identity } => { - let _ = self - .engine_tx - .send(EngineEvent::DataStreamChunk { chunk, participant_identity }); + SessionEvent::DataStreamChunk { chunk, participant_identity, encryption_type } => { + let _ = self.engine_tx.send(EngineEvent::DataStreamChunk { + chunk, + participant_identity, + encryption_type, + }); } SessionEvent::DataStreamTrailer { trailer, participant_identity } => { let _ = self diff --git a/livekit/src/rtc_engine/rtc_session.rs b/livekit/src/rtc_engine/rtc_session.rs index ceb2b0005..95822ecf4 100644 --- a/livekit/src/rtc_engine/rtc_session.rs +++ b/livekit/src/rtc_engine/rtc_session.rs @@ -113,6 +113,7 @@ pub enum SessionEvent { payload: Vec, topic: Option, kind: DataPacketKind, + encryption_type: proto::encryption::Type, }, ChatMessage { participant_identity: ParticipantIdentity, @@ -174,10 +175,12 @@ pub enum SessionEvent { DataStreamHeader { header: proto::data_stream::Header, participant_identity: String, + encryption_type: proto::encryption::Type, }, DataStreamChunk { chunk: proto::data_stream::Chunk, participant_identity: String, + encryption_type: proto::encryption::Type, }, DataStreamTrailer { trailer: proto::data_stream::Trailer, @@ -1081,7 +1084,13 @@ impl SessionInner { packet.participant_sid.try_into().ok(); let participant_identity: Option = packet.participant_identity.try_into().ok(); - self.emit_incoming_packet(kind, participant_sid, participant_identity, detail); + self.emit_incoming_packet( + kind, + participant_sid, + participant_identity, + detail, + proto::encryption::Type::None, + ); } } RtcEvent::DataChannelBufferedAmountChange { sent, amount: _, kind } => { @@ -1104,6 +1113,7 @@ impl SessionInner { participant_sid: Option, participant_identity: Option, value: proto::data_packet::Value, + encryption_type: proto::encryption::Type, ) { let send_result = match value { proto::data_packet::Value::User(user) => { @@ -1120,6 +1130,7 @@ impl SessionInner { participant_identity, payload: user.payload, topic: user.topic, + encryption_type, }) } proto::data_packet::Value::SipDtmf(dtmf) => self.emitter.send(SessionEvent::SipDTMF { @@ -1184,12 +1195,20 @@ impl SessionInner { proto::data_packet::Value::StreamHeader(header) => { let participant_identity = participant_identity.map_or("".into(), |identity| identity.0); - self.emitter.send(SessionEvent::DataStreamHeader { header, participant_identity }) + self.emitter.send(SessionEvent::DataStreamHeader { + header, + participant_identity, + encryption_type, + }) } proto::data_packet::Value::StreamChunk(chunk) => { let participant_identity = participant_identity.map_or("".into(), |identity| identity.0); - self.emitter.send(SessionEvent::DataStreamChunk { chunk, participant_identity }) + self.emitter.send(SessionEvent::DataStreamChunk { + chunk, + participant_identity, + encryption_type, + }) } proto::data_packet::Value::StreamTrailer(trailer) => { let participant_identity = @@ -1219,6 +1238,7 @@ impl SessionInner { participant_sid, participant_identity, convert_encrypted_to_data_packet_value(decrypted_value), + encrypted_packet.encryption_type(), ); Ok(()) } else { From fbdfe81e81d7dcd0c3a5223131c8e4c54080d205 Mon Sep 17 00:00:00 2001 From: lukasIO Date: Tue, 30 Sep 2025 14:16:57 +0200 Subject: [PATCH 50/52] track participant's encryption status based on publications and incoming data messages --- livekit/src/room/data_stream/incoming.rs | 26 ++++-- livekit/src/room/data_stream/mod.rs | 44 +++++++-- livekit/src/room/mod.rs | 40 ++++++++- .../src/room/participant/local_participant.rs | 9 ++ livekit/src/room/participant/mod.rs | 89 ++++++++++++++++++- .../room/participant/remote_participant.rs | 13 +++ 6 files changed, 201 insertions(+), 20 deletions(-) diff --git a/livekit/src/room/data_stream/incoming.rs b/livekit/src/room/data_stream/incoming.rs index e5215a169..d9b9ecf3b 100644 --- a/livekit/src/room/data_stream/incoming.rs +++ b/livekit/src/room/data_stream/incoming.rs @@ -225,6 +225,7 @@ impl AnyStreamReader { struct Descriptor { progress: StreamProgress, chunk_tx: UnboundedSender>, + encryption_type: EncryptionType, // TODO(ladvoc): keep track of open time. } @@ -252,16 +253,15 @@ impl IncomingStreamManager { identity: String, encryption_type: livekit_protocol::encryption::Type, ) { - let Ok(info) = - AnyStreamInfo::try_from(header).inspect_err(|e| log::error!("Invalid header: {}", e)) + let Ok(info) = AnyStreamInfo::try_from_with_encryption(header, encryption_type.into()) + .inspect_err(|e| log::error!("Invalid header: {}", e)) else { return; }; - info.encryption_type = encryption_type.into(); - let id = info.id().to_owned(); let bytes_total = info.total_length(); + let stream_encryption_type = info.encryption_type(); let mut inner = self.inner.lock(); if inner.open_streams.contains_key(&id) { @@ -272,19 +272,31 @@ impl IncomingStreamManager { let (reader, chunk_tx) = AnyStreamReader::from(info); let _ = self.open_tx.send((reader, identity)); - let descriptor = - Descriptor { progress: StreamProgress { bytes_total, ..Default::default() }, chunk_tx }; + let descriptor = Descriptor { + progress: StreamProgress { bytes_total, ..Default::default() }, + chunk_tx, + encryption_type: stream_encryption_type, + }; inner.open_streams.insert(id, descriptor); } /// Handles an incoming chunk packet. - pub fn handle_chunk(&self, chunk: proto::Chunk) { + pub fn handle_chunk( + &self, + chunk: proto::Chunk, + encryption_type: livekit_protocol::encryption::Type, + ) { let id = chunk.stream_id; let mut inner = self.inner.lock(); let Some(descriptor) = inner.open_streams.get_mut(&id) else { return; }; + if descriptor.encryption_type != encryption_type.into() { + inner.close_stream_with_error(&id, StreamError::EncryptionTypeMismatch); + return; + } + if descriptor.progress.chunk_index != chunk.chunk_index { inner.close_stream_with_error(&id, StreamError::MissedChunk); return; diff --git a/livekit/src/room/data_stream/mod.rs b/livekit/src/room/data_stream/mod.rs index e83ee037f..940580024 100644 --- a/livekit/src/room/data_stream/mod.rs +++ b/livekit/src/room/data_stream/mod.rs @@ -61,6 +61,9 @@ pub enum StreamError { #[error("internal error")] Internal, + + #[error("encryption type mismatch")] + EncryptionTypeMismatch, } /// Progress of a data stream. @@ -142,16 +145,25 @@ impl TryFrom for AnyStreamInfo { type Error = StreamError; fn try_from(mut header: proto::Header) -> Result { + Self::try_from_with_encryption(header, EncryptionType::None) + } +} + +impl AnyStreamInfo { + pub fn try_from_with_encryption( + mut header: proto::Header, + encryption_type: EncryptionType, + ) -> Result { let Some(content_header) = header.content_header.take() else { Err(StreamError::InvalidHeader)? }; let info = match content_header { - proto::header::ContentHeader::ByteHeader(byte_header) => { - Self::Byte(ByteStreamInfo::from_headers(header, byte_header)) - } - proto::header::ContentHeader::TextHeader(text_header) => { - Self::Text(TextStreamInfo::from_headers(header, text_header)) - } + proto::header::ContentHeader::ByteHeader(byte_header) => Self::Byte( + ByteStreamInfo::from_headers_with_encryption(header, byte_header, encryption_type), + ), + proto::header::ContentHeader::TextHeader(text_header) => Self::Text( + TextStreamInfo::from_headers_with_encryption(header, text_header, encryption_type), + ), }; Ok(info) } @@ -159,6 +171,14 @@ impl TryFrom for AnyStreamInfo { impl ByteStreamInfo { pub(crate) fn from_headers(header: proto::Header, byte_header: proto::ByteHeader) -> Self { + Self::from_headers_with_encryption(header, byte_header, EncryptionType::None) + } + + pub(crate) fn from_headers_with_encryption( + header: proto::Header, + byte_header: proto::ByteHeader, + encryption_type: EncryptionType, + ) -> Self { Self { id: header.stream_id, topic: header.topic, @@ -168,13 +188,21 @@ impl ByteStreamInfo { attributes: header.attributes, mime_type: header.mime_type, name: byte_header.name, - encryption_type: EncryptionType::None, + encryption_type, } } } impl TextStreamInfo { pub(crate) fn from_headers(header: proto::Header, text_header: proto::TextHeader) -> Self { + Self::from_headers_with_encryption(header, text_header, EncryptionType::None) + } + + pub(crate) fn from_headers_with_encryption( + header: proto::Header, + text_header: proto::TextHeader, + encryption_type: EncryptionType, + ) -> Self { Self { id: header.stream_id, topic: header.topic, @@ -189,7 +217,7 @@ impl TextStreamInfo { .then_some(text_header.reply_to_stream_id), attached_stream_ids: text_header.attached_stream_ids, generated: text_header.generated, - encryption_type: EncryptionType::None, + encryption_type, } } } diff --git a/livekit/src/room/mod.rs b/livekit/src/room/mod.rs index 812e1afd5..0bd009aa7 100644 --- a/livekit/src/room/mod.rs +++ b/livekit/src/room/mod.rs @@ -23,8 +23,8 @@ use libwebrtc::{ RtcError, }; use livekit_api::signal_client::{SignalOptions, SignalSdkOptions}; -use livekit_protocol as proto; use livekit_protocol::observer::Dispatcher; +use livekit_protocol::{self as proto, encryption}; use livekit_runtime::JoinHandle; use parking_lot::RwLock; pub use proto::DisconnectReason; @@ -825,8 +825,22 @@ impl RoomSession { self.handle_signal_restarted(join_response, tx) } EngineEvent::Disconnected { reason } => self.handle_disconnected(reason), - EngineEvent::Data { payload, topic, kind, participant_sid, participant_identity } => { - self.handle_data(payload, topic, kind, participant_sid, participant_identity); + EngineEvent::Data { + payload, + topic, + kind, + participant_sid, + participant_identity, + encryption_type, + } => { + self.handle_data( + payload, + topic, + kind, + participant_sid, + participant_identity, + encryption_type, + ); } EngineEvent::ChatMessage { participant_identity, message } => { self.handle_chat_message(participant_identity, message); @@ -1396,6 +1410,7 @@ impl RoomSession { kind: DataPacketKind, participant_sid: Option, participant_identity: Option, + encryption_type: proto::encryption::Type, ) { let mut participant = participant_identity .as_ref() @@ -1414,6 +1429,13 @@ impl RoomSession { return; } + // Update participant's data encryption status for regular data messages + if let Some(ref p) = participant { + use crate::e2ee::EncryptionType; + let is_encrypted = EncryptionType::from(encryption_type) != EncryptionType::None; + p.update_data_encryption_status(is_encrypted); + } + self.dispatcher.dispatch(&RoomEvent::DataReceived { payload: Arc::new(payload), topic, @@ -1493,6 +1515,15 @@ impl RoomSession { encryption_type, ); + // Update participant's data encryption status + if let Some(participant) = + self.remote_participants.read().get(&participant_identity.clone().into()).cloned() + { + use crate::e2ee::EncryptionType; + let is_encrypted = EncryptionType::from(encryption_type) != EncryptionType::None; + participant.update_data_encryption_status(is_encrypted); + } + // For backwards compatibly let event = RoomEvent::StreamHeaderReceived { header, participant_identity }; self.dispatcher.dispatch(&event); @@ -1502,8 +1533,9 @@ impl RoomSession { &self, chunk: proto::data_stream::Chunk, participant_identity: String, + encryption_type: proto::encryption::Type, ) { - self.incoming_stream_manager.handle_chunk(chunk.clone()); + self.incoming_stream_manager.handle_chunk(chunk.clone(), encryption_type); // For backwards compatibly let event = RoomEvent::StreamChunkReceived { chunk, participant_identity }; diff --git a/livekit/src/room/participant/local_participant.rs b/livekit/src/room/participant/local_participant.rs index 982463e1d..be8deed96 100644 --- a/livekit/src/room/participant/local_participant.rs +++ b/livekit/src/room/participant/local_participant.rs @@ -997,4 +997,13 @@ impl LocalParticipant { pub async fn stream_bytes(&self, options: StreamByteOptions) -> StreamResult { self.session().unwrap().outgoing_stream_manager.stream_bytes(options).await } + + pub fn is_encrypted(&self) -> bool { + *self.inner.is_encrypted.read() + } + + #[doc(hidden)] + pub fn update_data_encryption_status(&self, _is_encrypted: bool) { + // Local participants don't receive data messages, so this is a no-op + } } diff --git a/livekit/src/room/participant/mod.rs b/livekit/src/room/participant/mod.rs index b5ab45f73..d3105d5e8 100644 --- a/livekit/src/room/participant/mod.rs +++ b/livekit/src/room/participant/mod.rs @@ -85,6 +85,7 @@ impl Participant { pub fn connection_quality(self: &Self) -> ConnectionQuality; pub fn kind(self: &Self) -> ParticipantKind; pub fn disconnect_reason(self: &Self) -> DisconnectReason; + pub fn is_encrypted(self: &Self) -> bool; pub(crate) fn update_info(self: &Self, info: proto::ParticipantInfo) -> (); @@ -94,6 +95,7 @@ impl Participant { pub(crate) fn set_connection_quality(self: &Self, quality: ConnectionQuality) -> (); pub(crate) fn add_publication(self: &Self, publication: TrackPublication) -> (); pub(crate) fn remove_publication(self: &Self, sid: &TrackSid) -> Option; + pub(crate) fn update_data_encryption_status(self: &Self, is_encrypted: bool) -> (); ); pub fn track_publications(&self) -> HashMap { @@ -122,6 +124,7 @@ type TrackUnmutedHandler = Box; type MetadataChangedHandler = Box; type AttributesChangedHandler = Box) + Send>; type NameChangedHandler = Box; +type EncryptionStatusChangedHandler = Box; #[derive(Default)] struct ParticipantEvents { @@ -130,6 +133,7 @@ struct ParticipantEvents { metadata_changed: Mutex>, attributes_changed: Mutex>, name_changed: Mutex>, + encryption_status_changed: Mutex>, } pub(super) struct ParticipantInner { @@ -137,6 +141,8 @@ pub(super) struct ParticipantInner { info: RwLock, track_publications: RwLock>, events: Arc, + is_encrypted: RwLock, + is_data_encrypted: RwLock>, } #[derive(Clone)] @@ -171,6 +177,8 @@ pub(super) fn new_inner( }), track_publications: Default::default(), events: Default::default(), + is_encrypted: RwLock::new(false), + is_data_encrypted: RwLock::new(None), }) } @@ -268,9 +276,80 @@ pub(super) fn on_attributes_changed( *inner.events.attributes_changed.lock() = Some(Box::new(handler)); } +pub(super) fn on_encryption_status_changed( + inner: &Arc, + handler: impl Fn(Participant, bool) + Send + 'static, +) { + *inner.events.encryption_status_changed.lock() = Some(Box::new(handler)); +} + +pub(super) fn update_encryption_status(inner: &Arc, participant: &Participant) { + use crate::e2ee::EncryptionType; + + let track_publications = inner.track_publications.read(); + let data_encryption_status = inner.is_data_encrypted.read(); + + // Check if all track publications are encrypted + let tracks_encrypted = !track_publications.is_empty() + && track_publications.values().all(|pub_| pub_.encryption_type() != EncryptionType::None); + + // Overall encryption status: both tracks and data must be encrypted (if data exists) + let is_encrypted = match *data_encryption_status { + Some(data_encrypted) => tracks_encrypted && data_encrypted, + None => tracks_encrypted, // No data messages yet, only consider tracks + }; + + let mut current_status = inner.is_encrypted.write(); + if *current_status != is_encrypted { + *current_status = is_encrypted; + drop(current_status); + drop(track_publications); + drop(data_encryption_status); + + if let Some(cb) = inner.events.encryption_status_changed.lock().as_ref() { + cb(participant.clone(), is_encrypted); + } + } +} + +pub(super) fn update_data_encryption_status( + inner: &Arc, + participant: &Participant, + is_encrypted: bool, +) { + let mut data_encryption_status = inner.is_data_encrypted.write(); + let previous_status = *data_encryption_status; + + match previous_status { + Some(current) if current == is_encrypted => { + // No change needed + return; + } + Some(true) if !is_encrypted => { + // Data was encrypted, now unencrypted - update immediately + *data_encryption_status = Some(false); + } + Some(false) if is_encrypted => { + // Data was unencrypted, now encrypted - but we need to keep it false + // because once we've seen unencrypted data, participant is not fully encrypted + return; + } + None => { + // First data message - set the status + *data_encryption_status = Some(is_encrypted); + } + _ => return, + } + + drop(data_encryption_status); + + // Update overall encryption status + update_encryption_status(inner, participant); +} + pub(super) fn remove_publication( inner: &Arc, - _participant: &Participant, + participant: &Participant, sid: &TrackSid, ) -> Option { let mut tracks = inner.track_publications.write(); @@ -283,6 +362,10 @@ pub(super) fn remove_publication( // shouldn't happen (internal) log::warn!("could not find publication to remove: {:?}", sid); } + drop(tracks); + + // Update encryption status after removing publication + update_encryption_status(inner, participant); publication } @@ -346,4 +429,8 @@ pub(super) fn add_publication( } } }); + drop(tracks); + + // Update encryption status after adding publication + update_encryption_status(inner, participant); } diff --git a/livekit/src/room/participant/remote_participant.rs b/livekit/src/room/participant/remote_participant.rs index 58a1659e7..e4940308a 100644 --- a/livekit/src/room/participant/remote_participant.rs +++ b/livekit/src/room/participant/remote_participant.rs @@ -492,4 +492,17 @@ impl RemoteParticipant { pub fn disconnect_reason(&self) -> DisconnectReason { self.inner.info.read().disconnect_reason } + + pub fn is_encrypted(&self) -> bool { + *self.inner.is_encrypted.read() + } + + #[doc(hidden)] + pub fn update_data_encryption_status(&self, is_encrypted: bool) { + super::update_data_encryption_status( + &self.inner, + &super::Participant::Remote(self.clone()), + is_encrypted, + ); + } } From 451eca9b8ffd02019f068ee62a60b4f94031612f Mon Sep 17 00:00:00 2001 From: lukasIO Date: Tue, 30 Sep 2025 14:35:32 +0200 Subject: [PATCH 51/52] use is_encrypted getter on participants --- livekit-ffi/protocol/room.proto | 7 ++++++- livekit-ffi/src/conversion/data_stream.rs | 2 ++ livekit-ffi/src/livekit.proto.rs | 16 +++++++++++++++- livekit-ffi/src/server/room.rs | 8 ++++++++ livekit/src/room/mod.rs | 13 +++++++++++++ .../src/room/participant/remote_participant.rs | 7 +++++++ 6 files changed, 51 insertions(+), 2 deletions(-) diff --git a/livekit-ffi/protocol/room.proto b/livekit-ffi/protocol/room.proto index 57293e485..d1f25d669 100644 --- a/livekit-ffi/protocol/room.proto +++ b/livekit-ffi/protocol/room.proto @@ -359,6 +359,7 @@ message RoomEvent { ParticipantMetadataChanged participant_metadata_changed = 17; ParticipantNameChanged participant_name_changed = 18; ParticipantAttributesChanged participant_attributes_changed = 19; + ParticipantEncryptionStatusChanged participant_encryption_status_changed = 39; ConnectionQualityChanged connection_quality_changed = 20; ConnectionStateChanged connection_state_changed = 21; // Connected connected = 21; @@ -497,6 +498,11 @@ message ParticipantAttributesChanged { repeated AttributesEntry changed_attributes = 3; } +message ParticipantEncryptionStatusChanged { + required string participant_identity = 1; + required bool is_encrypted = 2; +} + message ParticipantNameChanged { required string participant_identity = 1; required string name = 2; @@ -510,7 +516,6 @@ message ConnectionQualityChanged { message UserPacket { required OwnedBuffer data = 1; optional string topic = 2; - required EncryptionType encryption_type = 3; } message ChatMessage { diff --git a/livekit-ffi/src/conversion/data_stream.rs b/livekit-ffi/src/conversion/data_stream.rs index d0df96a50..a59da350b 100644 --- a/livekit-ffi/src/conversion/data_stream.rs +++ b/livekit-ffi/src/conversion/data_stream.rs @@ -35,6 +35,7 @@ impl From for proto::TextStreamInfo { reply_to_stream_id: info.reply_to_stream_id, attached_stream_ids: info.attached_stream_ids, generated: Some(info.generated), + encryption_type: info.encryption_type.into(), } } } @@ -49,6 +50,7 @@ impl From for proto::ByteStreamInfo { total_length: info.total_length, attributes: info.attributes, name: info.name, + encryption_type: info.encryption_type.into(), } } } diff --git a/livekit-ffi/src/livekit.proto.rs b/livekit-ffi/src/livekit.proto.rs index 7260f305c..be29c4b49 100644 --- a/livekit-ffi/src/livekit.proto.rs +++ b/livekit-ffi/src/livekit.proto.rs @@ -2747,6 +2747,8 @@ pub struct TextStreamInfo { /// true if the text has been generated by an agent from a participant's audio transcription #[prost(bool, optional, tag="11")] pub generated: ::core::option::Option, + #[prost(enumeration="EncryptionType", required, tag="12")] + pub encryption_type: i32, } /// Nested message and enum types in `TextStreamInfo`. pub mod text_stream_info { @@ -2804,6 +2806,8 @@ pub struct ByteStreamInfo { pub attributes: ::std::collections::HashMap<::prost::alloc::string::String, ::prost::alloc::string::String>, #[prost(string, required, tag="7")] pub name: ::prost::alloc::string::String, + #[prost(enumeration="EncryptionType", required, tag="8")] + pub encryption_type: i32, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -3376,7 +3380,7 @@ pub struct OwnedBuffer { pub struct RoomEvent { #[prost(uint64, required, tag="1")] pub room_handle: u64, - #[prost(oneof="room_event::Message", tags="2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38")] + #[prost(oneof="room_event::Message", tags="2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 39, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38")] pub message: ::core::option::Option, } /// Nested message and enum types in `RoomEvent`. @@ -3420,6 +3424,8 @@ pub mod room_event { ParticipantNameChanged(super::ParticipantNameChanged), #[prost(message, tag="19")] ParticipantAttributesChanged(super::ParticipantAttributesChanged), + #[prost(message, tag="39")] + ParticipantEncryptionStatusChanged(super::ParticipantEncryptionStatusChanged), #[prost(message, tag="20")] ConnectionQualityChanged(super::ConnectionQualityChanged), #[prost(message, tag="21")] @@ -3651,6 +3657,14 @@ pub struct ParticipantAttributesChanged { } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] +pub struct ParticipantEncryptionStatusChanged { + #[prost(string, required, tag="1")] + pub participant_identity: ::prost::alloc::string::String, + #[prost(bool, required, tag="2")] + pub is_encrypted: bool, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] pub struct ParticipantNameChanged { #[prost(string, required, tag="1")] pub participant_identity: ::prost::alloc::string::String, diff --git a/livekit-ffi/src/server/room.rs b/livekit-ffi/src/server/room.rs index 761fb40aa..b004eba01 100644 --- a/livekit-ffi/src/server/room.rs +++ b/livekit-ffi/src/server/room.rs @@ -1179,6 +1179,14 @@ async fn forward_event( }, )); } + RoomEvent::ParticipantEncryptionStatusChanged { participant, is_encrypted } => { + let _ = send_event(proto::room_event::Message::ParticipantEncryptionStatusChanged( + proto::ParticipantEncryptionStatusChanged { + participant_identity: participant.identity().to_string(), + is_encrypted, + }, + )); + } RoomEvent::ActiveSpeakersChanged { speakers } => { let participant_identities = speakers.iter().map(|p| p.identity().to_string()).collect::>(); diff --git a/livekit/src/room/mod.rs b/livekit/src/room/mod.rs index 0bd009aa7..4e9fc2902 100644 --- a/livekit/src/room/mod.rs +++ b/livekit/src/room/mod.rs @@ -149,6 +149,10 @@ pub enum RoomEvent { participant: Participant, changed_attributes: HashMap, }, + ParticipantEncryptionStatusChanged { + participant: Participant, + is_encrypted: bool, + }, ActiveSpeakersChanged { speakers: Vec, }, @@ -1689,6 +1693,15 @@ impl RoomSession { } }); + participant.on_encryption_status_changed({ + let dispatcher = self.dispatcher.clone(); + move |participant, is_encrypted| { + let event = + RoomEvent::ParticipantEncryptionStatusChanged { participant, is_encrypted }; + dispatcher.dispatch(&event); + } + }); + let mut participants = self.remote_participants.write(); participants.insert(identity, participant.clone()); participant diff --git a/livekit/src/room/participant/remote_participant.rs b/livekit/src/room/participant/remote_participant.rs index e4940308a..4122ab5b0 100644 --- a/livekit/src/room/participant/remote_participant.rs +++ b/livekit/src/room/participant/remote_participant.rs @@ -293,6 +293,13 @@ impl RemoteParticipant { super::on_attributes_changed(&self.inner, handler) } + pub(crate) fn on_encryption_status_changed( + &self, + handler: impl Fn(Participant, bool) + Send + 'static, + ) { + super::on_encryption_status_changed(&self.inner, handler); + } + pub(crate) fn set_speaking(&self, speaking: bool) { super::set_speaking(&self.inner, &Participant::Remote(self.clone()), speaking); } From 54fb7c9f7602cc377dd113985346dc7ccaf2b6c9 Mon Sep 17 00:00:00 2001 From: lukasIO Date: Wed, 8 Oct 2025 14:03:48 +0200 Subject: [PATCH 52/52] update deprecation notice --- livekit/src/room/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/livekit/src/room/mod.rs b/livekit/src/room/mod.rs index 4e9fc2902..666164e13 100644 --- a/livekit/src/room/mod.rs +++ b/livekit/src/room/mod.rs @@ -354,7 +354,8 @@ pub struct RoomOptions { pub auto_subscribe: bool, pub adaptive_stream: bool, pub dynacast: bool, - #[deprecated(note = "Use `encryption` field instead, see x for a detailed explanation")] + // TODO: link to encryption docs in deprecation notice once available + #[deprecated(note = "Use `encryption` field instead")] pub e2ee: Option, pub encryption: Option, pub rtc_config: RtcConfiguration,