Skip to content

Commit 81eb312

Browse files
other_sdks for specifying sdk info beyond client-sdk-*
1 parent 0b5462a commit 81eb312

6 files changed

Lines changed: 104 additions & 4 deletions

File tree

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
livekit: minor
3+
livekit-api: minor
4+
livekit-ffi: minor
5+
---
6+
7+
Add `other_sdks` field to propagate additional SDK metadata to the server.

livekit-api/src/signal_client/mod.rs

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,11 +147,17 @@ pub enum SignalError {
147147
pub struct SignalSdkOptions {
148148
pub sdk: String,
149149
pub sdk_version: Option<String>,
150+
/// Comma separated list of additional LiveKit SDKs layered on top of this one, with
151+
/// versions, e.g. `"components-js:1.2.3,track-processors-js:1.2.3"`. Sent to the server
152+
/// as `ClientInfo.other_sdks`. `None` when there are none — optional so callers that
153+
/// predate the field keep working unchanged.
154+
#[doc(hidden)]
155+
pub other_sdks: Option<String>,
150156
}
151157

152158
impl Default for SignalSdkOptions {
153159
fn default() -> Self {
154-
Self { sdk: "rust".to_string(), sdk_version: None }
160+
Self { sdk: "rust".to_string(), sdk_version: None, other_sdks: None }
155161
}
156162
}
157163

@@ -816,6 +822,7 @@ fn create_join_request_param(
816822
device_model,
817823
capabilities: CLIENT_CAPABILITIES.iter().map(|c| *c as i32).collect(),
818824
client_protocol: advertised_client_protocol(options),
825+
other_sdks: options.sdk_options.other_sdks.clone().unwrap_or_default(),
819826
..Default::default()
820827
};
821828

@@ -945,6 +952,12 @@ fn get_livekit_url(
945952
lk_url.query_pairs_mut().append_pair("version", sdk_version.as_str());
946953
}
947954

955+
if let Some(other_sdks) =
956+
options.sdk_options.other_sdks.as_deref().filter(|s| !s.is_empty())
957+
{
958+
lk_url.query_pairs_mut().append_pair("other_sdks", other_sdks);
959+
}
960+
948961
// parse client capabilities
949962
if !CLIENT_CAPABILITIES.is_empty() {
950963
let caps =
@@ -1300,6 +1313,57 @@ mod tests {
13001313
assert_eq!(client_protocol, CLIENT_PROTOCOL_DATA_STREAM_RPC.to_string());
13011314
}
13021315

1316+
#[test]
1317+
fn livekit_url_forwards_other_sdks_on_both_paths() {
1318+
let mut io = signal_options_for_cpp("9.9.9-test");
1319+
io.sdk_options.other_sdks = Some("ros_portal:1.2.3,another-sdk:2.0.0".to_string());
1320+
1321+
// v1 path: other_sdks travels inside the join_request param
1322+
let lk_url =
1323+
get_livekit_url("wss://localhost:7880", &io, true, false, None, "", None).unwrap();
1324+
let join_request_param = lk_url
1325+
.query_pairs()
1326+
.find_map(|(key, value)| (key == "join_request").then(|| value.into_owned()))
1327+
.unwrap();
1328+
let join_request = decode_join_request_param_for_test(&join_request_param);
1329+
let client_info = join_request.client_info.unwrap();
1330+
assert_eq!(client_info.other_sdks, "ros_portal:1.2.3,another-sdk:2.0.0");
1331+
1332+
// v0 path: other_sdks is a query param
1333+
let lk_url =
1334+
get_livekit_url("wss://localhost:7880", &io, false, false, None, "", None).unwrap();
1335+
let other_sdks = lk_url
1336+
.query_pairs()
1337+
.find_map(|(key, value)| (key == "other_sdks").then(|| value.into_owned()))
1338+
.unwrap();
1339+
assert_eq!(other_sdks, "ros_portal:1.2.3,another-sdk:2.0.0");
1340+
}
1341+
1342+
#[test]
1343+
fn livekit_url_omits_other_sdks_when_unset() {
1344+
assert!(SignalOptions::default().sdk_options.other_sdks.is_none());
1345+
1346+
// `None` (callers predating the field) and `Some("")` must both behave as
1347+
// "no additional SDKs" on either path.
1348+
for other_sdks in [None, Some(String::new())] {
1349+
let mut io = SignalOptions::default();
1350+
io.sdk_options.other_sdks = other_sdks;
1351+
1352+
let lk_url =
1353+
get_livekit_url("wss://localhost:7880", &io, false, false, None, "", None).unwrap();
1354+
assert!(lk_url.query_pairs().all(|(key, _)| key != "other_sdks"));
1355+
1356+
let lk_url =
1357+
get_livekit_url("wss://localhost:7880", &io, true, false, None, "", None).unwrap();
1358+
let join_request_param = lk_url
1359+
.query_pairs()
1360+
.find_map(|(key, value)| (key == "join_request").then(|| value.into_owned()))
1361+
.unwrap();
1362+
let join_request = decode_join_request_param_for_test(&join_request_param);
1363+
assert!(join_request.client_info.unwrap().other_sdks.is_empty());
1364+
}
1365+
}
1366+
13031367
#[test]
13041368
fn validate_url_test() {
13051369
let io = SignalOptions::default();

livekit-ffi/protocol/room.proto

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,9 @@ message RoomOptions {
400400
optional bool single_peer_connection = 8; // use single peer connection for both publish/subscribe (default: false)
401401
optional uint64 connect_timeout_ms = 9; // timeout in milliseconds for each signal connection attempt (default: 5000)
402402
optional RoomDataStreamOptions data_stream = 10; // data stream behavior for this room
403+
// Comma separated list of additional LiveKit SDKs layered on top of this one, with versions,
404+
// e.g. "components-js:1.2.3,track-processors-js:1.2.3". Forwarded to ClientInfo.other_sdks.
405+
optional string other_sdks = 11;
403406
}
404407

405408
//

livekit-ffi/src/conversion/room.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,7 @@ impl From<proto::RoomOptions> for RoomOptions {
300300
value.single_peer_connection.unwrap_or(options.single_peer_connection);
301301
options.connect_timeout =
302302
value.connect_timeout_ms.map(Duration::from_millis).unwrap_or(options.connect_timeout);
303+
options.sdk_options.other_sdks = value.other_sdks;
303304
if let Some(data_stream) = value.data_stream {
304305
let mut data_stream_options = RoomDataStreamOptions::default();
305306
if let Some(max_payload_byte_length) = data_stream.max_payload_byte_length {
@@ -383,7 +384,10 @@ impl From<proto::AudioEncoding> for AudioEncoding {
383384

384385
#[cfg(test)]
385386
mod tests {
386-
use livekit::options::{TrackPublishOptions, VideoEncoderBackend};
387+
use livekit::{
388+
options::{TrackPublishOptions, VideoEncoderBackend},
389+
prelude::RoomOptions,
390+
};
387391

388392
use super::{frame_metadata_features_from_proto, video_encoder_from_proto};
389393
use crate::proto;
@@ -407,6 +411,23 @@ mod tests {
407411
assert!(features.frame_id);
408412
}
409413

414+
#[test]
415+
fn other_sdks_round_trips_from_room_options() {
416+
let options = RoomOptions::from(proto::RoomOptions {
417+
other_sdks: Some("ros_portal:1.2.3".to_string()),
418+
..Default::default()
419+
});
420+
421+
assert_eq!(options.sdk_options.other_sdks.as_deref(), Some("ros_portal:1.2.3"));
422+
}
423+
424+
#[test]
425+
fn other_sdks_defaults_to_none() {
426+
let options = RoomOptions::from(proto::RoomOptions::default());
427+
428+
assert!(options.sdk_options.other_sdks.is_none());
429+
}
430+
410431
#[test]
411432
fn video_encoder_defaults_to_auto() {
412433
let options = TrackPublishOptions::from(proto::TrackPublishOptions::default());

livekit/src/room/mod.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -383,11 +383,15 @@ pub struct RpcAck {
383383
pub struct RoomSdkOptions {
384384
pub sdk: String,
385385
pub sdk_version: String,
386+
/// Comma separated list of additional LiveKit SDKs layered on top of this one, with
387+
/// versions, e.g. `"components-js:1.2.3,track-processors-js:1.2.3"`. Reported to the
388+
/// server as `ClientInfo.other_sdks`. `None` when there are none.
389+
pub other_sdks: Option<String>,
386390
}
387391

388392
impl Default for RoomSdkOptions {
389393
fn default() -> Self {
390-
Self { sdk: "rust".to_string(), sdk_version: SDK_VERSION.to_string() }
394+
Self { sdk: "rust".to_string(), sdk_version: SDK_VERSION.to_string(), other_sdks: None }
391395
}
392396
}
393397

@@ -396,6 +400,7 @@ impl From<RoomSdkOptions> for SignalSdkOptions {
396400
let mut sdk_options = SignalSdkOptions::default();
397401
sdk_options.sdk = options.sdk;
398402
sdk_options.sdk_version = Some(options.sdk_version);
403+
sdk_options.other_sdks = options.other_sdks;
399404
sdk_options
400405
}
401406
}

0 commit comments

Comments
 (0)