diff --git a/Cargo.lock b/Cargo.lock index dc6e29d1..6b2c9038 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1641,7 +1641,7 @@ dependencies = [ [[package]] name = "livekit-ffi" -version = "0.11.3" +version = "0.12.0" dependencies = [ "console-subscriber", "dashmap", diff --git a/livekit-api/src/signal_client/mod.rs b/livekit-api/src/signal_client/mod.rs index 711ba7ed..2a8cb16f 100644 --- a/livekit-api/src/signal_client/mod.rs +++ b/livekit-api/src/signal_client/mod.rs @@ -65,14 +65,33 @@ pub enum SignalError { } #[derive(Debug, Clone)] +#[non_exhaustive] +pub struct SignalSdkOptions { + pub sdk: String, + pub sdk_version: Option, +} + +impl Default for SignalSdkOptions { + fn default() -> Self { + Self { sdk: "rust".to_string(), sdk_version: None } + } +} + +#[derive(Debug, Clone)] +#[non_exhaustive] pub struct SignalOptions { pub auto_subscribe: bool, pub adaptive_stream: bool, + pub sdk_options: SignalSdkOptions, } impl Default for SignalOptions { fn default() -> Self { - Self { auto_subscribe: true, adaptive_stream: false } + Self { + auto_subscribe: true, + adaptive_stream: false, + sdk_options: SignalSdkOptions::default(), + } } } @@ -431,12 +450,16 @@ fn get_livekit_url(url: &str, token: &str, options: &SignalOptions) -> SignalRes lk_url .query_pairs_mut() - .append_pair("sdk", "rust") - .append_pair("access_token", token) + .append_pair("sdk", options.sdk_options.sdk.as_str()) .append_pair("protocol", PROTOCOL_VERSION.to_string().as_str()) + .append_pair("access_token", token) .append_pair("auto_subscribe", if options.auto_subscribe { "1" } else { "0" }) .append_pair("adaptive_stream", if options.adaptive_stream { "1" } else { "0" }); + if let Some(sdk_version) = &options.sdk_options.sdk_version { + lk_url.query_pairs_mut().append_pair("version", sdk_version.as_str()); + } + Ok(lk_url) } diff --git a/livekit-ffi/src/cabi.rs b/livekit-ffi/src/cabi.rs index 1df37c53..5cc630a7 100644 --- a/livekit-ffi/src/cabi.rs +++ b/livekit-ffi/src/cabi.rs @@ -1,5 +1,7 @@ use prost::Message; use server::FfiDataBuffer; +use std::ffi::CStr; +use std::os::raw::c_char; use std::{panic, sync::Arc}; use crate::{ @@ -15,13 +17,20 @@ pub type FfiCallbackFn = unsafe extern "C" fn(*const u8, usize); /// /// The foreign language must only provide valid pointers #[no_mangle] -pub unsafe extern "C" fn livekit_ffi_initialize(cb: FfiCallbackFn, capture_logs: bool) { +pub unsafe extern "C" fn livekit_ffi_initialize( + cb: FfiCallbackFn, + capture_logs: bool, + sdk: *const c_char, + sdk_version: *const c_char, +) { FFI_SERVER.setup(FfiConfig { callback_fn: Arc::new(move |event| { let data = event.encode_to_vec(); cb(data.as_ptr(), data.len()); }), capture_logs, + sdk: CStr::from_ptr(sdk).to_string_lossy().into_owned(), + sdk_version: CStr::from_ptr(sdk_version).to_string_lossy().into_owned(), }); log::info!("initializing ffi server v{}", env!("CARGO_PKG_VERSION")); diff --git a/livekit-ffi/src/conversion/room.rs b/livekit-ffi/src/conversion/room.rs index 514396ab..b5295f1b 100644 --- a/livekit-ffi/src/conversion/room.rs +++ b/livekit-ffi/src/conversion/room.rs @@ -176,14 +176,15 @@ impl From for RoomOptions { let rtc_config = value.rtc_config.map(Into::into).unwrap_or(RoomOptions::default().rtc_config); - Self { - adaptive_stream: value.adaptive_stream, - auto_subscribe: value.auto_subscribe, - dynacast: value.dynacast, - e2ee, - rtc_config, - join_retries: value.join_retries, - } + let mut options = RoomOptions::default(); + options.adaptive_stream = value.adaptive_stream; + options.auto_subscribe = value.auto_subscribe; + options.dynacast = value.dynacast; + options.e2ee = e2ee; + options.rtc_config = rtc_config; + options.join_retries = value.join_retries; + options.sdk_options = RoomSdkOptions::default(); + options } } diff --git a/livekit-ffi/src/server/mod.rs b/livekit-ffi/src/server/mod.rs index a9ef1515..461439ab 100644 --- a/livekit-ffi/src/server/mod.rs +++ b/livekit-ffi/src/server/mod.rs @@ -52,6 +52,8 @@ pub mod video_stream; pub struct FfiConfig { pub callback_fn: Arc, pub capture_logs: bool, + pub sdk: String, + pub sdk_version: String, } /// To make sure we use the right types, only types that implement this trait diff --git a/livekit-ffi/src/server/room.rs b/livekit-ffi/src/server/room.rs index ddd1b936..a6da9b63 100644 --- a/livekit-ffi/src/server/room.rs +++ b/livekit-ffi/src/server/room.rs @@ -116,8 +116,18 @@ impl FfiRoom { ) -> proto::ConnectResponse { let async_id = server.next_id(); + let mut options: RoomOptions = connect.options.into(); + + { + let config = server.config.lock(); + if let Some(c) = config.as_ref() { + options.sdk_options.sdk = c.sdk.clone(); + options.sdk_options.sdk_version = c.sdk_version.clone(); + } + } + let connect = async move { - match Room::connect(&connect.url, &connect.token, connect.options.into()).await { + match Room::connect(&connect.url, &connect.token, options.clone()).await { Ok((room, mut events)) => { // Successfully connected to the room // Forward the initial state for the FfiClient diff --git a/livekit/src/prelude.rs b/livekit/src/prelude.rs index e801014a..f53fdda1 100644 --- a/livekit/src/prelude.rs +++ b/livekit/src/prelude.rs @@ -21,5 +21,5 @@ pub use crate::{ RemoteVideoTrack, StreamState, Track, TrackDimension, TrackKind, TrackSource, VideoTrack, }, ConnectionState, DataPacket, DataPacketKind, DisconnectReason, Room, RoomError, RoomEvent, - RoomOptions, RoomResult, SipDTMF, Transcription, TranscriptionSegment, + RoomOptions, RoomResult, RoomSdkOptions, SipDTMF, Transcription, TranscriptionSegment, }; diff --git a/livekit/src/room/mod.rs b/livekit/src/room/mod.rs index 346d4145..ab296b18 100644 --- a/livekit/src/room/mod.rs +++ b/livekit/src/room/mod.rs @@ -23,7 +23,7 @@ use libwebrtc::{ rtp_transceiver::RtpTransceiver, RtcError, }; -use livekit_api::signal_client::SignalOptions; +use livekit_api::signal_client::{SignalOptions, SignalSdkOptions}; use livekit_protocol as proto; use livekit_protocol::observer::Dispatcher; use livekit_runtime::JoinHandle; @@ -31,7 +31,10 @@ use parking_lot::RwLock; pub use proto::DisconnectReason; use proto::{promise::Promise, SignalTarget}; use thiserror::Error; -use tokio::sync::{mpsc, oneshot, Mutex as AsyncMutex}; +use tokio::{ + signal, + sync::{mpsc, oneshot, Mutex as AsyncMutex}, +}; pub use self::{ e2ee::{manager::E2eeManager, E2eeOptions}, @@ -55,6 +58,8 @@ pub mod publication; pub mod track; pub(crate) mod utils; +pub const SDK_VERSION: &str = env!("CARGO_PKG_VERSION"); + pub type RoomResult = Result; #[derive(Error, Debug)] @@ -251,6 +256,29 @@ pub struct ChatMessage { } #[derive(Debug, Clone)] +#[non_exhaustive] +pub struct RoomSdkOptions { + pub sdk: String, + pub sdk_version: String, +} + +impl Default for RoomSdkOptions { + fn default() -> Self { + Self { sdk: "rust".to_string(), sdk_version: SDK_VERSION.to_string() } + } +} + +impl From for SignalSdkOptions { + fn from(options: RoomSdkOptions) -> Self { + let mut sdk_options = SignalSdkOptions::default(); + sdk_options.sdk = options.sdk; + sdk_options.sdk_version = Some(options.sdk_version); + sdk_options + } +} + +#[derive(Debug, Clone)] +#[non_exhaustive] pub struct RoomOptions { pub auto_subscribe: bool, pub adaptive_stream: bool, @@ -258,6 +286,7 @@ pub struct RoomOptions { pub e2ee: Option, pub rtc_config: RtcConfiguration, pub join_retries: u32, + pub sdk_options: RoomSdkOptions, } impl Default for RoomOptions { @@ -276,6 +305,7 @@ impl Default for RoomOptions { ice_transport_type: IceTransportsType::All, }, join_retries: 3, + sdk_options: RoomSdkOptions::default(), } } } @@ -331,15 +361,16 @@ impl Room { ) -> RoomResult<(Self, mpsc::UnboundedReceiver)> { // TODO(theomonnom): move connection logic to the RoomSession let e2ee_manager = E2eeManager::new(options.e2ee.clone()); + let mut signal_options = SignalOptions::default(); + signal_options.sdk_options = options.sdk_options.clone().into(); + signal_options.auto_subscribe = options.auto_subscribe; + signal_options.adaptive_stream = options.adaptive_stream; let (rtc_engine, join_response, engine_events) = RtcEngine::connect( url, token, EngineOptions { rtc_config: options.rtc_config.clone(), - signal_options: SignalOptions { - auto_subscribe: options.auto_subscribe, - adaptive_stream: options.adaptive_stream, - }, + signal_options, join_retries: options.join_retries, }, ) @@ -445,7 +476,7 @@ impl Room { }), remote_participants: Default::default(), active_speakers: Default::default(), - options, + options: options.clone(), rtc_engine: rtc_engine.clone(), local_participant, dispatcher: dispatcher.clone(),