@@ -147,11 +147,17 @@ pub enum SignalError {
147147pub 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
152158impl 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 ( ) ;
0 commit comments