From d92166f9f602b2904c96bf7d41cd3b58c2421ffb Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Mon, 18 Nov 2024 11:43:53 +0200 Subject: [PATCH] Revert "Use livekit's Rust SDK instead of their swift SDK (#13343)" (#20809) Issues found: * audio does not work well with various set-ups using USB * switching audio during initial join may leave the client with no audio at all * audio streaming is done on the main thread, beachballing certain set-ups * worse screenshare quality (seems that there's no dynamic scaling anymore, compared to the Swift SDK) This reverts commit 1235d0808ed7697874085fc8528f22aec988c85e. Release Notes: - N/A --- .cargo/config.toml | 6 - Cargo.lock | 2330 ++++++----------- Cargo.toml | 6 - crates/call/Cargo.toml | 1 - crates/call/src/call.rs | 9 - crates/call/src/participant.rs | 28 +- crates/call/src/room.rs | 814 +++--- crates/collab/src/tests.rs | 3 - .../collab/src/tests/channel_guest_tests.rs | 24 +- crates/collab/src/tests/following_tests.rs | 13 +- crates/collab/src/tests/integration_tests.rs | 27 +- crates/collab/src/tests/test_server.rs | 6 +- crates/collab_ui/src/collab_panel.rs | 5 +- crates/gpui/build.rs | 1 - crates/gpui/src/app.rs | 11 +- crates/gpui/src/app/test_context.rs | 10 +- crates/gpui/src/geometry.rs | 5 - crates/gpui/src/platform.rs | 26 - crates/gpui/src/platform/linux.rs | 2 - crates/gpui/src/platform/linux/platform.rs | 12 +- crates/gpui/src/platform/mac.rs | 5 - crates/gpui/src/platform/mac/platform.rs | 14 +- .../gpui/src/platform/mac/screen_capture.rs | 239 -- crates/gpui/src/platform/test.rs | 2 - crates/gpui/src/platform/test/platform.rs | 58 +- crates/gpui/src/platform/windows.rs | 2 - crates/gpui/src/platform/windows/platform.rs | 8 - crates/http_client/Cargo.toml | 2 +- crates/live_kit_client/Cargo.toml | 29 +- .../LiveKitBridge/Package.resolved | 52 + .../LiveKitBridge/Package.swift | 27 + .../live_kit_client/LiveKitBridge/README.md | 3 + .../Sources/LiveKitBridge/LiveKitBridge.swift | 383 +++ crates/live_kit_client/build.rs | 185 ++ crates/live_kit_client/examples/test_app.rs | 520 +--- crates/live_kit_client/src/live_kit_client.rs | 406 +-- crates/live_kit_client/src/prod.rs | 981 +++++++ .../src/remote_video_track_view.rs | 61 - crates/live_kit_client/src/test.rs | 865 +++--- .../live_kit_client/src/test/participant.rs | 111 - .../live_kit_client/src/test/publication.rs | 116 - crates/live_kit_client/src/test/track.rs | 201 -- crates/live_kit_client/src/test/webrtc.rs | 136 - crates/media/Cargo.toml | 1 - crates/media/src/media.rs | 11 +- crates/title_bar/src/collab.rs | 65 +- crates/workspace/src/shared_screen.rs | 52 +- crates/workspace/src/workspace.rs | 13 +- 48 files changed, 3599 insertions(+), 4288 deletions(-) delete mode 100644 crates/gpui/src/platform/mac/screen_capture.rs create mode 100644 crates/live_kit_client/LiveKitBridge/Package.resolved create mode 100644 crates/live_kit_client/LiveKitBridge/Package.swift create mode 100644 crates/live_kit_client/LiveKitBridge/README.md create mode 100644 crates/live_kit_client/LiveKitBridge/Sources/LiveKitBridge/LiveKitBridge.swift create mode 100644 crates/live_kit_client/build.rs create mode 100644 crates/live_kit_client/src/prod.rs delete mode 100644 crates/live_kit_client/src/remote_video_track_view.rs delete mode 100644 crates/live_kit_client/src/test/participant.rs delete mode 100644 crates/live_kit_client/src/test/publication.rs delete mode 100644 crates/live_kit_client/src/test/track.rs delete mode 100644 crates/live_kit_client/src/test/webrtc.rs diff --git a/.cargo/config.toml b/.cargo/config.toml index 043adf6b30..a657ae61b9 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -13,12 +13,6 @@ rustflags = ["-C", "link-arg=-fuse-ld=mold"] linker = "clang" rustflags = ["-C", "link-arg=-fuse-ld=mold"] -[target.aarch64-apple-darwin] -rustflags = ["-C", "link-args=-Objc -all_load"] - -[target.x86_64-apple-darwin] -rustflags = ["-C", "link-args=-Objc -all_load"] - # This cfg will reduce the size of `windows::core::Error` from 16 bytes to 4 bytes [target.'cfg(target_os = "windows")'] rustflags = ["--cfg", "windows_slim_errors"] diff --git a/Cargo.lock b/Cargo.lock index 440002cb24..1b735b431d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10,7 +10,7 @@ dependencies = [ "auto_update", "editor", "extension_host", - "futures 0.3.31", + "futures 0.3.30", "gpui", "language", "lsp", @@ -23,13 +23,19 @@ dependencies = [ [[package]] name = "addr2line" -version = "0.24.2" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375" dependencies = [ - "gimli 0.31.1", + "gimli 0.31.0", ] +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "adler2" version = "2.0.0" @@ -94,8 +100,8 @@ dependencies = [ "miow", "parking_lot", "piper", - "polling 3.7.4", - "regex-automata 0.4.9", + "polling 3.7.3", + "regex-automata 0.4.7", "rustix-openpty", "serde", "signal-hook", @@ -118,9 +124,9 @@ checksum = "4aa90d7ce82d4be67b64039a3d588d38dbcc6736577de4a847025ce5b0c468d1" [[package]] name = "allocator-api2" -version = "0.2.20" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" [[package]] name = "alsa" @@ -186,9 +192,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstream" -version = "0.6.18" +version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" dependencies = [ "anstyle", "anstyle-parse", @@ -201,36 +207,36 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.10" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" [[package]] name = "anstyle-parse" -version = "0.2.6" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.2" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.6" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" dependencies = [ "anstyle", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -239,13 +245,13 @@ version = "0.1.0" dependencies = [ "anyhow", "chrono", - "futures 0.3.31", + "futures 0.3.30", "http_client", "schemars", "serde", "serde_json", "strum 0.25.0", - "thiserror 1.0.69", + "thiserror", "util", ] @@ -272,9 +278,9 @@ dependencies = [ [[package]] name = "arbitrary" -version = "1.4.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" +checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" [[package]] name = "arg_enum_proc_macro" @@ -295,9 +301,9 @@ checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236" [[package]] name = "arrayref" -version = "0.3.9" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" +checksum = "9d151e35f61089500b617991b791fc8bfd237ae50cd5950803758a179b41e67a" [[package]] name = "arrayvec" @@ -390,7 +396,7 @@ dependencies = [ "env_logger 0.11.5", "feature_flags", "fs", - "futures 0.3.31", + "futures 0.3.30", "fuzzy", "globset", "gpui", @@ -457,7 +463,7 @@ dependencies = [ "collections", "derive_more", "extension", - "futures 0.3.31", + "futures 0.3.30", "gpui", "language", "language_model", @@ -567,14 +573,14 @@ dependencies = [ [[package]] name = "async-executor" -version = "1.13.1" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" +checksum = "d7ebdfa2ebdab6b1760375fa7d6f382b9f486eac35fc994625a00e89280bdbb7" dependencies = [ "async-task", "concurrent-queue", - "fastrand 2.2.0", - "futures-lite 2.5.0", + "fastrand 2.1.1", + "futures-lite 2.3.0", "slab", ] @@ -598,7 +604,7 @@ checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a" dependencies = [ "async-lock 3.4.0", "blocking", - "futures-lite 2.5.0", + "futures-lite 2.3.0", ] [[package]] @@ -609,10 +615,10 @@ checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" dependencies = [ "async-channel 2.3.1", "async-executor", - "async-io 2.4.0", + "async-io 2.3.4", "async-lock 3.4.0", "blocking", - "futures-lite 2.5.0", + "futures-lite 2.3.0", "once_cell", ] @@ -638,18 +644,18 @@ dependencies = [ [[package]] name = "async-io" -version = "2.4.0" +version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059" +checksum = "444b0228950ee6501b3568d3c93bf1176a1fdbc3b758dcd9475046d30f4dc7e8" dependencies = [ "async-lock 3.4.0", "cfg-if", "concurrent-queue", "futures-io", - "futures-lite 2.5.0", + "futures-lite 2.3.0", "parking", - "polling 3.7.4", - "rustix 0.38.40", + "polling 3.7.3", + "rustix 0.38.35", "slab", "tracing", "windows-sys 0.59.0", @@ -683,7 +689,7 @@ checksum = "9343dc5acf07e79ff82d0c37899f079db3534d99f189a1837c8e549c99405bec" dependencies = [ "futures-util", "native-tls", - "thiserror 1.0.69", + "thiserror", "url", ] @@ -704,9 +710,9 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7" dependencies = [ - "async-io 2.4.0", + "async-io 2.3.4", "blocking", - "futures-lite 2.5.0", + "futures-lite 2.3.0", ] [[package]] @@ -714,7 +720,7 @@ name = "async-pipe" version = "0.1.3" source = "git+https://github.com/zed-industries/async-pipe-rs?rev=82d00a04211cf4e1236029aa03e6b6ce2a74c553#82d00a04211cf4e1236029aa03e6b6ce2a74c553" dependencies = [ - "futures 0.3.31", + "futures 0.3.30", "log", ] @@ -731,27 +737,28 @@ dependencies = [ "cfg-if", "event-listener 3.1.0", "futures-lite 1.13.0", - "rustix 0.38.40", + "rustix 0.38.35", "windows-sys 0.48.0", ] [[package]] name = "async-process" -version = "2.3.0" +version = "2.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb" +checksum = "a8a07789659a4d385b79b18b9127fc27e1a59e1e89117c78c5ea3b806f016374" dependencies = [ "async-channel 2.3.1", - "async-io 2.4.0", + "async-io 2.3.4", "async-lock 3.4.0", "async-signal", "async-task", "blocking", "cfg-if", "event-listener 5.3.1", - "futures-lite 2.5.0", - "rustix 0.38.40", + "futures-lite 2.3.0", + "rustix 0.38.35", "tracing", + "windows-sys 0.59.0", ] [[package]] @@ -782,13 +789,13 @@ version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3" dependencies = [ - "async-io 2.4.0", + "async-io 2.3.4", "async-lock 3.4.0", "atomic-waker", "cfg-if", "futures-core", "futures-io", - "rustix 0.38.40", + "rustix 0.38.35", "signal-hook-registry", "slab", "windows-sys 0.59.0", @@ -796,21 +803,21 @@ dependencies = [ [[package]] name = "async-std" -version = "1.13.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c634475f29802fde2b8f0b505b1bd00dfe4df7d4a000f0b36f7671197d5c3615" +checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" dependencies = [ "async-attributes", "async-channel 1.9.0", "async-global-executor", - "async-io 2.4.0", - "async-lock 3.4.0", - "async-process 2.3.0", + "async-io 1.13.0", + "async-lock 2.8.0", + "async-process 1.8.1", "crossbeam-utils", "futures-channel", "futures-core", "futures-io", - "futures-lite 2.5.0", + "futures-lite 1.13.0", "gloo-timers", "kv-log-macro", "log", @@ -824,9 +831,9 @@ dependencies = [ [[package]] name = "async-stream" -version = "0.3.6" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" +checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" dependencies = [ "async-stream-impl", "futures-core", @@ -835,9 +842,9 @@ dependencies = [ [[package]] name = "async-stream-impl" -version = "0.3.6" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" +checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", @@ -860,7 +867,7 @@ dependencies = [ "serde_qs 0.10.1", "smart-default", "smol_str", - "thiserror 1.0.69", + "thiserror", "tokio", ] @@ -908,22 +915,6 @@ dependencies = [ "syn 2.0.87", ] -[[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", - "async-tls", - "futures-io", - "futures-util", - "log", - "pin-project-lite", - "tungstenite 0.21.0", -] - [[package]] name = "async-tungstenite" version = "0.28.0" @@ -956,9 +947,9 @@ checksum = "00b9f7252833d5ed4b00aa9604b563529dd5e11de9c23615de2dcdf91eb87b52" dependencies = [ "async-compression", "crc32fast", - "futures-lite 2.5.0", + "futures-lite 2.3.0", "pin-project", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -967,7 +958,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a860072022177f903e59730004fb5dc13db9275b79bb2aef7ba8ce831956c233" dependencies = [ - "bytes 1.8.0", + "bytes 1.7.2", "futures-sink", "futures-util", "memchr", @@ -1037,9 +1028,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.4.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "av1-grain" @@ -1057,18 +1048,18 @@ dependencies = [ [[package]] name = "avif-serialize" -version = "0.8.2" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e335041290c43101ca215eed6f43ec437eb5a42125573f600fc3fa42b9bddd62" +checksum = "876c75a42f6364451a033496a14c44bffe41f5f4a8236f697391f11024e596d2" dependencies = [ "arrayvec", ] [[package]] name = "aws-config" -version = "1.5.10" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b49afaa341e8dd8577e1a2200468f98956d6eda50bcf4a53246cc00174ba924" +checksum = "4e95816a168520d72c0e7680c405a5a8c1fb6a035b4bc4b9d7b0de8e1a941697" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1082,8 +1073,8 @@ dependencies = [ "aws-smithy-runtime-api", "aws-smithy-types", "aws-types", - "bytes 1.8.0", - "fastrand 2.2.0", + "bytes 1.7.2", + "fastrand 2.1.1", "hex", "http 0.2.12", "ring", @@ -1121,8 +1112,8 @@ dependencies = [ "aws-smithy-runtime-api", "aws-smithy-types", "aws-types", - "bytes 1.8.0", - "fastrand 2.2.0", + "bytes 1.7.2", + "fastrand 2.1.1", "http 0.2.12", "http-body 0.4.6", "once_cell", @@ -1147,7 +1138,7 @@ dependencies = [ "aws-smithy-runtime-api", "aws-smithy-types", "aws-types", - "bytes 1.8.0", + "bytes 1.7.2", "http 0.2.12", "once_cell", "regex-lite", @@ -1156,10 +1147,11 @@ dependencies = [ [[package]] name = "aws-sdk-s3" -version = "1.61.0" +version = "1.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e531658a0397d22365dfe26c3e1c0c8448bf6a3a2d8a098ded802f2b1261615" +checksum = "cca49303c05d2a740b8a4552fac63a4db6ead84f7e7eeed04761fd3014c26f25" dependencies = [ + "ahash 0.8.11", "aws-credential-types", "aws-runtime", "aws-sigv4", @@ -1173,8 +1165,8 @@ dependencies = [ "aws-smithy-types", "aws-smithy-xml", "aws-types", - "bytes 1.8.0", - "fastrand 2.2.0", + "bytes 1.7.2", + "fastrand 2.1.1", "hex", "hmac", "http 0.2.12", @@ -1190,9 +1182,9 @@ dependencies = [ [[package]] name = "aws-sdk-sso" -version = "1.49.0" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09677244a9da92172c8dc60109b4a9658597d4d298b188dd0018b6a66b410ca4" +checksum = "e5879bec6e74b648ce12f6085e7245417bc5f6d672781028384d2e494be3eb6d" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1203,7 +1195,7 @@ dependencies = [ "aws-smithy-runtime-api", "aws-smithy-types", "aws-types", - "bytes 1.8.0", + "bytes 1.7.2", "http 0.2.12", "once_cell", "regex-lite", @@ -1212,9 +1204,9 @@ dependencies = [ [[package]] name = "aws-sdk-ssooidc" -version = "1.50.0" +version = "1.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fea2f3a8bb3bd10932ae7ad59cc59f65f270fc9183a7e91f501dc5efbef7ee" +checksum = "4ef4cd9362f638c22a3b959fd8df292e7e47fdf170270f86246b97109b5f2f7d" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1225,7 +1217,7 @@ dependencies = [ "aws-smithy-runtime-api", "aws-smithy-types", "aws-types", - "bytes 1.8.0", + "bytes 1.7.2", "http 0.2.12", "once_cell", "regex-lite", @@ -1234,9 +1226,9 @@ dependencies = [ [[package]] name = "aws-sdk-sts" -version = "1.50.0" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ada54e5f26ac246dc79727def52f7f8ed38915cb47781e2a72213957dc3a7d5" +checksum = "0b1e2735d2ab28b35ecbb5496c9d41857f52a0d6a0075bbf6a8af306045ea6f6" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1266,7 +1258,7 @@ dependencies = [ "aws-smithy-http", "aws-smithy-runtime-api", "aws-smithy-types", - "bytes 1.8.0", + "bytes 1.7.2", "crypto-bigint 0.5.5", "form_urlencoded", "hex", @@ -1297,13 +1289,13 @@ dependencies = [ [[package]] name = "aws-smithy-checksums" -version = "0.60.13" +version = "0.60.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba1a71073fca26775c8b5189175ea8863afb1c9ea2cceb02a5de5ad9dfbaa795" +checksum = "598b1689d001c4d4dc3cb386adb07d37786783aee3ac4b324bcadac116bf3d23" dependencies = [ "aws-smithy-http", "aws-smithy-types", - "bytes 1.8.0", + "bytes 1.7.2", "crc32c", "crc32fast", "hex", @@ -1323,7 +1315,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cef7d0a272725f87e51ba2bf89f8c21e4df61b9e49ae1ac367a6d69916ef7c90" dependencies = [ "aws-smithy-types", - "bytes 1.8.0", + "bytes 1.7.2", "crc32fast", ] @@ -1336,7 +1328,7 @@ dependencies = [ "aws-smithy-eventstream", "aws-smithy-runtime-api", "aws-smithy-types", - "bytes 1.8.0", + "bytes 1.7.2", "bytes-utils", "futures-core", "http 0.2.12", @@ -1377,8 +1369,8 @@ dependencies = [ "aws-smithy-http", "aws-smithy-runtime-api", "aws-smithy-types", - "bytes 1.8.0", - "fastrand 2.2.0", + "bytes 1.7.2", + "fastrand 2.1.1", "h2 0.3.26", "http 0.2.12", "http-body 0.4.6", @@ -1402,7 +1394,7 @@ checksum = "92165296a47a812b267b4f41032ff8069ab7ff783696d217f0994a0d7ab585cd" dependencies = [ "aws-smithy-async", "aws-smithy-types", - "bytes 1.8.0", + "bytes 1.7.2", "http 0.2.12", "http 1.1.0", "pin-project-lite", @@ -1418,7 +1410,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fbd94a32b3a7d55d3806fe27d98d3ad393050439dd05eb53ece36ec5e3d3510" dependencies = [ "base64-simd", - "bytes 1.8.0", + "bytes 1.7.2", "bytes-utils", "futures-core", "http 0.2.12", @@ -1439,9 +1431,9 @@ dependencies = [ [[package]] name = "aws-smithy-xml" -version = "0.60.9" +version = "0.60.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab0b0166827aa700d3dc519f72f8b3a91c35d0b8d042dc5d643a91e6f80648fc" +checksum = "d123fbc2a4adc3c301652ba8e149bf4bc1d1725affb9784eb20c953ace06bf55" dependencies = [ "xmlparser", ] @@ -1470,7 +1462,7 @@ dependencies = [ "axum-core", "base64 0.21.7", "bitflags 1.3.2", - "bytes 1.8.0", + "bytes 1.7.2", "futures-util", "headers", "http 0.2.12", @@ -1503,7 +1495,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" dependencies = [ "async-trait", - "bytes 1.8.0", + "bytes 1.7.2", "futures-util", "http 0.2.12", "http-body 0.4.6", @@ -1520,7 +1512,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9a320103719de37b7b4da4c8eb629d4573f6bcfd3dfe80d3208806895ccf81d" dependencies = [ "axum", - "bytes 1.8.0", + "bytes 1.7.2", "futures-util", "http 0.2.12", "mime", @@ -1543,7 +1535,7 @@ dependencies = [ "addr2line", "cfg-if", "libc", - "miniz_oxide", + "miniz_oxide 0.8.0", "object", "rustc-demangle", "windows-targets 0.52.6", @@ -1591,9 +1583,9 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "bigdecimal" -version = "0.4.6" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f850665a0385e070b64c38d2354e6c104c8479c59868d1e48a0c13ee2c7a1c1" +checksum = "51d712318a27c7150326677b321a5fa91b55f6d9034ffd67f20319e147d40cee" dependencies = [ "autocfg", "libm", @@ -1612,6 +1604,26 @@ dependencies = [ "serde", ] +[[package]] +name = "bindgen" +version = "0.69.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" +dependencies = [ + "bitflags 2.6.0", + "cexpr", + "clang-sys", + "itertools 0.12.1", + "lazy_static", + "lazycell", + "proc-macro2", + "quote", + "regex", + "rustc-hash 1.1.0", + "shlex", + "syn 2.0.87", +] + [[package]] name = "bindgen" version = "0.70.1" @@ -1700,9 +1712,9 @@ dependencies = [ [[package]] name = "bitstream-io" -version = "2.6.0" +version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6099cdc01846bc367c4e7dd630dc5966dccf36b652fae7a74e17b640411a91b2" +checksum = "b81e1519b0d82120d2fd469d5bfb2919a9361c48b02d82d04befc1cdd2002452" [[package]] name = "bitvec" @@ -1777,7 +1789,7 @@ dependencies = [ "arrayvec", "cc", "cfg-if", - "constant_time_eq 0.3.1", + "constant_time_eq", ] [[package]] @@ -1813,15 +1825,15 @@ dependencies = [ "async-channel 2.3.1", "async-task", "futures-io", - "futures-lite 2.5.0", + "futures-lite 2.3.0", "piper", ] [[package]] name = "borsh" -version = "1.5.3" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2506947f73ad44e344215ccd6403ac2ae18cd8e046e581a441bf8d199f257f03" +checksum = "a6362ed55def622cddc70a4746a68554d7b687713770de539e59a739b249f8ed" dependencies = [ "borsh-derive", "cfg_aliases 0.2.1", @@ -1829,15 +1841,16 @@ dependencies = [ [[package]] name = "borsh-derive" -version = "1.5.3" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2593a3b8b938bd68373196c9832f516be11fa487ef4ae745eb282e6a56a7244" +checksum = "c3ef8005764f53cd4dca619f5bf64cafd4664dada50ece25e4d81de54c80cc0b" dependencies = [ "once_cell", "proc-macro-crate", "proc-macro2", "quote", "syn 2.0.87", + "syn_derive", ] [[package]] @@ -1855,20 +1868,20 @@ dependencies = [ [[package]] name = "bstr" -version = "1.11.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a68f1f47cdf0ec8ee4b941b2eee2a80cb796db73118c0dd09ac63fbe405be22" +checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" dependencies = [ "memchr", - "regex-automata 0.4.9", + "regex-automata 0.4.7", "serde", ] [[package]] name = "built" -version = "0.7.5" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c360505aed52b7ec96a3636c3f039d99103c37d1d9b4f7a8c743d3ea9ffcd03b" +checksum = "236e6289eda5a812bc6b53c3b024039382a2895fbbeef2d748b2931546d392c4" [[package]] name = "bumpalo" @@ -1906,18 +1919,18 @@ dependencies = [ [[package]] name = "bytemuck" -version = "1.19.0" +version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d" +checksum = "773d90827bc3feecfb67fab12e24de0749aad83c74b9504ecde46237b5cd24e2" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.8.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcfcc3cd946cb52f0bbfdbbcfa2f4e24f75ebb6c0e1002f7c25904fada18b9ec" +checksum = "0cc8b54b395f2fcfbb3d90c47b01c7f444d94d05bdeb775811dec868ac3bbc26" dependencies = [ "proc-macro2", "quote", @@ -1948,9 +1961,9 @@ dependencies = [ [[package]] name = "bytes" -version = "1.8.0" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" +checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" [[package]] name = "bytes-utils" @@ -1958,31 +1971,10 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7dafe3a8757b027e2be6e4e5601ed563c55989fcf1546e933c66c8eb3a058d35" dependencies = [ - "bytes 1.8.0", + "bytes 1.7.2", "either", ] -[[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.11+1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" -dependencies = [ - "cc", - "libc", - "pkg-config", -] - [[package]] name = "call" version = "0.1.0" @@ -1991,9 +1983,8 @@ dependencies = [ "audio", "client", "collections", - "feature_flags", "fs", - "futures 0.3.31", + "futures 0.3.30", "gpui", "http_client", "language", @@ -2016,10 +2007,10 @@ checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" dependencies = [ "bitflags 2.6.0", "log", - "polling 3.7.4", - "rustix 0.38.40", + "polling 3.7.3", + "rustix 0.38.35", "slab", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -2029,7 +2020,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95a66a987056935f7efce4ab5668920b5d0dac4a7c99991a67395f13702ddd20" dependencies = [ "calloop", - "rustix 0.38.40", + "rustix 0.38.35", "wayland-backend", "wayland-client", ] @@ -2045,9 +2036,9 @@ dependencies = [ [[package]] name = "cap-fs-ext" -version = "3.4.1" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16619ada836f12897a72011fe99b03f0025b87a8dbbea4f3c9f89b458a23bf3" +checksum = "eb23061fc1c4ead4e45ca713080fe768e6234e959f5a5c399c39eb41aa34e56e" dependencies = [ "cap-primitives", "cap-std", @@ -2057,21 +2048,21 @@ dependencies = [ [[package]] name = "cap-net-ext" -version = "3.4.1" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "710b0eb776410a22c89a98f2f80b2187c2ac3a8206b99f3412332e63c9b09de0" +checksum = "f83ae11f116bcbafc5327c6af250341db96b5930046732e1905f7dc65887e0e1" dependencies = [ "cap-primitives", "cap-std", - "rustix 0.38.40", + "rustix 0.38.35", "smallvec", ] [[package]] name = "cap-primitives" -version = "3.4.1" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82fa6c3f9773feab88d844aa50035a33fb6e7e7426105d2f4bb7aadc42a5f89a" +checksum = "6d00bd8d26c4270d950eaaa837387964a2089a1c3c349a690a1fa03221d29531" dependencies = [ "ambient-authority", "fs-set-times", @@ -2079,16 +2070,16 @@ dependencies = [ "io-lifetimes 2.0.3", "ipnet", "maybe-owned", - "rustix 0.38.40", + "rustix 0.38.35", "windows-sys 0.52.0", "winx", ] [[package]] name = "cap-rand" -version = "3.4.1" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53774d49369892b70184f8312e50c1b87edccb376691de4485b0ff554b27c36c" +checksum = "dbcb16a619d8b8211ed61f42bd290d2a1ac71277a69cf8417ec0996fa92f5211" dependencies = [ "ambient-authority", "rand 0.8.5", @@ -2096,27 +2087,27 @@ dependencies = [ [[package]] name = "cap-std" -version = "3.4.1" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f71b70818556b4fe2a10c7c30baac3f5f45e973f49fc2673d7c75c39d0baf5b" +checksum = "19eb8e3d71996828751c1ed3908a439639752ac6bdc874e41469ef7fc15fbd7f" dependencies = [ "cap-primitives", "io-extras", "io-lifetimes 2.0.3", - "rustix 0.38.40", + "rustix 0.38.35", ] [[package]] name = "cap-time-ext" -version = "3.4.1" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69dd48afa2363f746c93f961c211f6f099fb594a3446b8097bc5f79db51b6816" +checksum = "61142dc51e25b7acc970ca578ce2c3695eac22bbba46c1073f5f583e78957725" dependencies = [ "ambient-authority", "cap-primitives", "iana-time-zone", "once_cell", - "rustix 0.38.40", + "rustix 0.38.35", "winx", ] @@ -2140,7 +2131,7 @@ dependencies = [ "semver", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -2175,7 +2166,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fce8dd7fcfcbf3a0a87d8f515194b49d6135acab73e18bd380d1d93bb1a15eb" dependencies = [ "heck 0.4.1", - "indexmap 2.6.0", + "indexmap 2.4.0", "log", "proc-macro2", "quote", @@ -2188,9 +2179,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.1" +version = "1.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47" +checksum = "57b6a275aa2903740dc87da01c62040406b8812552e97129a63ea8850a17c6e6" dependencies = [ "jobserver", "libc", @@ -2248,7 +2239,7 @@ dependencies = [ "client", "clock", "collections", - "futures 0.3.31", + "futures 0.3.30", "gpui", "http_client", "language", @@ -2358,9 +2349,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.38" +version = "4.5.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9647a559c112175f17cf724dc72d3645680a883c58481332779192b0d8e7a01" +checksum = "6d7db6eca8c205649e8d3ccd05aa5042b1800a784e56bc7c43524fde8abbfa9b" dependencies = [ "clap", ] @@ -2379,9 +2370,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.3" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "cli" @@ -2412,17 +2403,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0875e527e299fc5f4faba42870bf199a39ab0bb2dbba1b8aef0a2151451130f" dependencies = [ "bstr", - "bytes 1.8.0", + "bytes 1.7.2", "clickhouse-derive", "clickhouse-rs-cityhash-sys", - "futures 0.3.31", + "futures 0.3.30", "hyper 0.14.31", "hyper-tls", "lz4", "sealed", "serde", "static_assertions", - "thiserror 1.0.69", + "thiserror", "tokio", "url", ] @@ -2455,13 +2446,13 @@ dependencies = [ "anyhow", "async-native-tls", "async-recursion 0.3.2", - "async-tungstenite 0.28.0", + "async-tungstenite", "chrono", "clock", "cocoa 0.26.0", "collections", "feature_flags", - "futures 0.3.31", + "futures 0.3.30", "gpui", "http_client", "log", @@ -2483,7 +2474,7 @@ dependencies = [ "sysinfo", "telemetry_events", "text", - "thiserror 1.0.69", + "thiserror", "time", "tiny_http", "tokio-socks", @@ -2588,7 +2579,7 @@ dependencies = [ "assistant", "async-stripe", "async-trait", - "async-tungstenite 0.28.0", + "async-tungstenite", "audio", "aws-config", "aws-sdk-kinesis", @@ -2606,14 +2597,14 @@ dependencies = [ "collections", "context_servers", "ctor", - "dashmap 6.1.0", + "dashmap 6.0.1", "derive_more", "editor", "env_logger 0.11.5", "envy", "file_finder", "fs", - "futures 0.3.31", + "futures 0.3.30", "git", "git_hosting_providers", "google_ai", @@ -2639,7 +2630,7 @@ dependencies = [ "pretty_assertions", "project", "prometheus", - "prost 0.9.0", + "prost", "rand 0.8.5", "recent_projects", "release_channel", @@ -2666,7 +2657,7 @@ dependencies = [ "telemetry_events", "text", "theme", - "thiserror 1.0.69", + "thiserror", "time", "tokio", "toml 0.8.19", @@ -2694,7 +2685,7 @@ dependencies = [ "db", "editor", "emojis", - "futures 0.3.31", + "futures 0.3.30", "fuzzy", "gpui", "http_client", @@ -2741,9 +2732,9 @@ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" [[package]] name = "colorchoice" -version = "1.0.3" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" [[package]] name = "combine" @@ -2751,7 +2742,7 @@ version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" dependencies = [ - "bytes 1.8.0", + "bytes 1.7.2", "memchr", ] @@ -2840,12 +2831,6 @@ dependencies = [ "tiny-keccak", ] -[[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - [[package]] name = "constant_time_eq" version = "0.3.1" @@ -2859,7 +2844,7 @@ dependencies = [ "anyhow", "collections", "command_palette_hooks", - "futures 0.3.31", + "futures 0.3.30", "gpui", "log", "parking_lot", @@ -2904,7 +2889,7 @@ dependencies = [ "command_palette_hooks", "editor", "fs", - "futures 0.3.31", + "futures 0.3.30", "gpui", "http_client", "indoc", @@ -3037,11 +3022,11 @@ dependencies = [ [[package]] name = "coreaudio-sys" -version = "0.2.16" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ce857aa0b77d77287acc1ac3e37a05a8c95a2af3647d23b15f263bdaeb7562b" +checksum = "7f01585027057ff5f0a5bf276174ae4c1594a2c5bde93d5f46a016d76270f5a9" dependencies = [ - "bindgen", + "bindgen 0.69.4", ] [[package]] @@ -3069,7 +3054,8 @@ dependencies = [ [[package]] name = "cpal" version = "0.15.3" -source = "git+https://github.com/zed-industries/cpal?rev=fd8bc2fd39f1f5fdee5a0690656caff9a26d9d50#fd8bc2fd39f1f5fdee5a0690656caff9a26d9d50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "873dab07c8f743075e57f524c583985fbaf745602acbe916a01539364369a779" dependencies = [ "alsa", "core-foundation-sys", @@ -3099,9 +3085,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.15" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ca741a962e1b0bff6d724a1a0958b686406e853bb14061f218562e1896f95e6" +checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" dependencies = [ "libc", ] @@ -3405,50 +3391,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991" -[[package]] -name = "cxx" -version = "1.0.130" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23c042a0ba58aaff55299632834d1ea53ceff73d62373f62c9ae60890ad1b942" -dependencies = [ - "cc", - "cxxbridge-flags", - "cxxbridge-macro", - "link-cplusplus", -] - -[[package]] -name = "cxx-build" -version = "1.0.130" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45dc1c88d0fdac57518a9b1f6c4f4fb2aca8f3c30c0d03d7d8518b47ca0bcea6" -dependencies = [ - "cc", - "codespan-reporting", - "proc-macro2", - "quote", - "scratch", - "syn 2.0.87", -] - -[[package]] -name = "cxxbridge-flags" -version = "1.0.130" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa7ed7d30b289e2592cc55bc2ccd89803a63c913e008e6eb59f06cddf45bb52f" - -[[package]] -name = "cxxbridge-macro" -version = "1.0.130" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b8c465d22de46b851c04630a5fc749a26005b263632ed2e0d9cc81518ead78d" -dependencies = [ - "proc-macro2", - "quote", - "rustversion", - "syn 2.0.87", -] - [[package]] name = "dashmap" version = "5.5.3" @@ -3464,9 +3406,9 @@ dependencies = [ [[package]] name = "dashmap" -version = "6.1.0" +version = "6.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" +checksum = "804c8821570c3f8b70230c2ba75ffa5c0f9a4189b9a432b6656c536712acae28" dependencies = [ "cfg-if", "crossbeam-utils", @@ -3619,7 +3561,7 @@ dependencies = [ "fuzzy-matcher", "shell-words", "tempfile", - "thiserror 1.0.69", + "thiserror", "zeroize", ] @@ -3682,17 +3624,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "displaydoc" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - [[package]] name = "dlib" version = "0.5.2" @@ -3739,9 +3670,9 @@ dependencies = [ [[package]] name = "dwrote" -version = "0.11.2" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70182709525a3632b2ba96b6569225467b18ecb4a77f46d255f713a6bebf05fd" +checksum = "2da3498378ed373237bdef1eddcc64e7be2d3ba4841f4c22a998e81cadeea83c" dependencies = [ "lazy_static", "libc", @@ -3790,7 +3721,7 @@ dependencies = [ "emojis", "env_logger 0.11.5", "file_icons", - "futures 0.3.31", + "futures 0.3.30", "fuzzy", "git", "gpui", @@ -3836,6 +3767,18 @@ dependencies = [ "workspace", ] +[[package]] +name = "educe" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4bd92664bf78c4d3dba9b7cdafce6fa15b13ed3ed16175218196942e99168a8" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "either" version = "1.13.0" @@ -3879,9 +3822,9 @@ dependencies = [ [[package]] name = "embed-resource" -version = "2.5.1" +version = "2.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b68b6f9f63a0b6a38bc447d4ce84e2b388f3ec95c99c641c8ff0dd3ef89a6379" +checksum = "4edcacde9351c33139a41e3c97eb2334351a81a2791bebb0b243df837128f602" dependencies = [ "cc", "memchr", @@ -3920,9 +3863,9 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" [[package]] name = "encoding_rs" -version = "0.8.35" +version = "0.8.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" dependencies = [ "cfg-if", ] @@ -3933,6 +3876,26 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf" +[[package]] +name = "enum-ordinalize" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea0dcfa4e54eeb516fe454635a95753ddd39acda650ce703031c6973e315dd5" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "enumflags2" version = "0.7.10" @@ -4154,14 +4117,15 @@ dependencies = [ [[package]] name = "exr" -version = "1.73.0" +version = "1.72.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83197f59927b46c04a183a619b7c29df34e63e63c7869320862268c0ef687e0" +checksum = "887d93f60543e9a9362ef8a21beedd0a833c5d9610e18c67abe15a5963dcb1a4" dependencies = [ "bit_field", + "flume", "half", "lebe", - "miniz_oxide", + "miniz_oxide 0.7.4", "rayon-core", "smallvec", "zune-inflate", @@ -4177,7 +4141,7 @@ dependencies = [ "async-trait", "collections", "fs", - "futures 0.3.31", + "futures 0.3.30", "gpui", "http_client", "language", @@ -4229,7 +4193,7 @@ dependencies = [ "env_logger 0.11.5", "extension", "fs", - "futures 0.3.31", + "futures 0.3.30", "gpui", "http_client", "language", @@ -4318,8 +4282,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e24cb5a94bcae1e5408b0effca5cd7172ea3c5755049c5f3af4cd283a165298" dependencies = [ "bit-set 0.8.0", - "regex-automata 0.4.9", - "regex-syntax 0.8.5", + "regex-automata 0.4.7", + "regex-syntax 0.8.4", ] [[package]] @@ -4339,9 +4303,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.2.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "fd-lock" @@ -4350,15 +4314,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e5768da2206272c81ef0b5e951a41862938a6070da63bcea197899942d3b947" dependencies = [ "cfg-if", - "rustix 0.38.40", + "rustix 0.38.35", "windows-sys 0.52.0", ] [[package]] name = "fdeflate" -version = "0.3.6" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07c6f4c64c1d33a3111c4466f7365ebdcc37c5bd1ea0d62aae2e3d722aacbedb" +checksum = "4f9bfee30e4dedf0ab8b422f03af778d9612b63f502710fc500a334ebe2de645" dependencies = [ "simd-adler32", ] @@ -4367,7 +4331,7 @@ dependencies = [ name = "feature_flags" version = "0.1.0" dependencies = [ - "futures 0.3.31", + "futures 0.3.30", "gpui", ] @@ -4380,7 +4344,7 @@ dependencies = [ "client", "db", "editor", - "futures 0.3.31", + "futures 0.3.30", "gpui", "http_client", "human_bytes", @@ -4421,7 +4385,7 @@ dependencies = [ "editor", "env_logger 0.11.5", "file_icons", - "futures 0.3.31", + "futures 0.3.30", "fuzzy", "gpui", "language", @@ -4459,7 +4423,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7199d965852c3bac31f779ef99cbb4537f80e952e2d6aa0ffeb30cce00f4f46e" dependencies = [ "libc", - "thiserror 1.0.69", + "thiserror", "winapi", ] @@ -4483,12 +4447,12 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.0.35" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" +checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" dependencies = [ "crc32fast", - "miniz_oxide", + "miniz_oxide 0.8.0", ] [[package]] @@ -4521,12 +4485,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "foldhash" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" - [[package]] name = "font-kit" version = "0.14.1" @@ -4553,9 +4511,9 @@ dependencies = [ [[package]] name = "font-types" -version = "0.7.3" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3971f9a5ca983419cdc386941ba3b9e1feba01a0ab888adf78739feb2798492" +checksum = "8f0189ccb084f77c5523e08288d418cbaa09c451a08515678a0aa265df9a8b60" dependencies = [ "bytemuck", ] @@ -4665,7 +4623,7 @@ dependencies = [ "cocoa 0.26.0", "collections", "fsevent", - "futures 0.3.31", + "futures 0.3.30", "git", "git2", "gpui", @@ -4692,20 +4650,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "033b337d725b97690d86893f9de22b67b80dcc4e9ad815f348254c38119db8fb" dependencies = [ "io-lifetimes 2.0.3", - "rustix 0.38.40", + "rustix 0.38.35", "windows-sys 0.52.0", ] -[[package]] -name = "fs2" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "fsevent" version = "0.1.0" @@ -4759,9 +4707,9 @@ checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678" [[package]] name = "futures" -version = "0.3.31" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" dependencies = [ "futures-channel", "futures-core", @@ -4778,16 +4726,16 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f444c45a1cb86f2a7e301469fd50a82084a60dadc25d94529a8312276ecb71a" dependencies = [ - "futures 0.3.31", + "futures 0.3.30", "futures-timer", "pin-utils", ] [[package]] name = "futures-channel" -version = "0.3.31" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", "futures-sink", @@ -4795,15 +4743,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.31" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" [[package]] name = "futures-executor" -version = "0.3.31" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" dependencies = [ "futures-core", "futures-task", @@ -4823,9 +4771,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.31" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" [[package]] name = "futures-lite" @@ -4844,11 +4792,11 @@ dependencies = [ [[package]] name = "futures-lite" -version = "2.5.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cef40d21ae2c515b51041df9ed313ed21e572df340ea58a922a0aefe7e8891a1" +checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" dependencies = [ - "fastrand 2.2.0", + "fastrand 2.1.1", "futures-core", "futures-io", "parking", @@ -4857,9 +4805,9 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.31" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", @@ -4868,15 +4816,15 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.31" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" [[package]] name = "futures-task" -version = "0.3.31" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-timer" @@ -4886,9 +4834,9 @@ checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" [[package]] name = "futures-util" -version = "0.3.31" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures 0.1.31", "futures-channel", @@ -4982,15 +4930,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" dependencies = [ "fallible-iterator", - "indexmap 2.6.0", + "indexmap 2.4.0", "stable_deref_trait", ] [[package]] name = "gimli" -version = "0.31.1" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" [[package]] name = "git" @@ -5039,7 +4987,7 @@ version = "0.1.0" dependencies = [ "anyhow", "async-trait", - "futures 0.3.31", + "futures 0.3.30", "git", "gpui", "http_client", @@ -5067,15 +5015,15 @@ dependencies = [ "aho-corasick", "bstr", "log", - "regex-automata 0.4.9", - "regex-syntax 0.8.5", + "regex-automata 0.4.7", + "regex-syntax 0.8.4", ] [[package]] name = "gloo-timers" -version = "0.3.0" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" +checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" dependencies = [ "futures-channel", "futures-core", @@ -5085,9 +5033,9 @@ dependencies = [ [[package]] name = "glow" -version = "0.14.2" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d51fa363f025f5c111e03f13eda21162faeacb6911fe8caa0c0349f9cf0c4483" +checksum = "f865cbd94bd355b89611211e49508da98a1fce0ad755c1e8448fb96711b24528" dependencies = [ "js-sys", "slotmap", @@ -5125,7 +5073,7 @@ name = "google_ai" version = "0.1.0" dependencies = [ "anyhow", - "futures 0.3.31", + "futures 0.3.30", "http_client", "schemars", "serde", @@ -5172,7 +5120,7 @@ dependencies = [ "ashpd", "async-task", "backtrace", - "bindgen", + "bindgen 0.70.1", "blade-graphics", "blade-macros", "blade-util", @@ -5197,7 +5145,7 @@ dependencies = [ "flume", "font-kit", "foreign-types 0.5.0", - "futures 0.3.31", + "futures 0.3.30", "gpui_macros", "http_client", "image", @@ -5231,7 +5179,7 @@ dependencies = [ "strum 0.25.0", "sum_tree", "taffy", - "thiserror 1.0.69", + "thiserror", "unicode-segmentation", "usvg", "util", @@ -5282,13 +5230,13 @@ version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" dependencies = [ - "bytes 1.8.0", + "bytes 1.7.2", "fnv", "futures-core", "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.6.0", + "indexmap 2.4.0", "slab", "tokio", "tokio-util", @@ -5302,12 +5250,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" dependencies = [ "atomic-waker", - "bytes 1.8.0", + "bytes 1.7.2", "fnv", "futures-core", "futures-sink", "http 1.1.0", - "indexmap 2.6.0", + "indexmap 2.4.0", "slab", "tokio", "tokio-util", @@ -5335,7 +5283,7 @@ dependencies = [ "pest_derive", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -5350,7 +5298,7 @@ dependencies = [ "pest_derive", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -5382,17 +5330,6 @@ dependencies = [ "serde", ] -[[package]] -name = "hashbrown" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" -dependencies = [ - "allocator-api2", - "equivalent", - "foldhash", -] - [[package]] name = "hashlink" version = "0.8.4" @@ -5418,7 +5355,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" dependencies = [ "base64 0.21.7", - "bytes 1.8.0", + "bytes 1.7.2", "headers-core", "http 0.2.12", "httpdate", @@ -5597,7 +5534,7 @@ version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ - "bytes 1.8.0", + "bytes 1.7.2", "fnv", "itoa", ] @@ -5608,7 +5545,7 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" dependencies = [ - "bytes 1.8.0", + "bytes 1.7.2", "fnv", "itoa", ] @@ -5619,7 +5556,7 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ - "bytes 1.8.0", + "bytes 1.7.2", "http 0.2.12", "pin-project-lite", ] @@ -5630,7 +5567,7 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ - "bytes 1.8.0", + "bytes 1.7.2", "http 1.1.0", ] @@ -5640,7 +5577,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ - "bytes 1.8.0", + "bytes 1.7.2", "futures-util", "http 1.1.0", "http-body 1.0.1", @@ -5679,9 +5616,9 @@ name = "http_client" version = "0.1.0" dependencies = [ "anyhow", - "bytes 1.8.0", + "bytes 1.7.2", "derive_more", - "futures 0.3.31", + "futures 0.3.30", "http 1.1.0", "log", "serde", @@ -5691,9 +5628,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.9.5" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" [[package]] name = "httpdate" @@ -5719,7 +5656,7 @@ version = "0.14.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c08302e8fa335b151b788c775ff56e7a03ae64ff85c548ee820fecb70356e85" dependencies = [ - "bytes 1.8.0", + "bytes 1.7.2", "futures-channel", "futures-core", "futures-util", @@ -5739,11 +5676,11 @@ dependencies = [ [[package]] name = "hyper" -version = "1.5.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a" +checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" dependencies = [ - "bytes 1.8.0", + "bytes 1.7.2", "futures-channel", "futures-util", "h2 0.4.6", @@ -5781,9 +5718,9 @@ checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ "futures-util", "http 1.1.0", - "hyper 1.5.0", + "hyper 1.4.1", "hyper-util", - "rustls 0.23.16", + "rustls 0.23.13", "rustls-native-certs 0.8.0", "rustls-pki-types", "tokio", @@ -5797,7 +5734,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ - "bytes 1.8.0", + "bytes 1.7.2", "hyper 0.14.31", "native-tls", "tokio", @@ -5806,16 +5743,16 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.10" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" +checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b" dependencies = [ - "bytes 1.8.0", + "bytes 1.7.2", "futures-channel", "futures-util", "http 1.1.0", "http-body 1.0.1", - "hyper 1.5.0", + "hyper 1.4.1", "pin-project-lite", "socket2 0.5.7", "tokio", @@ -5825,9 +5762,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.61" +version = "0.1.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -5846,124 +5783,6 @@ dependencies = [ "cc", ] -[[package]] -name = "icu_collections" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locid" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_locid_transform" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_locid_transform_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" - -[[package]] -name = "icu_normalizer" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "utf16_iter", - "utf8_iter", - "write16", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" - -[[package]] -name = "icu_properties" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_locid_transform", - "icu_properties_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" - -[[package]] -name = "icu_provider" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_provider_macros", - "stable_deref_trait", - "tinystr", - "writeable", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_provider_macros" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - [[package]] name = "id-arena" version = "2.2.1" @@ -5972,23 +5791,12 @@ checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" [[package]] name = "idna" -version = "1.0.3" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "idna_adapter" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" -dependencies = [ - "icu_normalizer", - "icu_properties", + "unicode-bidi", + "unicode-normalization", ] [[package]] @@ -6001,7 +5809,7 @@ dependencies = [ "globset", "log", "memchr", - "regex-automata 0.4.9", + "regex-automata 0.4.7", "same-file", "walkdir", "winapi-util", @@ -6009,9 +5817,9 @@ dependencies = [ [[package]] name = "image" -version = "0.25.5" +version = "0.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd6f44aed642f18953a158afeb30206f4d50da59fbc66ecb53c66488de73563b" +checksum = "99314c8a2152b8ddb211f924cdae532d8c5e4c8bb54728e12fff1b0cd5963a10" dependencies = [ "bytemuck", "byteorder-lite", @@ -6032,9 +5840,9 @@ dependencies = [ [[package]] name = "image-webp" -version = "0.2.0" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e031e8e3d94711a9ccb5d6ea357439ef3dcbed361798bd4071dc4d9793fbe22f" +checksum = "f79afb8cbee2ef20f59ccd477a218c12a93943d075b492015ecb1bb81f8ee904" dependencies = [ "byteorder-lite", "quick-error", @@ -6064,9 +5872,9 @@ checksum = "edcd27d72f2f071c64249075f42e205ff93c9a4c5f6c6da53e79ed9f9832c285" [[package]] name = "imgref" -version = "1.11.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0263a3d970d5c054ed9312c0057b4f3bde9c0b33836d3637361d4a9e6e7a408" +checksum = "44feda355f4159a7c757171a77de25daf6411e217b4cabd03bd6650690468126" [[package]] name = "indexed_docs" @@ -6079,7 +5887,7 @@ dependencies = [ "derive_more", "extension", "fs", - "futures 0.3.31", + "futures 0.3.30", "fuzzy", "gpui", "heed", @@ -6108,12 +5916,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.6.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" dependencies = [ "equivalent", - "hashbrown 0.15.1", + "hashbrown 0.14.5", "serde", ] @@ -6148,7 +5956,7 @@ dependencies = [ "copilot", "editor", "fs", - "futures 0.3.31", + "futures 0.3.30", "gpui", "indoc", "language", @@ -6227,9 +6035,9 @@ dependencies = [ [[package]] name = "io-extras" -version = "0.18.3" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d45fd7584f9b67ac37bc041212d06bfac0700b36456b05890d36a3b626260eb" +checksum = "c9f046b9af244f13b3bd939f55d16830ac3a201e8a9ba9661bfcb03e2be72b9b" dependencies = [ "io-lifetimes 2.0.3", "windows-sys 0.52.0", @@ -6282,9 +6090,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.10.1" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] name = "is-docker" @@ -6331,15 +6139,6 @@ dependencies = [ "either", ] -[[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" @@ -6375,7 +6174,7 @@ dependencies = [ "combine", "jni-sys", "log", - "thiserror 1.0.69", + "thiserror", "walkdir", "windows-sys 0.45.0", ] @@ -6419,9 +6218,9 @@ checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" [[package]] name = "js-sys" -version = "0.3.72" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" dependencies = [ "wasm-bindgen", ] @@ -6450,7 +6249,7 @@ dependencies = [ "anyhow", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror", "uuid", ] @@ -6486,9 +6285,9 @@ dependencies = [ [[package]] name = "kurbo" -version = "0.11.1" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89234b2cc610a7dd927ebde6b41dd1a5d4214cffaef4cf1fb2195d592f92518f" +checksum = "6e5aa9f0f96a938266bdb12928a67169e8d22c6a786fda8ed984b85e6ba93c3c" dependencies = [ "arrayvec", "smallvec", @@ -6515,7 +6314,7 @@ dependencies = [ "ctor", "ec4rs", "env_logger 0.11.5", - "futures 0.3.31", + "futures 0.3.30", "fuzzy", "git", "globset", @@ -6573,7 +6372,7 @@ dependencies = [ "editor", "env_logger 0.11.5", "feature_flags", - "futures 0.3.31", + "futures 0.3.30", "google_ai", "gpui", "http_client", @@ -6597,7 +6396,7 @@ dependencies = [ "telemetry_events", "text", "theme", - "thiserror 1.0.69", + "thiserror", "tiktoken-rs", "ui", "unindent", @@ -6630,7 +6429,7 @@ dependencies = [ "copilot", "editor", "env_logger 0.11.5", - "futures 0.3.31", + "futures 0.3.30", "gpui", "itertools 0.13.0", "language", @@ -6656,7 +6455,7 @@ dependencies = [ "async-tar", "async-trait", "collections", - "futures 0.3.31", + "futures 0.3.30", "gpui", "http_client", "language", @@ -6713,6 +6512,12 @@ dependencies = [ "spin", ] +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + [[package]] name = "leb128" version = "0.2.5" @@ -6743,12 +6548,13 @@ dependencies = [ [[package]] name = "libfuzzer-sys" -version = "0.4.8" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b9569d2f74e257076d8c6bfa73fb505b46b851e51ddaecc825944aa3bed17fa" +checksum = "a96cfd5557eb82f2b83fed4955246c988d331975a002961b07c81584d107e7f7" dependencies = [ "arbitrary", "cc", + "once_cell", ] [[package]] @@ -6775,9 +6581,9 @@ dependencies = [ [[package]] name = "libm" -version = "0.2.11" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "libmimalloc-sys" @@ -6797,7 +6603,7 @@ checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ "bitflags 2.6.0", "libc", - "redox_syscall 0.5.7", + "redox_syscall 0.5.3", ] [[package]] @@ -6811,29 +6617,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "libwebrtc" -version = "0.3.7" -source = "git+https://github.com/zed-industries/rust-sdks?rev=4262308983646ab5b0e0802c3d8bc52154f99aab#4262308983646ab5b0e0802c3d8bc52154f99aab" -dependencies = [ - "cxx", - "jni", - "js-sys", - "lazy_static", - "livekit-protocol", - "livekit-runtime", - "log", - "parking_lot", - "serde", - "serde_json", - "thiserror 1.0.69", - "tokio", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "webrtc-sys", -] - [[package]] name = "libz-sys" version = "1.1.20" @@ -6846,15 +6629,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "link-cplusplus" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d240c6f7e1ba3a28b0249f774e6a9dd0175054b52dfbb61b16eb8505c3785c9" -dependencies = [ - "cc", -] - [[package]] name = "linkify" version = "0.10.0" @@ -6896,27 +6670,18 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" -[[package]] -name = "litemap" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" - [[package]] name = "live_kit_client" version = "0.1.0" dependencies = [ "anyhow", + "async-broadcast", "async-trait", "collections", "core-foundation 0.9.4", - "cpal", - "futures 0.3.31", + "futures 0.3.30", "gpui", - "http 0.2.12", - "http_client", "live_kit_server", - "livekit", "log", "media", "nanoid", @@ -6926,7 +6691,6 @@ dependencies = [ "serde_json", "sha2", "simplelog", - "util", ] [[package]] @@ -6937,88 +6701,13 @@ dependencies = [ "async-trait", "jsonwebtoken", "log", - "prost 0.9.0", - "prost-build 0.9.0", - "prost-types 0.9.0", + "prost", + "prost-build", + "prost-types", "reqwest 0.12.8", "serde", ] -[[package]] -name = "livekit" -version = "0.7.0" -source = "git+https://github.com/zed-industries/rust-sdks?rev=4262308983646ab5b0e0802c3d8bc52154f99aab#4262308983646ab5b0e0802c3d8bc52154f99aab" -dependencies = [ - "chrono", - "futures-util", - "lazy_static", - "libwebrtc", - "livekit-api", - "livekit-protocol", - "livekit-runtime", - "log", - "parking_lot", - "prost 0.12.6", - "semver", - "serde", - "serde_json", - "thiserror 1.0.69", - "tokio", -] - -[[package]] -name = "livekit-api" -version = "0.4.1" -source = "git+https://github.com/zed-industries/rust-sdks?rev=4262308983646ab5b0e0802c3d8bc52154f99aab#4262308983646ab5b0e0802c3d8bc52154f99aab" -dependencies = [ - "async-tungstenite 0.25.1", - "futures-util", - "http 0.2.12", - "jsonwebtoken", - "livekit-protocol", - "livekit-runtime", - "log", - "parking_lot", - "prost 0.12.6", - "reqwest 0.11.27", - "scopeguard", - "serde", - "serde_json", - "sha2", - "thiserror 1.0.69", - "tokio", - "tokio-tungstenite 0.20.1", - "url", -] - -[[package]] -name = "livekit-protocol" -version = "0.3.6" -source = "git+https://github.com/zed-industries/rust-sdks?rev=4262308983646ab5b0e0802c3d8bc52154f99aab#4262308983646ab5b0e0802c3d8bc52154f99aab" -dependencies = [ - "futures-util", - "livekit-runtime", - "parking_lot", - "pbjson", - "pbjson-types", - "prost 0.12.6", - "prost-types 0.12.6", - "serde", - "thiserror 1.0.69", - "tokio", -] - -[[package]] -name = "livekit-runtime" -version = "0.3.1" -source = "git+https://github.com/zed-industries/rust-sdks?rev=4262308983646ab5b0e0802c3d8bc52154f99aab#4262308983646ab5b0e0802c3d8bc52154f99aab" -dependencies = [ - "async-io 2.4.0", - "async-std", - "async-task", - "futures 0.3.31", -] - [[package]] name = "lmdb-master-sys" version = "0.2.4" @@ -7061,11 +6750,11 @@ dependencies = [ [[package]] name = "lru" -version = "0.12.5" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" +checksum = "37ee39891760e7d94734f6f63fedc29a2e4a152f836120753a72503f09fcf904" dependencies = [ - "hashbrown 0.15.1", + "hashbrown 0.14.5", ] [[package]] @@ -7077,7 +6766,7 @@ dependencies = [ "collections", "ctor", "env_logger 0.11.5", - "futures 0.3.31", + "futures 0.3.30", "gpui", "log", "lsp-types", @@ -7106,18 +6795,19 @@ dependencies = [ [[package]] name = "lz4" -version = "1.28.0" +version = "1.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d1febb2b4a79ddd1980eede06a8f7902197960aa0383ffcfdd62fe723036725" +checksum = "958b4caa893816eea05507c20cfe47574a43d9a697138a7872990bba8a0ece68" dependencies = [ + "libc", "lz4-sys", ] [[package]] name = "lz4-sys" -version = "1.11.1+lz4-1.10.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bd8c0d6c6ed0cd30b3652886bb8711dc4bb01d637a68105a3d5158039b418e6" +checksum = "109de74d5d2353660401699a4174a4ff23fcc649caf553df71933c7fb45ad868" dependencies = [ "cc", "libc", @@ -7160,7 +6850,7 @@ dependencies = [ "anyhow", "assets", "env_logger 0.11.5", - "futures 0.3.31", + "futures 0.3.30", "gpui", "language", "languages", @@ -7248,7 +6938,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" dependencies = [ "cfg-if", - "rayon", ] [[package]] @@ -7302,9 +6991,8 @@ name = "media" version = "0.1.0" dependencies = [ "anyhow", - "bindgen", + "bindgen 0.70.1", "core-foundation 0.9.4", - "ctor", "foreign-types 0.5.0", "metal", "objc", @@ -7322,14 +7010,14 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2cffa4ad52c6f791f4f8b15f0c05f9824b2ced1160e88cc393d64fff9a8ac64" dependencies = [ - "rustix 0.38.40", + "rustix 0.38.35", ] [[package]] name = "memmap2" -version = "0.9.5" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" +checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" dependencies = [ "libc", ] @@ -7397,6 +7085,16 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +[[package]] +name = "miniz_oxide" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +dependencies = [ + "adler", + "simd-adler32", +] + [[package]] name = "miniz_oxide" version = "0.8.0" @@ -7404,7 +7102,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" dependencies = [ "adler2", - "simd-adler32", ] [[package]] @@ -7465,7 +7162,7 @@ dependencies = [ "collections", "ctor", "env_logger 0.11.5", - "futures 0.3.31", + "futures 0.3.30", "gpui", "itertools 0.13.0", "language", @@ -7487,12 +7184,6 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" -[[package]] -name = "multimap" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" - [[package]] name = "naga" version = "22.1.0" @@ -7505,12 +7196,12 @@ dependencies = [ "cfg_aliases 0.1.1", "codespan-reporting", "hexf-parse", - "indexmap 2.6.0", + "indexmap 2.4.0", "log", "rustc-hash 1.1.0", "spirv", "termcolor", - "thiserror 1.0.69", + "thiserror", "unicode-xid", ] @@ -7560,7 +7251,7 @@ dependencies = [ "jupyter-serde", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror", "uuid", ] @@ -7575,7 +7266,7 @@ dependencies = [ "log", "ndk-sys", "num_enum", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -7623,7 +7314,7 @@ dependencies = [ "async-trait", "async-watch", "async_zip", - "futures 0.3.31", + "futures 0.3.30", "http_client", "log", "paths", @@ -7909,7 +7600,7 @@ version = "0.8.0-pre" source = "git+https://github.com/KillTheMule/nvim-rs?branch=master#69500bae73b8b3f02a05b7bee621a0d0e633da6c" dependencies = [ "async-trait", - "futures 0.3.31", + "futures 0.3.30", "log", "parity-tokio-ipc", "rmp", @@ -7930,13 +7621,13 @@ dependencies = [ [[package]] name = "object" -version = "0.36.5" +version = "0.36.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" +checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" dependencies = [ "crc32fast", - "hashbrown 0.15.1", - "indexmap 2.6.0", + "hashbrown 0.14.5", + "indexmap 2.4.0", "memchr", ] @@ -7968,7 +7659,7 @@ name = "ollama" version = "0.1.0" dependencies = [ "anyhow", - "futures 0.3.31", + "futures 0.3.30", "http_client", "schemars", "serde", @@ -7977,9 +7668,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.2" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "oo7" @@ -7989,7 +7680,7 @@ checksum = "8fc6ce4692fbfd044ce22ca07dcab1a30fa12432ca2aa5b1294eca50d3332a24" dependencies = [ "aes", "async-fs 2.1.2", - "async-io 2.4.0", + "async-io 2.3.4", "async-lock 3.4.0", "async-net 2.0.0", "blocking", @@ -7997,14 +7688,14 @@ dependencies = [ "cipher", "digest", "endi", - "futures-lite 2.5.0", + "futures-lite 2.3.0", "futures-util", "hkdf", "hmac", "md-5", "num", "num-bigint-dig", - "pbkdf2 0.12.2", + "pbkdf2", "rand 0.8.5", "serde", "sha2", @@ -8022,9 +7713,9 @@ checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" [[package]] name = "open" -version = "5.3.1" +version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ecd52f0b8d15c40ce4820aa251ed5de032e5d91fab27f7db2f40d42a8bdf69c" +checksum = "61a877bf6abd716642a53ef1b89fb498923a4afca5c754f9050b4d081c05c4b3" dependencies = [ "is-wsl", "libc", @@ -8036,7 +7727,7 @@ name = "open_ai" version = "0.1.0" dependencies = [ "anyhow", - "futures 0.3.31", + "futures 0.3.30", "http_client", "schemars", "serde", @@ -8058,9 +7749,9 @@ dependencies = [ [[package]] name = "openssl" -version = "0.10.68" +version = "0.10.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" +checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" dependencies = [ "bitflags 2.6.0", "cfg-if", @@ -8090,18 +7781,18 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-src" -version = "300.4.0+3.4.0" +version = "300.3.1+3.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a709e02f2b4aca747929cca5ed248880847c650233cf8b8cdc48f40aaf4898a6" +checksum = "7259953d42a81bf137fbbd73bd30a8e1914d6dce43c2b90ed575783a22608b91" dependencies = [ "cc", ] [[package]] name = "openssl-sys" -version = "0.9.104" +version = "0.9.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" +checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" dependencies = [ "cc", "libc", @@ -8287,7 +7978,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9981e32fb75e004cc148f5fb70342f393830e0a4aa62e3cc93b50976218d42b6" dependencies = [ - "futures 0.3.31", + "futures 0.3.30", "libc", "log", "rand 0.7.3", @@ -8319,22 +8010,11 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.7", + "redox_syscall 0.5.3", "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 = "password-hash" version = "0.5.0" @@ -8385,55 +8065,6 @@ dependencies = [ "util", ] -[[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 0.12.6", - "prost-types 0.12.6", -] - -[[package]] -name = "pbjson-types" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18f596653ba4ac51bdecbb4ef6773bc7f56042dc13927910de1684ad3d32aa12" -dependencies = [ - "bytes 1.8.0", - "chrono", - "pbjson", - "pbjson-build", - "prost 0.12.6", - "prost-build 0.12.6", - "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 0.4.2", - "sha2", -] - [[package]] name = "pbkdf2" version = "0.12.2" @@ -8479,20 +8110,20 @@ dependencies = [ [[package]] name = "pest" -version = "2.7.14" +version = "2.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442" +checksum = "cd53dff83f26735fdc1ca837098ccf133605d794cdae66acfc2bfac3ec809d95" dependencies = [ "memchr", - "thiserror 1.0.69", + "thiserror", "ucd-trie", ] [[package]] name = "pest_derive" -version = "2.7.14" +version = "2.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d214365f632b123a47fd913301e14c946c61d1c183ee245fa76eb752e59a02dd" +checksum = "2a548d2beca6773b1c244554d36fcf8548a8a58e74156968211567250e48e49a" dependencies = [ "pest", "pest_generator", @@ -8500,9 +8131,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.14" +version = "2.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb55586734301717aea2ac313f50b2eb8f60d2fc3dc01d190eefa2e625f60c4e" +checksum = "3c93a82e8d145725dcbaf44e5ea887c8a869efdcc28706df2d08c69e17077183" dependencies = [ "pest", "pest_meta", @@ -8513,9 +8144,9 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.7.14" +version = "2.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b75da2a70cf4d9cb76833c990ac9cd3923c9a8905a8929789ce347c84564d03d" +checksum = "a941429fea7e08bedec25e4f6785b6ffaacc6b755da98df5ef3e7dcf4a124c4f" dependencies = [ "once_cell", "pest", @@ -8889,7 +8520,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.6.0", + "indexmap 2.4.0", ] [[package]] @@ -8987,18 +8618,18 @@ checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" [[package]] name = "pin-project" -version = "1.1.7" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.7" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", @@ -9007,9 +8638,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.15" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -9024,7 +8655,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" dependencies = [ "atomic-waker", - "fastrand 2.2.0", + "fastrand 2.1.1", "futures-io", ] @@ -9061,9 +8692,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.31" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "plist" @@ -9072,7 +8703,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016" dependencies = [ "base64 0.22.1", - "indexmap 2.6.0", + "indexmap 2.4.0", "quick-xml 0.32.0", "serde", "time", @@ -9080,9 +8711,9 @@ dependencies = [ [[package]] name = "plotters" -version = "0.3.7" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" +checksum = "a15b6eccb8484002195a3e44fe65a4ce8e93a625797a063735536fd59cb01cf3" dependencies = [ "num-traits", "plotters-backend", @@ -9093,30 +8724,30 @@ dependencies = [ [[package]] name = "plotters-backend" -version = "0.3.7" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" +checksum = "414cec62c6634ae900ea1c56128dfe87cf63e7caece0852ec76aba307cebadb7" [[package]] name = "plotters-svg" -version = "0.3.7" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" +checksum = "81b30686a7d9c3e010b84284bdd26a29f2138574f52f5eb6f794fc0ad924e705" dependencies = [ "plotters-backend", ] [[package]] name = "png" -version = "0.17.14" +version = "0.17.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52f9d46a34a05a6a57566bc2bfae066ef07585a6e3fa30fbbdff5936380623f0" +checksum = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1" dependencies = [ "bitflags 1.3.2", "crc32fast", "fdeflate", "flate2", - "miniz_oxide", + "miniz_oxide 0.7.4", ] [[package]] @@ -9137,15 +8768,15 @@ dependencies = [ [[package]] name = "polling" -version = "3.7.4" +version = "3.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" +checksum = "cc2790cd301dec6cd3b7a025e4815cf825724a51c98dccfe6a3e55f05ffb6511" dependencies = [ "cfg-if", "concurrent-queue", "hermit-abi 0.4.0", "pin-project-lite", - "rustix 0.38.40", + "rustix 0.38.35", "tracing", "windows-sys 0.59.0", ] @@ -9164,13 +8795,13 @@ checksum = "af3fb618632874fb76937c2361a7f22afd393c982a2165595407edc75b06d3c1" dependencies = [ "atomic", "crossbeam-queue", - "futures 0.3.31", + "futures 0.3.30", "log", "parking_lot", "pin-project", "pollster", "static_assertions", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -9237,9 +8868,9 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.25" +version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" +checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba" dependencies = [ "proc-macro2", "syn 2.0.87", @@ -9251,7 +8882,7 @@ version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ - "toml_edit 0.22.22", + "toml_edit 0.22.20", ] [[package]] @@ -9278,28 +8909,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "proc-macro-error-attr2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" -dependencies = [ - "proc-macro2", - "quote", -] - -[[package]] -name = "proc-macro-error2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" -dependencies = [ - "proc-macro-error-attr2", - "proc-macro2", - "quote", - "syn 2.0.87", -] - [[package]] name = "proc-macro2" version = "1.0.89" @@ -9341,7 +8950,7 @@ dependencies = [ "env_logger 0.11.5", "fancy-regex 0.14.0", "fs", - "futures 0.3.31", + "futures 0.3.30", "fuzzy", "git", "git2", @@ -9425,7 +9034,7 @@ version = "0.1.0" dependencies = [ "anyhow", "editor", - "futures 0.3.31", + "futures 0.3.30", "fuzzy", "gpui", "language", @@ -9453,7 +9062,7 @@ dependencies = [ "memchr", "parking_lot", "protobuf", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -9462,18 +9071,8 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "444879275cb4fd84958b1a1d5420d15e6fcf7c235fe47f053c9c2a80aceb6001" dependencies = [ - "bytes 1.8.0", - "prost-derive 0.9.0", -] - -[[package]] -name = "prost" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" -dependencies = [ - "bytes 1.8.0", - "prost-derive 0.12.6", + "bytes 1.7.2", + "prost-derive", ] [[package]] @@ -9482,41 +9081,20 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62941722fb675d463659e49c4f3fe1fe792ff24fe5bbaa9c08cd3b98a1c354f5" dependencies = [ - "bytes 1.8.0", + "bytes 1.7.2", "heck 0.3.3", "itertools 0.10.5", "lazy_static", "log", - "multimap 0.8.3", + "multimap", "petgraph", - "prost 0.9.0", - "prost-types 0.9.0", + "prost", + "prost-types", "regex", "tempfile", "which 4.4.2", ] -[[package]] -name = "prost-build" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22505a5c94da8e3b7c2996394d1c933236c4d743e81a410bcca4e6989fc066a4" -dependencies = [ - "bytes 1.8.0", - "heck 0.5.0", - "itertools 0.12.1", - "log", - "multimap 0.10.0", - "once_cell", - "petgraph", - "prettyplease", - "prost 0.12.6", - "prost-types 0.12.6", - "regex", - "syn 2.0.87", - "tempfile", -] - [[package]] name = "prost-derive" version = "0.9.0" @@ -9530,36 +9108,14 @@ dependencies = [ "syn 1.0.109", ] -[[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 2.0.87", -] - [[package]] name = "prost-types" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "534b7a0e836e3c482d2693070f982e39e7611da9695d4d1f5a4b186b51faef0a" dependencies = [ - "bytes 1.8.0", - "prost 0.9.0", -] - -[[package]] -name = "prost-types" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9091c90b0a32608e984ff2fa4091273cbdd755d54935c51d520887f4a1dbd5b0" -dependencies = [ - "prost 0.12.6", + "bytes 1.7.2", + "prost", ] [[package]] @@ -9568,8 +9124,8 @@ version = "0.1.0" dependencies = [ "anyhow", "collections", - "prost 0.9.0", - "prost-build 0.9.0", + "prost", + "prost-build", "serde", ] @@ -9581,9 +9137,9 @@ checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94" [[package]] name = "psm" -version = "0.1.24" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200b9ff220857e53e184257720a14553b2f4aa02577d2ed9842d45d4b9654810" +checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874" dependencies = [ "cc", ] @@ -9663,9 +9219,9 @@ dependencies = [ [[package]] name = "quick-xml" -version = "0.36.2" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7649a7b4df05aed9ea7ec6f628c67c9953a43869b8bc50929569b2999d443fe" +checksum = "6f24d770aeca0eacb81ac29dfbc55ebcc09312fdd1f8bbecdc7e4a84e000e3b4" dependencies = [ "memchr", ] @@ -9690,49 +9246,45 @@ dependencies = [ [[package]] name = "quinn" -version = "0.11.6" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef" +checksum = "8c7c5fdde3cdae7203427dc4f0a68fe0ed09833edc525a03456b153b79828684" dependencies = [ - "bytes 1.8.0", + "bytes 1.7.2", "pin-project-lite", "quinn-proto", "quinn-udp", "rustc-hash 2.0.0", - "rustls 0.23.16", + "rustls 0.23.13", "socket2 0.5.7", - "thiserror 2.0.3", + "thiserror", "tokio", "tracing", ] [[package]] name = "quinn-proto" -version = "0.11.9" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d" +checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6" dependencies = [ - "bytes 1.8.0", - "getrandom 0.2.15", + "bytes 1.7.2", "rand 0.8.5", "ring", "rustc-hash 2.0.0", - "rustls 0.23.16", - "rustls-pki-types", + "rustls 0.23.13", "slab", - "thiserror 2.0.3", + "thiserror", "tinyvec", "tracing", - "web-time", ] [[package]] name = "quinn-udp" -version = "0.5.7" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d5a626c6807713b15cac82a6acaccd6043c9a5408c24baae07611fec3f243da" +checksum = "4fe68c2e9e1a1234e218683dbdf9f9dfcb094113c5ac2b938dfcb9bab4c4140b" dependencies = [ - "cfg_aliases 0.2.1", "libc", "once_cell", "socket2 0.5.7", @@ -9862,23 +9414,22 @@ dependencies = [ "rand_chacha 0.3.1", "simd_helpers", "system-deps", - "thiserror 1.0.69", + "thiserror", "v_frame", "wasm-bindgen", ] [[package]] name = "ravif" -version = "0.11.11" +version = "0.11.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2413fd96bd0ea5cdeeb37eaf446a22e6ed7b981d792828721e74ded1980a45c6" +checksum = "a8f0bfd976333248de2078d350bfdf182ff96e168a24d23d2436cef320dd4bdd" dependencies = [ "avif-serialize", "imgref", "loop9", "quick-error", "rav1e", - "rayon", "rgb", ] @@ -9922,9 +9473,9 @@ dependencies = [ [[package]] name = "read-fonts" -version = "0.22.5" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a04b892cb6f91951f144c33321843790c8574c825aafdb16d815fd7183b5229" +checksum = "8c141b9980e1150201b2a3a32879001c8f975fe313ec3df5471a9b5c79a880cd" dependencies = [ "bytemuck", "font-types", @@ -9938,7 +9489,7 @@ dependencies = [ "auto_update", "editor", "file_finder", - "futures 0.3.31", + "futures 0.3.30", "fuzzy", "gpui", "itertools 0.13.0", @@ -9975,9 +9526,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.7" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" dependencies = [ "bitflags 2.6.0", ] @@ -9990,7 +9550,7 @@ checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom 0.2.15", "libredox", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -10015,14 +9575,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.1" +version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.9", - "regex-syntax 0.8.5", + "regex-automata 0.4.7", + "regex-syntax 0.8.4", ] [[package]] @@ -10036,13 +9596,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.9" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.5", + "regex-syntax 0.8.4", ] [[package]] @@ -10059,9 +9619,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.5" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "release_channel" @@ -10079,13 +9639,13 @@ dependencies = [ "async-trait", "collections", "fs", - "futures 0.3.31", + "futures 0.3.30", "gpui", "itertools 0.13.0", "log", "parking_lot", "paths", - "prost 0.9.0", + "prost", "release_channel", "rpc", "serde", @@ -10093,7 +9653,7 @@ dependencies = [ "shlex", "smol", "tempfile", - "thiserror 1.0.69", + "thiserror", "util", "which 6.0.3", ] @@ -10113,7 +9673,7 @@ dependencies = [ "env_logger 0.11.5", "fork", "fs", - "futures 0.3.31", + "futures 0.3.30", "git", "git_hosting_providers", "gpui", @@ -10167,7 +9727,7 @@ dependencies = [ "editor", "env_logger 0.11.5", "feature_flags", - "futures 0.3.31", + "futures 0.3.30", "gpui", "http_client", "image", @@ -10207,7 +9767,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" dependencies = [ "base64 0.21.7", - "bytes 1.8.0", + "bytes 1.7.2", "encoding_rs", "futures-core", "futures-util", @@ -10215,7 +9775,6 @@ dependencies = [ "http 0.2.12", "http-body 0.4.6", "hyper 0.14.31", - "hyper-rustls 0.24.2", "hyper-tls", "ipnet", "js-sys", @@ -10225,8 +9784,6 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls 0.21.12", - "rustls-native-certs 0.6.3", "rustls-pemfile 1.0.4", "serde", "serde_json", @@ -10235,7 +9792,6 @@ dependencies = [ "system-configuration 0.5.1", "tokio", "tokio-native-tls", - "tokio-rustls 0.24.1", "tower-service", "url", "wasm-bindgen", @@ -10250,7 +9806,7 @@ version = "0.12.8" source = "git+https://github.com/zed-industries/reqwest.git?rev=fd110f6998da16bbca97b6dddda9be7827c50e29#fd110f6998da16bbca97b6dddda9be7827c50e29" dependencies = [ "base64 0.22.1", - "bytes 1.8.0", + "bytes 1.7.2", "encoding_rs", "futures-core", "futures-util", @@ -10258,7 +9814,7 @@ dependencies = [ "http 1.1.0", "http-body 1.0.1", "http-body-util", - "hyper 1.5.0", + "hyper 1.4.1", "hyper-rustls 0.27.3", "hyper-util", "ipnet", @@ -10269,9 +9825,9 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.16", + "rustls 0.23.13", "rustls-native-certs 0.8.0", - "rustls-pemfile 2.2.0", + "rustls-pemfile 2.1.3", "rustls-pki-types", "serde", "serde_json", @@ -10296,8 +9852,8 @@ name = "reqwest_client" version = "0.1.0" dependencies = [ "anyhow", - "bytes 1.8.0", - "futures 0.3.31", + "bytes 1.7.2", + "futures 0.3.30", "gpui", "http_client", "log", @@ -10334,9 +9890,9 @@ dependencies = [ [[package]] name = "rgb" -version = "0.8.50" +version = "0.8.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a" +checksum = "09cd5a1e95672f201913966f39baf355b53b5d92833431847295ae0346a5b939" dependencies = [ "bytemuck", ] @@ -10345,7 +9901,7 @@ dependencies = [ name = "rich_text" version = "0.1.0" dependencies = [ - "futures 0.3.31", + "futures 0.3.30", "gpui", "language", "linkify", @@ -10378,7 +9934,7 @@ checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" dependencies = [ "bitvec", "bytecheck", - "bytes 1.8.0", + "bytes 1.7.2", "hashbrown 0.12.3", "ptr_meta", "rend", @@ -10428,7 +9984,7 @@ checksum = "6006a627c1a38d37f3d3a85c6575418cfe34a5392d60a686d0071e1c8d427acb" dependencies = [ "cpal", "hound", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -10460,12 +10016,12 @@ name = "rpc" version = "0.1.0" dependencies = [ "anyhow", - "async-tungstenite 0.28.0", + "async-tungstenite", "base64 0.22.1", "chrono", "collections", "env_logger 0.11.5", - "futures 0.3.31", + "futures 0.3.30", "gpui", "parking_lot", "proto", @@ -10510,11 +10066,11 @@ dependencies = [ "async-dispatcher", "async-std", "base64 0.22.1", - "bytes 1.8.0", + "bytes 1.7.2", "chrono", "data-encoding", "dirs 5.0.1", - "futures 0.3.31", + "futures 0.3.30", "glob", "jupyter-serde", "rand 0.8.5", @@ -10570,7 +10126,7 @@ checksum = "b082d80e3e3cc52b2ed634388d436fe1f4de6af5786cc2de9ba9737527bdf555" dependencies = [ "arrayvec", "borsh", - "bytes 1.8.0", + "bytes 1.7.2", "num-traits", "rand 0.8.5", "rkyv", @@ -10621,9 +10177,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.40" +version = "0.38.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99e4ea3e1cdc4b559b8e5650f9c8e5998e3e5c1343b4eaf034565f32318d63c0" +checksum = "a85d50532239da68e9addb745ba38ff4612a242c1c7ceea689c4bc7c2f43c36f" dependencies = [ "bitflags 2.6.0", "errno 0.3.9", @@ -10642,7 +10198,7 @@ checksum = "a25c3aad9fc1424eb82c88087789a7d938e1829724f3e4043163baf0d13cfc12" dependencies = [ "errno 0.3.9", "libc", - "rustix 0.38.40", + "rustix 0.38.35", ] [[package]] @@ -10659,9 +10215,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.16" +version = "0.23.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eee87ff5d9b36712a58574e12e9f0ea80f915a5b0ac518d322b24a465617925e" +checksum = "f2dabaac7466917e566adb06783a81ca48944c6898a1b08b9374106dd671f4c8" dependencies = [ "once_cell", "ring", @@ -10690,7 +10246,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcaf18a4f2be7326cd874a5fa579fae794320a0f388d365dca7e480e55f83f8a" dependencies = [ "openssl-probe", - "rustls-pemfile 2.2.0", + "rustls-pemfile 2.1.3", "rustls-pki-types", "schannel", "security-framework", @@ -10707,21 +10263,19 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "2.2.0" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" dependencies = [ + "base64 0.22.1", "rustls-pki-types", ] [[package]] name = "rustls-pki-types" -version = "1.10.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" -dependencies = [ - "web-time", -] +checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" [[package]] name = "rustls-webpki" @@ -10746,9 +10300,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.18" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" [[package]] name = "rustybuzz" @@ -10793,11 +10347,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.26" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -10837,20 +10391,14 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "scratch" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3cf7c11c38cb994f3d40e8a8cde3bbd1f72a435e4c49e85d6553d8312306152" - [[package]] name = "scrypt" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0516a385866c09368f0b5bcd1caff3366aace790fcd46e2bb032697bb172fd1f" dependencies = [ - "password-hash 0.5.0", - "pbkdf2 0.12.2", + "password-hash", + "pbkdf2", "salsa20", "sha2", ] @@ -10867,12 +10415,12 @@ dependencies = [ [[package]] name = "sea-bae" -version = "0.2.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f694a6ab48f14bc063cfadff30ab551d3c7e46d8f81836c51989d548f44a2a25" +checksum = "3bd3534a9978d0aa7edd2808dc1f8f31c4d0ecd31ddf71d997b3c98e9f3c9114" dependencies = [ "heck 0.4.1", - "proc-macro-error2", + "proc-macro-error", "proc-macro2", "quote", "syn 2.0.87", @@ -10888,7 +10436,7 @@ dependencies = [ "async-trait", "bigdecimal", "chrono", - "futures 0.3.31", + "futures 0.3.30", "log", "ouroboros", "rust_decimal", @@ -10899,7 +10447,7 @@ dependencies = [ "serde_json", "sqlx", "strum 0.26.3", - "thiserror 1.0.69", + "thiserror", "time", "tracing", "url", @@ -10908,9 +10456,9 @@ dependencies = [ [[package]] name = "sea-orm-macros" -version = "1.1.1" +version = "1.1.0-rc.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a239e3bb1b566ad4ec2654d0d193d6ceddfd733487edc9c21a64d214c773910" +checksum = "07aadcb2ee9fad78a3bf74f6430ba94865ab4d8ad237f978e99dafa97ee0df57" dependencies = [ "heck 0.4.1", "proc-macro2", @@ -10922,12 +10470,13 @@ dependencies = [ [[package]] name = "sea-query" -version = "0.32.0" +version = "0.32.0-rc.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff504d13b5e4b52fffcf2fb203d0352a5722fa5151696db768933e41e1e591bb" +checksum = "6fba498acd58ce434669f273505cd07737065472eb541c3f813c7f4ce33993f5" dependencies = [ "bigdecimal", "chrono", + "educe", "inherent", "ordered-float 3.9.2", "rust_decimal", @@ -10938,9 +10487,9 @@ dependencies = [ [[package]] name = "sea-query-binder" -version = "0.7.0" +version = "0.7.0-rc.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0019f47430f7995af63deda77e238c17323359af241233ec768aba1faea7608" +checksum = "edc3296903e60ddc7c9f4601cd6ef31a4b1584bf22480587e00b9ef743071b57" dependencies = [ "bigdecimal", "chrono", @@ -10980,7 +10529,7 @@ dependencies = [ "client", "collections", "editor", - "futures 0.3.31", + "futures 0.3.30", "gpui", "language", "menu", @@ -11025,9 +10574,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.12.1" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2" +checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf" dependencies = [ "core-foundation-sys", "libc", @@ -11052,7 +10601,7 @@ dependencies = [ "env_logger 0.11.5", "feature_flags", "fs", - "futures 0.3.31", + "futures 0.3.30", "futures-batch", "gpui", "heed", @@ -11099,18 +10648,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.215" +version = "1.0.209" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" +checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.215" +version = "1.0.209" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170" dependencies = [ "proc-macro2", "quote", @@ -11154,7 +10703,7 @@ version = "1.0.132" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" dependencies = [ - "indexmap 2.6.0", + "indexmap 2.4.0", "itoa", "memchr", "ryu", @@ -11163,13 +10712,12 @@ dependencies = [ [[package]] name = "serde_json_lenient" -version = "0.2.3" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bf0c7e21364d0e199dd2f6c339ca18d6fca75b69458a247e8b27ff1c92f5b86" +checksum = "a5d0bae483150302560d7cb52e7932f39b69a6fbdd099e48d33ef060a8c9c078" dependencies = [ - "indexmap 2.6.0", + "indexmap 2.4.0", "itoa", - "memchr", "ryu", "serde", ] @@ -11192,7 +10740,7 @@ checksum = "c7715380eec75f029a4ef7de39a9200e0a63823176b759d055b613f5a87df6a6" dependencies = [ "percent-encoding", "serde", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -11203,7 +10751,7 @@ checksum = "8cac3f1e2ca2fe333923a1ae72caca910b98ed0630bb35ef6f8c8517d6e81afa" dependencies = [ "percent-encoding", "serde", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -11219,9 +10767,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.8" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" dependencies = [ "serde", ] @@ -11257,7 +10805,7 @@ dependencies = [ "collections", "ec4rs", "fs", - "futures 0.3.31", + "futures 0.3.30", "gpui", "indoc", "log", @@ -11414,9 +10962,9 @@ dependencies = [ [[package]] name = "simdutf8" -version = "0.1.5" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" +checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" [[package]] name = "similar" @@ -11432,7 +10980,7 @@ checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" dependencies = [ "num-bigint", "num-traits", - "thiserror 1.0.69", + "thiserror", "time", ] @@ -11470,9 +11018,9 @@ checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" [[package]] name = "skrifa" -version = "0.22.3" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e1c44ad1f6c5bdd4eefed8326711b7dbda9ea45dfd36068c427d332aa382cbe" +checksum = "abea4738067b1e628c6ce28b2c216c19e9ea95715cdb332680e821c3bec2ef23" dependencies = [ "bytemuck", "read-fonts", @@ -11570,7 +11118,7 @@ dependencies = [ "anyhow", "collections", "fs", - "futures 0.3.31", + "futures 0.3.30", "gpui", "parking_lot", "paths", @@ -11616,9 +11164,9 @@ dependencies = [ [[package]] name = "spdx" -version = "0.10.7" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bae30cc7bfe3656d60ee99bf6836f472b0c53dddcbf335e253329abb16e535a2" +checksum = "47317bbaf63785b53861e1ae2d11b80d6b624211d42cb20efcd210ee6f8a14bc" dependencies = [ "smallvec", ] @@ -11673,7 +11221,7 @@ version = "0.1.0" dependencies = [ "anyhow", "collections", - "futures 0.3.31", + "futures 0.3.30", "indoc", "libsqlite3-sys", "parking_lot", @@ -11725,7 +11273,7 @@ dependencies = [ "atoi", "bigdecimal", "byteorder", - "bytes 1.8.0", + "bytes 1.7.2", "chrono", "crc", "crossbeam-queue", @@ -11739,7 +11287,7 @@ dependencies = [ "hashbrown 0.14.5", "hashlink 0.9.1", "hex", - "indexmap 2.6.0", + "indexmap 2.4.0", "log", "memchr", "once_cell", @@ -11753,7 +11301,7 @@ dependencies = [ "sha2", "smallvec", "sqlformat", - "thiserror 1.0.69", + "thiserror", "time", "tokio", "tokio-stream", @@ -11813,7 +11361,7 @@ dependencies = [ "bigdecimal", "bitflags 2.6.0", "byteorder", - "bytes 1.8.0", + "bytes 1.7.2", "chrono", "crc", "digest", @@ -11842,7 +11390,7 @@ dependencies = [ "smallvec", "sqlx-core", "stringprep", - "thiserror 1.0.69", + "thiserror", "time", "tracing", "uuid", @@ -11886,7 +11434,7 @@ dependencies = [ "smallvec", "sqlx-core", "stringprep", - "thiserror 1.0.69", + "thiserror", "time", "tracing", "uuid", @@ -12076,7 +11624,7 @@ dependencies = [ "collections", "editor", "env_logger 0.11.5", - "futures 0.3.31", + "futures 0.3.30", "gpui", "http_client", "language", @@ -12101,7 +11649,7 @@ name = "supermaven_api" version = "0.1.0" dependencies = [ "anyhow", - "futures 0.3.31", + "futures 0.3.30", "http_client", "paths", "serde", @@ -12111,15 +11659,15 @@ dependencies = [ [[package]] name = "sval" -version = "2.13.2" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6dc0f9830c49db20e73273ffae9b5240f63c42e515af1da1fceefb69fceafd8" +checksum = "53eb957fbc79a55306d5d25d87daf3627bc3800681491cda0709eef36c748bfe" [[package]] name = "sval_buffer" -version = "2.13.2" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "429922f7ad43c0ef8fd7309e14d750e38899e32eb7e8da656ea169dd28ee212f" +checksum = "96e860aef60e9cbf37888d4953a13445abf523c534640d1f6174d310917c410d" dependencies = [ "sval", "sval_ref", @@ -12127,18 +11675,18 @@ dependencies = [ [[package]] name = "sval_dynamic" -version = "2.13.2" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f16ff5d839396c11a30019b659b0976348f3803db0626f736764c473b50ff4" +checksum = "ea3f2b07929a1127d204ed7cb3905049381708245727680e9139dac317ed556f" dependencies = [ "sval", ] [[package]] name = "sval_fmt" -version = "2.13.2" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c01c27a80b6151b0557f9ccbe89c11db571dc5f68113690c1e028d7e974bae94" +checksum = "c4e188677497de274a1367c4bda15bd2296de4070d91729aac8f0a09c1abf64d" dependencies = [ "itoa", "ryu", @@ -12147,9 +11695,9 @@ dependencies = [ [[package]] name = "sval_json" -version = "2.13.2" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0deef63c70da622b2a8069d8600cf4b05396459e665862e7bdb290fd6cf3f155" +checksum = "32f456c07dae652744781f2245d5e3b78e6a9ebad70790ac11eb15dbdbce5282" dependencies = [ "itoa", "ryu", @@ -12158,9 +11706,9 @@ dependencies = [ [[package]] name = "sval_nested" -version = "2.13.2" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a39ce5976ae1feb814c35d290cf7cf8cd4f045782fe1548d6bc32e21f6156e9f" +checksum = "886feb24709f0476baaebbf9ac10671a50163caa7e439d7a7beb7f6d81d0a6fb" dependencies = [ "sval", "sval_buffer", @@ -12169,18 +11717,18 @@ dependencies = [ [[package]] name = "sval_ref" -version = "2.13.2" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb7c6ee3751795a728bc9316a092023529ffea1783499afbc5c66f5fabebb1fa" +checksum = "be2e7fc517d778f44f8cb64140afa36010999565528d48985f55e64d45f369ce" dependencies = [ "sval", ] [[package]] name = "sval_serde" -version = "2.13.2" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a5572d0321b68109a343634e3a5d576bf131b82180c6c442dee06349dfc652a" +checksum = "79bf66549a997ff35cd2114a27ac4b0c2843280f2cfa84b240d169ecaa0add46" dependencies = [ "serde", "sval", @@ -12189,9 +11737,9 @@ dependencies = [ [[package]] name = "svg_fmt" -version = "0.4.4" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce5d813d71d82c4cbc1742135004e4a79fd870214c155443451c139c9470a0aa" +checksum = "20e16a0f46cf5fd675563ef54f26e83e20f2366bcf027bcb3cc3ed2b98aaf2ca" [[package]] name = "svgtypes" @@ -12205,9 +11753,9 @@ dependencies = [ [[package]] name = "swash" -version = "0.1.19" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbd59f3f359ddd2c95af4758c18270eddd9c730dde98598023cdabff472c2ca2" +checksum = "93cdc334a50fcc2aa3f04761af3b28196280a6aaadb1ef11215c478ae32615ac" dependencies = [ "skrifa", "yazi", @@ -12236,6 +11784,18 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn_derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "sync_wrapper" version = "0.1.2" @@ -12260,17 +11820,6 @@ dependencies = [ "crossbeam-queue", ] -[[package]] -name = "synstructure" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - [[package]] name = "sys-locale" version = "0.3.2" @@ -12291,7 +11840,7 @@ dependencies = [ "memchr", "ntapi", "rayon", - "windows 0.57.0", + "windows 0.54.0", ] [[package]] @@ -12360,7 +11909,7 @@ dependencies = [ "cap-std", "fd-lock", "io-lifetimes 2.0.3", - "rustix 0.38.40", + "rustix 0.38.35", "windows-sys 0.52.0", "winx", ] @@ -12425,7 +11974,7 @@ version = "0.1.0" dependencies = [ "anyhow", "collections", - "futures 0.3.31", + "futures 0.3.30", "gpui", "hex", "parking_lot", @@ -12472,14 +12021,14 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.14.0" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" +checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" dependencies = [ "cfg-if", - "fastrand 2.2.0", + "fastrand 2.1.1", "once_cell", - "rustix 0.38.40", + "rustix 0.38.35", "windows-sys 0.59.0", ] @@ -12511,7 +12060,7 @@ dependencies = [ "anyhow", "collections", "dirs 4.0.0", - "futures 0.3.31", + "futures 0.3.30", "gpui", "libc", "rand 0.8.5", @@ -12525,7 +12074,7 @@ dependencies = [ "sysinfo", "task", "theme", - "thiserror 1.0.69", + "thiserror", "util", "windows 0.58.0", ] @@ -12536,7 +12085,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4f599bd7ca042cfdf8f4512b277c02ba102247820f9d9d4a9f521f496751a6ef" dependencies = [ - "rustix 0.38.40", + "rustix 0.38.35", "windows-sys 0.59.0", ] @@ -12550,7 +12099,7 @@ dependencies = [ "db", "dirs 4.0.0", "editor", - "futures 0.3.31", + "futures 0.3.30", "gpui", "itertools 0.13.0", "language", @@ -12602,7 +12151,7 @@ dependencies = [ "collections", "derive_more", "fs", - "futures 0.3.31", + "futures 0.3.30", "gpui", "indexmap 1.9.3", "log", @@ -12666,16 +12215,7 @@ version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl 1.0.69", -] - -[[package]] -name = "thiserror" -version = "2.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa" -dependencies = [ - "thiserror-impl 2.0.3", + "thiserror-impl", ] [[package]] @@ -12689,17 +12229,6 @@ dependencies = [ "syn 2.0.87", ] -[[package]] -name = "thiserror-impl" -version = "2.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - [[package]] name = "thread_local" version = "1.1.8" @@ -12827,16 +12356,6 @@ dependencies = [ "url", ] -[[package]] -name = "tinystr" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" -dependencies = [ - "displaydoc", - "zerovec", -] - [[package]] name = "tinytemplate" version = "1.2.1" @@ -12900,12 +12419,12 @@ dependencies = [ [[package]] name = "tokio" -version = "1.41.1" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" dependencies = [ "backtrace", - "bytes 1.8.0", + "bytes 1.7.2", "libc", "mio 1.0.2", "parking_lot", @@ -12964,7 +12483,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.16", + "rustls 0.23.13", "rustls-pki-types", "tokio", ] @@ -12978,15 +12497,15 @@ dependencies = [ "either", "futures-io", "futures-util", - "thiserror 1.0.69", + "thiserror", "tokio", ] [[package]] name = "tokio-stream" -version = "0.1.16" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" dependencies = [ "futures-core", "pin-project-lite", @@ -13001,10 +12520,7 @@ checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" dependencies = [ "futures-util", "log", - "rustls 0.21.12", - "rustls-native-certs 0.6.3", "tokio", - "tokio-rustls 0.24.1", "tungstenite 0.20.1", ] @@ -13026,7 +12542,7 @@ version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" dependencies = [ - "bytes 1.8.0", + "bytes 1.7.2", "futures-core", "futures-io", "futures-sink", @@ -13064,7 +12580,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.22", + "toml_edit 0.22.20", ] [[package]] @@ -13082,7 +12598,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.6.0", + "indexmap 2.4.0", "serde", "serde_spanned", "toml_datetime", @@ -13091,15 +12607,15 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.22" +version = "0.22.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" dependencies = [ - "indexmap 2.6.0", + "indexmap 2.4.0", "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.20", + "winnow 0.6.18", ] [[package]] @@ -13146,7 +12662,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f873044bf02dd1e8239e9c1293ea39dad76dc594ec16185d0a1bf31d8dc8d858" dependencies = [ "bitflags 1.3.2", - "bytes 1.8.0", + "bytes 1.7.2", "futures-core", "futures-util", "http 0.2.12", @@ -13164,7 +12680,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" dependencies = [ "bitflags 2.6.0", - "bytes 1.8.0", + "bytes 1.7.2", "futures-core", "futures-util", "http 0.2.12", @@ -13265,22 +12781,22 @@ dependencies = [ [[package]] name = "tree-sitter" -version = "0.23.2" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0203df02a3b6dd63575cc1d6e609edc2181c9a11867a271b25cfd2abff3ec5ca" +checksum = "20f4cd3642c47a85052a887d86704f4eac272969f61b686bdd3f772122aabaff" dependencies = [ "cc", "regex", - "regex-syntax 0.8.5", + "regex-syntax 0.8.4", "tree-sitter-language", "wasmtime-c-api-impl", ] [[package]] name = "tree-sitter-bash" -version = "0.23.3" +version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "329a4d48623ac337d42b1df84e81a1c9dbb2946907c102ca72db158c1964a52e" +checksum = "3aa5e1c6bd02c0053f3f68edcf5d8866b38a8640584279e30fca88149ce14dda" dependencies = [ "cc", "tree-sitter-language", @@ -13298,9 +12814,9 @@ dependencies = [ [[package]] name = "tree-sitter-cpp" -version = "0.23.4" +version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df2196ea9d47b4ab4a31b9297eaa5a5d19a0b121dceb9f118f6790ad0ab94743" +checksum = "1d67e862242878d6ee50e1e5814f267ee3eea0168aea2cdbd700ccfb4c74b6d3" dependencies = [ "cc", "tree-sitter-language", @@ -13308,9 +12824,9 @@ dependencies = [ [[package]] name = "tree-sitter-css" -version = "0.23.1" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25435a275adb3226b6fddab891bbc50d1a500774a44ceb97022a39666ccda75d" +checksum = "8d0018d6b1692a806f9cddaa1e5616951fd58840c39a0b21401b55ab3df12292" dependencies = [ "cc", "tree-sitter-language", @@ -13338,9 +12854,9 @@ dependencies = [ [[package]] name = "tree-sitter-embedded-template" -version = "0.23.2" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "790063ef14e5b67556abc0b3be0ed863fb41d65ee791cf8c0b20eb42a1fa46af" +checksum = "9644d7586ebe850c84037ee2f4804dda4a9348eef053be6b1e0d7712342a2495" dependencies = [ "cc", "tree-sitter-language", @@ -13348,9 +12864,9 @@ dependencies = [ [[package]] name = "tree-sitter-go" -version = "0.23.3" +version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc4ee804a89f5c0e606b0b20579c86afc7cd0174aebd45c33b6b9c6237bcd97d" +checksum = "caf57626e4c9b6d6efaf8a8d5ee1241c5f178ae7bfdf693713ae6a774f01424e" dependencies = [ "cc", "tree-sitter-language", @@ -13395,9 +12911,9 @@ dependencies = [ [[package]] name = "tree-sitter-jsdoc" -version = "0.23.2" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3862dfcb1038fc5e7812d7df14190afdeb7e1415288fd5f51f58395f8cb0faf" +checksum = "f8c4049eb0ad690e34e5f63640f75ce12a2ff8ba18344d0a13926805b139c0c8" dependencies = [ "cc", "tree-sitter-language", @@ -13415,9 +12931,9 @@ dependencies = [ [[package]] name = "tree-sitter-language" -version = "0.1.2" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8ddffe35a0e5eeeadf13ff7350af564c6e73993a24db62caee1822b185c2600" +checksum = "2545046bd1473dac6c626659cc2567c6c0ff302fc8b84a56c4243378276f7f57" [[package]] name = "tree-sitter-md" @@ -13430,9 +12946,9 @@ dependencies = [ [[package]] name = "tree-sitter-python" -version = "0.23.4" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2416de7eea3f2e1bd53c250f2d3f3394fc77f78497680f37f4b87918b8d752e3" +checksum = "65661b1a3e24139e2e54207e47d910ab07e28790d78efc7d5dc3a11ce2a110eb" dependencies = [ "cc", "tree-sitter-language", @@ -13450,9 +12966,9 @@ dependencies = [ [[package]] name = "tree-sitter-ruby" -version = "0.23.1" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be0484ea4ef6bb9c575b4fdabde7e31340a8d2dbc7d52b321ac83da703249f95" +checksum = "6ec5ee842e27791e0adffa0b2a177614de51d2a26e5c7e84d014ed7f097e5ed0" dependencies = [ "cc", "tree-sitter-language", @@ -13460,9 +12976,9 @@ dependencies = [ [[package]] name = "tree-sitter-rust" -version = "0.23.1" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "137ff3de3cc8a98302d048963459ead91135d4a1b423f09d25028b847ec3d3e3" +checksum = "cffbbcb780348fbae8395742ae5b34c1fd794e4085d43aac9f259387f9a84dc8" dependencies = [ "cc", "tree-sitter-language", @@ -13470,9 +12986,9 @@ dependencies = [ [[package]] name = "tree-sitter-typescript" -version = "0.23.2" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5f76ed8d947a75cc446d5fccd8b602ebf0cde64ccf2ffa434d873d7a575eff" +checksum = "aecf1585ae2a9dddc2b1d4c0e2140b2ec9876e2a25fd79de47fcf7dae0384685" dependencies = [ "cc", "tree-sitter-language", @@ -13506,15 +13022,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" dependencies = [ "byteorder", - "bytes 1.8.0", + "bytes 1.7.2", "data-encoding", "http 0.2.12", "httparse", "log", "rand 0.8.5", - "rustls 0.21.12", "sha1", - "thiserror 1.0.69", + "thiserror", "url", "utf-8", ] @@ -13526,15 +13041,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" dependencies = [ "byteorder", - "bytes 1.8.0", + "bytes 1.7.2", "data-encoding", "http 1.1.0", "httparse", "log", - "native-tls", "rand 0.8.5", "sha1", - "thiserror 1.0.69", + "thiserror", "url", "utf-8", ] @@ -13546,14 +13060,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a" dependencies = [ "byteorder", - "bytes 1.8.0", + "bytes 1.7.2", "data-encoding", "http 1.1.0", "httparse", "log", "rand 0.8.5", "sha1", - "thiserror 1.0.69", + "thiserror", "utf-8", ] @@ -13571,9 +13085,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "ucd-trie" -version = "0.1.7" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" [[package]] name = "uds_windows" @@ -13627,15 +13141,18 @@ dependencies = [ [[package]] name = "unicase" -version = "2.8.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] [[package]] name = "unicode-bidi" -version = "0.3.17" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-bidi-mirroring" @@ -13651,9 +13168,9 @@ checksum = "1df77b101bcc4ea3d78dafc5ad7e4f58ceffe0b2b16bf446aeb50b6cb4157656" [[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-linebreak" @@ -13663,18 +13180,18 @@ checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" [[package]] name = "unicode-normalization" -version = "0.1.24" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" dependencies = [ "tinyvec", ] [[package]] name = "unicode-properties" -version = "0.1.3" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" +checksum = "52ea75f83c0137a9b98608359a5f1af8144876eb67bcb1ce837368e906a9f524" [[package]] name = "unicode-script" @@ -13684,21 +13201,21 @@ checksum = "9fb421b350c9aff471779e262955939f565ec18b86c15364e6bdf0d662ca7c1f" [[package]] name = "unicode-segmentation" -version = "1.12.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "unicode-width" -version = "0.1.14" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" [[package]] name = "unicode-xid" -version = "0.2.6" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a" [[package]] name = "unicode_categories" @@ -13720,9 +13237,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.3" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d157f1b96d14500ffdc1f10ba712e780825526c03d9a49b4d0324b0d9113ada" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ "form_urlencoded", "idna", @@ -13764,18 +13281,6 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - -[[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" @@ -13790,7 +13295,7 @@ dependencies = [ "async-fs 1.6.0", "collections", "dirs 4.0.0", - "futures 0.3.31", + "futures 0.3.30", "futures-lite 1.13.0", "git2", "globset", @@ -13808,9 +13313,9 @@ dependencies = [ [[package]] name = "uuid" -version = "1.11.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" +checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" dependencies = [ "getrandom 0.2.15", "serde", @@ -13836,9 +13341,9 @@ checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" [[package]] name = "value-bag" -version = "1.10.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ef4c4aa54d5d05a279399bfa921ec387b7aba77caf7a682ae8d86785b8fdad2" +checksum = "5a84c137d37ab0142f0f2ddfe332651fdbf252e7b7dbb4e67b6c1f1b2e925101" dependencies = [ "value-bag-serde1", "value-bag-sval2", @@ -13846,9 +13351,9 @@ dependencies = [ [[package]] name = "value-bag-serde1" -version = "1.10.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bb773bd36fd59c7ca6e336c94454d9c66386416734817927ac93d81cb3c5b0b" +checksum = "ccacf50c5cb077a9abb723c5bcb5e0754c1a433f1e1de89edc328e2760b6328b" dependencies = [ "erased-serde", "serde", @@ -13857,9 +13362,9 @@ dependencies = [ [[package]] name = "value-bag-sval2" -version = "1.10.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53a916a702cac43a88694c97657d449775667bcd14b70419441d05b7fea4a83a" +checksum = "1785bae486022dfb9703915d42287dcb284c1ee37bd1080eeba78cc04721285b" dependencies = [ "sval", "sval_buffer", @@ -13914,7 +13419,7 @@ dependencies = [ "command_palette", "command_palette_hooks", "editor", - "futures 0.3.31", + "futures 0.3.30", "gpui", "indoc", "itertools 0.13.0", @@ -14029,7 +13534,7 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4378d202ff965b011c64817db11d5829506d3404edeadb61f190d111da3f231c" dependencies = [ - "bytes 1.8.0", + "bytes 1.7.2", "futures-channel", "futures-util", "headers", @@ -14071,9 +13576,9 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.95" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" dependencies = [ "cfg-if", "once_cell", @@ -14082,9 +13587,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.95" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" dependencies = [ "bumpalo", "log", @@ -14097,9 +13602,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.45" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" +checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" dependencies = [ "cfg-if", "js-sys", @@ -14109,9 +13614,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.95" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -14119,9 +13624,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.95" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", @@ -14132,9 +13637,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.95" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "wasm-encoder" @@ -14161,7 +13666,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fd83062c17b9f4985d438603cde0a5e8c5c8198201a6937f778b607924c7da2" dependencies = [ "anyhow", - "indexmap 2.6.0", + "indexmap 2.4.0", "serde", "serde_derive", "serde_json", @@ -14172,9 +13677,9 @@ dependencies = [ [[package]] name = "wasm-streams" -version = "0.4.2" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" +checksum = "4e072d4e72f700fb3443d8fe94a39315df013eef1104903cdb0a2abd322bbecd" dependencies = [ "futures-util", "js-sys", @@ -14190,7 +13695,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84e5df6dba6c0d7fafc63a450f1738451ed7a0b52295d83e868218fa286bf708" dependencies = [ "bitflags 2.6.0", - "indexmap 2.6.0", + "indexmap 2.4.0", "semver", ] @@ -14203,7 +13708,7 @@ dependencies = [ "ahash 0.8.11", "bitflags 2.6.0", "hashbrown 0.14.5", - "indexmap 2.6.0", + "indexmap 2.4.0", "semver", "serde", ] @@ -14233,7 +13738,7 @@ dependencies = [ "cfg-if", "encoding_rs", "hashbrown 0.14.5", - "indexmap 2.6.0", + "indexmap 2.4.0", "libc", "libm", "log", @@ -14244,7 +13749,7 @@ dependencies = [ "paste", "postcard", "psm", - "rustix 0.38.40", + "rustix 0.38.35", "semver", "serde", "serde_derive", @@ -14276,9 +13781,9 @@ dependencies = [ [[package]] name = "wasmtime-c-api-impl" -version = "24.0.2" +version = "24.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e038dd412700174019867608617127e7cc4f113f764dd10e7488dbf5f47b191" +checksum = "765e302e7d9125e614aaeec3ad6b6083605393004eca00214106a4ff6b47fc58" dependencies = [ "anyhow", "log", @@ -14290,9 +13795,9 @@ dependencies = [ [[package]] name = "wasmtime-c-api-macros" -version = "24.0.2" +version = "24.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bde0ca2263811d980ab676bcb2a190c990737f58969a908976101ad208149a17" +checksum = "2d09d02eaa84aa2de5babee7b0296557ad6e4903bb10aa8d135e393e753a43d6" dependencies = [ "proc-macro2", "quote", @@ -14337,7 +13842,7 @@ dependencies = [ "log", "object", "target-lexicon", - "thiserror 1.0.69", + "thiserror", "wasmparser 0.215.0", "wasmtime-environ", "wasmtime-versioned-export-macros", @@ -14354,7 +13859,7 @@ dependencies = [ "cranelift-bitset", "cranelift-entity", "gimli 0.29.0", - "indexmap 2.6.0", + "indexmap 2.4.0", "log", "object", "postcard", @@ -14379,7 +13884,7 @@ dependencies = [ "anyhow", "cc", "cfg-if", - "rustix 0.38.40", + "rustix 0.38.35", "wasmtime-asm-macros", "wasmtime-versioned-export-macros", "windows-sys 0.52.0", @@ -14430,27 +13935,27 @@ dependencies = [ [[package]] name = "wasmtime-wasi" -version = "24.0.2" +version = "24.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f88f94e393084426f5055d57ce7ae6346ae623783ee6792f411282d6b9e1e5c3" +checksum = "fda03f5bfd5c4cc09f75c7e44846663f25f2c48a2d688fbfb5c7a33af6cf34f5" dependencies = [ "anyhow", "async-trait", "bitflags 2.6.0", - "bytes 1.8.0", + "bytes 1.7.2", "cap-fs-ext", "cap-net-ext", "cap-rand", "cap-std", "cap-time-ext", "fs-set-times", - "futures 0.3.31", + "futures 0.3.30", "io-extras", "io-lifetimes 2.0.3", "once_cell", - "rustix 0.38.40", + "rustix 0.38.35", "system-interface", - "thiserror 1.0.69", + "thiserror", "tokio", "tracing", "url", @@ -14484,7 +13989,7 @@ checksum = "c58b085b2d330e5057dddd31f3ca527569b90fcdd35f6d373420c304927a5190" dependencies = [ "anyhow", "heck 0.4.1", - "indexmap 2.6.0", + "indexmap 2.4.0", "wit-parser 0.215.0", ] @@ -14499,13 +14004,13 @@ dependencies = [ [[package]] name = "wayland-backend" -version = "0.3.7" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "056535ced7a150d45159d3a8dc30f91a2e2d588ca0b23f70e56033622b8016f6" +checksum = "f90e11ce2ca99c97b940ee83edbae9da2d56a08f9ea8158550fd77fa31722993" dependencies = [ "cc", "downcast-rs", - "rustix 0.38.40", + "rustix 0.38.35", "scoped-tls", "smallvec", "wayland-sys", @@ -14513,23 +14018,23 @@ dependencies = [ [[package]] name = "wayland-client" -version = "0.31.7" +version = "0.31.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b66249d3fc69f76fd74c82cc319300faa554e9d865dab1f7cd66cc20db10b280" +checksum = "7e321577a0a165911bdcfb39cf029302479d7527b517ee58ab0f6ad09edf0943" dependencies = [ "bitflags 2.6.0", - "rustix 0.38.40", + "rustix 0.38.35", "wayland-backend", "wayland-scanner", ] [[package]] name = "wayland-cursor" -version = "0.31.7" +version = "0.31.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b08bc3aafdb0035e7fe0fdf17ba0c09c268732707dca4ae098f60cb28c9e4c" +checksum = "6ef9489a8df197ebf3a8ce8a7a7f0a2320035c3743f3c1bd0bdbccf07ce64f95" dependencies = [ - "rustix 0.38.40", + "rustix 0.38.35", "wayland-client", "xcursor", ] @@ -14561,20 +14066,20 @@ dependencies = [ [[package]] name = "wayland-scanner" -version = "0.31.5" +version = "0.31.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597f2001b2e5fc1121e3d5b9791d3e78f05ba6bfa4641053846248e3a13661c3" +checksum = "d7b56f89937f1cf2ee1f1259cf2936a17a1f45d8f0aa1019fae6d470d304cfa6" dependencies = [ "proc-macro2", - "quick-xml 0.36.2", + "quick-xml 0.34.0", "quote", ] [[package]] name = "wayland-sys" -version = "0.31.5" +version = "0.31.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efa8ac0d8e8ed3e3b5c9fc92c7881406a268e11555abe36493efabe649a29e09" +checksum = "43676fe2daf68754ecf1d72026e4e6c15483198b5d24e888b74d3f22f887a148" dependencies = [ "dlib", "log", @@ -14584,19 +14089,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.72" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "web-time" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" dependencies = [ "js-sys", "wasm-bindgen", @@ -14627,32 +14122,6 @@ version = "0.25.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" -[[package]] -name = "webrtc-sys" -version = "0.3.5" -source = "git+https://github.com/zed-industries/rust-sdks?rev=4262308983646ab5b0e0802c3d8bc52154f99aab#4262308983646ab5b0e0802c3d8bc52154f99aab" -dependencies = [ - "cc", - "cxx", - "cxx-build", - "glob", - "log", - "webrtc-sys-build", -] - -[[package]] -name = "webrtc-sys-build" -version = "0.3.5" -source = "git+https://github.com/zed-industries/rust-sdks?rev=4262308983646ab5b0e0802c3d8bc52154f99aab#4262308983646ab5b0e0802c3d8bc52154f99aab" -dependencies = [ - "fs2", - "regex", - "reqwest 0.11.27", - "scratch", - "semver", - "zip", -] - [[package]] name = "weezl" version = "0.1.8" @@ -14694,7 +14163,7 @@ dependencies = [ "either", "home", "once_cell", - "rustix 0.38.40", + "rustix 0.38.35", ] [[package]] @@ -14705,30 +14174,30 @@ checksum = "b4ee928febd44d98f2f459a4a79bd4d928591333a494a10a868418ac1b39cf1f" dependencies = [ "either", "home", - "rustix 0.38.40", + "rustix 0.38.35", "winsafe", ] [[package]] name = "whoami" -version = "1.5.2" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "372d5b87f58ec45c384ba03563b03544dc5fadc3983e434b286913f5b4a9bb6d" +checksum = "a44ab49fad634e88f55bf8f9bb3abd2f27d7204172a112c7c9987e01c1c94ea9" dependencies = [ - "redox_syscall 0.5.7", + "redox_syscall 0.4.1", "wasite", ] [[package]] name = "wiggle" -version = "24.0.2" +version = "24.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c72a4c92952216582f55eab27819a1fe8d3c54b292b7b8e5f849b23bfed96e78" +checksum = "2d3b31bd2b4d2d82a4b747b8dbc45f566214214a4ffdc5690429a73bc221dc8a" dependencies = [ "anyhow", "async-trait", "bitflags 2.6.0", - "thiserror 1.0.69", + "thiserror", "tracing", "wasmtime", "wiggle-macro", @@ -14736,9 +14205,9 @@ dependencies = [ [[package]] name = "wiggle-generate" -version = "24.0.2" +version = "24.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb744fb938a9fc38207838829b4a43831c1de499e3526eaea71deeff4d9cbb83" +checksum = "e2c6136b195fc12067aa9d4e7a5baf118729394df7bc7cbf8c63119bc9f2a7cd" dependencies = [ "anyhow", "heck 0.4.1", @@ -14751,9 +14220,9 @@ dependencies = [ [[package]] name = "wiggle-macro" -version = "24.0.2" +version = "24.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cef395fff17bf8f9c1dee6c0e12801a3ba24928139af0ecb5ccb82ff87bf9d2" +checksum = "8a41eaceee468da976ac43b85c4eb82e482f828d5e8e56f49f90dfac2d9bc3b4" dependencies = [ "proc-macro2", "quote", @@ -14819,16 +14288,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143" -dependencies = [ - "windows-core 0.57.0", - "windows-targets 0.52.6", -] - [[package]] name = "windows" version = "0.58.0" @@ -14858,42 +14317,19 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-core" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" -dependencies = [ - "windows-implement 0.57.0", - "windows-interface 0.57.0", - "windows-result 0.1.2", - "windows-targets 0.52.6", -] - [[package]] name = "windows-core" version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" dependencies = [ - "windows-implement 0.58.0", - "windows-interface 0.58.0", + "windows-implement", + "windows-interface", "windows-result 0.2.0", "windows-strings", "windows-targets 0.52.6", ] -[[package]] -name = "windows-implement" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - [[package]] name = "windows-implement" version = "0.58.0" @@ -14905,17 +14341,6 @@ dependencies = [ "syn 2.0.87", ] -[[package]] -name = "windows-interface" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - [[package]] name = "windows-interface" version = "0.58.0" @@ -15191,9 +14616,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.20" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" dependencies = [ "memchr", ] @@ -15288,7 +14713,7 @@ checksum = "d8a39a15d1ae2077688213611209849cad40e9e5cccf6e61951a425850677ff3" dependencies = [ "anyhow", "heck 0.4.1", - "indexmap 2.6.0", + "indexmap 2.4.0", "wasm-metadata", "wit-bindgen-core", "wit-component", @@ -15316,7 +14741,7 @@ checksum = "421c0c848a0660a8c22e2fd217929a0191f14476b68962afd2af89fd22e39825" dependencies = [ "anyhow", "bitflags 2.6.0", - "indexmap 2.6.0", + "indexmap 2.4.0", "log", "serde", "serde_derive", @@ -15335,7 +14760,7 @@ checksum = "196d3ecfc4b759a8573bf86a9b3f8996b304b3732e4c7de81655f875f6efdca6" dependencies = [ "anyhow", "id-arena", - "indexmap 2.6.0", + "indexmap 2.4.0", "log", "semver", "serde", @@ -15353,7 +14778,7 @@ checksum = "935a97eaffd57c3b413aa510f8f0b550a4a9fe7d59e79cd8b89a83dcb860321f" dependencies = [ "anyhow", "id-arena", - "indexmap 2.6.0", + "indexmap 2.4.0", "log", "semver", "serde", @@ -15371,7 +14796,7 @@ checksum = "e366f27a5cabcddb2706a78296a40b8fcc451e1a6aba2fc1d94b4a01bdaaef4b" dependencies = [ "anyhow", "log", - "thiserror 1.0.69", + "thiserror", "wast", ] @@ -15391,7 +14816,7 @@ dependencies = [ "derive_more", "env_logger 0.11.5", "fs", - "futures 0.3.31", + "futures 0.3.30", "git", "gpui", "http_client", @@ -15428,7 +14853,7 @@ dependencies = [ "collections", "env_logger 0.11.5", "fs", - "futures 0.3.31", + "futures 0.3.30", "fuzzy", "git", "git2", @@ -15455,18 +14880,6 @@ dependencies = [ "util", ] -[[package]] -name = "write16" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" - -[[package]] -name = "writeable" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" - [[package]] name = "wyz" version = "0.5.1" @@ -15478,9 +14891,9 @@ dependencies = [ [[package]] name = "x11-clipboard" -version = "0.9.3" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "662d74b3d77e396b8e5beb00b9cad6a9eccf40b2ef68cc858784b14c41d535a3" +checksum = "b98785a09322d7446e28a13203d2cae1059a0dd3dfb32cb06d0a225f023d8286" dependencies = [ "libc", "x11rb", @@ -15495,7 +14908,7 @@ dependencies = [ "as-raw-xcb-connection", "gethostname", "libc", - "rustix 0.38.40", + "rustix 0.38.35", "x11rb-protocol", ] @@ -15643,30 +15056,6 @@ dependencies = [ "pkg-config", ] -[[package]] -name = "yoke" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" -dependencies = [ - "serde", - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", - "synstructure", -] - [[package]] name = "zbus" version = "4.4.0" @@ -15676,9 +15065,9 @@ dependencies = [ "async-broadcast", "async-executor", "async-fs 2.1.2", - "async-io 2.4.0", + "async-io 2.3.4", "async-lock 3.4.0", - "async-process 2.3.0", + "async-process 2.2.4", "async-recursion 1.1.1", "async-task", "async-trait", @@ -15767,7 +15156,7 @@ dependencies = [ "file_finder", "file_icons", "fs", - "futures 0.3.31", + "futures 0.3.30", "git", "git_hosting_providers", "go_to_line", @@ -16069,27 +15458,6 @@ dependencies = [ "syn 2.0.87", ] -[[package]] -name = "zerofrom" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", - "synstructure", -] - [[package]] name = "zeroize" version = "1.8.1" @@ -16112,15 +15480,15 @@ dependencies = [ [[package]] name = "zeromq" -version = "0.4.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a4528179201f6eecf211961a7d3276faa61554c82651ecc66387f68fc3004bd" +checksum = "fb0560d00172817b7f7c2265060783519c475702ae290b154115ca75e976d4d0" dependencies = [ "async-dispatcher", "async-std", "async-trait", "asynchronous-codec", - "bytes 1.8.0", + "bytes 1.7.2", "crossbeam-queue", "dashmap 5.5.3", "futures-channel", @@ -16133,52 +15501,10 @@ dependencies = [ "parking_lot", "rand 0.8.5", "regex", - "thiserror 1.0.69", + "thiserror", "uuid", ] -[[package]] -name = "zerovec" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[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 0.1.5", - "crc32fast", - "crossbeam-utils", - "flate2", - "hmac", - "pbkdf2 0.11.0", - "sha1", - "time", - "zstd", -] - [[package]] name = "zstd" version = "0.11.2+zstd.1.5.2" diff --git a/Cargo.toml b/Cargo.toml index 9d86bc1b20..c6d182fd58 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -363,7 +363,6 @@ heed = { version = "0.20.1", features = ["read-txn-no-tls"] } hex = "0.4.3" html5ever = "0.27.0" hyper = "0.14" -http = "1.1" ignore = "0.4.22" image = "0.25.1" indexmap = { version = "1.6.2", features = ["serde"] } @@ -372,7 +371,6 @@ itertools = "0.13.0" jsonwebtoken = "9.3" libc = "0.2" linkify = "0.10.0" -livekit = { git = "https://github.com/zed-industries/rust-sdks", rev="4262308983646ab5b0e0802c3d8bc52154f99aab", features = ["dispatcher", "services-dispatcher", "rustls-tls-native-roots"], default-features = false } log = { version = "0.4.16", features = ["kv_unstable_serde", "serde"] } markup5ever_rcdom = "0.3.0" nanoid = "0.4" @@ -551,10 +549,6 @@ features = [ "Win32_UI_WindowsAndMessaging", ] -# TODO livekit https://github.com/RustAudio/cpal/pull/891 -[patch.crates-io] -cpal = { git = "https://github.com/zed-industries/cpal", rev = "fd8bc2fd39f1f5fdee5a0690656caff9a26d9d50" } - [profile.dev] split-debuginfo = "unpacked" debug = "limited" diff --git a/crates/call/Cargo.toml b/crates/call/Cargo.toml index 3ac55078e7..974c860c08 100644 --- a/crates/call/Cargo.toml +++ b/crates/call/Cargo.toml @@ -27,7 +27,6 @@ anyhow.workspace = true audio.workspace = true client.workspace = true collections.workspace = true -feature_flags.workspace = true fs.workspace = true futures.workspace = true gpui.workspace = true diff --git a/crates/call/src/call.rs b/crates/call/src/call.rs index eb91ff0885..c7993f3658 100644 --- a/crates/call/src/call.rs +++ b/crates/call/src/call.rs @@ -18,11 +18,6 @@ use room::Event; use settings::Settings; use std::sync::Arc; -#[cfg(not(target_os = "windows"))] -pub use live_kit_client::play_remote_video_track; -pub use live_kit_client::{ - track::RemoteVideoTrack, RemoteVideoTrackView, RemoteVideoTrackViewEvent, -}; pub use participant::ParticipantLocation; pub use room::Room; @@ -31,10 +26,6 @@ struct GlobalActiveCall(Model); impl Global for GlobalActiveCall {} pub fn init(client: Arc, user_store: Model, cx: &mut AppContext) { - live_kit_client::init( - cx.background_executor().dispatcher.clone(), - cx.http_client(), - ); CallSettings::register(cx); let active_call = cx.new_model(|cx| ActiveCall::new(client, user_store, cx)); diff --git a/crates/call/src/participant.rs b/crates/call/src/participant.rs index 67bb95a3b7..9faefc63c3 100644 --- a/crates/call/src/participant.rs +++ b/crates/call/src/participant.rs @@ -1,17 +1,13 @@ -#![cfg_attr(target_os = "windows", allow(unused))] - use anyhow::{anyhow, Result}; -use client::{proto, ParticipantIndex, User}; +use client::ParticipantIndex; +use client::{proto, User}; use collections::HashMap; use gpui::WeakModel; -use live_kit_client::AudioStream; +pub use live_kit_client::Frame; +pub use live_kit_client::{RemoteAudioTrack, RemoteVideoTrack}; use project::Project; use std::sync::Arc; -#[cfg(not(target_os = "windows"))] -pub use live_kit_client::id::TrackSid; -pub use live_kit_client::track::{RemoteAudioTrack, RemoteVideoTrack}; - #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum ParticipantLocation { SharedProject { project_id: u64 }, @@ -43,6 +39,7 @@ pub struct LocalParticipant { pub role: proto::ChannelRole, } +#[derive(Clone, Debug)] pub struct RemoteParticipant { pub user: Arc, pub peer_id: proto::PeerId, @@ -52,17 +49,6 @@ pub struct RemoteParticipant { pub participant_index: ParticipantIndex, pub muted: bool, pub speaking: bool, - #[cfg(not(target_os = "windows"))] - pub video_tracks: HashMap, - #[cfg(not(target_os = "windows"))] - pub audio_tracks: HashMap, -} - -impl RemoteParticipant { - pub fn has_video_tracks(&self) -> bool { - #[cfg(not(target_os = "windows"))] - return !self.video_tracks.is_empty(); - #[cfg(target_os = "windows")] - return false; - } + pub video_tracks: HashMap>, + pub audio_tracks: HashMap>, } diff --git a/crates/call/src/room.rs b/crates/call/src/room.rs index a0e9de201a..3eb98f3109 100644 --- a/crates/call/src/room.rs +++ b/crates/call/src/room.rs @@ -1,5 +1,3 @@ -#![cfg_attr(target_os = "windows", allow(unused))] - use crate::{ call_settings::CallSettings, participant::{LocalParticipant, ParticipantLocation, RemoteParticipant}, @@ -17,23 +15,11 @@ use gpui::{ AppContext, AsyncAppContext, Context, EventEmitter, Model, ModelContext, Task, WeakModel, }; use language::LanguageRegistry; -use live_kit_client as livekit; -#[cfg(not(target_os = "windows"))] -use livekit::{ - capture_local_audio_track, capture_local_video_track, - id::ParticipantIdentity, - options::{TrackPublishOptions, VideoCodec}, - play_remote_audio_track, - publication::LocalTrackPublication, - track::{TrackKind, TrackSource}, - RoomEvent, RoomOptions, -}; -#[cfg(target_os = "windows")] -use livekit::{publication::LocalTrackPublication, RoomEvent}; +use live_kit_client::{LocalAudioTrack, LocalTrackPublication, LocalVideoTrack, RoomUpdate}; use postage::{sink::Sink, stream::Stream, watch}; use project::Project; use settings::Settings as _; -use std::{any::Any, future::Future, mem, sync::Arc, time::Duration}; +use std::{future::Future, mem, sync::Arc, time::Duration}; use util::{post_inc, ResultExt, TryFutureExt}; pub const RECONNECT_TIMEOUT: Duration = Duration::from_secs(30); @@ -106,10 +92,13 @@ impl Room { !self.shared_projects.is_empty() } - #[cfg(all(any(test, feature = "test-support"), not(target_os = "windows")))] + #[cfg(any(test, feature = "test-support"))] pub fn is_connected(&self) -> bool { if let Some(live_kit) = self.live_kit.as_ref() { - live_kit.room.connection_state() == livekit::ConnectionState::Connected + matches!( + *live_kit.room.status().borrow(), + live_kit_client::ConnectionState::Connected { .. } + ) } else { false } @@ -123,7 +112,77 @@ impl Room { user_store: Model, cx: &mut ModelContext, ) -> Self { - spawn_room_connection(live_kit_connection_info, cx); + let live_kit_room = if let Some(connection_info) = live_kit_connection_info { + let room = live_kit_client::Room::new(); + let mut status = room.status(); + // Consume the initial status of the room. + let _ = status.try_recv(); + let _maintain_room = cx.spawn(|this, mut cx| async move { + while let Some(status) = status.next().await { + let this = if let Some(this) = this.upgrade() { + this + } else { + break; + }; + + if status == live_kit_client::ConnectionState::Disconnected { + this.update(&mut cx, |this, cx| this.leave(cx).log_err()) + .ok(); + break; + } + } + }); + + let _handle_updates = cx.spawn({ + let room = room.clone(); + move |this, mut cx| async move { + let mut updates = room.updates(); + while let Some(update) = updates.next().await { + let this = if let Some(this) = this.upgrade() { + this + } else { + break; + }; + + this.update(&mut cx, |this, cx| { + this.live_kit_room_updated(update, cx).log_err() + }) + .ok(); + } + } + }); + + let connect = room.connect(&connection_info.server_url, &connection_info.token); + cx.spawn(|this, mut cx| async move { + connect.await?; + this.update(&mut cx, |this, cx| { + if this.can_use_microphone() { + if let Some(live_kit) = &this.live_kit { + if !live_kit.muted_by_user && !live_kit.deafened { + return this.share_microphone(cx); + } + } + } + Task::ready(Ok(())) + })? + .await + }) + .detach_and_log_err(cx); + + Some(LiveKitRoom { + room, + screen_track: LocalTrack::None, + microphone_track: LocalTrack::None, + next_publish_id: 0, + muted_by_user: Self::mute_on_join(cx), + deafened: false, + speaking: false, + _maintain_room, + _handle_updates, + }) + } else { + None + }; let maintain_connection = cx.spawn({ let client = client.clone(); @@ -137,7 +196,7 @@ impl Room { Self { id, channel_id, - live_kit: None, + live_kit: live_kit_room, status: RoomStatus::Online, shared_projects: Default::default(), joined_projects: Default::default(), @@ -647,45 +706,11 @@ impl Room { this.update(&mut cx, |this, cx| this.apply_room_update(room, cx))? } - fn apply_room_update(&mut self, room: proto::Room, cx: &mut ModelContext) -> Result<()> { - log::trace!( - "client {:?}. room update: {:?}", - self.client.user_id(), - &room - ); - - self.pending_room_update = Some(self.start_room_connection(room, cx)); - - cx.notify(); - Ok(()) - } - - pub fn room_update_completed(&mut self) -> impl Future { - let mut done_rx = self.room_update_completed_rx.clone(); - async move { - while let Some(result) = done_rx.next().await { - if result.is_some() { - break; - } - } - } - } - - #[cfg(target_os = "windows")] - fn start_room_connection( - &self, + fn apply_room_update( + &mut self, mut room: proto::Room, cx: &mut ModelContext, - ) -> Task<()> { - Task::ready(()) - } - - #[cfg(not(target_os = "windows"))] - fn start_room_connection( - &self, - mut room: proto::Room, - cx: &mut ModelContext, - ) -> Task<()> { + ) -> Result<()> { // Filter ourselves out from the room's participants. let local_participant_ix = room .participants @@ -712,7 +737,8 @@ impl Room { user_store.get_users(pending_participant_user_ids, cx), ) }); - cx.spawn(|this, mut cx| async move { + + self.pending_room_update = Some(cx.spawn(|this, mut cx| async move { let (remote_participants, pending_participants) = futures::join!(remote_participants, pending_participants); @@ -750,11 +776,6 @@ impl Room { this.local_participant.projects.clear(); } - let livekit_participants = this - .live_kit - .as_ref() - .map(|live_kit| live_kit.room.remote_participants()); - if let Some(participants) = remote_participants.log_err() { for (participant, user) in room.participants.into_iter().zip(participants) { let Some(peer_id) = participant.peer_id else { @@ -837,31 +858,40 @@ impl Room { muted: true, speaking: false, video_tracks: Default::default(), - #[cfg(not(target_os = "windows"))] audio_tracks: Default::default(), }, ); Audio::play_sound(Sound::Joined, cx); - if let Some(livekit_participants) = &livekit_participants { - if let Some(livekit_participant) = livekit_participants - .get(&ParticipantIdentity(user.id.to_string())) + + if let Some(live_kit) = this.live_kit.as_ref() { + let video_tracks = + live_kit.room.remote_video_tracks(&user.id.to_string()); + let audio_tracks = + live_kit.room.remote_audio_tracks(&user.id.to_string()); + let publications = live_kit + .room + .remote_audio_track_publications(&user.id.to_string()); + + for track in video_tracks { + this.live_kit_room_updated( + RoomUpdate::SubscribedToRemoteVideoTrack(track), + cx, + ) + .log_err(); + } + + for (track, publication) in + audio_tracks.iter().zip(publications.iter()) { - for publication in - livekit_participant.track_publications().into_values() - { - if let Some(track) = publication.track() { - this.live_kit_room_updated( - RoomEvent::TrackSubscribed { - track, - publication, - participant: livekit_participant.clone(), - }, - cx, - ) - .warn_on_err(); - } - } + this.live_kit_room_updated( + RoomUpdate::SubscribedToRemoteAudioTrack( + track.clone(), + publication.clone(), + ), + cx, + ) + .log_err(); } } } @@ -929,89 +959,61 @@ impl Room { cx.notify(); }) .ok(); - }) + })); + + cx.notify(); + Ok(()) + } + + pub fn room_update_completed(&mut self) -> impl Future { + let mut done_rx = self.room_update_completed_rx.clone(); + async move { + while let Some(result) = done_rx.next().await { + if result.is_some() { + break; + } + } + } } fn live_kit_room_updated( &mut self, - event: RoomEvent, + update: RoomUpdate, cx: &mut ModelContext, ) -> Result<()> { - log::trace!( - "client {:?}. livekit event: {:?}", - self.client.user_id(), - &event - ); - - match event { - #[cfg(not(target_os = "windows"))] - RoomEvent::TrackSubscribed { - track, - participant, - publication, - } => { - let user_id = participant.identity().0.parse()?; - let track_id = track.sid(); - let participant = self.remote_participants.get_mut(&user_id).ok_or_else(|| { - anyhow!( - "{:?} subscribed to track by unknown participant {user_id}", - self.client.user_id() - ) - })?; - if self.live_kit.as_ref().map_or(true, |kit| kit.deafened) { - track.rtc_track().set_enabled(false); - } - match track { - livekit::track::RemoteTrack::Audio(track) => { - cx.emit(Event::RemoteAudioTracksChanged { - participant_id: participant.peer_id, - }); - let stream = play_remote_audio_track(&track, cx); - participant.audio_tracks.insert(track_id, (track, stream)); - participant.muted = publication.is_muted(); - } - livekit::track::RemoteTrack::Video(track) => { - cx.emit(Event::RemoteVideoTracksChanged { - participant_id: participant.peer_id, - }); - participant.video_tracks.insert(track_id, track); - } - } + match update { + RoomUpdate::SubscribedToRemoteVideoTrack(track) => { + let user_id = track.publisher_id().parse()?; + let track_id = track.sid().to_string(); + let participant = self + .remote_participants + .get_mut(&user_id) + .ok_or_else(|| anyhow!("subscribed to track by unknown participant"))?; + participant.video_tracks.insert(track_id.clone(), track); + cx.emit(Event::RemoteVideoTracksChanged { + participant_id: participant.peer_id, + }); } - #[cfg(not(target_os = "windows"))] - RoomEvent::TrackUnsubscribed { - track, participant, .. + RoomUpdate::UnsubscribedFromRemoteVideoTrack { + publisher_id, + track_id, } => { - let user_id = participant.identity().0.parse()?; - let participant = self.remote_participants.get_mut(&user_id).ok_or_else(|| { - anyhow!( - "{:?}, unsubscribed from track by unknown participant {user_id}", - self.client.user_id() - ) - })?; - match track { - livekit::track::RemoteTrack::Audio(track) => { - participant.audio_tracks.remove(&track.sid()); - participant.muted = true; - cx.emit(Event::RemoteAudioTracksChanged { - participant_id: participant.peer_id, - }); - } - livekit::track::RemoteTrack::Video(track) => { - participant.video_tracks.remove(&track.sid()); - cx.emit(Event::RemoteVideoTracksChanged { - participant_id: participant.peer_id, - }); - } - } + let user_id = publisher_id.parse()?; + let participant = self + .remote_participants + .get_mut(&user_id) + .ok_or_else(|| anyhow!("unsubscribed from track by unknown participant"))?; + participant.video_tracks.remove(&track_id); + cx.emit(Event::RemoteVideoTracksChanged { + participant_id: participant.peer_id, + }); } - #[cfg(not(target_os = "windows"))] - RoomEvent::ActiveSpeakersChanged { speakers } => { + RoomUpdate::ActiveSpeakersChanged { speakers } => { let mut speaker_ids = speakers .into_iter() - .filter_map(|speaker| speaker.identity().0.parse().ok()) + .filter_map(|speaker_sid| speaker_sid.parse().ok()) .collect::>(); speaker_ids.sort_unstable(); for (sid, participant) in &mut self.remote_participants { @@ -1024,65 +1026,82 @@ impl Room { } } - #[cfg(not(target_os = "windows"))] - RoomEvent::TrackMuted { - participant, - publication, - } - | RoomEvent::TrackUnmuted { - participant, - publication, - } => { + RoomUpdate::RemoteAudioTrackMuteChanged { track_id, muted } => { let mut found = false; - let user_id = participant.identity().0.parse()?; - let track_id = publication.sid(); - if let Some(participant) = self.remote_participants.get_mut(&user_id) { - for (track, _) in participant.audio_tracks.values() { + for participant in &mut self.remote_participants.values_mut() { + for track in participant.audio_tracks.values() { if track.sid() == track_id { found = true; break; } } if found { - participant.muted = publication.is_muted(); + participant.muted = muted; + break; } } } - #[cfg(not(target_os = "windows"))] - RoomEvent::LocalTrackUnpublished { publication, .. } => { - log::info!("unpublished track {}", publication.sid()); + RoomUpdate::SubscribedToRemoteAudioTrack(track, publication) => { + if let Some(live_kit) = &self.live_kit { + if live_kit.deafened { + track.stop(); + cx.foreground_executor() + .spawn(publication.set_enabled(false)) + .detach(); + } + } + + let user_id = track.publisher_id().parse()?; + let track_id = track.sid().to_string(); + let participant = self + .remote_participants + .get_mut(&user_id) + .ok_or_else(|| anyhow!("subscribed to track by unknown participant"))?; + participant.audio_tracks.insert(track_id.clone(), track); + participant.muted = publication.is_muted(); + + cx.emit(Event::RemoteAudioTracksChanged { + participant_id: participant.peer_id, + }); + } + + RoomUpdate::UnsubscribedFromRemoteAudioTrack { + publisher_id, + track_id, + } => { + let user_id = publisher_id.parse()?; + let participant = self + .remote_participants + .get_mut(&user_id) + .ok_or_else(|| anyhow!("unsubscribed from track by unknown participant"))?; + participant.audio_tracks.remove(&track_id); + cx.emit(Event::RemoteAudioTracksChanged { + participant_id: participant.peer_id, + }); + } + + RoomUpdate::LocalAudioTrackUnpublished { publication } => { + log::info!("unpublished audio track {}", publication.sid()); if let Some(room) = &mut self.live_kit { - if let LocalTrack::Published { - track_publication, .. - } = &room.microphone_track - { - if track_publication.sid() == publication.sid() { - room.microphone_track = LocalTrack::None; - } - } - if let LocalTrack::Published { - track_publication, .. - } = &room.screen_track - { - if track_publication.sid() == publication.sid() { - room.screen_track = LocalTrack::None; - } - } + room.microphone_track = LocalTrack::None; } } - #[cfg(not(target_os = "windows"))] - RoomEvent::LocalTrackPublished { publication, .. } => { - log::info!("published track {:?}", publication.sid()); + RoomUpdate::LocalVideoTrackUnpublished { publication } => { + log::info!("unpublished video track {}", publication.sid()); + if let Some(room) = &mut self.live_kit { + room.screen_track = LocalTrack::None; + } } - #[cfg(not(target_os = "windows"))] - RoomEvent::Disconnected { reason } => { - log::info!("disconnected from room: {reason:?}"); - self.leave(cx).detach_and_log_err(cx); + RoomUpdate::LocalAudioTrackPublished { publication } => { + log::info!("published audio track {}", publication.sid()); + } + + RoomUpdate::LocalVideoTrackPublished { publication } => { + log::info!("published video track {}", publication.sid()); } - _ => {} } cx.notify(); @@ -1298,17 +1317,8 @@ impl Room { self.live_kit.as_ref().map(|live_kit| live_kit.deafened) } - pub fn can_use_microphone(&self, _cx: &AppContext) -> bool { + pub fn can_use_microphone(&self) -> bool { use proto::ChannelRole::*; - - #[cfg(not(any(test, feature = "test-support")))] - { - use feature_flags::FeatureFlagAppExt as _; - if cfg!(target_os = "windows") || (cfg!(target_os = "linux") && !_cx.is_staff()) { - return false; - } - } - match self.local_participant.role { Admin | Member | Talker => true, Guest | Banned => false, @@ -1323,177 +1333,161 @@ impl Room { } } - #[cfg(target_os = "windows")] - pub fn share_microphone(&mut self, cx: &mut ModelContext) -> Task> { - Task::ready(Err(anyhow!("Windows is not supported yet"))) - } - - #[cfg(not(target_os = "windows"))] #[track_caller] pub fn share_microphone(&mut self, cx: &mut ModelContext) -> Task> { if self.status.is_offline() { return Task::ready(Err(anyhow!("room is offline"))); } - let (participant, publish_id) = if let Some(live_kit) = self.live_kit.as_mut() { + let publish_id = if let Some(live_kit) = self.live_kit.as_mut() { let publish_id = post_inc(&mut live_kit.next_publish_id); live_kit.microphone_track = LocalTrack::Pending { publish_id }; cx.notify(); - (live_kit.room.local_participant(), publish_id) + publish_id } else { return Task::ready(Err(anyhow!("live-kit was not initialized"))); }; cx.spawn(move |this, mut cx| async move { - let (track, stream) = cx.update(capture_local_audio_track)??; + let publish_track = async { + let track = LocalAudioTrack::create(); + this.upgrade() + .ok_or_else(|| anyhow!("room was dropped"))? + .update(&mut cx, |this, _| { + this.live_kit + .as_ref() + .map(|live_kit| live_kit.room.publish_audio_track(track)) + })? + .ok_or_else(|| anyhow!("live-kit was not initialized"))? + .await + }; + let publication = publish_track.await; + this.upgrade() + .ok_or_else(|| anyhow!("room was dropped"))? + .update(&mut cx, |this, cx| { + let live_kit = this + .live_kit + .as_mut() + .ok_or_else(|| anyhow!("live-kit was not initialized"))?; - let publication = participant - .publish_track( - livekit::track::LocalTrack::Audio(track), - TrackPublishOptions { - source: TrackSource::Microphone, - ..Default::default() - }, - ) - .await - .map_err(|error| anyhow!("failed to publish track: {error}")); - this.update(&mut cx, |this, cx| { - let live_kit = this - .live_kit - .as_mut() - .ok_or_else(|| anyhow!("live-kit was not initialized"))?; + let canceled = if let LocalTrack::Pending { + publish_id: cur_publish_id, + } = &live_kit.microphone_track + { + *cur_publish_id != publish_id + } else { + true + }; - let canceled = if let LocalTrack::Pending { - publish_id: cur_publish_id, - } = &live_kit.microphone_track - { - *cur_publish_id != publish_id - } else { - true - }; - - match publication { - Ok(publication) => { - if canceled { - cx.background_executor() - .spawn(async move { - participant.unpublish_track(&publication.sid()).await - }) - .detach_and_log_err(cx) - } else { - if live_kit.muted_by_user || live_kit.deafened { - publication.mute(); + match publication { + Ok(publication) => { + if canceled { + live_kit.room.unpublish_track(publication); + } else { + if live_kit.muted_by_user || live_kit.deafened { + cx.background_executor() + .spawn(publication.set_mute(true)) + .detach(); + } + live_kit.microphone_track = LocalTrack::Published { + track_publication: publication, + }; + cx.notify(); } - live_kit.microphone_track = LocalTrack::Published { - track_publication: publication, - _stream: Box::new(stream), - }; - cx.notify(); - } - Ok(()) - } - Err(error) => { - if canceled { Ok(()) - } else { - live_kit.microphone_track = LocalTrack::None; - cx.notify(); - Err(error) + } + Err(error) => { + if canceled { + Ok(()) + } else { + live_kit.microphone_track = LocalTrack::None; + cx.notify(); + Err(error) + } } } - } - })? + })? }) } - #[cfg(target_os = "windows")] - pub fn share_screen(&mut self, cx: &mut ModelContext) -> Task> { - Task::ready(Err(anyhow!("Windows is not supported yet"))) - } - - #[cfg(not(target_os = "windows"))] pub fn share_screen(&mut self, cx: &mut ModelContext) -> Task> { if self.status.is_offline() { return Task::ready(Err(anyhow!("room is offline"))); - } - if self.is_screen_sharing() { + } else if self.is_screen_sharing() { return Task::ready(Err(anyhow!("screen was already shared"))); } - let (participant, publish_id) = if let Some(live_kit) = self.live_kit.as_mut() { + let (displays, publish_id) = if let Some(live_kit) = self.live_kit.as_mut() { let publish_id = post_inc(&mut live_kit.next_publish_id); live_kit.screen_track = LocalTrack::Pending { publish_id }; cx.notify(); - (live_kit.room.local_participant(), publish_id) + (live_kit.room.display_sources(), publish_id) } else { return Task::ready(Err(anyhow!("live-kit was not initialized"))); }; - let sources = cx.screen_capture_sources(); - cx.spawn(move |this, mut cx| async move { - let sources = sources.await??; - let source = sources.first().ok_or_else(|| anyhow!("no display found"))?; + let publish_track = async { + let displays = displays.await?; + let display = displays + .first() + .ok_or_else(|| anyhow!("no display found"))?; + let track = LocalVideoTrack::screen_share_for_display(display); + this.upgrade() + .ok_or_else(|| anyhow!("room was dropped"))? + .update(&mut cx, |this, _| { + this.live_kit + .as_ref() + .map(|live_kit| live_kit.room.publish_video_track(track)) + })? + .ok_or_else(|| anyhow!("live-kit was not initialized"))? + .await + }; - let (track, stream) = capture_local_video_track(&**source).await?; + let publication = publish_track.await; + this.upgrade() + .ok_or_else(|| anyhow!("room was dropped"))? + .update(&mut cx, |this, cx| { + let live_kit = this + .live_kit + .as_mut() + .ok_or_else(|| anyhow!("live-kit was not initialized"))?; - let publication = participant - .publish_track( - livekit::track::LocalTrack::Video(track), - TrackPublishOptions { - source: TrackSource::Screenshare, - video_codec: VideoCodec::H264, - ..Default::default() - }, - ) - .await - .map_err(|error| anyhow!("error publishing screen track {error:?}")); + let canceled = if let LocalTrack::Pending { + publish_id: cur_publish_id, + } = &live_kit.screen_track + { + *cur_publish_id != publish_id + } else { + true + }; - this.update(&mut cx, |this, cx| { - let live_kit = this - .live_kit - .as_mut() - .ok_or_else(|| anyhow!("live-kit was not initialized"))?; + match publication { + Ok(publication) => { + if canceled { + live_kit.room.unpublish_track(publication); + } else { + live_kit.screen_track = LocalTrack::Published { + track_publication: publication, + }; + cx.notify(); + } - let canceled = if let LocalTrack::Pending { - publish_id: cur_publish_id, - } = &live_kit.screen_track - { - *cur_publish_id != publish_id - } else { - true - }; + Audio::play_sound(Sound::StartScreenshare, cx); - match publication { - Ok(publication) => { - if canceled { - cx.background_executor() - .spawn(async move { - participant.unpublish_track(&publication.sid()).await - }) - .detach() - } else { - live_kit.screen_track = LocalTrack::Published { - track_publication: publication, - _stream: Box::new(stream), - }; - cx.notify(); - } - - Audio::play_sound(Sound::StartScreenshare, cx); - Ok(()) - } - Err(error) => { - if canceled { Ok(()) - } else { - live_kit.screen_track = LocalTrack::None; - cx.notify(); - Err(error) + } + Err(error) => { + if canceled { + Ok(()) + } else { + live_kit.screen_track = LocalTrack::None; + cx.notify(); + Err(error) + } } } - } - })? + })? }) } @@ -1518,7 +1512,9 @@ impl Room { } if should_undeafen { - self.set_deafened(false, cx); + if let Some(task) = self.set_deafened(false, cx) { + task.detach_and_log_err(cx); + } } } } @@ -1531,7 +1527,9 @@ impl Room { live_kit.deafened = deafened; let should_change_mute = !live_kit.muted_by_user; - self.set_deafened(deafened, cx); + if let Some(task) = self.set_deafened(deafened, cx) { + task.detach_and_log_err(cx); + } if should_change_mute { if let Some(task) = self.set_mute(deafened, cx) { @@ -1559,36 +1557,47 @@ impl Room { LocalTrack::Published { track_publication, .. } => { - #[cfg(not(target_os = "windows"))] - { - let local_participant = live_kit.room.local_participant(); - let sid = track_publication.sid(); - cx.background_executor() - .spawn(async move { local_participant.unpublish_track(&sid).await }) - .detach_and_log_err(cx); - cx.notify(); - } + live_kit.room.unpublish_track(track_publication); + cx.notify(); + Audio::play_sound(Sound::StopScreenshare, cx); Ok(()) } } } - fn set_deafened(&mut self, deafened: bool, cx: &mut ModelContext) -> Option<()> { - #[cfg(not(target_os = "windows"))] - { - let live_kit = self.live_kit.as_mut()?; - cx.notify(); - for (_, participant) in live_kit.room.remote_participants() { - for (_, publication) in participant.track_publications() { - if publication.kind() == TrackKind::Audio { - publication.set_enabled(!deafened); - } + fn set_deafened( + &mut self, + deafened: bool, + cx: &mut ModelContext, + ) -> Option>> { + let live_kit = self.live_kit.as_mut()?; + cx.notify(); + + let mut track_updates = Vec::new(); + for participant in self.remote_participants.values() { + for publication in live_kit + .room + .remote_audio_track_publications(&participant.user.id.to_string()) + { + track_updates.push(publication.set_enabled(!deafened)); + } + + for track in participant.audio_tracks.values() { + if deafened { + track.stop(); + } else { + track.start(); } } } - None + Some(cx.foreground_executor().spawn(async move { + for result in futures::future::join_all(track_updates).await { + result?; + } + Ok(()) + })) } fn set_mute( @@ -1614,84 +1623,25 @@ impl Room { } } LocalTrack::Pending { .. } => None, - LocalTrack::Published { - track_publication, .. - } => { - #[cfg(not(target_os = "windows"))] - { - if should_mute { - track_publication.mute() - } else { - track_publication.unmute() - } - } - None - } + LocalTrack::Published { track_publication } => Some( + cx.foreground_executor() + .spawn(track_publication.set_mute(should_mute)), + ), } } -} -#[cfg(target_os = "windows")] -fn spawn_room_connection( - live_kit_connection_info: Option, - cx: &mut ModelContext<'_, Room>, -) { -} - -#[cfg(not(target_os = "windows"))] -fn spawn_room_connection( - live_kit_connection_info: Option, - cx: &mut ModelContext<'_, Room>, -) { - if let Some(connection_info) = live_kit_connection_info { - cx.spawn(|this, mut cx| async move { - let (room, mut events) = livekit::Room::connect( - &connection_info.server_url, - &connection_info.token, - RoomOptions::default(), - ) - .await?; - - this.update(&mut cx, |this, cx| { - let _handle_updates = cx.spawn(|this, mut cx| async move { - while let Some(event) = events.recv().await { - if this - .update(&mut cx, |this, cx| { - this.live_kit_room_updated(event, cx).warn_on_err(); - }) - .is_err() - { - break; - } - } - }); - - let muted_by_user = Room::mute_on_join(cx); - this.live_kit = Some(LiveKitRoom { - room: Arc::new(room), - screen_track: LocalTrack::None, - microphone_track: LocalTrack::None, - next_publish_id: 0, - muted_by_user, - deafened: false, - speaking: false, - _handle_updates, - }); - - if !muted_by_user && this.can_use_microphone(cx) { - this.share_microphone(cx) - } else { - Task::ready(Ok(())) - } - })? - .await - }) - .detach_and_log_err(cx); + #[cfg(any(test, feature = "test-support"))] + pub fn set_display_sources(&self, sources: Vec) { + self.live_kit + .as_ref() + .unwrap() + .room + .set_display_sources(sources); } } struct LiveKitRoom { - room: Arc, + room: Arc, screen_track: LocalTrack, microphone_track: LocalTrack, /// Tracks whether we're currently in a muted state due to auto-mute from deafening or manual mute performed by user. @@ -1699,21 +1649,17 @@ struct LiveKitRoom { deafened: bool, speaking: bool, next_publish_id: usize, + _maintain_room: Task<()>, _handle_updates: Task<()>, } impl LiveKitRoom { - #[cfg(target_os = "windows")] - fn stop_publishing(&mut self, _cx: &mut ModelContext) {} - - #[cfg(not(target_os = "windows"))] fn stop_publishing(&mut self, cx: &mut ModelContext) { - let mut tracks_to_unpublish = Vec::new(); if let LocalTrack::Published { track_publication, .. } = mem::replace(&mut self.microphone_track, LocalTrack::None) { - tracks_to_unpublish.push(track_publication.sid()); + self.room.unpublish_track(track_publication); cx.notify(); } @@ -1721,18 +1667,9 @@ impl LiveKitRoom { track_publication, .. } = mem::replace(&mut self.screen_track, LocalTrack::None) { - tracks_to_unpublish.push(track_publication.sid()); + self.room.unpublish_track(track_publication); cx.notify(); } - - let participant = self.room.local_participant(); - cx.background_executor() - .spawn(async move { - for sid in tracks_to_unpublish { - participant.unpublish_track(&sid).await.log_err(); - } - }) - .detach(); } } @@ -1743,7 +1680,6 @@ enum LocalTrack { }, Published { track_publication: LocalTrackPublication, - _stream: Box, }, } diff --git a/crates/collab/src/tests.rs b/crates/collab/src/tests.rs index 2ce69efc9b..29373bc6ea 100644 --- a/crates/collab/src/tests.rs +++ b/crates/collab/src/tests.rs @@ -1,6 +1,3 @@ -// todo(windows): Actually run the tests -#![cfg(not(target_os = "windows"))] - use std::sync::Arc; use call::Room; diff --git a/crates/collab/src/tests/channel_guest_tests.rs b/crates/collab/src/tests/channel_guest_tests.rs index 006a3e5d1c..5a091fe308 100644 --- a/crates/collab/src/tests/channel_guest_tests.rs +++ b/crates/collab/src/tests/channel_guest_tests.rs @@ -107,9 +107,7 @@ async fn test_channel_guest_promotion(cx_a: &mut TestAppContext, cx_b: &mut Test }); assert!(project_b.read_with(cx_b, |project, cx| project.is_read_only(cx))); assert!(editor_b.update(cx_b, |e, cx| e.read_only(cx))); - cx_b.update(|cx_b| { - assert!(room_b.read_with(cx_b, |room, cx| !room.can_use_microphone(cx))); - }); + assert!(room_b.read_with(cx_b, |room, _| !room.can_use_microphone())); assert!(room_b .update(cx_b, |room, cx| room.share_microphone(cx)) .await @@ -135,9 +133,7 @@ async fn test_channel_guest_promotion(cx_a: &mut TestAppContext, cx_b: &mut Test assert!(editor_b.update(cx_b, |editor, cx| !editor.read_only(cx))); // B sees themselves as muted, and can unmute. - cx_b.update(|cx_b| { - assert!(room_b.read_with(cx_b, |room, cx| room.can_use_microphone(cx))); - }); + assert!(room_b.read_with(cx_b, |room, _| room.can_use_microphone())); room_b.read_with(cx_b, |room, _| assert!(room.is_muted())); room_b.update(cx_b, |room, cx| room.toggle_mute(cx)); cx_a.run_until_parked(); @@ -230,9 +226,7 @@ async fn test_channel_requires_zed_cla(cx_a: &mut TestAppContext, cx_b: &mut Tes let room_b = cx_b .read(ActiveCall::global) .update(cx_b, |call, _| call.room().unwrap().clone()); - cx_b.update(|cx_b| { - assert!(room_b.read_with(cx_b, |room, cx| !room.can_use_microphone(cx))); - }); + assert!(room_b.read_with(cx_b, |room, _| !room.can_use_microphone())); // A tries to grant write access to B, but cannot because B has not // yet signed the zed CLA. @@ -250,9 +244,7 @@ async fn test_channel_requires_zed_cla(cx_a: &mut TestAppContext, cx_b: &mut Tes .unwrap_err(); cx_a.run_until_parked(); assert!(room_b.read_with(cx_b, |room, _| !room.can_share_projects())); - cx_b.update(|cx_b| { - assert!(room_b.read_with(cx_b, |room, cx| !room.can_use_microphone(cx))); - }); + assert!(room_b.read_with(cx_b, |room, _| !room.can_use_microphone())); // A tries to grant write access to B, but cannot because B has not // yet signed the zed CLA. @@ -270,9 +262,7 @@ async fn test_channel_requires_zed_cla(cx_a: &mut TestAppContext, cx_b: &mut Tes .unwrap(); cx_a.run_until_parked(); assert!(room_b.read_with(cx_b, |room, _| !room.can_share_projects())); - cx_b.update(|cx_b| { - assert!(room_b.read_with(cx_b, |room, cx| room.can_use_microphone(cx))); - }); + assert!(room_b.read_with(cx_b, |room, _| room.can_use_microphone())); // User B signs the zed CLA. server @@ -297,7 +287,5 @@ async fn test_channel_requires_zed_cla(cx_a: &mut TestAppContext, cx_b: &mut Tes .unwrap(); cx_a.run_until_parked(); assert!(room_b.read_with(cx_b, |room, _| room.can_share_projects())); - cx_b.update(|cx_b| { - assert!(room_b.read_with(cx_b, |room, cx| room.can_use_microphone(cx))); - }); + assert!(room_b.read_with(cx_b, |room, _| room.can_use_microphone())); } diff --git a/crates/collab/src/tests/following_tests.rs b/crates/collab/src/tests/following_tests.rs index 778d67b81d..d708194f58 100644 --- a/crates/collab/src/tests/following_tests.rs +++ b/crates/collab/src/tests/following_tests.rs @@ -9,9 +9,10 @@ use collab_ui::{ use editor::{Editor, ExcerptRange, MultiBuffer}; use gpui::{ point, BackgroundExecutor, BorrowAppContext, Context, Entity, SharedString, TestAppContext, - TestScreenCaptureSource, View, VisualContext, VisualTestContext, + View, VisualContext, VisualTestContext, }; use language::Capability; +use live_kit_client::MacOSDisplay; use project::WorktreeSettings; use rpc::proto::PeerId; use serde_json::json; @@ -428,17 +429,17 @@ async fn test_basic_following( ); // Client B activates an external window, which causes a new screen-sharing item to be added to the pane. - let display = TestScreenCaptureSource::new(); + let display = MacOSDisplay::new(); active_call_b .update(cx_b, |call, cx| call.set_location(None, cx)) .await .unwrap(); - cx_b.set_screen_capture_sources(vec![display]); active_call_b .update(cx_b, |call, cx| { - call.room() - .unwrap() - .update(cx, |room, cx| room.share_screen(cx)) + call.room().unwrap().update(cx, |room, cx| { + room.set_display_sources(vec![display.clone()]); + room.share_screen(cx) + }) }) .await .unwrap(); diff --git a/crates/collab/src/tests/integration_tests.rs b/crates/collab/src/tests/integration_tests.rs index 94b7ad81c5..5ec9a574a1 100644 --- a/crates/collab/src/tests/integration_tests.rs +++ b/crates/collab/src/tests/integration_tests.rs @@ -15,7 +15,7 @@ use futures::{channel::mpsc, StreamExt as _}; use git::repository::GitFileStatus; use gpui::{ px, size, AppContext, BackgroundExecutor, Model, Modifiers, MouseButton, MouseDownEvent, - TestAppContext, TestScreenCaptureSource, UpdateGlobal, + TestAppContext, UpdateGlobal, }; use language::{ language_settings::{ @@ -24,6 +24,7 @@ use language::{ tree_sitter_rust, tree_sitter_typescript, Diagnostic, DiagnosticEntry, FakeLspAdapter, Language, LanguageConfig, LanguageMatcher, LineEnding, OffsetRangeExt, Point, Rope, }; +use live_kit_client::MacOSDisplay; use lsp::LanguageServerId; use parking_lot::Mutex; use project::lsp_store::FormatTarget; @@ -240,15 +241,15 @@ async fn test_basic_calls( ); // User A shares their screen - let display = TestScreenCaptureSource::new(); + let display = MacOSDisplay::new(); let events_b = active_call_events(cx_b); let events_c = active_call_events(cx_c); - cx_a.set_screen_capture_sources(vec![display]); active_call_a .update(cx_a, |call, cx| { - call.room() - .unwrap() - .update(cx, |room, cx| room.share_screen(cx)) + call.room().unwrap().update(cx, |room, cx| { + room.set_display_sources(vec![display.clone()]); + room.share_screen(cx) + }) }) .await .unwrap(); @@ -1941,7 +1942,7 @@ async fn test_mute_deafen( room_a.read_with(cx_a, |room, _| assert!(!room.is_muted())); room_b.read_with(cx_b, |room, _| assert!(!room.is_muted())); - // Users A and B are both unmuted. + // Users A and B are both muted. assert_eq!( participant_audio_state(&room_a, cx_a), &[ParticipantAudioState { @@ -2073,7 +2074,7 @@ async fn test_mute_deafen( audio_tracks_playing: participant .audio_tracks .values() - .map(|(track, _)| track.rtc_track().enabled()) + .map(|track| track.is_playing()) .collect(), }) .collect::>() @@ -6056,13 +6057,13 @@ async fn test_join_call_after_screen_was_shared( assert_eq!(call_b.calling_user.github_login, "user_a"); // User A shares their screen - let display = TestScreenCaptureSource::new(); - cx_a.set_screen_capture_sources(vec![display]); + let display = MacOSDisplay::new(); active_call_a .update(cx_a, |call, cx| { - call.room() - .unwrap() - .update(cx, |room, cx| room.share_screen(cx)) + call.room().unwrap().update(cx, |room, cx| { + room.set_display_sources(vec![display.clone()]); + room.share_screen(cx) + }) }) .await .unwrap(); diff --git a/crates/collab/src/tests/test_server.rs b/crates/collab/src/tests/test_server.rs index ae9e101031..17cd1b51c4 100644 --- a/crates/collab/src/tests/test_server.rs +++ b/crates/collab/src/tests/test_server.rs @@ -47,7 +47,7 @@ use workspace::{Workspace, WorkspaceStore}; pub struct TestServer { pub app_state: Arc, - pub test_live_kit_server: Arc, + pub test_live_kit_server: Arc, server: Arc, next_github_user_id: i32, connection_killers: Arc>>>, @@ -89,7 +89,7 @@ impl TestServer { TestDb::sqlite(deterministic.clone()) }; let live_kit_server_id = NEXT_LIVE_KIT_SERVER_ID.fetch_add(1, SeqCst); - let live_kit_server = live_kit_client::test::TestServer::create( + let live_kit_server = live_kit_client::TestServer::create( format!("http://livekit.{}.test", live_kit_server_id), format!("devkey-{}", live_kit_server_id), format!("secret-{}", live_kit_server_id), @@ -499,7 +499,7 @@ impl TestServer { pub async fn build_app_state( test_db: &TestDb, - live_kit_test_server: &live_kit_client::test::TestServer, + live_kit_test_server: &live_kit_client::TestServer, executor: Executor, ) -> Arc { Arc::new(AppState { diff --git a/crates/collab_ui/src/collab_panel.rs b/crates/collab_ui/src/collab_panel.rs index fa3ab0219b..c93a48096a 100644 --- a/crates/collab_ui/src/collab_panel.rs +++ b/crates/collab_ui/src/collab_panel.rs @@ -474,10 +474,11 @@ impl CollabPanel { project_id: project.id, worktree_root_names: project.worktree_root_names.clone(), host_user_id: participant.user.id, - is_last: projects.peek().is_none() && !participant.has_video_tracks(), + is_last: projects.peek().is_none() + && participant.video_tracks.is_empty(), }); } - if participant.has_video_tracks() { + if !participant.video_tracks.is_empty() { self.entries.push(ListEntry::ParticipantScreen { peer_id: Some(participant.peer_id), is_last: true, diff --git a/crates/gpui/build.rs b/crates/gpui/build.rs index e5917a0f05..5a015106c7 100644 --- a/crates/gpui/build.rs +++ b/crates/gpui/build.rs @@ -48,7 +48,6 @@ mod macos { fn generate_dispatch_bindings() { println!("cargo:rustc-link-lib=framework=System"); - println!("cargo:rustc-link-lib=framework=ScreenCaptureKit"); println!("cargo:rerun-if-changed=src/platform/mac/dispatch.h"); let bindings = bindgen::Builder::default() diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 50cadeff8f..0776e5c72e 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -33,8 +33,8 @@ use crate::{ Entity, EventEmitter, ForegroundExecutor, Global, KeyBinding, Keymap, Keystroke, LayoutId, Menu, MenuItem, OwnedMenu, PathPromptOptions, Pixels, Platform, PlatformDisplay, Point, PromptBuilder, PromptHandle, PromptLevel, Render, RenderablePromptHandle, Reservation, - ScreenCaptureSource, SharedString, SubscriberSet, Subscription, SvgRenderer, Task, TextSystem, - View, ViewContext, Window, WindowAppearance, WindowContext, WindowHandle, WindowId, + SharedString, SubscriberSet, Subscription, SvgRenderer, Task, TextSystem, View, ViewContext, + Window, WindowAppearance, WindowContext, WindowHandle, WindowId, }; mod async_context; @@ -599,13 +599,6 @@ impl AppContext { self.platform.primary_display() } - /// Returns a list of available screen capture sources. - pub fn screen_capture_sources( - &self, - ) -> oneshot::Receiver>>> { - self.platform.screen_capture_sources() - } - /// Returns the display with the given ID, if one exists. pub fn find_display(&self, id: DisplayId) -> Option> { self.displays() diff --git a/crates/gpui/src/app/test_context.rs b/crates/gpui/src/app/test_context.rs index 2f5053a382..34449c91ec 100644 --- a/crates/gpui/src/app/test_context.rs +++ b/crates/gpui/src/app/test_context.rs @@ -4,8 +4,8 @@ use crate::{ Element, Empty, Entity, EventEmitter, ForegroundExecutor, Global, InputEvent, Keystroke, Model, ModelContext, Modifiers, ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels, Platform, Point, Render, Result, Size, Task, TestDispatcher, - TestPlatform, TestScreenCaptureSource, TestWindow, TextSystem, View, ViewContext, - VisualContext, WindowBounds, WindowContext, WindowHandle, WindowOptions, + TestPlatform, TestWindow, TextSystem, View, ViewContext, VisualContext, WindowBounds, + WindowContext, WindowHandle, WindowOptions, }; use anyhow::{anyhow, bail}; use futures::{channel::oneshot, Stream, StreamExt}; @@ -287,12 +287,6 @@ impl TestAppContext { self.test_window(window_handle).simulate_resize(size); } - /// Causes the given sources to be returned if the application queries for screen - /// capture sources. - pub fn set_screen_capture_sources(&self, sources: Vec) { - self.test_platform.set_screen_capture_sources(sources); - } - /// Returns all windows open in the test. pub fn windows(&self) -> Vec { self.app.borrow().windows().clone() diff --git a/crates/gpui/src/geometry.rs b/crates/gpui/src/geometry.rs index b636c95a61..9e0b9b9014 100644 --- a/crates/gpui/src/geometry.rs +++ b/crates/gpui/src/geometry.rs @@ -704,11 +704,6 @@ pub struct Bounds { pub size: Size, } -/// Create a bounds with the given origin and size -pub fn bounds(origin: Point, size: Size) -> Bounds { - Bounds { origin, size } -} - impl Bounds { /// Generate a centered bounds for the given display or primary display if none is provided pub fn centered(display_id: Option, size: Size, cx: &AppContext) -> Self { diff --git a/crates/gpui/src/platform.rs b/crates/gpui/src/platform.rs index 3e4d0706f0..d9016afb68 100644 --- a/crates/gpui/src/platform.rs +++ b/crates/gpui/src/platform.rs @@ -70,9 +70,6 @@ pub(crate) use test::*; #[cfg(target_os = "windows")] pub(crate) use windows::*; -#[cfg(any(test, feature = "test-support"))] -pub use test::TestScreenCaptureSource; - #[cfg(target_os = "macos")] pub(crate) fn current_platform(headless: bool) -> Rc { Rc::new(MacPlatform::new(headless)) @@ -152,10 +149,6 @@ pub(crate) trait Platform: 'static { None } - fn screen_capture_sources( - &self, - ) -> oneshot::Receiver>>>; - fn open_window( &self, handle: AnyWindowHandle, @@ -235,25 +228,6 @@ pub trait PlatformDisplay: Send + Sync + Debug { } } -/// A source of on-screen video content that can be captured. -pub trait ScreenCaptureSource { - /// Returns the video resolution of this source. - fn resolution(&self) -> Result>; - - /// Start capture video from this source, invoking the given callback - /// with each frame. - fn stream( - &self, - frame_callback: Box, - ) -> oneshot::Receiver>>; -} - -/// A video stream captured from a screen. -pub trait ScreenCaptureStream {} - -/// A frame of video captured from a screen. -pub struct ScreenCaptureFrame(pub PlatformScreenCaptureFrame); - /// An opaque identifier for a hardware display #[derive(PartialEq, Eq, Hash, Copy, Clone)] pub struct DisplayId(pub(crate) u32); diff --git a/crates/gpui/src/platform/linux.rs b/crates/gpui/src/platform/linux.rs index 089b52cf1e..0499869361 100644 --- a/crates/gpui/src/platform/linux.rs +++ b/crates/gpui/src/platform/linux.rs @@ -20,5 +20,3 @@ pub(crate) use text_system::*; pub(crate) use wayland::*; #[cfg(feature = "x11")] pub(crate) use x11::*; - -pub(crate) type PlatformScreenCaptureFrame = (); diff --git a/crates/gpui/src/platform/linux/platform.rs b/crates/gpui/src/platform/linux/platform.rs index 5865e50092..a2e9af691b 100644 --- a/crates/gpui/src/platform/linux/platform.rs +++ b/crates/gpui/src/platform/linux/platform.rs @@ -35,8 +35,8 @@ use crate::{ px, Action, AnyWindowHandle, BackgroundExecutor, ClipboardItem, CursorStyle, DisplayId, ForegroundExecutor, Keymap, Keystroke, LinuxDispatcher, Menu, MenuItem, Modifiers, OwnedMenu, PathPromptOptions, Pixels, Platform, PlatformDisplay, PlatformInputHandler, PlatformTextSystem, - PlatformWindow, Point, PromptLevel, Result, ScreenCaptureSource, SemanticVersion, SharedString, - Size, Task, WindowAppearance, WindowOptions, WindowParams, + PlatformWindow, Point, PromptLevel, Result, SemanticVersion, SharedString, Size, Task, + WindowAppearance, WindowOptions, WindowParams, }; pub(crate) const SCROLL_LINES: f32 = 3.0; @@ -242,14 +242,6 @@ impl Platform for P { self.displays() } - fn screen_capture_sources( - &self, - ) -> oneshot::Receiver>>> { - let (mut tx, rx) = oneshot::channel(); - tx.send(Err(anyhow!("screen capture not implemented"))).ok(); - rx - } - fn active_window(&self) -> Option { self.active_window() } diff --git a/crates/gpui/src/platform/mac.rs b/crates/gpui/src/platform/mac.rs index bd3d8f35ac..396fd49d04 100644 --- a/crates/gpui/src/platform/mac.rs +++ b/crates/gpui/src/platform/mac.rs @@ -4,14 +4,12 @@ mod dispatcher; mod display; mod display_link; mod events; -mod screen_capture; #[cfg(not(feature = "macos-blade"))] mod metal_atlas; #[cfg(not(feature = "macos-blade"))] pub mod metal_renderer; -use media::core_video::CVImageBuffer; #[cfg(not(feature = "macos-blade"))] use metal_renderer as renderer; @@ -51,9 +49,6 @@ pub(crate) use window::*; #[cfg(feature = "font-kit")] pub(crate) use text_system::*; -/// A frame of video captured from a screen. -pub(crate) type PlatformScreenCaptureFrame = CVImageBuffer; - trait BoolExt { fn to_objc(self) -> BOOL; } diff --git a/crates/gpui/src/platform/mac/platform.rs b/crates/gpui/src/platform/mac/platform.rs index d0fd8a85f4..b744c658ce 100644 --- a/crates/gpui/src/platform/mac/platform.rs +++ b/crates/gpui/src/platform/mac/platform.rs @@ -1,14 +1,14 @@ use super::{ attributed_string::{NSAttributedString, NSMutableAttributedString}, events::key_to_native, - renderer, screen_capture, BoolExt, + BoolExt, }; use crate::{ hash, Action, AnyWindowHandle, BackgroundExecutor, ClipboardEntry, ClipboardItem, ClipboardString, CursorStyle, ForegroundExecutor, Image, ImageFormat, Keymap, MacDispatcher, MacDisplay, MacWindow, Menu, MenuItem, PathPromptOptions, Platform, PlatformDisplay, - PlatformTextSystem, PlatformWindow, Result, ScreenCaptureSource, SemanticVersion, Task, - WindowAppearance, WindowParams, + PlatformTextSystem, PlatformWindow, Result, SemanticVersion, Task, WindowAppearance, + WindowParams, }; use anyhow::anyhow; use block::ConcreteBlock; @@ -58,6 +58,8 @@ use std::{ }; use strum::IntoEnumIterator; +use super::renderer; + #[allow(non_upper_case_globals)] const NSUTF8StringEncoding: NSUInteger = 4; @@ -548,12 +550,6 @@ impl Platform for MacPlatform { .collect() } - fn screen_capture_sources( - &self, - ) -> oneshot::Receiver>>> { - screen_capture::get_sources() - } - fn active_window(&self) -> Option { MacWindow::active_window() } diff --git a/crates/gpui/src/platform/mac/screen_capture.rs b/crates/gpui/src/platform/mac/screen_capture.rs deleted file mode 100644 index a2b535996f..0000000000 --- a/crates/gpui/src/platform/mac/screen_capture.rs +++ /dev/null @@ -1,239 +0,0 @@ -use crate::{ - platform::{ScreenCaptureFrame, ScreenCaptureSource, ScreenCaptureStream}, - px, size, Pixels, Size, -}; -use anyhow::{anyhow, Result}; -use block::ConcreteBlock; -use cocoa::{ - base::{id, nil, YES}, - foundation::NSArray, -}; -use core_foundation::base::TCFType; -use ctor::ctor; -use futures::channel::oneshot; -use media::core_media::{CMSampleBuffer, CMSampleBufferRef}; -use metal::NSInteger; -use objc::{ - class, - declare::ClassDecl, - msg_send, - runtime::{Class, Object, Sel}, - sel, sel_impl, -}; -use std::{cell::RefCell, ffi::c_void, mem, ptr, rc::Rc}; - -#[derive(Clone)] -pub struct MacScreenCaptureSource { - sc_display: id, -} - -pub struct MacScreenCaptureStream { - sc_stream: id, - sc_stream_output: id, -} - -#[link(name = "ScreenCaptureKit", kind = "framework")] -extern "C" {} - -static mut DELEGATE_CLASS: *const Class = ptr::null(); -static mut OUTPUT_CLASS: *const Class = ptr::null(); -const FRAME_CALLBACK_IVAR: &str = "frame_callback"; - -#[allow(non_upper_case_globals)] -const SCStreamOutputTypeScreen: NSInteger = 0; - -impl ScreenCaptureSource for MacScreenCaptureSource { - fn resolution(&self) -> Result> { - unsafe { - let width: i64 = msg_send![self.sc_display, width]; - let height: i64 = msg_send![self.sc_display, height]; - Ok(size(px(width as f32), px(height as f32))) - } - } - - fn stream( - &self, - frame_callback: Box, - ) -> oneshot::Receiver>> { - unsafe { - let stream: id = msg_send![class!(SCStream), alloc]; - let filter: id = msg_send![class!(SCContentFilter), alloc]; - let configuration: id = msg_send![class!(SCStreamConfiguration), alloc]; - let delegate: id = msg_send![DELEGATE_CLASS, alloc]; - let output: id = msg_send![OUTPUT_CLASS, alloc]; - - let excluded_windows = NSArray::array(nil); - let filter: id = msg_send![filter, initWithDisplay:self.sc_display excludingWindows:excluded_windows]; - let configuration: id = msg_send![configuration, init]; - let delegate: id = msg_send![delegate, init]; - let output: id = msg_send![output, init]; - - output.as_mut().unwrap().set_ivar( - FRAME_CALLBACK_IVAR, - Box::into_raw(Box::new(frame_callback)) as *mut c_void, - ); - - let stream: id = msg_send![stream, initWithFilter:filter configuration:configuration delegate:delegate]; - - let (mut tx, rx) = oneshot::channel(); - - let mut error: id = nil; - let _: () = msg_send![stream, addStreamOutput:output type:SCStreamOutputTypeScreen sampleHandlerQueue:0 error:&mut error as *mut id]; - if error != nil { - let message: id = msg_send![error, localizedDescription]; - tx.send(Err(anyhow!("failed to add stream output {message:?}"))) - .ok(); - return rx; - } - - let tx = Rc::new(RefCell::new(Some(tx))); - let handler = ConcreteBlock::new({ - move |error: id| { - let result = if error == nil { - let stream = MacScreenCaptureStream { - sc_stream: stream, - sc_stream_output: output, - }; - Ok(Box::new(stream) as Box) - } else { - let message: id = msg_send![error, localizedDescription]; - Err(anyhow!("failed to stop screen capture stream {message:?}")) - }; - if let Some(tx) = tx.borrow_mut().take() { - tx.send(result).ok(); - } - } - }); - let handler = handler.copy(); - let _: () = msg_send![stream, startCaptureWithCompletionHandler:handler]; - rx - } - } -} - -impl Drop for MacScreenCaptureSource { - fn drop(&mut self) { - unsafe { - let _: () = msg_send![self.sc_display, release]; - } - } -} - -impl ScreenCaptureStream for MacScreenCaptureStream {} - -impl Drop for MacScreenCaptureStream { - fn drop(&mut self) { - unsafe { - let mut error: id = nil; - let _: () = msg_send![self.sc_stream, removeStreamOutput:self.sc_stream_output type:SCStreamOutputTypeScreen error:&mut error as *mut _]; - if error != nil { - let message: id = msg_send![error, localizedDescription]; - log::error!("failed to add stream output {message:?}"); - } - - let handler = ConcreteBlock::new(move |error: id| { - if error != nil { - let message: id = msg_send![error, localizedDescription]; - log::error!("failed to stop screen capture stream {message:?}"); - } - }); - let block = handler.copy(); - let _: () = msg_send![self.sc_stream, stopCaptureWithCompletionHandler:block]; - let _: () = msg_send![self.sc_stream, release]; - let _: () = msg_send![self.sc_stream_output, release]; - } - } -} - -pub(crate) fn get_sources() -> oneshot::Receiver>>> { - unsafe { - let (mut tx, rx) = oneshot::channel(); - let tx = Rc::new(RefCell::new(Some(tx))); - - let block = ConcreteBlock::new(move |shareable_content: id, error: id| { - let Some(mut tx) = tx.borrow_mut().take() else { - return; - }; - let result = if error == nil { - let displays: id = msg_send![shareable_content, displays]; - let mut result = Vec::new(); - for i in 0..displays.count() { - let display = displays.objectAtIndex(i); - let source = MacScreenCaptureSource { - sc_display: msg_send![display, retain], - }; - result.push(Box::new(source) as Box); - } - Ok(result) - } else { - let msg: id = msg_send![error, localizedDescription]; - Err(anyhow!("Failed to register: {:?}", msg)) - }; - tx.send(result).ok(); - }); - let block = block.copy(); - - let _: () = msg_send![ - class!(SCShareableContent), - getShareableContentExcludingDesktopWindows:YES - onScreenWindowsOnly:YES - completionHandler:block]; - rx - } -} - -#[ctor] -unsafe fn build_classes() { - let mut decl = ClassDecl::new("GPUIStreamDelegate", class!(NSObject)).unwrap(); - decl.add_method( - sel!(outputVideoEffectDidStartForStream:), - output_video_effect_did_start_for_stream as extern "C" fn(&Object, Sel, id), - ); - decl.add_method( - sel!(outputVideoEffectDidStopForStream:), - output_video_effect_did_stop_for_stream as extern "C" fn(&Object, Sel, id), - ); - decl.add_method( - sel!(stream:didStopWithError:), - stream_did_stop_with_error as extern "C" fn(&Object, Sel, id, id), - ); - DELEGATE_CLASS = decl.register(); - - let mut decl = ClassDecl::new("GPUIStreamOutput", class!(NSObject)).unwrap(); - decl.add_method( - sel!(stream:didOutputSampleBuffer:ofType:), - stream_did_output_sample_buffer_of_type as extern "C" fn(&Object, Sel, id, id, NSInteger), - ); - decl.add_ivar::<*mut c_void>(FRAME_CALLBACK_IVAR); - - OUTPUT_CLASS = decl.register(); -} - -extern "C" fn output_video_effect_did_start_for_stream(_this: &Object, _: Sel, _stream: id) {} - -extern "C" fn output_video_effect_did_stop_for_stream(_this: &Object, _: Sel, _stream: id) {} - -extern "C" fn stream_did_stop_with_error(_this: &Object, _: Sel, _stream: id, _error: id) {} - -extern "C" fn stream_did_output_sample_buffer_of_type( - this: &Object, - _: Sel, - _stream: id, - sample_buffer: id, - buffer_type: NSInteger, -) { - if buffer_type != SCStreamOutputTypeScreen { - return; - } - - unsafe { - let sample_buffer = sample_buffer as CMSampleBufferRef; - let sample_buffer = CMSampleBuffer::wrap_under_get_rule(sample_buffer); - if let Some(buffer) = sample_buffer.image_buffer() { - let callback: Box> = - Box::from_raw(*this.get_ivar::<*mut c_void>(FRAME_CALLBACK_IVAR) as *mut _); - callback(ScreenCaptureFrame(buffer)); - mem::forget(callback); - } - } -} diff --git a/crates/gpui/src/platform/test.rs b/crates/gpui/src/platform/test.rs index 70462cb5e2..d17739239e 100644 --- a/crates/gpui/src/platform/test.rs +++ b/crates/gpui/src/platform/test.rs @@ -7,5 +7,3 @@ pub(crate) use dispatcher::*; pub(crate) use display::*; pub(crate) use platform::*; pub(crate) use window::*; - -pub use platform::TestScreenCaptureSource; diff --git a/crates/gpui/src/platform/test/platform.rs b/crates/gpui/src/platform/test/platform.rs index 67227b60fe..aadbe9b595 100644 --- a/crates/gpui/src/platform/test/platform.rs +++ b/crates/gpui/src/platform/test/platform.rs @@ -1,7 +1,7 @@ use crate::{ - px, size, AnyWindowHandle, BackgroundExecutor, ClipboardItem, CursorStyle, ForegroundExecutor, - Keymap, Platform, PlatformDisplay, PlatformTextSystem, ScreenCaptureFrame, ScreenCaptureSource, - ScreenCaptureStream, Task, TestDisplay, TestWindow, WindowAppearance, WindowParams, + AnyWindowHandle, BackgroundExecutor, ClipboardItem, CursorStyle, ForegroundExecutor, Keymap, + Platform, PlatformDisplay, PlatformTextSystem, Task, TestDisplay, TestWindow, WindowAppearance, + WindowParams, }; use anyhow::Result; use collections::VecDeque; @@ -31,7 +31,6 @@ pub(crate) struct TestPlatform { #[cfg(any(target_os = "linux", target_os = "freebsd"))] current_primary_item: Mutex>, pub(crate) prompts: RefCell, - screen_capture_sources: RefCell>, pub opened_url: RefCell>, pub text_system: Arc, #[cfg(target_os = "windows")] @@ -39,31 +38,6 @@ pub(crate) struct TestPlatform { weak: Weak, } -#[derive(Clone)] -/// A fake screen capture source, used for testing. -pub struct TestScreenCaptureSource {} - -pub struct TestScreenCaptureStream {} - -impl ScreenCaptureSource for TestScreenCaptureSource { - fn resolution(&self) -> Result> { - Ok(size(px(1.), px(1.))) - } - - fn stream( - &self, - _frame_callback: Box, - ) -> oneshot::Receiver>> { - let (mut tx, rx) = oneshot::channel(); - let stream = TestScreenCaptureStream {}; - tx.send(Ok(Box::new(stream) as Box)) - .ok(); - rx - } -} - -impl ScreenCaptureStream for TestScreenCaptureStream {} - #[derive(Default)] pub(crate) struct TestPrompts { multiple_choice: VecDeque>, @@ -98,7 +72,6 @@ impl TestPlatform { background_executor: executor, foreground_executor, prompts: Default::default(), - screen_capture_sources: Default::default(), active_cursor: Default::default(), active_display: Rc::new(TestDisplay::new()), active_window: Default::default(), @@ -141,10 +114,6 @@ impl TestPlatform { !self.prompts.borrow().multiple_choice.is_empty() } - pub(crate) fn set_screen_capture_sources(&self, sources: Vec) { - *self.screen_capture_sources.borrow_mut() = sources; - } - pub(crate) fn prompt(&self, msg: &str, detail: Option<&str>) -> oneshot::Receiver { let (tx, rx) = oneshot::channel(); self.background_executor() @@ -233,20 +202,6 @@ impl Platform for TestPlatform { Some(self.active_display.clone()) } - fn screen_capture_sources( - &self, - ) -> oneshot::Receiver>>> { - let (mut tx, rx) = oneshot::channel(); - tx.send(Ok(self - .screen_capture_sources - .borrow() - .iter() - .map(|source| Box::new(source.clone()) as Box) - .collect())) - .ok(); - rx - } - fn active_window(&self) -> Option { self.active_window .borrow() @@ -375,13 +330,6 @@ impl Platform for TestPlatform { } } -impl TestScreenCaptureSource { - /// Create a fake screen capture source, for testing. - pub fn new() -> Self { - Self {} - } -} - #[cfg(target_os = "windows")] impl Drop for TestPlatform { fn drop(&mut self) { diff --git a/crates/gpui/src/platform/windows.rs b/crates/gpui/src/platform/windows.rs index 51d09f0013..84cf107c70 100644 --- a/crates/gpui/src/platform/windows.rs +++ b/crates/gpui/src/platform/windows.rs @@ -21,5 +21,3 @@ pub(crate) use window::*; pub(crate) use wrapper::*; pub(crate) use windows::Win32::Foundation::HWND; - -pub(crate) type PlatformScreenCaptureFrame = (); diff --git a/crates/gpui/src/platform/windows/platform.rs b/crates/gpui/src/platform/windows/platform.rs index c2bbc9890c..29443afabb 100644 --- a/crates/gpui/src/platform/windows/platform.rs +++ b/crates/gpui/src/platform/windows/platform.rs @@ -325,14 +325,6 @@ impl Platform for WindowsPlatform { WindowsDisplay::primary_monitor().map(|display| Rc::new(display) as Rc) } - fn screen_capture_sources( - &self, - ) -> oneshot::Receiver>>> { - let (mut tx, rx) = oneshot::channel(); - tx.send(Err(anyhow!("screen capture not implemented"))).ok(); - rx - } - fn active_window(&self) -> Option { let active_window_hwnd = unsafe { GetActiveWindow() }; self.try_get_windows_inner_from_hwnd(active_window_hwnd) diff --git a/crates/http_client/Cargo.toml b/crates/http_client/Cargo.toml index a4f10cff18..ac8e254b84 100644 --- a/crates/http_client/Cargo.toml +++ b/crates/http_client/Cargo.toml @@ -20,7 +20,7 @@ bytes.workspace = true anyhow.workspace = true derive_more.workspace = true futures.workspace = true -http.workspace = true +http = "1.1" log.workspace = true serde.workspace = true serde_json.workspace = true diff --git a/crates/live_kit_client/Cargo.toml b/crates/live_kit_client/Cargo.toml index 921c048f23..e23c63453e 100644 --- a/crates/live_kit_client/Cargo.toml +++ b/crates/live_kit_client/Cargo.toml @@ -2,7 +2,7 @@ name = "live_kit_client" version = "0.1.0" edition = "2021" -description = "Logic for using LiveKit with GPUI" +description = "Bindings to LiveKit Swift client SDK" publish = false license = "GPL-3.0-or-later" @@ -19,37 +19,42 @@ name = "test_app" [features] no-webrtc = [] test-support = [ + "async-trait", "collections/test-support", "gpui/test-support", + "live_kit_server", "nanoid", ] [dependencies] anyhow.workspace = true -async-trait.workspace = true -collections.workspace = true -cpal = "0.15" +async-broadcast = "0.7" +async-trait = { workspace = true, optional = true } +collections = { workspace = true, optional = true } futures.workspace = true -gpui.workspace = true -http_2 = { package = "http", version = "0.2.1" } -live_kit_server.workspace = true +gpui = { workspace = true, optional = true } +live_kit_server = { workspace = true, optional = true } log.workspace = true media.workspace = true nanoid = { workspace = true, optional = true} parking_lot.workspace = true postage.workspace = true -util.workspace = true -http_client.workspace = true - -[target.'cfg(not(target_os = "windows"))'.dependencies] -livekit.workspace = true [target.'cfg(target_os = "macos")'.dependencies] core-foundation.workspace = true +[target.'cfg(all(not(target_os = "macos")))'.dependencies] +async-trait = { workspace = true } +collections = { workspace = true } +gpui = { workspace = true } +live_kit_server.workspace = true +nanoid.workspace = true + [dev-dependencies] +async-trait.workspace = true collections = { workspace = true, features = ["test-support"] } gpui = { workspace = true, features = ["test-support"] } +live_kit_server.workspace = true nanoid.workspace = true sha2.workspace = true simplelog.workspace = true diff --git a/crates/live_kit_client/LiveKitBridge/Package.resolved b/crates/live_kit_client/LiveKitBridge/Package.resolved new file mode 100644 index 0000000000..b925bc8f0d --- /dev/null +++ b/crates/live_kit_client/LiveKitBridge/Package.resolved @@ -0,0 +1,52 @@ +{ + "object": { + "pins": [ + { + "package": "LiveKit", + "repositoryURL": "https://github.com/livekit/client-sdk-swift.git", + "state": { + "branch": null, + "revision": "7331b813a5ab8a95cfb81fb2b4ed10519428b9ff", + "version": "1.0.12" + } + }, + { + "package": "Promises", + "repositoryURL": "https://github.com/google/promises.git", + "state": { + "branch": null, + "revision": "ec957ccddbcc710ccc64c9dcbd4c7006fcf8b73a", + "version": "2.2.0" + } + }, + { + "package": "WebRTC", + "repositoryURL": "https://github.com/webrtc-sdk/Specs.git", + "state": { + "branch": null, + "revision": "2f6bab30c8df0fe59ab3e58bc99097f757f85f65", + "version": "104.5112.17" + } + }, + { + "package": "swift-log", + "repositoryURL": "https://github.com/apple/swift-log.git", + "state": { + "branch": null, + "revision": "32e8d724467f8fe623624570367e3d50c5638e46", + "version": "1.5.2" + } + }, + { + "package": "SwiftProtobuf", + "repositoryURL": "https://github.com/apple/swift-protobuf.git", + "state": { + "branch": null, + "revision": "ce20dc083ee485524b802669890291c0d8090170", + "version": "1.22.1" + } + } + ] + }, + "version": 1 +} diff --git a/crates/live_kit_client/LiveKitBridge/Package.swift b/crates/live_kit_client/LiveKitBridge/Package.swift new file mode 100644 index 0000000000..d7b5c271b9 --- /dev/null +++ b/crates/live_kit_client/LiveKitBridge/Package.swift @@ -0,0 +1,27 @@ +// swift-tools-version: 5.5 + +import PackageDescription + +let package = Package( + name: "LiveKitBridge", + platforms: [ + .macOS(.v10_15) + ], + products: [ + // Products define the executables and libraries a package produces, and make them visible to other packages. + .library( + name: "LiveKitBridge", + type: .static, + targets: ["LiveKitBridge"]), + ], + dependencies: [ + .package(url: "https://github.com/livekit/client-sdk-swift.git", .exact("1.0.12")), + ], + targets: [ + // Targets are the basic building blocks of a package. A target can define a module or a test suite. + // Targets can depend on other targets in this package, and on products in packages this package depends on. + .target( + name: "LiveKitBridge", + dependencies: [.product(name: "LiveKit", package: "client-sdk-swift")]), + ] +) diff --git a/crates/live_kit_client/LiveKitBridge/README.md b/crates/live_kit_client/LiveKitBridge/README.md new file mode 100644 index 0000000000..b982c67286 --- /dev/null +++ b/crates/live_kit_client/LiveKitBridge/README.md @@ -0,0 +1,3 @@ +# LiveKitBridge + +A description of this package. diff --git a/crates/live_kit_client/LiveKitBridge/Sources/LiveKitBridge/LiveKitBridge.swift b/crates/live_kit_client/LiveKitBridge/Sources/LiveKitBridge/LiveKitBridge.swift new file mode 100644 index 0000000000..7468c08791 --- /dev/null +++ b/crates/live_kit_client/LiveKitBridge/Sources/LiveKitBridge/LiveKitBridge.swift @@ -0,0 +1,383 @@ +import Foundation +import LiveKit +import WebRTC +import ScreenCaptureKit + +class LKRoomDelegate: RoomDelegate { + var data: UnsafeRawPointer + var onDidDisconnect: @convention(c) (UnsafeRawPointer) -> Void + var onDidSubscribeToRemoteAudioTrack: @convention(c) (UnsafeRawPointer, CFString, CFString, UnsafeRawPointer, UnsafeRawPointer) -> Void + var onDidUnsubscribeFromRemoteAudioTrack: @convention(c) (UnsafeRawPointer, CFString, CFString) -> Void + var onMuteChangedFromRemoteAudioTrack: @convention(c) (UnsafeRawPointer, CFString, Bool) -> Void + var onActiveSpeakersChanged: @convention(c) (UnsafeRawPointer, CFArray) -> Void + var onDidSubscribeToRemoteVideoTrack: @convention(c) (UnsafeRawPointer, CFString, CFString, UnsafeRawPointer) -> Void + var onDidUnsubscribeFromRemoteVideoTrack: @convention(c) (UnsafeRawPointer, CFString, CFString) -> Void + var onDidPublishOrUnpublishLocalAudioTrack: @convention(c) (UnsafeRawPointer, UnsafeRawPointer, Bool) -> Void + var onDidPublishOrUnpublishLocalVideoTrack: @convention(c) (UnsafeRawPointer, UnsafeRawPointer, Bool) -> Void + + init( + data: UnsafeRawPointer, + onDidDisconnect: @escaping @convention(c) (UnsafeRawPointer) -> Void, + onDidSubscribeToRemoteAudioTrack: @escaping @convention(c) (UnsafeRawPointer, CFString, CFString, UnsafeRawPointer, UnsafeRawPointer) -> Void, + onDidUnsubscribeFromRemoteAudioTrack: @escaping @convention(c) (UnsafeRawPointer, CFString, CFString) -> Void, + onMuteChangedFromRemoteAudioTrack: @escaping @convention(c) (UnsafeRawPointer, CFString, Bool) -> Void, + onActiveSpeakersChanged: @convention(c) (UnsafeRawPointer, CFArray) -> Void, + onDidSubscribeToRemoteVideoTrack: @escaping @convention(c) (UnsafeRawPointer, CFString, CFString, UnsafeRawPointer) -> Void, + onDidUnsubscribeFromRemoteVideoTrack: @escaping @convention(c) (UnsafeRawPointer, CFString, CFString) -> Void, + onDidPublishOrUnpublishLocalAudioTrack: @escaping @convention(c) (UnsafeRawPointer, UnsafeRawPointer, Bool) -> Void, + onDidPublishOrUnpublishLocalVideoTrack: @escaping @convention(c) (UnsafeRawPointer, UnsafeRawPointer, Bool) -> Void + ) + { + self.data = data + self.onDidDisconnect = onDidDisconnect + self.onDidSubscribeToRemoteAudioTrack = onDidSubscribeToRemoteAudioTrack + self.onDidUnsubscribeFromRemoteAudioTrack = onDidUnsubscribeFromRemoteAudioTrack + self.onDidSubscribeToRemoteVideoTrack = onDidSubscribeToRemoteVideoTrack + self.onDidUnsubscribeFromRemoteVideoTrack = onDidUnsubscribeFromRemoteVideoTrack + self.onMuteChangedFromRemoteAudioTrack = onMuteChangedFromRemoteAudioTrack + self.onActiveSpeakersChanged = onActiveSpeakersChanged + self.onDidPublishOrUnpublishLocalAudioTrack = onDidPublishOrUnpublishLocalAudioTrack + self.onDidPublishOrUnpublishLocalVideoTrack = onDidPublishOrUnpublishLocalVideoTrack + } + + func room(_ room: Room, didUpdate connectionState: ConnectionState, oldValue: ConnectionState) { + if connectionState.isDisconnected { + self.onDidDisconnect(self.data) + } + } + + func room(_ room: Room, participant: RemoteParticipant, didSubscribe publication: RemoteTrackPublication, track: Track) { + if track.kind == .video { + self.onDidSubscribeToRemoteVideoTrack(self.data, participant.identity as CFString, track.sid! as CFString, Unmanaged.passUnretained(track).toOpaque()) + } else if track.kind == .audio { + self.onDidSubscribeToRemoteAudioTrack(self.data, participant.identity as CFString, track.sid! as CFString, Unmanaged.passUnretained(track).toOpaque(), Unmanaged.passUnretained(publication).toOpaque()) + } + } + + func room(_ room: Room, participant: Participant, didUpdate publication: TrackPublication, muted: Bool) { + if publication.kind == .audio { + self.onMuteChangedFromRemoteAudioTrack(self.data, publication.sid as CFString, muted) + } + } + + func room(_ room: Room, didUpdate speakers: [Participant]) { + guard let speaker_ids = speakers.compactMap({ $0.identity as CFString }) as CFArray? else { return } + self.onActiveSpeakersChanged(self.data, speaker_ids) + } + + func room(_ room: Room, participant: RemoteParticipant, didUnsubscribe publication: RemoteTrackPublication, track: Track) { + if track.kind == .video { + self.onDidUnsubscribeFromRemoteVideoTrack(self.data, participant.identity as CFString, track.sid! as CFString) + } else if track.kind == .audio { + self.onDidUnsubscribeFromRemoteAudioTrack(self.data, participant.identity as CFString, track.sid! as CFString) + } + } + + func room(_ room: Room, localParticipant: LocalParticipant, didPublish publication: LocalTrackPublication) { + if publication.kind == .video { + self.onDidPublishOrUnpublishLocalVideoTrack(self.data, Unmanaged.passUnretained(publication).toOpaque(), true) + } else if publication.kind == .audio { + self.onDidPublishOrUnpublishLocalAudioTrack(self.data, Unmanaged.passUnretained(publication).toOpaque(), true) + } + } + + func room(_ room: Room, localParticipant: LocalParticipant, didUnpublish publication: LocalTrackPublication) { + if publication.kind == .video { + self.onDidPublishOrUnpublishLocalVideoTrack(self.data, Unmanaged.passUnretained(publication).toOpaque(), false) + } else if publication.kind == .audio { + self.onDidPublishOrUnpublishLocalAudioTrack(self.data, Unmanaged.passUnretained(publication).toOpaque(), false) + } + } +} + +class LKVideoRenderer: NSObject, VideoRenderer { + var data: UnsafeRawPointer + var onFrame: @convention(c) (UnsafeRawPointer, CVPixelBuffer) -> Bool + var onDrop: @convention(c) (UnsafeRawPointer) -> Void + var adaptiveStreamIsEnabled: Bool = false + var adaptiveStreamSize: CGSize = .zero + weak var track: VideoTrack? + + init(data: UnsafeRawPointer, onFrame: @escaping @convention(c) (UnsafeRawPointer, CVPixelBuffer) -> Bool, onDrop: @escaping @convention(c) (UnsafeRawPointer) -> Void) { + self.data = data + self.onFrame = onFrame + self.onDrop = onDrop + } + + deinit { + self.onDrop(self.data) + } + + func setSize(_ size: CGSize) { + } + + func renderFrame(_ frame: RTCVideoFrame?) { + let buffer = frame?.buffer as? RTCCVPixelBuffer + if let pixelBuffer = buffer?.pixelBuffer { + if !self.onFrame(self.data, pixelBuffer) { + DispatchQueue.main.async { + self.track?.remove(videoRenderer: self) + } + } + } + } +} + +@_cdecl("LKRoomDelegateCreate") +public func LKRoomDelegateCreate( + data: UnsafeRawPointer, + onDidDisconnect: @escaping @convention(c) (UnsafeRawPointer) -> Void, + onDidSubscribeToRemoteAudioTrack: @escaping @convention(c) (UnsafeRawPointer, CFString, CFString, UnsafeRawPointer, UnsafeRawPointer) -> Void, + onDidUnsubscribeFromRemoteAudioTrack: @escaping @convention(c) (UnsafeRawPointer, CFString, CFString) -> Void, + onMuteChangedFromRemoteAudioTrack: @escaping @convention(c) (UnsafeRawPointer, CFString, Bool) -> Void, + onActiveSpeakerChanged: @escaping @convention(c) (UnsafeRawPointer, CFArray) -> Void, + onDidSubscribeToRemoteVideoTrack: @escaping @convention(c) (UnsafeRawPointer, CFString, CFString, UnsafeRawPointer) -> Void, + onDidUnsubscribeFromRemoteVideoTrack: @escaping @convention(c) (UnsafeRawPointer, CFString, CFString) -> Void, + onDidPublishOrUnpublishLocalAudioTrack: @escaping @convention(c) (UnsafeRawPointer, UnsafeRawPointer, Bool) -> Void, + onDidPublishOrUnpublishLocalVideoTrack: @escaping @convention(c) (UnsafeRawPointer, UnsafeRawPointer, Bool) -> Void +) -> UnsafeMutableRawPointer { + let delegate = LKRoomDelegate( + data: data, + onDidDisconnect: onDidDisconnect, + onDidSubscribeToRemoteAudioTrack: onDidSubscribeToRemoteAudioTrack, + onDidUnsubscribeFromRemoteAudioTrack: onDidUnsubscribeFromRemoteAudioTrack, + onMuteChangedFromRemoteAudioTrack: onMuteChangedFromRemoteAudioTrack, + onActiveSpeakersChanged: onActiveSpeakerChanged, + onDidSubscribeToRemoteVideoTrack: onDidSubscribeToRemoteVideoTrack, + onDidUnsubscribeFromRemoteVideoTrack: onDidUnsubscribeFromRemoteVideoTrack, + onDidPublishOrUnpublishLocalAudioTrack: onDidPublishOrUnpublishLocalAudioTrack, + onDidPublishOrUnpublishLocalVideoTrack: onDidPublishOrUnpublishLocalVideoTrack + ) + return Unmanaged.passRetained(delegate).toOpaque() +} + +@_cdecl("LKRoomCreate") +public func LKRoomCreate(delegate: UnsafeRawPointer) -> UnsafeMutableRawPointer { + let delegate = Unmanaged.fromOpaque(delegate).takeUnretainedValue() + return Unmanaged.passRetained(Room(delegate: delegate)).toOpaque() +} + +@_cdecl("LKRoomConnect") +public func LKRoomConnect(room: UnsafeRawPointer, url: CFString, token: CFString, callback: @escaping @convention(c) (UnsafeRawPointer, CFString?) -> Void, callback_data: UnsafeRawPointer) { + let room = Unmanaged.fromOpaque(room).takeUnretainedValue() + + room.connect(url as String, token as String).then { _ in + callback(callback_data, UnsafeRawPointer(nil) as! CFString?) + }.catch { error in + callback(callback_data, error.localizedDescription as CFString) + } +} + +@_cdecl("LKRoomDisconnect") +public func LKRoomDisconnect(room: UnsafeRawPointer) { + let room = Unmanaged.fromOpaque(room).takeUnretainedValue() + room.disconnect() +} + +@_cdecl("LKRoomPublishVideoTrack") +public func LKRoomPublishVideoTrack(room: UnsafeRawPointer, track: UnsafeRawPointer, callback: @escaping @convention(c) (UnsafeRawPointer, UnsafeMutableRawPointer?, CFString?) -> Void, callback_data: UnsafeRawPointer) { + let room = Unmanaged.fromOpaque(room).takeUnretainedValue() + let track = Unmanaged.fromOpaque(track).takeUnretainedValue() + room.localParticipant?.publishVideoTrack(track: track).then { publication in + callback(callback_data, Unmanaged.passRetained(publication).toOpaque(), nil) + }.catch { error in + callback(callback_data, nil, error.localizedDescription as CFString) + } +} + +@_cdecl("LKRoomPublishAudioTrack") +public func LKRoomPublishAudioTrack(room: UnsafeRawPointer, track: UnsafeRawPointer, callback: @escaping @convention(c) (UnsafeRawPointer, UnsafeMutableRawPointer?, CFString?) -> Void, callback_data: UnsafeRawPointer) { + let room = Unmanaged.fromOpaque(room).takeUnretainedValue() + let track = Unmanaged.fromOpaque(track).takeUnretainedValue() + room.localParticipant?.publishAudioTrack(track: track).then { publication in + callback(callback_data, Unmanaged.passRetained(publication).toOpaque(), nil) + }.catch { error in + callback(callback_data, nil, error.localizedDescription as CFString) + } +} + + +@_cdecl("LKRoomUnpublishTrack") +public func LKRoomUnpublishTrack(room: UnsafeRawPointer, publication: UnsafeRawPointer) { + let room = Unmanaged.fromOpaque(room).takeUnretainedValue() + let publication = Unmanaged.fromOpaque(publication).takeUnretainedValue() + let _ = room.localParticipant?.unpublish(publication: publication) +} + +@_cdecl("LKRoomAudioTracksForRemoteParticipant") +public func LKRoomAudioTracksForRemoteParticipant(room: UnsafeRawPointer, participantId: CFString) -> CFArray? { + let room = Unmanaged.fromOpaque(room).takeUnretainedValue() + + for (_, participant) in room.remoteParticipants { + if participant.identity == participantId as String { + return participant.audioTracks.compactMap { $0.track as? RemoteAudioTrack } as CFArray? + } + } + + return nil; +} + +@_cdecl("LKRoomAudioTrackPublicationsForRemoteParticipant") +public func LKRoomAudioTrackPublicationsForRemoteParticipant(room: UnsafeRawPointer, participantId: CFString) -> CFArray? { + let room = Unmanaged.fromOpaque(room).takeUnretainedValue() + + for (_, participant) in room.remoteParticipants { + if participant.identity == participantId as String { + return participant.audioTracks.compactMap { $0 as? RemoteTrackPublication } as CFArray? + } + } + + return nil; +} + +@_cdecl("LKRoomVideoTracksForRemoteParticipant") +public func LKRoomVideoTracksForRemoteParticipant(room: UnsafeRawPointer, participantId: CFString) -> CFArray? { + let room = Unmanaged.fromOpaque(room).takeUnretainedValue() + + for (_, participant) in room.remoteParticipants { + if participant.identity == participantId as String { + return participant.videoTracks.compactMap { $0.track as? RemoteVideoTrack } as CFArray? + } + } + + return nil; +} + +@_cdecl("LKLocalAudioTrackCreateTrack") +public func LKLocalAudioTrackCreateTrack() -> UnsafeMutableRawPointer { + let track = LocalAudioTrack.createTrack(options: AudioCaptureOptions( + echoCancellation: true, + noiseSuppression: true + )) + + return Unmanaged.passRetained(track).toOpaque() +} + + +@_cdecl("LKCreateScreenShareTrackForDisplay") +public func LKCreateScreenShareTrackForDisplay(display: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer { + let display = Unmanaged.fromOpaque(display).takeUnretainedValue() + let track = LocalVideoTrack.createMacOSScreenShareTrack(source: display, preferredMethod: .legacy) + return Unmanaged.passRetained(track).toOpaque() +} + +@_cdecl("LKVideoRendererCreate") +public func LKVideoRendererCreate(data: UnsafeRawPointer, onFrame: @escaping @convention(c) (UnsafeRawPointer, CVPixelBuffer) -> Bool, onDrop: @escaping @convention(c) (UnsafeRawPointer) -> Void) -> UnsafeMutableRawPointer { + Unmanaged.passRetained(LKVideoRenderer(data: data, onFrame: onFrame, onDrop: onDrop)).toOpaque() +} + +@_cdecl("LKVideoTrackAddRenderer") +public func LKVideoTrackAddRenderer(track: UnsafeRawPointer, renderer: UnsafeRawPointer) { + let track = Unmanaged.fromOpaque(track).takeUnretainedValue() as! VideoTrack + let renderer = Unmanaged.fromOpaque(renderer).takeRetainedValue() + renderer.track = track + track.add(videoRenderer: renderer) +} + +@_cdecl("LKRemoteVideoTrackGetSid") +public func LKRemoteVideoTrackGetSid(track: UnsafeRawPointer) -> CFString { + let track = Unmanaged.fromOpaque(track).takeUnretainedValue() + return track.sid! as CFString +} + +@_cdecl("LKRemoteAudioTrackGetSid") +public func LKRemoteAudioTrackGetSid(track: UnsafeRawPointer) -> CFString { + let track = Unmanaged.fromOpaque(track).takeUnretainedValue() + return track.sid! as CFString +} + +@_cdecl("LKRemoteAudioTrackStart") +public func LKRemoteAudioTrackStart(track: UnsafeRawPointer) { + let track = Unmanaged.fromOpaque(track).takeUnretainedValue() + track.start() +} + +@_cdecl("LKRemoteAudioTrackStop") +public func LKRemoteAudioTrackStop(track: UnsafeRawPointer) { + let track = Unmanaged.fromOpaque(track).takeUnretainedValue() + track.stop() +} + +@_cdecl("LKDisplaySources") +public func LKDisplaySources(data: UnsafeRawPointer, callback: @escaping @convention(c) (UnsafeRawPointer, CFArray?, CFString?) -> Void) { + MacOSScreenCapturer.sources(for: .display, includeCurrentApplication: false, preferredMethod: .legacy).then { displaySources in + callback(data, displaySources as CFArray, nil) + }.catch { error in + callback(data, nil, error.localizedDescription as CFString) + } +} + +@_cdecl("LKLocalTrackPublicationSetMute") +public func LKLocalTrackPublicationSetMute( + publication: UnsafeRawPointer, + muted: Bool, + on_complete: @escaping @convention(c) (UnsafeRawPointer, CFString?) -> Void, + callback_data: UnsafeRawPointer +) { + let publication = Unmanaged.fromOpaque(publication).takeUnretainedValue() + + if muted { + publication.mute().then { + on_complete(callback_data, nil) + }.catch { error in + on_complete(callback_data, error.localizedDescription as CFString) + } + } else { + publication.unmute().then { + on_complete(callback_data, nil) + }.catch { error in + on_complete(callback_data, error.localizedDescription as CFString) + } + } +} + +@_cdecl("LKLocalTrackPublicationIsMuted") +public func LKLocalTrackPublicationIsMuted( + publication: UnsafeRawPointer +) -> Bool { + let publication = Unmanaged.fromOpaque(publication).takeUnretainedValue() + return publication.muted +} + +@_cdecl("LKRemoteTrackPublicationSetEnabled") +public func LKRemoteTrackPublicationSetEnabled( + publication: UnsafeRawPointer, + enabled: Bool, + on_complete: @escaping @convention(c) (UnsafeRawPointer, CFString?) -> Void, + callback_data: UnsafeRawPointer +) { + let publication = Unmanaged.fromOpaque(publication).takeUnretainedValue() + + publication.set(enabled: enabled).then { + on_complete(callback_data, nil) + }.catch { error in + on_complete(callback_data, error.localizedDescription as CFString) + } +} + +@_cdecl("LKRemoteTrackPublicationIsMuted") +public func LKRemoteTrackPublicationIsMuted( + publication: UnsafeRawPointer +) -> Bool { + let publication = Unmanaged.fromOpaque(publication).takeUnretainedValue() + + return publication.muted +} + +@_cdecl("LKRemoteTrackPublicationGetSid") +public func LKRemoteTrackPublicationGetSid( + publication: UnsafeRawPointer +) -> CFString { + let publication = Unmanaged.fromOpaque(publication).takeUnretainedValue() + + return publication.sid as CFString +} + +@_cdecl("LKLocalTrackPublicationGetSid") +public func LKLocalTrackPublicationGetSid( + publication: UnsafeRawPointer +) -> CFString { + let publication = Unmanaged.fromOpaque(publication).takeUnretainedValue() + + return publication.sid as CFString +} diff --git a/crates/live_kit_client/build.rs b/crates/live_kit_client/build.rs new file mode 100644 index 0000000000..2fdfd982bf --- /dev/null +++ b/crates/live_kit_client/build.rs @@ -0,0 +1,185 @@ +use serde::Deserialize; +use std::{ + env, + path::{Path, PathBuf}, + process::Command, +}; + +const SWIFT_PACKAGE_NAME: &str = "LiveKitBridge"; + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct SwiftTargetInfo { + pub triple: String, + pub unversioned_triple: String, + pub module_triple: String, + pub swift_runtime_compatibility_version: String, + #[serde(rename = "librariesRequireRPath")] + pub libraries_require_rpath: bool, +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct SwiftPaths { + pub runtime_library_paths: Vec, + pub runtime_library_import_paths: Vec, + pub runtime_resource_path: String, +} + +#[derive(Debug, Deserialize)] +pub struct SwiftTarget { + pub target: SwiftTargetInfo, + pub paths: SwiftPaths, +} + +const MACOS_TARGET_VERSION: &str = "10.15.7"; + +fn main() { + if cfg!(all( + target_os = "macos", + not(any(test, feature = "test-support", feature = "no-webrtc")), + )) { + let swift_target = get_swift_target(); + + build_bridge(&swift_target); + link_swift_stdlib(&swift_target); + link_webrtc_framework(&swift_target); + + // Register exported Objective-C selectors, protocols, etc when building example binaries. + println!("cargo:rustc-link-arg=-Wl,-ObjC"); + } +} + +fn build_bridge(swift_target: &SwiftTarget) { + println!("cargo:rerun-if-env-changed=MACOSX_DEPLOYMENT_TARGET"); + println!("cargo:rerun-if-changed={}/Sources", SWIFT_PACKAGE_NAME); + println!( + "cargo:rerun-if-changed={}/Package.swift", + SWIFT_PACKAGE_NAME + ); + println!( + "cargo:rerun-if-changed={}/Package.resolved", + SWIFT_PACKAGE_NAME + ); + + let swift_package_root = swift_package_root(); + let swift_target_folder = swift_target_folder(); + let swift_cache_folder = swift_cache_folder(); + if !Command::new("swift") + .arg("build") + .arg("--disable-automatic-resolution") + .args(["--configuration", &env::var("PROFILE").unwrap()]) + .args(["--triple", &swift_target.target.triple]) + .args(["--build-path".into(), swift_target_folder]) + .args(["--cache-path".into(), swift_cache_folder]) + .current_dir(&swift_package_root) + .status() + .unwrap() + .success() + { + panic!( + "Failed to compile swift package in {}", + swift_package_root.display() + ); + } + + println!( + "cargo:rustc-link-search=native={}", + swift_target.out_dir_path().display() + ); + println!("cargo:rustc-link-lib=static={}", SWIFT_PACKAGE_NAME); +} + +fn link_swift_stdlib(swift_target: &SwiftTarget) { + for path in &swift_target.paths.runtime_library_paths { + println!("cargo:rustc-link-search=native={}", path); + } +} + +fn link_webrtc_framework(swift_target: &SwiftTarget) { + let swift_out_dir_path = swift_target.out_dir_path(); + println!("cargo:rustc-link-lib=framework=WebRTC"); + println!( + "cargo:rustc-link-search=framework={}", + swift_out_dir_path.display() + ); + // Find WebRTC.framework as a sibling of the executable when running tests. + println!("cargo:rustc-link-arg=-Wl,-rpath,@executable_path"); + // Find WebRTC.framework in parent directory of the executable when running examples. + println!("cargo:rustc-link-arg=-Wl,-rpath,@executable_path/.."); + + let source_path = swift_out_dir_path.join("WebRTC.framework"); + let deps_dir_path = + PathBuf::from(env::var("OUT_DIR").unwrap()).join("../../../deps/WebRTC.framework"); + let target_dir_path = + PathBuf::from(env::var("OUT_DIR").unwrap()).join("../../../WebRTC.framework"); + copy_dir(&source_path, &deps_dir_path); + copy_dir(&source_path, &target_dir_path); +} + +fn get_swift_target() -> SwiftTarget { + let mut arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); + if arch == "aarch64" { + arch = "arm64".into(); + } + let target = format!("{}-apple-macosx{}", arch, MACOS_TARGET_VERSION); + + let swift_target_info_str = Command::new("swift") + .args(["-target", &target, "-print-target-info"]) + .output() + .unwrap() + .stdout; + + serde_json::from_slice(&swift_target_info_str).unwrap() +} + +fn swift_package_root() -> PathBuf { + env::current_dir().unwrap().join(SWIFT_PACKAGE_NAME) +} + +fn swift_target_folder() -> PathBuf { + let target = env::var("TARGET").unwrap(); + env::current_dir() + .unwrap() + .join(format!("../../target/{target}/{SWIFT_PACKAGE_NAME}_target")) +} + +fn swift_cache_folder() -> PathBuf { + let target = env::var("TARGET").unwrap(); + env::current_dir() + .unwrap() + .join(format!("../../target/{target}/{SWIFT_PACKAGE_NAME}_cache")) +} + +fn copy_dir(source: &Path, destination: &Path) { + assert!( + Command::new("rm") + .arg("-rf") + .arg(destination) + .status() + .unwrap() + .success(), + "could not remove {:?} before copying", + destination + ); + + assert!( + Command::new("cp") + .arg("-R") + .args([source, destination]) + .status() + .unwrap() + .success(), + "could not copy {:?} to {:?}", + source, + destination + ); +} + +impl SwiftTarget { + fn out_dir_path(&self) -> PathBuf { + swift_target_folder() + .join(&self.target.unversioned_triple) + .join(env::var("PROFILE").unwrap()) + } +} diff --git a/crates/live_kit_client/examples/test_app.rs b/crates/live_kit_client/examples/test_app.rs index 8edd171d84..de8be97e86 100644 --- a/crates/live_kit_client/examples/test_app.rs +++ b/crates/live_kit_client/examples/test_app.rs @@ -1,53 +1,18 @@ -#![cfg_attr(windows, allow(unused))] - -use gpui::{ - actions, bounds, div, point, - prelude::{FluentBuilder as _, IntoElement}, - px, rgb, size, AsyncAppContext, Bounds, InteractiveElement, KeyBinding, Menu, MenuItem, - ParentElement, Pixels, Render, ScreenCaptureStream, SharedString, - StatefulInteractiveElement as _, Styled, Task, View, ViewContext, VisualContext, WindowBounds, - WindowHandle, WindowOptions, -}; -#[cfg(not(target_os = "windows"))] -use live_kit_client::{ - capture_local_audio_track, capture_local_video_track, - id::ParticipantIdentity, - options::{TrackPublishOptions, VideoCodec}, - participant::{Participant, RemoteParticipant}, - play_remote_audio_track, - publication::{LocalTrackPublication, RemoteTrackPublication}, - track::{LocalTrack, RemoteTrack, RemoteVideoTrack, TrackSource}, - AudioStream, RemoteVideoTrackView, Room, RoomEvent, RoomOptions, -}; - -#[cfg(target_os = "windows")] -use live_kit_client::{ - participant::{Participant, RemoteParticipant}, - publication::{LocalTrackPublication, RemoteTrackPublication}, - track::{LocalTrack, RemoteTrack, RemoteVideoTrack}, - AudioStream, RemoteVideoTrackView, Room, RoomEvent, -}; +use std::time::Duration; +use futures::StreamExt; +use gpui::{actions, KeyBinding, Menu, MenuItem}; +use live_kit_client::{LocalAudioTrack, LocalVideoTrack, Room, RoomUpdate}; use live_kit_server::token::{self, VideoGrant}; use log::LevelFilter; -use postage::stream::Stream as _; use simplelog::SimpleLogger; actions!(live_kit_client, [Quit]); -#[cfg(windows)] -fn main() {} - -#[cfg(not(windows))] fn main() { SimpleLogger::init(LevelFilter::Info, Default::default()).expect("could not initialize logger"); gpui::App::new().run(|cx| { - live_kit_client::init( - cx.background_executor().dispatcher.clone(), - cx.http_client(), - ); - #[cfg(any(test, feature = "test-support"))] println!("USING TEST LIVEKIT"); @@ -55,8 +20,10 @@ fn main() { println!("USING REAL LIVEKIT"); cx.activate(true); + cx.on_action(quit); cx.bind_keys([KeyBinding::new("cmd-q", Quit, None)]); + cx.set_menus(vec![Menu { name: "Zed".into(), items: vec![MenuItem::Action { @@ -69,26 +36,132 @@ fn main() { let live_kit_url = std::env::var("LIVE_KIT_URL").unwrap_or("http://localhost:7880".into()); let live_kit_key = std::env::var("LIVE_KIT_KEY").unwrap_or("devkey".into()); let live_kit_secret = std::env::var("LIVE_KIT_SECRET").unwrap_or("secret".into()); - let height = px(800.); - let width = px(800.); cx.spawn(|cx| async move { - let mut windows = Vec::new(); - for i in 0..3 { - let token = token::create( - &live_kit_key, - &live_kit_secret, - Some(&format!("test-participant-{i}")), - VideoGrant::to_join("test-room"), - ) - .unwrap(); + let user_a_token = token::create( + &live_kit_key, + &live_kit_secret, + Some("test-participant-1"), + VideoGrant::to_join("test-room"), + ) + .unwrap(); + let room_a = Room::new(); + room_a.connect(&live_kit_url, &user_a_token).await.unwrap(); - let bounds = bounds(point(width * i, px(0.0)), size(width, height)); - let window = - LivekitWindow::new(live_kit_url.as_str(), token.as_str(), bounds, cx.clone()) - .await; - windows.push(window); + let user2_token = token::create( + &live_kit_key, + &live_kit_secret, + Some("test-participant-2"), + VideoGrant::to_join("test-room"), + ) + .unwrap(); + let room_b = Room::new(); + room_b.connect(&live_kit_url, &user2_token).await.unwrap(); + + let mut room_updates = room_b.updates(); + let audio_track = LocalAudioTrack::create(); + let audio_track_publication = room_a.publish_audio_track(audio_track).await.unwrap(); + + if let RoomUpdate::SubscribedToRemoteAudioTrack(track, _) = + room_updates.next().await.unwrap() + { + let remote_tracks = room_b.remote_audio_tracks("test-participant-1"); + assert_eq!(remote_tracks.len(), 1); + assert_eq!(remote_tracks[0].publisher_id(), "test-participant-1"); + assert_eq!(track.publisher_id(), "test-participant-1"); + } else { + panic!("unexpected message"); } + + audio_track_publication.set_mute(true).await.unwrap(); + + println!("waiting for mute changed!"); + if let RoomUpdate::RemoteAudioTrackMuteChanged { track_id, muted } = + room_updates.next().await.unwrap() + { + let remote_tracks = room_b.remote_audio_tracks("test-participant-1"); + assert_eq!(remote_tracks[0].sid(), track_id); + assert!(muted); + } else { + panic!("unexpected message"); + } + + audio_track_publication.set_mute(false).await.unwrap(); + + if let RoomUpdate::RemoteAudioTrackMuteChanged { track_id, muted } = + room_updates.next().await.unwrap() + { + let remote_tracks = room_b.remote_audio_tracks("test-participant-1"); + assert_eq!(remote_tracks[0].sid(), track_id); + assert!(!muted); + } else { + panic!("unexpected message"); + } + + println!("Pausing for 5 seconds to test audio, make some noise!"); + let timer = cx.background_executor().timer(Duration::from_secs(5)); + timer.await; + let remote_audio_track = room_b + .remote_audio_tracks("test-participant-1") + .pop() + .unwrap(); + room_a.unpublish_track(audio_track_publication); + + // Clear out any active speakers changed messages + let mut next = room_updates.next().await.unwrap(); + while let RoomUpdate::ActiveSpeakersChanged { speakers } = next { + println!("Speakers changed: {:?}", speakers); + next = room_updates.next().await.unwrap(); + } + + if let RoomUpdate::UnsubscribedFromRemoteAudioTrack { + publisher_id, + track_id, + } = next + { + assert_eq!(publisher_id, "test-participant-1"); + assert_eq!(remote_audio_track.sid(), track_id); + assert_eq!(room_b.remote_audio_tracks("test-participant-1").len(), 0); + } else { + panic!("unexpected message"); + } + + let displays = room_a.display_sources().await.unwrap(); + let display = displays.into_iter().next().unwrap(); + + let local_video_track = LocalVideoTrack::screen_share_for_display(&display); + let local_video_track_publication = + room_a.publish_video_track(local_video_track).await.unwrap(); + + if let RoomUpdate::SubscribedToRemoteVideoTrack(track) = + room_updates.next().await.unwrap() + { + let remote_video_tracks = room_b.remote_video_tracks("test-participant-1"); + assert_eq!(remote_video_tracks.len(), 1); + assert_eq!(remote_video_tracks[0].publisher_id(), "test-participant-1"); + assert_eq!(track.publisher_id(), "test-participant-1"); + } else { + panic!("unexpected message"); + } + + let remote_video_track = room_b + .remote_video_tracks("test-participant-1") + .pop() + .unwrap(); + room_a.unpublish_track(local_video_track_publication); + if let RoomUpdate::UnsubscribedFromRemoteVideoTrack { + publisher_id, + track_id, + } = room_updates.next().await.unwrap() + { + assert_eq!(publisher_id, "test-participant-1"); + assert_eq!(remote_video_track.sid(), track_id); + assert_eq!(room_b.remote_video_tracks("test-participant-1").len(), 0); + } else { + panic!("unexpected message"); + } + + cx.update(|cx| cx.shutdown()).ok(); }) .detach(); }); @@ -97,340 +170,3 @@ fn main() { fn quit(_: &Quit, cx: &mut gpui::AppContext) { cx.quit(); } - -struct LivekitWindow { - room: Room, - microphone_track: Option, - screen_share_track: Option, - microphone_stream: Option, - screen_share_stream: Option>, - #[cfg(not(target_os = "windows"))] - remote_participants: Vec<(ParticipantIdentity, ParticipantState)>, - _events_task: Task<()>, -} - -#[derive(Default)] -struct ParticipantState { - audio_output_stream: Option<(RemoteTrackPublication, AudioStream)>, - muted: bool, - screen_share_output_view: Option<(RemoteVideoTrack, View)>, - speaking: bool, -} - -#[cfg(not(windows))] -impl LivekitWindow { - async fn new( - url: &str, - token: &str, - bounds: Bounds, - cx: AsyncAppContext, - ) -> WindowHandle { - let (room, mut events) = Room::connect(url, token, RoomOptions::default()) - .await - .unwrap(); - - cx.update(|cx| { - cx.open_window( - WindowOptions { - window_bounds: Some(WindowBounds::Windowed(bounds)), - ..Default::default() - }, - |cx| { - cx.new_view(|cx| { - let _events_task = cx.spawn(|this, mut cx| async move { - while let Some(event) = events.recv().await { - this.update(&mut cx, |this: &mut LivekitWindow, cx| { - this.handle_room_event(event, cx) - }) - .ok(); - } - }); - - Self { - room, - microphone_track: None, - microphone_stream: None, - screen_share_track: None, - screen_share_stream: None, - remote_participants: Vec::new(), - _events_task, - } - }) - }, - ) - .unwrap() - }) - .unwrap() - } - - fn handle_room_event(&mut self, event: RoomEvent, cx: &mut ViewContext) { - eprintln!("event: {event:?}"); - - match event { - RoomEvent::TrackUnpublished { - publication, - participant, - } => { - let output = self.remote_participant(participant); - let unpublish_sid = publication.sid(); - if output - .audio_output_stream - .as_ref() - .map_or(false, |(track, _)| track.sid() == unpublish_sid) - { - output.audio_output_stream.take(); - } - if output - .screen_share_output_view - .as_ref() - .map_or(false, |(track, _)| track.sid() == unpublish_sid) - { - output.screen_share_output_view.take(); - } - cx.notify(); - } - - RoomEvent::TrackSubscribed { - publication, - participant, - track, - } => { - let output = self.remote_participant(participant); - match track { - RemoteTrack::Audio(track) => { - output.audio_output_stream = - Some((publication.clone(), play_remote_audio_track(&track, cx))); - } - RemoteTrack::Video(track) => { - output.screen_share_output_view = Some(( - track.clone(), - cx.new_view(|cx| RemoteVideoTrackView::new(track, cx)), - )); - } - } - cx.notify(); - } - - RoomEvent::TrackMuted { participant, .. } => { - if let Participant::Remote(participant) = participant { - self.remote_participant(participant).muted = true; - cx.notify(); - } - } - - RoomEvent::TrackUnmuted { participant, .. } => { - if let Participant::Remote(participant) = participant { - self.remote_participant(participant).muted = false; - cx.notify(); - } - } - - RoomEvent::ActiveSpeakersChanged { speakers } => { - for (identity, output) in &mut self.remote_participants { - output.speaking = speakers.iter().any(|speaker| { - if let Participant::Remote(speaker) = speaker { - speaker.identity() == *identity - } else { - false - } - }); - } - cx.notify(); - } - - _ => {} - } - - cx.notify(); - } - - fn remote_participant(&mut self, participant: RemoteParticipant) -> &mut ParticipantState { - match self - .remote_participants - .binary_search_by_key(&&participant.identity(), |row| &row.0) - { - Ok(ix) => &mut self.remote_participants[ix].1, - Err(ix) => { - self.remote_participants - .insert(ix, (participant.identity(), ParticipantState::default())); - &mut self.remote_participants[ix].1 - } - } - } - - fn toggle_mute(&mut self, cx: &mut ViewContext) { - if let Some(track) = &self.microphone_track { - if track.is_muted() { - track.unmute(); - } else { - track.mute(); - } - cx.notify(); - } else { - let participant = self.room.local_participant(); - cx.spawn(|this, mut cx| async move { - let (track, stream) = cx.update(|cx| capture_local_audio_track(cx))??; - let publication = participant - .publish_track( - LocalTrack::Audio(track), - TrackPublishOptions { - source: TrackSource::Microphone, - ..Default::default() - }, - ) - .await - .unwrap(); - this.update(&mut cx, |this, cx| { - this.microphone_track = Some(publication); - this.microphone_stream = Some(stream); - cx.notify(); - }) - }) - .detach(); - } - } - - fn toggle_screen_share(&mut self, cx: &mut ViewContext) { - if let Some(track) = self.screen_share_track.take() { - self.screen_share_stream.take(); - let participant = self.room.local_participant(); - cx.background_executor() - .spawn(async move { - participant.unpublish_track(&track.sid()).await.unwrap(); - }) - .detach(); - cx.notify(); - } else { - let participant = self.room.local_participant(); - let sources = cx.screen_capture_sources(); - cx.spawn(|this, mut cx| async move { - let sources = sources.await.unwrap()?; - let source = sources.into_iter().next().unwrap(); - let (track, stream) = capture_local_video_track(&*source).await?; - let publication = participant - .publish_track( - LocalTrack::Video(track), - TrackPublishOptions { - source: TrackSource::Screenshare, - video_codec: VideoCodec::H264, - ..Default::default() - }, - ) - .await - .unwrap(); - this.update(&mut cx, |this, cx| { - this.screen_share_track = Some(publication); - this.screen_share_stream = Some(stream); - cx.notify(); - }) - }) - .detach(); - } - } - - fn toggle_remote_audio_for_participant( - &mut self, - identity: &ParticipantIdentity, - cx: &mut ViewContext, - ) -> Option<()> { - let participant = self.remote_participants.iter().find_map(|(id, state)| { - if id == identity { - Some(state) - } else { - None - } - })?; - let publication = &participant.audio_output_stream.as_ref()?.0; - publication.set_enabled(!publication.is_enabled()); - cx.notify(); - Some(()) - } -} - -#[cfg(not(windows))] -impl Render for LivekitWindow { - fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { - fn button() -> gpui::Div { - div() - .w(px(180.0)) - .h(px(30.0)) - .px_2() - .m_2() - .bg(rgb(0x8888ff)) - } - - div() - .bg(rgb(0xffffff)) - .size_full() - .flex() - .flex_col() - .child( - div().bg(rgb(0xffd4a8)).flex().flex_row().children([ - button() - .id("toggle-mute") - .child(if let Some(track) = &self.microphone_track { - if track.is_muted() { - "Unmute" - } else { - "Mute" - } - } else { - "Publish mic" - }) - .on_click(cx.listener(|this, _, cx| this.toggle_mute(cx))), - button() - .id("toggle-screen-share") - .child(if self.screen_share_track.is_none() { - "Share screen" - } else { - "Unshare screen" - }) - .on_click(cx.listener(|this, _, cx| this.toggle_screen_share(cx))), - ]), - ) - .child( - div() - .id("remote-participants") - .overflow_y_scroll() - .flex() - .flex_col() - .flex_grow() - .children(self.remote_participants.iter().map(|(identity, state)| { - div() - .h(px(300.0)) - .flex() - .flex_col() - .m_2() - .px_2() - .bg(rgb(0x8888ff)) - .child(SharedString::from(if state.speaking { - format!("{} (speaking)", &identity.0) - } else if state.muted { - format!("{} (muted)", &identity.0) - } else { - identity.0.clone() - })) - .when_some(state.audio_output_stream.as_ref(), |el, state| { - el.child( - button() - .id(SharedString::from(identity.0.clone())) - .child(if state.0.is_enabled() { - "Deafen" - } else { - "Undeafen" - }) - .on_click(cx.listener({ - let identity = identity.clone(); - move |this, _, cx| { - this.toggle_remote_audio_for_participant( - &identity, cx, - ); - } - })), - ) - }) - .children(state.screen_share_output_view.as_ref().map(|e| e.1.clone())) - })), - ) - } -} diff --git a/crates/live_kit_client/src/live_kit_client.rs b/crates/live_kit_client/src/live_kit_client.rs index ad2e72d67f..4820a4eedb 100644 --- a/crates/live_kit_client/src/live_kit_client.rs +++ b/crates/live_kit_client/src/live_kit_client.rs @@ -1,387 +1,37 @@ -#![cfg_attr(target_os = "windows", allow(unused))] +#![allow(clippy::arc_with_non_send_sync)] -mod remote_video_track_view; -#[cfg(any(test, feature = "test-support", target_os = "windows"))] +use std::sync::Arc; + +#[cfg(all(target_os = "macos", not(any(test, feature = "test-support"))))] +pub mod prod; + +#[cfg(all(target_os = "macos", not(any(test, feature = "test-support"))))] +pub use prod::*; + +#[cfg(any(test, feature = "test-support", not(target_os = "macos")))] pub mod test; -use anyhow::{anyhow, Context as _, Result}; -use cpal::{ - traits::{DeviceTrait, HostTrait, StreamTrait as _}, - StreamConfig, -}; -use futures::{io, Stream, StreamExt as _}; -use gpui::{AppContext, ScreenCaptureFrame, ScreenCaptureSource, ScreenCaptureStream, Task}; -use parking_lot::Mutex; -use std::{borrow::Cow, future::Future, pin::Pin, sync::Arc}; -use util::{debug_panic, ResultExt as _, TryFutureExt}; -#[cfg(not(target_os = "windows"))] -use webrtc::{ - audio_frame::AudioFrame, - audio_source::{native::NativeAudioSource, AudioSourceOptions, RtcAudioSource}, - audio_stream::native::NativeAudioStream, - video_frame::{VideoBuffer, VideoFrame, VideoRotation}, - video_source::{native::NativeVideoSource, RtcVideoSource, VideoResolution}, - video_stream::native::NativeVideoStream, -}; - -#[cfg(all(not(any(test, feature = "test-support")), not(target_os = "windows")))] -pub use livekit::*; -#[cfg(any(test, feature = "test-support", target_os = "windows"))] +#[cfg(any(test, feature = "test-support", not(target_os = "macos")))] pub use test::*; -pub use remote_video_track_view::{RemoteVideoTrackView, RemoteVideoTrackViewEvent}; +pub type Sid = String; -pub struct AudioStream { - _tasks: [Task>; 2], +#[derive(Clone, Eq, PartialEq)] +pub enum ConnectionState { + Disconnected, + Connected { url: String, token: String }, } -struct Dispatcher(Arc); - -#[cfg(not(target_os = "windows"))] -impl livekit::dispatcher::Dispatcher for Dispatcher { - fn dispatch(&self, runnable: livekit::dispatcher::Runnable) { - self.0.dispatch(runnable, None); - } - - fn dispatch_after( - &self, - duration: std::time::Duration, - runnable: livekit::dispatcher::Runnable, - ) { - self.0.dispatch_after(duration, runnable); - } -} - -struct HttpClientAdapter(Arc); - -fn http_2_status(status: http_client::http::StatusCode) -> http_2::StatusCode { - http_2::StatusCode::from_u16(status.as_u16()) - .expect("valid status code to status code conversion") -} - -#[cfg(not(target_os = "windows"))] -impl livekit::dispatcher::HttpClient for HttpClientAdapter { - fn get( - &self, - url: &str, - ) -> Pin> + Send>> { - let http_client = self.0.clone(); - let url = url.to_string(); - Box::pin(async move { - let response = http_client - .get(&url, http_client::AsyncBody::empty(), false) - .await - .map_err(io::Error::other)?; - Ok(livekit::dispatcher::Response { - status: http_2_status(response.status()), - body: Box::pin(response.into_body()), - }) - }) - } - - fn send_async( - &self, - request: http_2::Request>, - ) -> Pin> + Send>> { - let http_client = self.0.clone(); - let mut builder = http_client::http::Request::builder() - .method(request.method().as_str()) - .uri(request.uri().to_string()); - - for (key, value) in request.headers().iter() { - builder = builder.header(key.as_str(), value.as_bytes()); - } - - if !request.extensions().is_empty() { - debug_panic!( - "Livekit sent an HTTP request with a protocol extension that Zed doesn't support!" - ); - } - - let request = builder - .body(http_client::AsyncBody::from_bytes( - request.into_body().into(), - )) - .unwrap(); - - Box::pin(async move { - let response = http_client.send(request).await.map_err(io::Error::other)?; - Ok(livekit::dispatcher::Response { - status: http_2_status(response.status()), - body: Box::pin(response.into_body()), - }) - }) - } -} - -#[cfg(target_os = "windows")] -pub fn init( - dispatcher: Arc, - http_client: Arc, -) { -} - -#[cfg(not(target_os = "windows"))] -pub fn init( - dispatcher: Arc, - http_client: Arc, -) { - livekit::dispatcher::set_dispatcher(Dispatcher(dispatcher)); - livekit::dispatcher::set_http_client(HttpClientAdapter(http_client)); -} - -#[cfg(not(target_os = "windows"))] -pub async fn capture_local_video_track( - capture_source: &dyn ScreenCaptureSource, -) -> Result<(track::LocalVideoTrack, Box)> { - let resolution = capture_source.resolution()?; - let track_source = NativeVideoSource::new(VideoResolution { - width: resolution.width.0 as u32, - height: resolution.height.0 as u32, - }); - - let capture_stream = capture_source - .stream({ - let track_source = track_source.clone(); - Box::new(move |frame| { - if let Some(buffer) = video_frame_buffer_to_webrtc(frame) { - track_source.capture_frame(&VideoFrame { - rotation: VideoRotation::VideoRotation0, - timestamp_us: 0, - buffer, - }); - } - }) - }) - .await??; - - Ok(( - track::LocalVideoTrack::create_video_track( - "screen share", - RtcVideoSource::Native(track_source), - ), - capture_stream, - )) -} - -#[cfg(not(target_os = "windows"))] -pub fn capture_local_audio_track( - cx: &mut AppContext, -) -> Result<(track::LocalAudioTrack, AudioStream)> { - let (frame_tx, mut frame_rx) = futures::channel::mpsc::unbounded(); - - let sample_rate; - let channels; - let stream; - if cfg!(any(test, feature = "test-support")) { - sample_rate = 1; - channels = 1; - stream = None; - } else { - let device = cpal::default_host() - .default_input_device() - .ok_or_else(|| anyhow!("no audio input device available"))?; - let config = device - .default_input_config() - .context("failed to get default input config")?; - sample_rate = config.sample_rate().0; - channels = config.channels() as u32; - stream = Some( - device - .build_input_stream_raw( - &config.config(), - cpal::SampleFormat::I16, - move |data, _: &_| { - frame_tx - .unbounded_send(AudioFrame { - data: Cow::Owned(data.as_slice::().unwrap().to_vec()), - sample_rate, - num_channels: channels, - samples_per_channel: data.len() as u32 / channels, - }) - .ok(); - }, - |err| log::error!("error capturing audio track: {:?}", err), - None, - ) - .context("failed to build input stream")?, - ); - } - - let source = NativeAudioSource::new( - AudioSourceOptions { - echo_cancellation: true, - noise_suppression: true, - auto_gain_control: false, - }, - sample_rate, - channels, - // TODO livekit: Pull these out of a proto later - 100, - ); - - let stream_task = cx.foreground_executor().spawn(async move { - if let Some(stream) = &stream { - stream.play().log_err(); - } - futures::future::pending().await - }); - - let transmit_task = cx.background_executor().spawn({ - let source = source.clone(); - async move { - while let Some(frame) = frame_rx.next().await { - source.capture_frame(&frame).await.ok(); - } - Some(()) - } - }); - - let track = - track::LocalAudioTrack::create_audio_track("microphone", RtcAudioSource::Native(source)); - - Ok(( - track, - AudioStream { - _tasks: [stream_task, transmit_task], - }, - )) -} - -#[cfg(not(target_os = "windows"))] -pub fn play_remote_audio_track( - track: &track::RemoteAudioTrack, - cx: &mut AppContext, -) -> AudioStream { - let buffer = Arc::new(Mutex::new(Vec::::new())); - let (stream_config_tx, mut stream_config_rx) = futures::channel::mpsc::unbounded(); - // TODO livekit: Pull these out of a proto later - let mut stream = NativeAudioStream::new(track.rtc_track(), 48000, 1); - - let receive_task = cx.background_executor().spawn({ - let buffer = buffer.clone(); - async move { - let mut stream_config = None; - while let Some(frame) = stream.next().await { - let mut buffer = buffer.lock(); - let buffer_size = frame.samples_per_channel * frame.num_channels; - debug_assert!(frame.data.len() == buffer_size as usize); - - let frame_config = StreamConfig { - channels: frame.num_channels as u16, - sample_rate: cpal::SampleRate(frame.sample_rate), - buffer_size: cpal::BufferSize::Fixed(buffer_size), - }; - - if stream_config.as_ref().map_or(true, |c| *c != frame_config) { - buffer.resize(buffer_size as usize, 0); - stream_config = Some(frame_config.clone()); - stream_config_tx.unbounded_send(frame_config).ok(); - } - - if frame.data.len() == buffer.len() { - buffer.copy_from_slice(&frame.data); - } else { - buffer.iter_mut().for_each(|x| *x = 0); - } - } - Some(()) - } - }); - - let play_task = cx.foreground_executor().spawn( - { - let buffer = buffer.clone(); - async move { - if cfg!(any(test, feature = "test-support")) { - return Err(anyhow!("can't play audio in tests")); - } - - let device = cpal::default_host() - .default_output_device() - .ok_or_else(|| anyhow!("no audio output device available"))?; - - let mut _output_stream = None; - while let Some(config) = stream_config_rx.next().await { - _output_stream = Some(device.build_output_stream( - &config, - { - let buffer = buffer.clone(); - move |data, _info| { - let buffer = buffer.lock(); - if data.len() == buffer.len() { - data.copy_from_slice(&buffer); - } else { - data.iter_mut().for_each(|x| *x = 0); - } - } - }, - |error| log::error!("error playing audio track: {:?}", error), - None, - )?); - } - - Ok(()) - } - } - .log_err(), - ); - - AudioStream { - _tasks: [receive_task, play_task], - } -} - -#[cfg(target_os = "windows")] -pub fn play_remote_video_track( - track: &track::RemoteVideoTrack, -) -> impl Stream { - futures::stream::empty() -} - -#[cfg(not(target_os = "windows"))] -pub fn play_remote_video_track( - track: &track::RemoteVideoTrack, -) -> impl Stream { - NativeVideoStream::new(track.rtc_track()) - .filter_map(|frame| async move { video_frame_buffer_from_webrtc(frame.buffer) }) -} - -#[cfg(target_os = "macos")] -fn video_frame_buffer_from_webrtc(buffer: Box) -> Option { - use core_foundation::base::TCFType as _; - use media::core_video::CVImageBuffer; - - let buffer = buffer.as_native()?; - let pixel_buffer = buffer.get_cv_pixel_buffer(); - if pixel_buffer.is_null() { - return None; - } - - unsafe { - Some(ScreenCaptureFrame(CVImageBuffer::wrap_under_get_rule( - pixel_buffer as _, - ))) - } -} - -#[cfg(not(any(target_os = "macos", target_os = "windows")))] -fn video_frame_buffer_from_webrtc(_buffer: Box) -> Option { - None -} - -#[cfg(target_os = "macos")] -fn video_frame_buffer_to_webrtc(frame: ScreenCaptureFrame) -> Option> { - use core_foundation::base::TCFType as _; - - let pixel_buffer = frame.0.as_concrete_TypeRef(); - std::mem::forget(frame.0); - unsafe { - Some(webrtc::video_frame::native::NativeBuffer::from_cv_pixel_buffer(pixel_buffer as _)) - } -} - -#[cfg(not(any(target_os = "macos", target_os = "windows")))] -fn video_frame_buffer_to_webrtc(_frame: ScreenCaptureFrame) -> Option> { - None as Option> +#[derive(Clone)] +pub enum RoomUpdate { + ActiveSpeakersChanged { speakers: Vec }, + RemoteAudioTrackMuteChanged { track_id: Sid, muted: bool }, + SubscribedToRemoteVideoTrack(Arc), + SubscribedToRemoteAudioTrack(Arc, Arc), + UnsubscribedFromRemoteVideoTrack { publisher_id: Sid, track_id: Sid }, + UnsubscribedFromRemoteAudioTrack { publisher_id: Sid, track_id: Sid }, + LocalAudioTrackPublished { publication: LocalTrackPublication }, + LocalAudioTrackUnpublished { publication: LocalTrackPublication }, + LocalVideoTrackPublished { publication: LocalTrackPublication }, + LocalVideoTrackUnpublished { publication: LocalTrackPublication }, } diff --git a/crates/live_kit_client/src/prod.rs b/crates/live_kit_client/src/prod.rs new file mode 100644 index 0000000000..f7452da710 --- /dev/null +++ b/crates/live_kit_client/src/prod.rs @@ -0,0 +1,981 @@ +use crate::{ConnectionState, RoomUpdate, Sid}; +use anyhow::{anyhow, Context, Result}; +use core_foundation::{ + array::{CFArray, CFArrayRef}, + base::{CFRelease, CFRetain, TCFType}, + string::{CFString, CFStringRef}, +}; +use futures::{ + channel::{mpsc, oneshot}, + Future, +}; +pub use media::core_video::CVImageBuffer; +use media::core_video::CVImageBufferRef; +use parking_lot::Mutex; +use postage::watch; +use std::{ + ffi::c_void, + sync::{Arc, Weak}, +}; + +macro_rules! pointer_type { + ($pointer_name:ident) => { + #[repr(transparent)] + #[derive(Copy, Clone, Debug)] + pub struct $pointer_name(pub *const std::ffi::c_void); + unsafe impl Send for $pointer_name {} + }; +} + +mod swift { + pointer_type!(Room); + pointer_type!(LocalAudioTrack); + pointer_type!(RemoteAudioTrack); + pointer_type!(LocalVideoTrack); + pointer_type!(RemoteVideoTrack); + pointer_type!(LocalTrackPublication); + pointer_type!(RemoteTrackPublication); + pointer_type!(MacOSDisplay); + pointer_type!(RoomDelegate); +} + +extern "C" { + fn LKRoomDelegateCreate( + callback_data: *mut c_void, + on_did_disconnect: extern "C" fn(callback_data: *mut c_void), + on_did_subscribe_to_remote_audio_track: extern "C" fn( + callback_data: *mut c_void, + publisher_id: CFStringRef, + track_id: CFStringRef, + remote_track: swift::RemoteAudioTrack, + remote_publication: swift::RemoteTrackPublication, + ), + on_did_unsubscribe_from_remote_audio_track: extern "C" fn( + callback_data: *mut c_void, + publisher_id: CFStringRef, + track_id: CFStringRef, + ), + on_mute_changed_from_remote_audio_track: extern "C" fn( + callback_data: *mut c_void, + track_id: CFStringRef, + muted: bool, + ), + on_active_speakers_changed: extern "C" fn( + callback_data: *mut c_void, + participants: CFArrayRef, + ), + on_did_subscribe_to_remote_video_track: extern "C" fn( + callback_data: *mut c_void, + publisher_id: CFStringRef, + track_id: CFStringRef, + remote_track: swift::RemoteVideoTrack, + ), + on_did_unsubscribe_from_remote_video_track: extern "C" fn( + callback_data: *mut c_void, + publisher_id: CFStringRef, + track_id: CFStringRef, + ), + on_did_publish_or_unpublish_local_audio_track: extern "C" fn( + callback_data: *mut c_void, + publication: swift::LocalTrackPublication, + is_published: bool, + ), + on_did_publish_or_unpublish_local_video_track: extern "C" fn( + callback_data: *mut c_void, + publication: swift::LocalTrackPublication, + is_published: bool, + ), + ) -> swift::RoomDelegate; + + fn LKRoomCreate(delegate: swift::RoomDelegate) -> swift::Room; + fn LKRoomConnect( + room: swift::Room, + url: CFStringRef, + token: CFStringRef, + callback: extern "C" fn(*mut c_void, CFStringRef), + callback_data: *mut c_void, + ); + fn LKRoomDisconnect(room: swift::Room); + fn LKRoomPublishVideoTrack( + room: swift::Room, + track: swift::LocalVideoTrack, + callback: extern "C" fn(*mut c_void, swift::LocalTrackPublication, CFStringRef), + callback_data: *mut c_void, + ); + fn LKRoomPublishAudioTrack( + room: swift::Room, + track: swift::LocalAudioTrack, + callback: extern "C" fn(*mut c_void, swift::LocalTrackPublication, CFStringRef), + callback_data: *mut c_void, + ); + fn LKRoomUnpublishTrack(room: swift::Room, publication: swift::LocalTrackPublication); + + fn LKRoomAudioTracksForRemoteParticipant( + room: swift::Room, + participant_id: CFStringRef, + ) -> CFArrayRef; + + fn LKRoomAudioTrackPublicationsForRemoteParticipant( + room: swift::Room, + participant_id: CFStringRef, + ) -> CFArrayRef; + + fn LKRoomVideoTracksForRemoteParticipant( + room: swift::Room, + participant_id: CFStringRef, + ) -> CFArrayRef; + + fn LKVideoRendererCreate( + callback_data: *mut c_void, + on_frame: extern "C" fn(callback_data: *mut c_void, frame: CVImageBufferRef) -> bool, + on_drop: extern "C" fn(callback_data: *mut c_void), + ) -> *const c_void; + + fn LKRemoteAudioTrackGetSid(track: swift::RemoteAudioTrack) -> CFStringRef; + fn LKRemoteVideoTrackGetSid(track: swift::RemoteVideoTrack) -> CFStringRef; + fn LKRemoteAudioTrackStart(track: swift::RemoteAudioTrack); + fn LKRemoteAudioTrackStop(track: swift::RemoteAudioTrack); + fn LKVideoTrackAddRenderer(track: swift::RemoteVideoTrack, renderer: *const c_void); + + fn LKDisplaySources( + callback_data: *mut c_void, + callback: extern "C" fn( + callback_data: *mut c_void, + sources: CFArrayRef, + error: CFStringRef, + ), + ); + fn LKCreateScreenShareTrackForDisplay(display: swift::MacOSDisplay) -> swift::LocalVideoTrack; + fn LKLocalAudioTrackCreateTrack() -> swift::LocalAudioTrack; + + fn LKLocalTrackPublicationSetMute( + publication: swift::LocalTrackPublication, + muted: bool, + on_complete: extern "C" fn(callback_data: *mut c_void, error: CFStringRef), + callback_data: *mut c_void, + ); + + fn LKRemoteTrackPublicationSetEnabled( + publication: swift::RemoteTrackPublication, + enabled: bool, + on_complete: extern "C" fn(callback_data: *mut c_void, error: CFStringRef), + callback_data: *mut c_void, + ); + + fn LKLocalTrackPublicationIsMuted(publication: swift::LocalTrackPublication) -> bool; + fn LKRemoteTrackPublicationIsMuted(publication: swift::RemoteTrackPublication) -> bool; + fn LKLocalTrackPublicationGetSid(publication: swift::LocalTrackPublication) -> CFStringRef; + fn LKRemoteTrackPublicationGetSid(publication: swift::RemoteTrackPublication) -> CFStringRef; +} + +pub struct Room { + native_room: swift::Room, + connection: Mutex<( + watch::Sender, + watch::Receiver, + )>, + update_subscribers: Mutex>>, + _delegate: RoomDelegate, +} + +impl Room { + pub fn new() -> Arc { + Arc::new_cyclic(|weak_room| { + let delegate = RoomDelegate::new(weak_room.clone()); + Self { + native_room: unsafe { LKRoomCreate(delegate.native_delegate) }, + connection: Mutex::new(watch::channel_with(ConnectionState::Disconnected)), + update_subscribers: Default::default(), + _delegate: delegate, + } + }) + } + + pub fn status(&self) -> watch::Receiver { + self.connection.lock().1.clone() + } + + pub fn connect(self: &Arc, url: &str, token: &str) -> impl Future> { + let url = CFString::new(url); + let token = CFString::new(token); + let (did_connect, tx, rx) = Self::build_done_callback(); + unsafe { + LKRoomConnect( + self.native_room, + url.as_concrete_TypeRef(), + token.as_concrete_TypeRef(), + did_connect, + tx, + ) + } + + let this = self.clone(); + let url = url.to_string(); + let token = token.to_string(); + async move { + rx.await.unwrap().context("error connecting to room")?; + *this.connection.lock().0.borrow_mut() = ConnectionState::Connected { url, token }; + Ok(()) + } + } + + fn did_disconnect(&self) { + *self.connection.lock().0.borrow_mut() = ConnectionState::Disconnected; + } + + pub fn display_sources(self: &Arc) -> impl Future>> { + extern "C" fn callback(tx: *mut c_void, sources: CFArrayRef, error: CFStringRef) { + unsafe { + let tx = Box::from_raw(tx as *mut oneshot::Sender>>); + + if sources.is_null() { + let _ = tx.send(Err(anyhow!("{}", CFString::wrap_under_get_rule(error)))); + } else { + let sources = CFArray::wrap_under_get_rule(sources) + .into_iter() + .map(|source| MacOSDisplay::new(swift::MacOSDisplay(*source))) + .collect(); + + let _ = tx.send(Ok(sources)); + } + } + } + + let (tx, rx) = oneshot::channel(); + + unsafe { + LKDisplaySources(Box::into_raw(Box::new(tx)) as *mut _, callback); + } + + async move { rx.await.unwrap() } + } + + pub fn publish_video_track( + self: &Arc, + track: LocalVideoTrack, + ) -> impl Future> { + let (tx, rx) = oneshot::channel::>(); + extern "C" fn callback( + tx: *mut c_void, + publication: swift::LocalTrackPublication, + error: CFStringRef, + ) { + let tx = + unsafe { Box::from_raw(tx as *mut oneshot::Sender>) }; + if error.is_null() { + let _ = tx.send(Ok(LocalTrackPublication::new(publication))); + } else { + let error = unsafe { CFString::wrap_under_get_rule(error).to_string() }; + let _ = tx.send(Err(anyhow!(error))); + } + } + unsafe { + LKRoomPublishVideoTrack( + self.native_room, + track.0, + callback, + Box::into_raw(Box::new(tx)) as *mut c_void, + ); + } + async { rx.await.unwrap().context("error publishing video track") } + } + + pub fn publish_audio_track( + self: &Arc, + track: LocalAudioTrack, + ) -> impl Future> { + let (tx, rx) = oneshot::channel::>(); + extern "C" fn callback( + tx: *mut c_void, + publication: swift::LocalTrackPublication, + error: CFStringRef, + ) { + let tx = + unsafe { Box::from_raw(tx as *mut oneshot::Sender>) }; + if error.is_null() { + let _ = tx.send(Ok(LocalTrackPublication::new(publication))); + } else { + let error = unsafe { CFString::wrap_under_get_rule(error).to_string() }; + let _ = tx.send(Err(anyhow!(error))); + } + } + unsafe { + LKRoomPublishAudioTrack( + self.native_room, + track.0, + callback, + Box::into_raw(Box::new(tx)) as *mut c_void, + ); + } + async { rx.await.unwrap().context("error publishing audio track") } + } + + pub fn unpublish_track(&self, publication: LocalTrackPublication) { + unsafe { + LKRoomUnpublishTrack(self.native_room, publication.0); + } + } + + pub fn remote_video_tracks(&self, participant_id: &str) -> Vec> { + unsafe { + let tracks = LKRoomVideoTracksForRemoteParticipant( + self.native_room, + CFString::new(participant_id).as_concrete_TypeRef(), + ); + + if tracks.is_null() { + Vec::new() + } else { + let tracks = CFArray::wrap_under_get_rule(tracks); + tracks + .into_iter() + .map(|native_track| { + let native_track = swift::RemoteVideoTrack(*native_track); + let id = + CFString::wrap_under_get_rule(LKRemoteVideoTrackGetSid(native_track)) + .to_string(); + Arc::new(RemoteVideoTrack::new( + native_track, + id, + participant_id.into(), + )) + }) + .collect() + } + } + } + + pub fn remote_audio_tracks(&self, participant_id: &str) -> Vec> { + unsafe { + let tracks = LKRoomAudioTracksForRemoteParticipant( + self.native_room, + CFString::new(participant_id).as_concrete_TypeRef(), + ); + + if tracks.is_null() { + Vec::new() + } else { + let tracks = CFArray::wrap_under_get_rule(tracks); + tracks + .into_iter() + .map(|native_track| { + let native_track = swift::RemoteAudioTrack(*native_track); + let id = + CFString::wrap_under_get_rule(LKRemoteAudioTrackGetSid(native_track)) + .to_string(); + Arc::new(RemoteAudioTrack::new( + native_track, + id, + participant_id.into(), + )) + }) + .collect() + } + } + } + + pub fn remote_audio_track_publications( + &self, + participant_id: &str, + ) -> Vec> { + unsafe { + let tracks = LKRoomAudioTrackPublicationsForRemoteParticipant( + self.native_room, + CFString::new(participant_id).as_concrete_TypeRef(), + ); + + if tracks.is_null() { + Vec::new() + } else { + let tracks = CFArray::wrap_under_get_rule(tracks); + tracks + .into_iter() + .map(|native_track_publication| { + let native_track_publication = + swift::RemoteTrackPublication(*native_track_publication); + Arc::new(RemoteTrackPublication::new(native_track_publication)) + }) + .collect() + } + } + } + + pub fn updates(&self) -> mpsc::UnboundedReceiver { + let (tx, rx) = mpsc::unbounded(); + self.update_subscribers.lock().push(tx); + rx + } + + fn did_subscribe_to_remote_audio_track( + &self, + track: RemoteAudioTrack, + publication: RemoteTrackPublication, + ) { + let track = Arc::new(track); + let publication = Arc::new(publication); + self.update_subscribers.lock().retain(|tx| { + tx.unbounded_send(RoomUpdate::SubscribedToRemoteAudioTrack( + track.clone(), + publication.clone(), + )) + .is_ok() + }); + } + + fn did_unsubscribe_from_remote_audio_track(&self, publisher_id: String, track_id: String) { + self.update_subscribers.lock().retain(|tx| { + tx.unbounded_send(RoomUpdate::UnsubscribedFromRemoteAudioTrack { + publisher_id: publisher_id.clone(), + track_id: track_id.clone(), + }) + .is_ok() + }); + } + + fn mute_changed_from_remote_audio_track(&self, track_id: String, muted: bool) { + self.update_subscribers.lock().retain(|tx| { + tx.unbounded_send(RoomUpdate::RemoteAudioTrackMuteChanged { + track_id: track_id.clone(), + muted, + }) + .is_ok() + }); + } + + fn active_speakers_changed(&self, speakers: Vec) { + self.update_subscribers.lock().retain(move |tx| { + tx.unbounded_send(RoomUpdate::ActiveSpeakersChanged { + speakers: speakers.clone(), + }) + .is_ok() + }); + } + + fn did_subscribe_to_remote_video_track(&self, track: RemoteVideoTrack) { + let track = Arc::new(track); + self.update_subscribers.lock().retain(|tx| { + tx.unbounded_send(RoomUpdate::SubscribedToRemoteVideoTrack(track.clone())) + .is_ok() + }); + } + + fn did_unsubscribe_from_remote_video_track(&self, publisher_id: String, track_id: String) { + self.update_subscribers.lock().retain(|tx| { + tx.unbounded_send(RoomUpdate::UnsubscribedFromRemoteVideoTrack { + publisher_id: publisher_id.clone(), + track_id: track_id.clone(), + }) + .is_ok() + }); + } + + fn build_done_callback() -> ( + extern "C" fn(*mut c_void, CFStringRef), + *mut c_void, + oneshot::Receiver>, + ) { + let (tx, rx) = oneshot::channel(); + extern "C" fn done_callback(tx: *mut c_void, error: CFStringRef) { + let tx = unsafe { Box::from_raw(tx as *mut oneshot::Sender>) }; + if error.is_null() { + let _ = tx.send(Ok(())); + } else { + let error = unsafe { CFString::wrap_under_get_rule(error).to_string() }; + let _ = tx.send(Err(anyhow!(error))); + } + } + ( + done_callback, + Box::into_raw(Box::new(tx)) as *mut c_void, + rx, + ) + } + + pub fn set_display_sources(&self, _: Vec) { + unreachable!("This is a test-only function") + } +} + +impl Drop for Room { + fn drop(&mut self) { + unsafe { + LKRoomDisconnect(self.native_room); + CFRelease(self.native_room.0); + } + } +} + +struct RoomDelegate { + native_delegate: swift::RoomDelegate, + weak_room: *mut c_void, +} + +impl RoomDelegate { + fn new(weak_room: Weak) -> Self { + let weak_room = weak_room.into_raw() as *mut c_void; + let native_delegate = unsafe { + LKRoomDelegateCreate( + weak_room, + Self::on_did_disconnect, + Self::on_did_subscribe_to_remote_audio_track, + Self::on_did_unsubscribe_from_remote_audio_track, + Self::on_mute_change_from_remote_audio_track, + Self::on_active_speakers_changed, + Self::on_did_subscribe_to_remote_video_track, + Self::on_did_unsubscribe_from_remote_video_track, + Self::on_did_publish_or_unpublish_local_audio_track, + Self::on_did_publish_or_unpublish_local_video_track, + ) + }; + Self { + native_delegate, + weak_room, + } + } + + extern "C" fn on_did_disconnect(room: *mut c_void) { + let room = unsafe { Weak::from_raw(room as *mut Room) }; + if let Some(room) = room.upgrade() { + room.did_disconnect(); + } + let _ = Weak::into_raw(room); + } + + extern "C" fn on_did_subscribe_to_remote_audio_track( + room: *mut c_void, + publisher_id: CFStringRef, + track_id: CFStringRef, + track: swift::RemoteAudioTrack, + publication: swift::RemoteTrackPublication, + ) { + let room = unsafe { Weak::from_raw(room as *mut Room) }; + let publisher_id = unsafe { CFString::wrap_under_get_rule(publisher_id).to_string() }; + let track_id = unsafe { CFString::wrap_under_get_rule(track_id).to_string() }; + let track = RemoteAudioTrack::new(track, track_id, publisher_id); + let publication = RemoteTrackPublication::new(publication); + if let Some(room) = room.upgrade() { + room.did_subscribe_to_remote_audio_track(track, publication); + } + let _ = Weak::into_raw(room); + } + + extern "C" fn on_did_unsubscribe_from_remote_audio_track( + room: *mut c_void, + publisher_id: CFStringRef, + track_id: CFStringRef, + ) { + let room = unsafe { Weak::from_raw(room as *mut Room) }; + let publisher_id = unsafe { CFString::wrap_under_get_rule(publisher_id).to_string() }; + let track_id = unsafe { CFString::wrap_under_get_rule(track_id).to_string() }; + if let Some(room) = room.upgrade() { + room.did_unsubscribe_from_remote_audio_track(publisher_id, track_id); + } + let _ = Weak::into_raw(room); + } + + extern "C" fn on_mute_change_from_remote_audio_track( + room: *mut c_void, + track_id: CFStringRef, + muted: bool, + ) { + let room = unsafe { Weak::from_raw(room as *mut Room) }; + let track_id = unsafe { CFString::wrap_under_get_rule(track_id).to_string() }; + if let Some(room) = room.upgrade() { + room.mute_changed_from_remote_audio_track(track_id, muted); + } + let _ = Weak::into_raw(room); + } + + extern "C" fn on_active_speakers_changed(room: *mut c_void, participants: CFArrayRef) { + if participants.is_null() { + return; + } + + let room = unsafe { Weak::from_raw(room as *mut Room) }; + let speakers = unsafe { + CFArray::wrap_under_get_rule(participants) + .into_iter() + .map( + |speaker: core_foundation::base::ItemRef<'_, *const c_void>| { + CFString::wrap_under_get_rule(*speaker as CFStringRef).to_string() + }, + ) + .collect() + }; + + if let Some(room) = room.upgrade() { + room.active_speakers_changed(speakers); + } + let _ = Weak::into_raw(room); + } + + extern "C" fn on_did_subscribe_to_remote_video_track( + room: *mut c_void, + publisher_id: CFStringRef, + track_id: CFStringRef, + track: swift::RemoteVideoTrack, + ) { + let room = unsafe { Weak::from_raw(room as *mut Room) }; + let publisher_id = unsafe { CFString::wrap_under_get_rule(publisher_id).to_string() }; + let track_id = unsafe { CFString::wrap_under_get_rule(track_id).to_string() }; + let track = RemoteVideoTrack::new(track, track_id, publisher_id); + if let Some(room) = room.upgrade() { + room.did_subscribe_to_remote_video_track(track); + } + let _ = Weak::into_raw(room); + } + + extern "C" fn on_did_unsubscribe_from_remote_video_track( + room: *mut c_void, + publisher_id: CFStringRef, + track_id: CFStringRef, + ) { + let room = unsafe { Weak::from_raw(room as *mut Room) }; + let publisher_id = unsafe { CFString::wrap_under_get_rule(publisher_id).to_string() }; + let track_id = unsafe { CFString::wrap_under_get_rule(track_id).to_string() }; + if let Some(room) = room.upgrade() { + room.did_unsubscribe_from_remote_video_track(publisher_id, track_id); + } + let _ = Weak::into_raw(room); + } + + extern "C" fn on_did_publish_or_unpublish_local_audio_track( + room: *mut c_void, + publication: swift::LocalTrackPublication, + is_published: bool, + ) { + let room = unsafe { Weak::from_raw(room as *mut Room) }; + if let Some(room) = room.upgrade() { + let publication = LocalTrackPublication::new(publication); + let update = if is_published { + RoomUpdate::LocalAudioTrackPublished { publication } + } else { + RoomUpdate::LocalAudioTrackUnpublished { publication } + }; + room.update_subscribers + .lock() + .retain(|tx| tx.unbounded_send(update.clone()).is_ok()); + } + let _ = Weak::into_raw(room); + } + + extern "C" fn on_did_publish_or_unpublish_local_video_track( + room: *mut c_void, + publication: swift::LocalTrackPublication, + is_published: bool, + ) { + let room = unsafe { Weak::from_raw(room as *mut Room) }; + if let Some(room) = room.upgrade() { + let publication = LocalTrackPublication::new(publication); + let update = if is_published { + RoomUpdate::LocalVideoTrackPublished { publication } + } else { + RoomUpdate::LocalVideoTrackUnpublished { publication } + }; + room.update_subscribers + .lock() + .retain(|tx| tx.unbounded_send(update.clone()).is_ok()); + } + let _ = Weak::into_raw(room); + } +} + +impl Drop for RoomDelegate { + fn drop(&mut self) { + unsafe { + CFRelease(self.native_delegate.0); + let _ = Weak::from_raw(self.weak_room as *mut Room); + } + } +} + +pub struct LocalAudioTrack(swift::LocalAudioTrack); + +impl LocalAudioTrack { + pub fn create() -> Self { + Self(unsafe { LKLocalAudioTrackCreateTrack() }) + } +} + +impl Drop for LocalAudioTrack { + fn drop(&mut self) { + unsafe { CFRelease(self.0 .0) } + } +} + +pub struct LocalVideoTrack(swift::LocalVideoTrack); + +impl LocalVideoTrack { + pub fn screen_share_for_display(display: &MacOSDisplay) -> Self { + Self(unsafe { LKCreateScreenShareTrackForDisplay(display.0) }) + } +} + +impl Drop for LocalVideoTrack { + fn drop(&mut self) { + unsafe { CFRelease(self.0 .0) } + } +} + +pub struct LocalTrackPublication(swift::LocalTrackPublication); + +impl LocalTrackPublication { + pub fn new(native_track_publication: swift::LocalTrackPublication) -> Self { + unsafe { + CFRetain(native_track_publication.0); + } + Self(native_track_publication) + } + + pub fn sid(&self) -> String { + unsafe { CFString::wrap_under_get_rule(LKLocalTrackPublicationGetSid(self.0)).to_string() } + } + + pub fn set_mute(&self, muted: bool) -> impl Future> { + let (tx, rx) = futures::channel::oneshot::channel(); + + extern "C" fn complete_callback(callback_data: *mut c_void, error: CFStringRef) { + let tx = unsafe { Box::from_raw(callback_data as *mut oneshot::Sender>) }; + if error.is_null() { + tx.send(Ok(())).ok(); + } else { + let error = unsafe { CFString::wrap_under_get_rule(error).to_string() }; + tx.send(Err(anyhow!(error))).ok(); + } + } + + unsafe { + LKLocalTrackPublicationSetMute( + self.0, + muted, + complete_callback, + Box::into_raw(Box::new(tx)) as *mut c_void, + ) + } + + async move { rx.await.unwrap() } + } + + pub fn is_muted(&self) -> bool { + unsafe { LKLocalTrackPublicationIsMuted(self.0) } + } +} + +impl Clone for LocalTrackPublication { + fn clone(&self) -> Self { + unsafe { + CFRetain(self.0 .0); + } + Self(self.0) + } +} + +impl Drop for LocalTrackPublication { + fn drop(&mut self) { + unsafe { CFRelease(self.0 .0) } + } +} + +pub struct RemoteTrackPublication(swift::RemoteTrackPublication); + +impl RemoteTrackPublication { + pub fn new(native_track_publication: swift::RemoteTrackPublication) -> Self { + unsafe { + CFRetain(native_track_publication.0); + } + Self(native_track_publication) + } + + pub fn sid(&self) -> String { + unsafe { CFString::wrap_under_get_rule(LKRemoteTrackPublicationGetSid(self.0)).to_string() } + } + + pub fn is_muted(&self) -> bool { + unsafe { LKRemoteTrackPublicationIsMuted(self.0) } + } + + pub fn set_enabled(&self, enabled: bool) -> impl Future> { + let (tx, rx) = futures::channel::oneshot::channel(); + + extern "C" fn complete_callback(callback_data: *mut c_void, error: CFStringRef) { + let tx = unsafe { Box::from_raw(callback_data as *mut oneshot::Sender>) }; + if error.is_null() { + tx.send(Ok(())).ok(); + } else { + let error = unsafe { CFString::wrap_under_get_rule(error).to_string() }; + tx.send(Err(anyhow!(error))).ok(); + } + } + + unsafe { + LKRemoteTrackPublicationSetEnabled( + self.0, + enabled, + complete_callback, + Box::into_raw(Box::new(tx)) as *mut c_void, + ) + } + + async move { rx.await.unwrap() } + } +} + +impl Drop for RemoteTrackPublication { + fn drop(&mut self) { + unsafe { CFRelease(self.0 .0) } + } +} + +#[derive(Debug)] +pub struct RemoteAudioTrack { + native_track: swift::RemoteAudioTrack, + sid: Sid, + publisher_id: String, +} + +impl RemoteAudioTrack { + fn new(native_track: swift::RemoteAudioTrack, sid: Sid, publisher_id: String) -> Self { + unsafe { + CFRetain(native_track.0); + } + Self { + native_track, + sid, + publisher_id, + } + } + + pub fn sid(&self) -> &str { + &self.sid + } + + pub fn publisher_id(&self) -> &str { + &self.publisher_id + } + + pub fn start(&self) { + unsafe { LKRemoteAudioTrackStart(self.native_track) } + } + + pub fn stop(&self) { + unsafe { LKRemoteAudioTrackStop(self.native_track) } + } +} + +impl Drop for RemoteAudioTrack { + fn drop(&mut self) { + // todo: uncomment this `CFRelease`, unless we find that it was causing + // the crash in the `livekit.multicast` thread. + // + // unsafe { CFRelease(self.native_track.0) } + let _ = self.native_track; + } +} + +#[derive(Debug)] +pub struct RemoteVideoTrack { + native_track: swift::RemoteVideoTrack, + sid: Sid, + publisher_id: String, +} + +impl RemoteVideoTrack { + fn new(native_track: swift::RemoteVideoTrack, sid: Sid, publisher_id: String) -> Self { + unsafe { + CFRetain(native_track.0); + } + Self { + native_track, + sid, + publisher_id, + } + } + + pub fn sid(&self) -> &str { + &self.sid + } + + pub fn publisher_id(&self) -> &str { + &self.publisher_id + } + + pub fn frames(&self) -> async_broadcast::Receiver { + extern "C" fn on_frame(callback_data: *mut c_void, frame: CVImageBufferRef) -> bool { + unsafe { + let tx = Box::from_raw(callback_data as *mut async_broadcast::Sender); + let buffer = CVImageBuffer::wrap_under_get_rule(frame); + let result = tx.try_broadcast(Frame(buffer)); + let _ = Box::into_raw(tx); + match result { + Ok(_) => true, + Err(async_broadcast::TrySendError::Closed(_)) + | Err(async_broadcast::TrySendError::Inactive(_)) => { + log::warn!("no active receiver for frame"); + false + } + Err(async_broadcast::TrySendError::Full(_)) => { + log::warn!("skipping frame as receiver is not keeping up"); + true + } + } + } + } + + extern "C" fn on_drop(callback_data: *mut c_void) { + unsafe { + let _ = Box::from_raw(callback_data as *mut async_broadcast::Sender); + } + } + + let (tx, rx) = async_broadcast::broadcast(64); + unsafe { + let renderer = LKVideoRendererCreate( + Box::into_raw(Box::new(tx)) as *mut c_void, + on_frame, + on_drop, + ); + LKVideoTrackAddRenderer(self.native_track, renderer); + rx + } + } +} + +impl Drop for RemoteVideoTrack { + fn drop(&mut self) { + unsafe { CFRelease(self.native_track.0) } + } +} + +pub struct MacOSDisplay(swift::MacOSDisplay); + +impl MacOSDisplay { + fn new(ptr: swift::MacOSDisplay) -> Self { + unsafe { + CFRetain(ptr.0); + } + Self(ptr) + } +} + +impl Drop for MacOSDisplay { + fn drop(&mut self) { + unsafe { CFRelease(self.0 .0) } + } +} + +#[derive(Clone)] +pub struct Frame(CVImageBuffer); + +impl Frame { + pub fn width(&self) -> usize { + self.0.width() + } + + pub fn height(&self) -> usize { + self.0.height() + } + + pub fn image(&self) -> CVImageBuffer { + self.0.clone() + } +} diff --git a/crates/live_kit_client/src/remote_video_track_view.rs b/crates/live_kit_client/src/remote_video_track_view.rs deleted file mode 100644 index bbfaea1875..0000000000 --- a/crates/live_kit_client/src/remote_video_track_view.rs +++ /dev/null @@ -1,61 +0,0 @@ -use crate::track::RemoteVideoTrack; -use anyhow::Result; -use futures::StreamExt as _; -use gpui::{ - Empty, EventEmitter, IntoElement, Render, ScreenCaptureFrame, Task, View, ViewContext, - VisualContext as _, -}; - -pub struct RemoteVideoTrackView { - track: RemoteVideoTrack, - frame: Option, - _maintain_frame: Task>, -} - -#[derive(Debug)] -pub enum RemoteVideoTrackViewEvent { - Close, -} - -impl RemoteVideoTrackView { - pub fn new(track: RemoteVideoTrack, cx: &mut ViewContext) -> Self { - cx.focus_handle(); - let frames = super::play_remote_video_track(&track); - - Self { - track, - frame: None, - _maintain_frame: cx.spawn(|this, mut cx| async move { - futures::pin_mut!(frames); - while let Some(frame) = frames.next().await { - this.update(&mut cx, |this, cx| { - this.frame = Some(frame); - cx.notify(); - })?; - } - this.update(&mut cx, |_, cx| cx.emit(RemoteVideoTrackViewEvent::Close))?; - Ok(()) - }), - } - } - - pub fn clone(&self, cx: &mut ViewContext) -> View { - cx.new_view(|cx| Self::new(self.track.clone(), cx)) - } -} - -impl EventEmitter for RemoteVideoTrackView {} - -impl Render for RemoteVideoTrackView { - fn render(&mut self, _cx: &mut ViewContext) -> impl IntoElement { - #[cfg(target_os = "macos")] - if let Some(frame) = &self.frame { - use gpui::Styled as _; - return gpui::surface(frame.0.clone()) - .size_full() - .into_any_element(); - } - - Empty.into_any_element() - } -} diff --git a/crates/live_kit_client/src/test.rs b/crates/live_kit_client/src/test.rs index 1bd2e60d17..2c26c88f72 100644 --- a/crates/live_kit_client/src/test.rs +++ b/crates/live_kit_client/src/test.rs @@ -1,29 +1,21 @@ -pub mod participant; -pub mod publication; -pub mod track; - -#[cfg(not(windows))] -pub mod webrtc; - -#[cfg(not(windows))] -use self::id::*; -use self::{participant::*, publication::*, track::*}; +use crate::{ConnectionState, RoomUpdate, Sid}; use anyhow::{anyhow, Context, Result}; use async_trait::async_trait; use collections::{btree_map::Entry as BTreeEntry, hash_map::Entry, BTreeMap, HashMap, HashSet}; -use gpui::BackgroundExecutor; +use futures::Stream; +use gpui::{BackgroundExecutor, SurfaceSource}; use live_kit_server::{proto, token}; -#[cfg(not(windows))] -use livekit::options::TrackPublishOptions; -use parking_lot::Mutex; -use postage::{mpsc, sink::Sink}; -use std::sync::{ - atomic::{AtomicBool, Ordering::SeqCst}, - Arc, Weak, -}; -#[cfg(not(windows))] -pub use livekit::{id, options, ConnectionState, DisconnectReason, RoomOptions}; +use parking_lot::Mutex; +use postage::watch; +use std::{ + future::Future, + mem, + sync::{ + atomic::{AtomicBool, Ordering::SeqCst}, + Arc, Weak, + }, +}; static SERVERS: Mutex>> = Mutex::new(BTreeMap::new()); @@ -31,12 +23,10 @@ pub struct TestServer { pub url: String, pub api_key: String, pub secret_key: String, - #[cfg(not(target_os = "windows"))] rooms: Mutex>, executor: BackgroundExecutor, } -#[cfg(not(target_os = "windows"))] impl TestServer { pub fn create( url: String, @@ -83,8 +73,9 @@ impl TestServer { } pub async fn create_room(&self, room: String) -> Result<()> { + // todo(linux): Remove this once the cross-platform LiveKit implementation is merged + #[cfg(any(test, feature = "test-support"))] self.executor.simulate_random_delay().await; - let mut server_rooms = self.rooms.lock(); if let Entry::Vacant(e) = server_rooms.entry(room.clone()) { e.insert(Default::default()); @@ -95,8 +86,10 @@ impl TestServer { } async fn delete_room(&self, room: String) -> Result<()> { + // TODO: clear state associated with all `Room`s. + // todo(linux): Remove this once the cross-platform LiveKit implementation is merged + #[cfg(any(test, feature = "test-support"))] self.executor.simulate_random_delay().await; - let mut server_rooms = self.rooms.lock(); server_rooms .remove(&room) @@ -104,64 +97,46 @@ impl TestServer { Ok(()) } - async fn join_room(&self, token: String, client_room: Room) -> Result { + async fn join_room(&self, token: String, client_room: Arc) -> Result<()> { + // todo(linux): Remove this once the cross-platform LiveKit implementation is merged + #[cfg(any(test, feature = "test-support"))] self.executor.simulate_random_delay().await; let claims = live_kit_server::token::validate(&token, &self.secret_key)?; - let identity = ParticipantIdentity(claims.sub.unwrap().to_string()); + let identity = claims.sub.unwrap().to_string(); let room_name = claims.video.room.unwrap(); let mut server_rooms = self.rooms.lock(); let room = (*server_rooms).entry(room_name.to_string()).or_default(); if let Entry::Vacant(e) = room.client_rooms.entry(identity.clone()) { - for server_track in &room.video_tracks { - let track = RemoteTrack::Video(RemoteVideoTrack { - server_track: server_track.clone(), - _room: client_room.downgrade(), - }); + for track in &room.video_tracks { client_room .0 .lock() .updates_tx - .blocking_send(RoomEvent::TrackSubscribed { - track: track.clone(), - publication: RemoteTrackPublication { - sid: server_track.sid.clone(), - room: client_room.downgrade(), - track, + .try_broadcast(RoomUpdate::SubscribedToRemoteVideoTrack(Arc::new( + RemoteVideoTrack { + server_track: track.clone(), }, - participant: RemoteParticipant { - room: client_room.downgrade(), - identity: server_track.publisher_id.clone(), - }, - }) + ))) .unwrap(); } - for server_track in &room.audio_tracks { - let track = RemoteTrack::Audio(RemoteAudioTrack { - server_track: server_track.clone(), - room: client_room.downgrade(), - }); + for track in &room.audio_tracks { client_room .0 .lock() .updates_tx - .blocking_send(RoomEvent::TrackSubscribed { - track: track.clone(), - publication: RemoteTrackPublication { - sid: server_track.sid.clone(), - room: client_room.downgrade(), - track, - }, - participant: RemoteParticipant { - room: client_room.downgrade(), - identity: server_track.publisher_id.clone(), - }, - }) + .try_broadcast(RoomUpdate::SubscribedToRemoteAudioTrack( + Arc::new(RemoteAudioTrack { + server_track: track.clone(), + room: Arc::downgrade(&client_room), + }), + Arc::new(RemoteTrackPublication), + )) .unwrap(); } e.insert(client_room); - Ok(identity) + Ok(()) } else { Err(anyhow!( "{:?} attempted to join room {:?} twice", @@ -172,10 +147,11 @@ impl TestServer { } async fn leave_room(&self, token: String) -> Result<()> { + // todo(linux): Remove this once the cross-platform LiveKit implementation is merged + #[cfg(any(test, feature = "test-support"))] self.executor.simulate_random_delay().await; - let claims = live_kit_server::token::validate(&token, &self.secret_key)?; - let identity = ParticipantIdentity(claims.sub.unwrap().to_string()); + let identity = claims.sub.unwrap().to_string(); let room_name = claims.video.room.unwrap(); let mut server_rooms = self.rooms.lock(); let room = server_rooms @@ -191,44 +167,10 @@ impl TestServer { Ok(()) } - fn remote_participants( - &self, - token: String, - ) -> Result> { - let claims = live_kit_server::token::validate(&token, &self.secret_key)?; - let local_identity = ParticipantIdentity(claims.sub.unwrap().to_string()); - let room_name = claims.video.room.unwrap().to_string(); - - if let Some(server_room) = self.rooms.lock().get(&room_name) { - let room = server_room - .client_rooms - .get(&local_identity) - .unwrap() - .downgrade(); - Ok(server_room - .client_rooms - .iter() - .filter(|(identity, _)| *identity != &local_identity) - .map(|(identity, _)| { - ( - identity.clone(), - RemoteParticipant { - room: room.clone(), - identity: identity.clone(), - }, - ) - }) - .collect()) - } else { - Ok(Default::default()) - } - } - - async fn remove_participant( - &self, - room_name: String, - identity: ParticipantIdentity, - ) -> Result<()> { + async fn remove_participant(&self, room_name: String, identity: String) -> Result<()> { + // TODO: clear state associated with the `Room`. + // todo(linux): Remove this once the cross-platform LiveKit implementation is merged + #[cfg(any(test, feature = "test-support"))] self.executor.simulate_random_delay().await; let mut server_rooms = self.rooms.lock(); @@ -251,32 +193,25 @@ impl TestServer { identity: String, permission: proto::ParticipantPermission, ) -> Result<()> { + // todo(linux): Remove this once the cross-platform LiveKit implementation is merged + #[cfg(any(test, feature = "test-support"))] self.executor.simulate_random_delay().await; - let mut server_rooms = self.rooms.lock(); let room = server_rooms .get_mut(&room_name) .ok_or_else(|| anyhow!("room {} does not exist", room_name))?; - room.participant_permissions - .insert(ParticipantIdentity(identity), permission); + room.participant_permissions.insert(identity, permission); Ok(()) } pub async fn disconnect_client(&self, client_identity: String) { - let client_identity = ParticipantIdentity(client_identity); - + // todo(linux): Remove this once the cross-platform LiveKit implementation is merged + #[cfg(any(test, feature = "test-support"))] self.executor.simulate_random_delay().await; - let mut server_rooms = self.rooms.lock(); for room in server_rooms.values_mut() { if let Some(room) = room.client_rooms.remove(&client_identity) { - let mut room = room.0.lock(); - room.connection_state = ConnectionState::Disconnected; - room.updates_tx - .blocking_send(RoomEvent::Disconnected { - reason: DisconnectReason::SignalClose, - }) - .ok(); + *room.0.lock().connection.0.borrow_mut() = ConnectionState::Disconnected; } } } @@ -284,12 +219,13 @@ impl TestServer { async fn publish_video_track( &self, token: String, - _local_track: LocalVideoTrack, - ) -> Result { + local_track: LocalVideoTrack, + ) -> Result { + // todo(linux): Remove this once the cross-platform LiveKit implementation is merged + #[cfg(any(test, feature = "test-support"))] self.executor.simulate_random_delay().await; - let claims = live_kit_server::token::validate(&token, &self.secret_key)?; - let identity = ParticipantIdentity(claims.sub.unwrap().to_string()); + let identity = claims.sub.unwrap().to_string(); let room_name = claims.video.room.unwrap(); let mut server_rooms = self.rooms.lock(); @@ -308,38 +244,26 @@ impl TestServer { return Err(anyhow!("user is not allowed to publish")); } - let sid: TrackSid = format!("TR_{}", nanoid::nanoid!(17)).try_into().unwrap(); - let server_track = Arc::new(TestServerVideoTrack { + let sid = nanoid::nanoid!(17); + let track = Arc::new(TestServerVideoTrack { sid: sid.clone(), publisher_id: identity.clone(), + frames_rx: local_track.frames_rx.clone(), }); - room.video_tracks.push(server_track.clone()); + room.video_tracks.push(track.clone()); - for (room_identity, client_room) in &room.client_rooms { - if *room_identity != identity { - let track = RemoteTrack::Video(RemoteVideoTrack { - server_track: server_track.clone(), - _room: client_room.downgrade(), - }); - let publication = RemoteTrackPublication { - sid: sid.clone(), - room: client_room.downgrade(), - track: track.clone(), - }; - let participant = RemoteParticipant { - identity: identity.clone(), - room: client_room.downgrade(), - }; - client_room + for (id, client_room) in &room.client_rooms { + if *id != identity { + let _ = client_room .0 .lock() .updates_tx - .blocking_send(RoomEvent::TrackSubscribed { - track, - publication, - participant, - }) + .try_broadcast(RoomUpdate::SubscribedToRemoteVideoTrack(Arc::new( + RemoteVideoTrack { + server_track: track.clone(), + }, + ))) .unwrap(); } } @@ -351,11 +275,13 @@ impl TestServer { &self, token: String, _local_track: &LocalAudioTrack, - ) -> Result { + ) -> Result { + // todo(linux): Remove this once the cross-platform LiveKit implementation is merged + #[cfg(any(test, feature = "test-support"))] self.executor.simulate_random_delay().await; let claims = live_kit_server::token::validate(&token, &self.secret_key)?; - let identity = ParticipantIdentity(claims.sub.unwrap().to_string()); + let identity = claims.sub.unwrap().to_string(); let room_name = claims.video.room.unwrap(); let mut server_rooms = self.rooms.lock(); @@ -374,54 +300,41 @@ impl TestServer { return Err(anyhow!("user is not allowed to publish")); } - let sid: TrackSid = format!("TR_{}", nanoid::nanoid!(17)).try_into().unwrap(); - let server_track = Arc::new(TestServerAudioTrack { + let sid = nanoid::nanoid!(17); + let track = Arc::new(TestServerAudioTrack { sid: sid.clone(), publisher_id: identity.clone(), muted: AtomicBool::new(false), }); - room.audio_tracks.push(server_track.clone()); + let publication = Arc::new(RemoteTrackPublication); - for (room_identity, client_room) in &room.client_rooms { - if *room_identity != identity { - let track = RemoteTrack::Audio(RemoteAudioTrack { - server_track: server_track.clone(), - room: client_room.downgrade(), - }); - let publication = RemoteTrackPublication { - sid: sid.clone(), - room: client_room.downgrade(), - track: track.clone(), - }; - let participant = RemoteParticipant { - identity: identity.clone(), - room: client_room.downgrade(), - }; - client_room + room.audio_tracks.push(track.clone()); + + for (id, client_room) in &room.client_rooms { + if *id != identity { + let _ = client_room .0 .lock() .updates_tx - .blocking_send(RoomEvent::TrackSubscribed { - track, - publication, - participant, - }) - .ok(); + .try_broadcast(RoomUpdate::SubscribedToRemoteAudioTrack( + Arc::new(RemoteAudioTrack { + server_track: track.clone(), + room: Arc::downgrade(client_room), + }), + publication.clone(), + )) + .unwrap(); } } Ok(sid) } - async fn unpublish_track(&self, _token: String, _track: &TrackSid) -> Result<()> { - Ok(()) - } - - fn set_track_muted(&self, token: &str, track_sid: &TrackSid, muted: bool) -> Result<()> { - let claims = live_kit_server::token::validate(&token, &self.secret_key)?; + fn set_track_muted(&self, token: &str, track_sid: &str, muted: bool) -> Result<()> { + let claims = live_kit_server::token::validate(token, &self.secret_key)?; let room_name = claims.video.room.unwrap(); - let identity = ParticipantIdentity(claims.sub.unwrap().to_string()); + let identity = claims.sub.unwrap(); let mut server_rooms = self.rooms.lock(); let room = server_rooms .get_mut(&*room_name) @@ -429,42 +342,19 @@ impl TestServer { if let Some(track) = room .audio_tracks .iter_mut() - .find(|track| track.sid == *track_sid) + .find(|track| track.sid == track_sid) { track.muted.store(muted, SeqCst); for (id, client_room) in room.client_rooms.iter() { if *id != identity { - let participant = Participant::Remote(RemoteParticipant { - identity: identity.clone(), - room: client_room.downgrade(), - }); - let track = RemoteTrack::Audio(RemoteAudioTrack { - server_track: track.clone(), - room: client_room.downgrade(), - }); - let publication = TrackPublication::Remote(RemoteTrackPublication { - sid: track_sid.clone(), - room: client_room.downgrade(), - track, - }); - - let event = if muted { - RoomEvent::TrackMuted { - participant, - publication, - } - } else { - RoomEvent::TrackUnmuted { - participant, - publication, - } - }; - client_room .0 .lock() .updates_tx - .blocking_send(event) + .try_broadcast(RoomUpdate::RemoteAudioTrackMuteChanged { + track_id: track_sid.to_string(), + muted, + }) .unwrap(); } } @@ -472,14 +362,14 @@ impl TestServer { Ok(()) } - fn is_track_muted(&self, token: &str, track_sid: &TrackSid) -> Option { - let claims = live_kit_server::token::validate(&token, &self.secret_key).ok()?; + fn is_track_muted(&self, token: &str, track_sid: &str) -> Option { + let claims = live_kit_server::token::validate(token, &self.secret_key).ok()?; let room_name = claims.video.room.unwrap(); let mut server_rooms = self.rooms.lock(); let room = server_rooms.get_mut(&*room_name)?; room.audio_tracks.iter().find_map(|track| { - if track.sid == *track_sid { + if track.sid == track_sid { Some(track.muted.load(SeqCst)) } else { None @@ -487,33 +377,33 @@ impl TestServer { }) } - fn video_tracks(&self, token: String) -> Result> { + fn video_tracks(&self, token: String) -> Result>> { let claims = live_kit_server::token::validate(&token, &self.secret_key)?; let room_name = claims.video.room.unwrap(); - let identity = ParticipantIdentity(claims.sub.unwrap().to_string()); + let identity = claims.sub.unwrap(); let mut server_rooms = self.rooms.lock(); let room = server_rooms .get_mut(&*room_name) .ok_or_else(|| anyhow!("room {} does not exist", room_name))?; - let client_room = room - .client_rooms - .get(&identity) + room.client_rooms + .get(identity.as_ref()) .ok_or_else(|| anyhow!("not a participant in room"))?; Ok(room .video_tracks .iter() - .map(|track| RemoteVideoTrack { - server_track: track.clone(), - _room: client_room.downgrade(), + .map(|track| { + Arc::new(RemoteVideoTrack { + server_track: track.clone(), + }) }) .collect()) } - fn audio_tracks(&self, token: String) -> Result> { + fn audio_tracks(&self, token: String) -> Result>> { let claims = live_kit_server::token::validate(&token, &self.secret_key)?; let room_name = claims.video.room.unwrap(); - let identity = ParticipantIdentity(claims.sub.unwrap().to_string()); + let identity = claims.sub.unwrap(); let mut server_rooms = self.rooms.lock(); let room = server_rooms @@ -521,125 +411,49 @@ impl TestServer { .ok_or_else(|| anyhow!("room {} does not exist", room_name))?; let client_room = room .client_rooms - .get(&identity) + .get(identity.as_ref()) .ok_or_else(|| anyhow!("not a participant in room"))?; Ok(room .audio_tracks .iter() - .map(|track| RemoteAudioTrack { - server_track: track.clone(), - room: client_room.downgrade(), + .map(|track| { + Arc::new(RemoteAudioTrack { + server_track: track.clone(), + room: Arc::downgrade(client_room), + }) }) .collect()) } } -#[cfg(not(target_os = "windows"))] -#[derive(Default, Debug)] +#[derive(Default)] struct TestServerRoom { - client_rooms: HashMap, + client_rooms: HashMap>, video_tracks: Vec>, audio_tracks: Vec>, - participant_permissions: HashMap, + participant_permissions: HashMap, } -#[cfg(not(target_os = "windows"))] #[derive(Debug)] struct TestServerVideoTrack { - sid: TrackSid, - publisher_id: ParticipantIdentity, - // frames_rx: async_broadcast::Receiver, + sid: Sid, + publisher_id: Sid, + frames_rx: async_broadcast::Receiver, } -#[cfg(not(target_os = "windows"))] #[derive(Debug)] struct TestServerAudioTrack { - sid: TrackSid, - publisher_id: ParticipantIdentity, + sid: Sid, + publisher_id: Sid, muted: AtomicBool, } +impl TestServerRoom {} + pub struct TestApiClient { url: String, } -#[derive(Clone, Debug)] -#[non_exhaustive] -pub enum RoomEvent { - ParticipantConnected(RemoteParticipant), - ParticipantDisconnected(RemoteParticipant), - LocalTrackPublished { - publication: LocalTrackPublication, - track: LocalTrack, - participant: LocalParticipant, - }, - LocalTrackUnpublished { - publication: LocalTrackPublication, - participant: LocalParticipant, - }, - TrackSubscribed { - track: RemoteTrack, - publication: RemoteTrackPublication, - participant: RemoteParticipant, - }, - TrackUnsubscribed { - track: RemoteTrack, - publication: RemoteTrackPublication, - participant: RemoteParticipant, - }, - TrackSubscriptionFailed { - participant: RemoteParticipant, - error: String, - #[cfg(not(target_os = "windows"))] - track_sid: TrackSid, - }, - TrackPublished { - publication: RemoteTrackPublication, - participant: RemoteParticipant, - }, - TrackUnpublished { - publication: RemoteTrackPublication, - participant: RemoteParticipant, - }, - TrackMuted { - participant: Participant, - publication: TrackPublication, - }, - TrackUnmuted { - participant: Participant, - publication: TrackPublication, - }, - RoomMetadataChanged { - old_metadata: String, - metadata: String, - }, - ParticipantMetadataChanged { - participant: Participant, - old_metadata: String, - metadata: String, - }, - ParticipantNameChanged { - participant: Participant, - old_name: String, - name: String, - }, - ActiveSpeakersChanged { - speakers: Vec, - }, - #[cfg(not(target_os = "windows"))] - ConnectionStateChanged(ConnectionState), - Connected { - participants_with_tracks: Vec<(RemoteParticipant, Vec)>, - }, - #[cfg(not(target_os = "windows"))] - Disconnected { - reason: DisconnectReason, - }, - Reconnecting, - Reconnected, -} - -#[cfg(not(target_os = "windows"))] #[async_trait] impl live_kit_server::api::Client for TestApiClient { fn url(&self) -> &str { @@ -660,9 +474,7 @@ impl live_kit_server::api::Client for TestApiClient { async fn remove_participant(&self, room: String, identity: String) -> Result<()> { let server = TestServer::get(&self.url)?; - server - .remove_participant(room, ParticipantIdentity(identity)) - .await?; + server.remove_participant(room, identity).await?; Ok(()) } @@ -701,125 +513,370 @@ impl live_kit_server::api::Client for TestApiClient { } struct RoomState { - url: String, - token: String, - #[cfg(not(target_os = "windows"))] - local_identity: ParticipantIdentity, - #[cfg(not(target_os = "windows"))] - connection_state: ConnectionState, - #[cfg(not(target_os = "windows"))] - paused_audio_tracks: HashSet, - updates_tx: mpsc::Sender, + connection: ( + watch::Sender, + watch::Receiver, + ), + display_sources: Vec, + paused_audio_tracks: HashSet, + updates_tx: async_broadcast::Sender, + updates_rx: async_broadcast::Receiver, } -#[derive(Clone, Debug)] -pub struct Room(Arc>); +pub struct Room(Mutex); -#[derive(Clone, Debug)] -pub(crate) struct WeakRoom(Weak>); - -#[cfg(not(target_os = "windows"))] -impl std::fmt::Debug for RoomState { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("Room") - .field("url", &self.url) - .field("token", &self.token) - .field("local_identity", &self.local_identity) - .field("connection_state", &self.connection_state) - .field("paused_audio_tracks", &self.paused_audio_tracks) - .finish() - } -} - -#[cfg(target_os = "windows")] -impl std::fmt::Debug for RoomState { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("Room") - .field("url", &self.url) - .field("token", &self.token) - .finish() - } -} - -#[cfg(not(target_os = "windows"))] impl Room { - fn downgrade(&self) -> WeakRoom { - WeakRoom(Arc::downgrade(&self.0)) - } - - pub fn connection_state(&self) -> ConnectionState { - self.0.lock().connection_state - } - - pub fn local_participant(&self) -> LocalParticipant { - let identity = self.0.lock().local_identity.clone(); - LocalParticipant { - identity, - room: self.clone(), - } - } - - pub async fn connect( - url: &str, - token: &str, - _options: RoomOptions, - ) -> Result<(Self, mpsc::Receiver)> { - let server = TestServer::get(&url)?; - let (updates_tx, updates_rx) = mpsc::channel(1024); - let this = Self(Arc::new(Mutex::new(RoomState { - local_identity: ParticipantIdentity(String::new()), - url: url.to_string(), - token: token.to_string(), - connection_state: ConnectionState::Disconnected, + pub fn new() -> Arc { + let (updates_tx, updates_rx) = async_broadcast::broadcast(128); + Arc::new(Self(Mutex::new(RoomState { + connection: watch::channel_with(ConnectionState::Disconnected), + display_sources: Default::default(), paused_audio_tracks: Default::default(), updates_tx, - }))); - - let identity = server - .join_room(token.to_string(), this.clone()) - .await - .context("room join")?; - { - let mut state = this.0.lock(); - state.local_identity = identity; - state.connection_state = ConnectionState::Connected; - } - - Ok((this, updates_rx)) + updates_rx, + }))) } - pub fn remote_participants(&self) -> HashMap { + pub fn status(&self) -> watch::Receiver { + self.0.lock().connection.1.clone() + } + + pub fn connect(self: &Arc, url: &str, token: &str) -> impl Future> { + let this = self.clone(); + let url = url.to_string(); + let token = token.to_string(); + async move { + let server = TestServer::get(&url)?; + server + .join_room(token.clone(), this.clone()) + .await + .context("room join")?; + *this.0.lock().connection.0.borrow_mut() = ConnectionState::Connected { url, token }; + Ok(()) + } + } + + pub fn display_sources(self: &Arc) -> impl Future>> { + let this = self.clone(); + async move { + // todo(linux): Remove this once the cross-platform LiveKit implementation is merged + #[cfg(any(test, feature = "test-support"))] + { + let server = this.test_server(); + server.executor.simulate_random_delay().await; + } + + Ok(this.0.lock().display_sources.clone()) + } + } + + pub fn publish_video_track( + self: &Arc, + track: LocalVideoTrack, + ) -> impl Future> { + let this = self.clone(); + let track = track.clone(); + async move { + let sid = this + .test_server() + .publish_video_track(this.token(), track) + .await?; + Ok(LocalTrackPublication { + room: Arc::downgrade(&this), + sid, + }) + } + } + + pub fn publish_audio_track( + self: &Arc, + track: LocalAudioTrack, + ) -> impl Future> { + let this = self.clone(); + let track = track.clone(); + async move { + let sid = this + .test_server() + .publish_audio_track(this.token(), &track) + .await?; + Ok(LocalTrackPublication { + room: Arc::downgrade(&this), + sid, + }) + } + } + + pub fn unpublish_track(&self, _publication: LocalTrackPublication) {} + + pub fn remote_audio_tracks(&self, publisher_id: &str) -> Vec> { + if !self.is_connected() { + return Vec::new(); + } + self.test_server() - .remote_participants(self.0.lock().token.clone()) + .audio_tracks(self.token()) .unwrap() + .into_iter() + .filter(|track| track.publisher_id() == publisher_id) + .collect() + } + + pub fn remote_audio_track_publications( + &self, + publisher_id: &str, + ) -> Vec> { + if !self.is_connected() { + return Vec::new(); + } + + self.test_server() + .audio_tracks(self.token()) + .unwrap() + .into_iter() + .filter(|track| track.publisher_id() == publisher_id) + .map(|_track| Arc::new(RemoteTrackPublication {})) + .collect() + } + + pub fn remote_video_tracks(&self, publisher_id: &str) -> Vec> { + if !self.is_connected() { + return Vec::new(); + } + + self.test_server() + .video_tracks(self.token()) + .unwrap() + .into_iter() + .filter(|track| track.publisher_id() == publisher_id) + .collect() + } + + pub fn updates(&self) -> impl Stream { + self.0.lock().updates_rx.clone() + } + + pub fn set_display_sources(&self, sources: Vec) { + self.0.lock().display_sources = sources; } fn test_server(&self) -> Arc { - TestServer::get(&self.0.lock().url).unwrap() + match self.0.lock().connection.1.borrow().clone() { + ConnectionState::Disconnected => panic!("must be connected to call this method"), + ConnectionState::Connected { url, .. } => TestServer::get(&url).unwrap(), + } } fn token(&self) -> String { - self.0.lock().token.clone() + match self.0.lock().connection.1.borrow().clone() { + ConnectionState::Disconnected => panic!("must be connected to call this method"), + ConnectionState::Connected { token, .. } => token, + } + } + + fn is_connected(&self) -> bool { + match *self.0.lock().connection.1.borrow() { + ConnectionState::Disconnected => false, + ConnectionState::Connected { .. } => true, + } } } -#[cfg(not(target_os = "windows"))] -impl Drop for RoomState { +impl Drop for Room { fn drop(&mut self) { - if self.connection_state == ConnectionState::Connected { - if let Ok(server) = TestServer::get(&self.url) { + if let ConnectionState::Connected { token, .. } = mem::replace( + &mut *self.0.lock().connection.0.borrow_mut(), + ConnectionState::Disconnected, + ) { + if let Ok(server) = TestServer::get(&token) { let executor = server.executor.clone(); - let token = self.token.clone(); executor - .spawn(async move { server.leave_room(token).await.ok() }) + .spawn(async move { server.leave_room(token).await.unwrap() }) .detach(); } } } } -impl WeakRoom { - fn upgrade(&self) -> Option { - self.0.upgrade().map(Room) +#[derive(Clone)] +pub struct LocalTrackPublication { + sid: String, + room: Weak, +} + +impl LocalTrackPublication { + pub fn set_mute(&self, mute: bool) -> impl Future> { + let sid = self.sid.clone(); + let room = self.room.clone(); + async move { + if let Some(room) = room.upgrade() { + room.test_server() + .set_track_muted(&room.token(), &sid, mute) + } else { + Err(anyhow!("no such room")) + } + } + } + + pub fn is_muted(&self) -> bool { + if let Some(room) = self.room.upgrade() { + room.test_server() + .is_track_muted(&room.token(), &self.sid) + .unwrap_or(false) + } else { + false + } + } + + pub fn sid(&self) -> String { + self.sid.clone() + } +} + +pub struct RemoteTrackPublication; + +impl RemoteTrackPublication { + pub fn set_enabled(&self, _enabled: bool) -> impl Future> { + async { Ok(()) } + } + + pub fn is_muted(&self) -> bool { + false + } + + pub fn sid(&self) -> String { + "".to_string() + } +} + +#[derive(Clone)] +pub struct LocalVideoTrack { + frames_rx: async_broadcast::Receiver, +} + +impl LocalVideoTrack { + pub fn screen_share_for_display(display: &MacOSDisplay) -> Self { + Self { + frames_rx: display.frames.1.clone(), + } + } +} + +#[derive(Clone)] +pub struct LocalAudioTrack; + +impl LocalAudioTrack { + pub fn create() -> Self { + Self + } +} + +#[derive(Debug)] +pub struct RemoteVideoTrack { + server_track: Arc, +} + +impl RemoteVideoTrack { + pub fn sid(&self) -> &str { + &self.server_track.sid + } + + pub fn publisher_id(&self) -> &str { + &self.server_track.publisher_id + } + + pub fn frames(&self) -> async_broadcast::Receiver { + self.server_track.frames_rx.clone() + } +} + +#[derive(Debug)] +pub struct RemoteAudioTrack { + server_track: Arc, + room: Weak, +} + +impl RemoteAudioTrack { + pub fn sid(&self) -> &str { + &self.server_track.sid + } + + pub fn publisher_id(&self) -> &str { + &self.server_track.publisher_id + } + + pub fn start(&self) { + if let Some(room) = self.room.upgrade() { + room.0 + .lock() + .paused_audio_tracks + .remove(&self.server_track.sid); + } + } + + pub fn stop(&self) { + if let Some(room) = self.room.upgrade() { + room.0 + .lock() + .paused_audio_tracks + .insert(self.server_track.sid.clone()); + } + } + + pub fn is_playing(&self) -> bool { + !self + .room + .upgrade() + .unwrap() + .0 + .lock() + .paused_audio_tracks + .contains(&self.server_track.sid) + } +} + +#[derive(Clone)] +pub struct MacOSDisplay { + frames: ( + async_broadcast::Sender, + async_broadcast::Receiver, + ), +} + +impl Default for MacOSDisplay { + fn default() -> Self { + Self::new() + } +} + +impl MacOSDisplay { + pub fn new() -> Self { + Self { + frames: async_broadcast::broadcast(128), + } + } + + pub fn send_frame(&self, frame: Frame) { + self.frames.0.try_broadcast(frame).unwrap(); + } +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Frame { + pub label: String, + pub width: usize, + pub height: usize, +} + +impl Frame { + pub fn width(&self) -> usize { + self.width + } + + pub fn height(&self) -> usize { + self.height + } + + pub fn image(&self) -> SurfaceSource { + unimplemented!("you can't call this in test mode") } } diff --git a/crates/live_kit_client/src/test/participant.rs b/crates/live_kit_client/src/test/participant.rs deleted file mode 100644 index 8d476b1537..0000000000 --- a/crates/live_kit_client/src/test/participant.rs +++ /dev/null @@ -1,111 +0,0 @@ -use super::*; - -#[derive(Clone, Debug)] -pub enum Participant { - Local(LocalParticipant), - Remote(RemoteParticipant), -} - -#[derive(Clone, Debug)] -pub struct LocalParticipant { - #[cfg(not(target_os = "windows"))] - pub(super) identity: ParticipantIdentity, - pub(super) room: Room, -} - -#[derive(Clone, Debug)] -pub struct RemoteParticipant { - #[cfg(not(target_os = "windows"))] - pub(super) identity: ParticipantIdentity, - pub(super) room: WeakRoom, -} - -#[cfg(not(target_os = "windows"))] -impl Participant { - pub fn identity(&self) -> ParticipantIdentity { - match self { - Participant::Local(participant) => participant.identity.clone(), - Participant::Remote(participant) => participant.identity.clone(), - } - } -} - -#[cfg(not(target_os = "windows"))] -impl LocalParticipant { - pub async fn unpublish_track(&self, track: &TrackSid) -> Result<()> { - self.room - .test_server() - .unpublish_track(self.room.token(), track) - .await - } - - pub async fn publish_track( - &self, - track: LocalTrack, - _options: TrackPublishOptions, - ) -> Result { - let this = self.clone(); - let track = track.clone(); - let server = this.room.test_server(); - let sid = match track { - LocalTrack::Video(track) => { - server.publish_video_track(this.room.token(), track).await? - } - LocalTrack::Audio(track) => { - server - .publish_audio_track(this.room.token(), &track) - .await? - } - }; - Ok(LocalTrackPublication { - room: self.room.downgrade(), - sid, - }) - } -} - -#[cfg(not(target_os = "windows"))] -impl RemoteParticipant { - pub fn track_publications(&self) -> HashMap { - if let Some(room) = self.room.upgrade() { - let server = room.test_server(); - let audio = server - .audio_tracks(room.token()) - .unwrap() - .into_iter() - .filter(|track| track.publisher_id() == self.identity) - .map(|track| { - ( - track.sid(), - RemoteTrackPublication { - sid: track.sid(), - room: self.room.clone(), - track: RemoteTrack::Audio(track), - }, - ) - }); - let video = server - .video_tracks(room.token()) - .unwrap() - .into_iter() - .filter(|track| track.publisher_id() == self.identity) - .map(|track| { - ( - track.sid(), - RemoteTrackPublication { - sid: track.sid(), - room: self.room.clone(), - track: RemoteTrack::Video(track), - }, - ) - }); - audio.chain(video).collect() - } else { - HashMap::default() - } - } - - pub fn identity(&self) -> ParticipantIdentity { - self.identity.clone() - } -} diff --git a/crates/live_kit_client/src/test/publication.rs b/crates/live_kit_client/src/test/publication.rs deleted file mode 100644 index 6a3dfa0a51..0000000000 --- a/crates/live_kit_client/src/test/publication.rs +++ /dev/null @@ -1,116 +0,0 @@ -use super::*; - -#[derive(Clone, Debug)] -pub enum TrackPublication { - Local(LocalTrackPublication), - Remote(RemoteTrackPublication), -} - -#[derive(Clone, Debug)] -pub struct LocalTrackPublication { - #[cfg(not(target_os = "windows"))] - pub(crate) sid: TrackSid, - pub(crate) room: WeakRoom, -} - -#[derive(Clone, Debug)] -pub struct RemoteTrackPublication { - #[cfg(not(target_os = "windows"))] - pub(crate) sid: TrackSid, - pub(crate) room: WeakRoom, - pub(crate) track: RemoteTrack, -} - -#[cfg(not(target_os = "windows"))] -impl TrackPublication { - pub fn sid(&self) -> TrackSid { - match self { - TrackPublication::Local(track) => track.sid(), - TrackPublication::Remote(track) => track.sid(), - } - } - - pub fn is_muted(&self) -> bool { - match self { - TrackPublication::Local(track) => track.is_muted(), - TrackPublication::Remote(track) => track.is_muted(), - } - } -} - -#[cfg(not(target_os = "windows"))] -impl LocalTrackPublication { - pub fn sid(&self) -> TrackSid { - self.sid.clone() - } - - pub fn mute(&self) { - self.set_mute(true) - } - - pub fn unmute(&self) { - self.set_mute(false) - } - - fn set_mute(&self, mute: bool) { - if let Some(room) = self.room.upgrade() { - room.test_server() - .set_track_muted(&room.token(), &self.sid, mute) - .ok(); - } - } - - pub fn is_muted(&self) -> bool { - if let Some(room) = self.room.upgrade() { - room.test_server() - .is_track_muted(&room.token(), &self.sid) - .unwrap_or(false) - } else { - false - } - } -} - -#[cfg(not(target_os = "windows"))] -impl RemoteTrackPublication { - pub fn sid(&self) -> TrackSid { - self.sid.clone() - } - - pub fn track(&self) -> Option { - Some(self.track.clone()) - } - - pub fn kind(&self) -> TrackKind { - self.track.kind() - } - - pub fn is_muted(&self) -> bool { - if let Some(room) = self.room.upgrade() { - room.test_server() - .is_track_muted(&room.token(), &self.sid) - .unwrap_or(false) - } else { - false - } - } - - pub fn is_enabled(&self) -> bool { - if let Some(room) = self.room.upgrade() { - !room.0.lock().paused_audio_tracks.contains(&self.sid) - } else { - false - } - } - - pub fn set_enabled(&self, enabled: bool) { - if let Some(room) = self.room.upgrade() { - let paused_audio_tracks = &mut room.0.lock().paused_audio_tracks; - if enabled { - paused_audio_tracks.remove(&self.sid); - } else { - paused_audio_tracks.insert(self.sid.clone()); - } - } - } -} diff --git a/crates/live_kit_client/src/test/track.rs b/crates/live_kit_client/src/test/track.rs deleted file mode 100644 index 302177a10a..0000000000 --- a/crates/live_kit_client/src/test/track.rs +++ /dev/null @@ -1,201 +0,0 @@ -use super::*; -#[cfg(not(windows))] -use webrtc::{audio_source::RtcAudioSource, video_source::RtcVideoSource}; - -#[cfg(not(windows))] -pub use livekit::track::{TrackKind, TrackSource}; - -#[derive(Clone, Debug)] -pub enum LocalTrack { - Audio(LocalAudioTrack), - Video(LocalVideoTrack), -} - -#[derive(Clone, Debug)] -pub enum RemoteTrack { - Audio(RemoteAudioTrack), - Video(RemoteVideoTrack), -} - -#[derive(Clone, Debug)] -pub struct LocalVideoTrack {} - -#[derive(Clone, Debug)] -pub struct LocalAudioTrack {} - -#[derive(Clone, Debug)] -pub struct RemoteVideoTrack { - #[cfg(not(target_os = "windows"))] - pub(super) server_track: Arc, - pub(super) _room: WeakRoom, -} - -#[derive(Clone, Debug)] -pub struct RemoteAudioTrack { - #[cfg(not(target_os = "windows"))] - pub(super) server_track: Arc, - pub(super) room: WeakRoom, -} - -pub enum RtcTrack { - Audio(RtcAudioTrack), - Video(RtcVideoTrack), -} - -pub struct RtcAudioTrack { - #[cfg(not(target_os = "windows"))] - pub(super) server_track: Arc, - pub(super) room: WeakRoom, -} - -pub struct RtcVideoTrack { - #[cfg(not(target_os = "windows"))] - pub(super) _server_track: Arc, -} - -#[cfg(not(target_os = "windows"))] -impl RemoteTrack { - pub fn sid(&self) -> TrackSid { - match self { - RemoteTrack::Audio(track) => track.sid(), - RemoteTrack::Video(track) => track.sid(), - } - } - - pub fn kind(&self) -> TrackKind { - match self { - RemoteTrack::Audio(_) => TrackKind::Audio, - RemoteTrack::Video(_) => TrackKind::Video, - } - } - - pub fn publisher_id(&self) -> ParticipantIdentity { - match self { - RemoteTrack::Audio(track) => track.publisher_id(), - RemoteTrack::Video(track) => track.publisher_id(), - } - } - - pub fn rtc_track(&self) -> RtcTrack { - match self { - RemoteTrack::Audio(track) => RtcTrack::Audio(track.rtc_track()), - RemoteTrack::Video(track) => RtcTrack::Video(track.rtc_track()), - } - } -} - -#[cfg(not(windows))] -impl LocalVideoTrack { - pub fn create_video_track(_name: &str, _source: RtcVideoSource) -> Self { - Self {} - } -} - -#[cfg(not(windows))] -impl LocalAudioTrack { - pub fn create_audio_track(_name: &str, _source: RtcAudioSource) -> Self { - Self {} - } -} - -#[cfg(not(target_os = "windows"))] -impl RemoteAudioTrack { - pub fn sid(&self) -> TrackSid { - self.server_track.sid.clone() - } - - pub fn publisher_id(&self) -> ParticipantIdentity { - self.server_track.publisher_id.clone() - } - - pub fn start(&self) { - if let Some(room) = self.room.upgrade() { - room.0 - .lock() - .paused_audio_tracks - .remove(&self.server_track.sid); - } - } - - pub fn stop(&self) { - if let Some(room) = self.room.upgrade() { - room.0 - .lock() - .paused_audio_tracks - .insert(self.server_track.sid.clone()); - } - } - - pub fn rtc_track(&self) -> RtcAudioTrack { - RtcAudioTrack { - server_track: self.server_track.clone(), - room: self.room.clone(), - } - } -} - -#[cfg(not(target_os = "windows"))] -impl RemoteVideoTrack { - pub fn sid(&self) -> TrackSid { - self.server_track.sid.clone() - } - - pub fn publisher_id(&self) -> ParticipantIdentity { - self.server_track.publisher_id.clone() - } - - pub fn rtc_track(&self) -> RtcVideoTrack { - RtcVideoTrack { - _server_track: self.server_track.clone(), - } - } -} - -#[cfg(not(target_os = "windows"))] -impl RtcTrack { - pub fn enabled(&self) -> bool { - match self { - RtcTrack::Audio(track) => track.enabled(), - RtcTrack::Video(track) => track.enabled(), - } - } - - pub fn set_enabled(&self, enabled: bool) { - match self { - RtcTrack::Audio(track) => track.set_enabled(enabled), - RtcTrack::Video(_) => {} - } - } -} - -#[cfg(not(target_os = "windows"))] -impl RtcAudioTrack { - pub fn set_enabled(&self, enabled: bool) { - if let Some(room) = self.room.upgrade() { - let paused_audio_tracks = &mut room.0.lock().paused_audio_tracks; - if enabled { - paused_audio_tracks.remove(&self.server_track.sid); - } else { - paused_audio_tracks.insert(self.server_track.sid.clone()); - } - } - } - - pub fn enabled(&self) -> bool { - if let Some(room) = self.room.upgrade() { - !room - .0 - .lock() - .paused_audio_tracks - .contains(&self.server_track.sid) - } else { - false - } - } -} - -impl RtcVideoTrack { - pub fn enabled(&self) -> bool { - true - } -} diff --git a/crates/live_kit_client/src/test/webrtc.rs b/crates/live_kit_client/src/test/webrtc.rs deleted file mode 100644 index 6ac06e0484..0000000000 --- a/crates/live_kit_client/src/test/webrtc.rs +++ /dev/null @@ -1,136 +0,0 @@ -use super::track::{RtcAudioTrack, RtcVideoTrack}; -use futures::Stream; -use livekit::webrtc as real; -use std::{ - pin::Pin, - task::{Context, Poll}, -}; - -pub mod video_stream { - use super::*; - - pub mod native { - use super::*; - use real::video_frame::BoxVideoFrame; - - pub struct NativeVideoStream { - pub track: RtcVideoTrack, - } - - impl NativeVideoStream { - pub fn new(track: RtcVideoTrack) -> Self { - Self { track } - } - } - - impl Stream for NativeVideoStream { - type Item = BoxVideoFrame; - - fn poll_next(self: Pin<&mut Self>, _cx: &mut Context) -> Poll> { - Poll::Pending - } - } - } -} - -pub mod audio_stream { - use super::*; - - pub mod native { - use super::*; - use real::audio_frame::AudioFrame; - - pub struct NativeAudioStream { - pub track: RtcAudioTrack, - } - - impl NativeAudioStream { - pub fn new(track: RtcAudioTrack, _sample_rate: i32, _num_channels: i32) -> Self { - Self { track } - } - } - - impl Stream for NativeAudioStream { - type Item = AudioFrame<'static>; - - fn poll_next(self: Pin<&mut Self>, _cx: &mut Context) -> Poll> { - Poll::Pending - } - } - } -} - -pub mod audio_source { - use super::*; - - pub use real::audio_source::AudioSourceOptions; - - pub mod native { - use std::sync::Arc; - - use super::*; - use real::{audio_frame::AudioFrame, RtcError}; - - #[derive(Clone)] - pub struct NativeAudioSource { - pub options: Arc, - pub sample_rate: u32, - pub num_channels: u32, - } - - impl NativeAudioSource { - pub fn new( - options: AudioSourceOptions, - sample_rate: u32, - num_channels: u32, - _queue_size_ms: u32, - ) -> Self { - Self { - options: Arc::new(options), - sample_rate, - num_channels, - } - } - - pub async fn capture_frame(&self, _frame: &AudioFrame<'_>) -> Result<(), RtcError> { - Ok(()) - } - } - } - - pub enum RtcAudioSource { - Native(native::NativeAudioSource), - } -} - -pub use livekit::webrtc::audio_frame; -pub use livekit::webrtc::video_frame; - -pub mod video_source { - use super::*; - pub use real::video_source::VideoResolution; - - pub struct RTCVideoSource; - - pub mod native { - use super::*; - use real::video_frame::{VideoBuffer, VideoFrame}; - - #[derive(Clone)] - pub struct NativeVideoSource { - pub resolution: VideoResolution, - } - - impl NativeVideoSource { - pub fn new(resolution: super::VideoResolution) -> Self { - Self { resolution } - } - - pub fn capture_frame>(&self, _frame: &VideoFrame) {} - } - } - - pub enum RtcVideoSource { - Native(native::NativeVideoSource), - } -} diff --git a/crates/media/Cargo.toml b/crates/media/Cargo.toml index 70478eeb75..92940d1c52 100644 --- a/crates/media/Cargo.toml +++ b/crates/media/Cargo.toml @@ -17,7 +17,6 @@ anyhow.workspace = true [target.'cfg(target_os = "macos")'.dependencies] core-foundation.workspace = true -ctor.workspace = true foreign-types = "0.5" metal = "0.29" objc = "0.2" diff --git a/crates/media/src/media.rs b/crates/media/src/media.rs index 3f55475589..8757249c31 100644 --- a/crates/media/src/media.rs +++ b/crates/media/src/media.rs @@ -253,14 +253,11 @@ pub mod core_media { } } - pub fn image_buffer(&self) -> Option { + pub fn image_buffer(&self) -> CVImageBuffer { unsafe { - let ptr = CMSampleBufferGetImageBuffer(self.as_concrete_TypeRef()); - if ptr.is_null() { - None - } else { - Some(CVImageBuffer::wrap_under_get_rule(ptr)) - } + CVImageBuffer::wrap_under_get_rule(CMSampleBufferGetImageBuffer( + self.as_concrete_TypeRef(), + )) } } diff --git a/crates/title_bar/src/collab.rs b/crates/title_bar/src/collab.rs index f043194a03..805c0e7202 100644 --- a/crates/title_bar/src/collab.rs +++ b/crates/title_bar/src/collab.rs @@ -296,9 +296,9 @@ impl TitleBar { let is_muted = room.is_muted(); let is_deafened = room.is_deafened().unwrap_or(false); let is_screen_sharing = room.is_screen_sharing(); - let can_use_microphone = room.can_use_microphone(cx); + let can_use_microphone = room.can_use_microphone(); let can_share_projects = room.can_share_projects(); - let screen_sharing_supported = match self.platform_style { + let platform_supported = match self.platform_style { PlatformStyle::Mac => true, PlatformStyle::Linux | PlatformStyle::Windows => false, }; @@ -365,7 +365,9 @@ impl TitleBar { ) .tooltip(move |cx| { Tooltip::text( - if is_muted { + if !platform_supported { + "Cannot share microphone" + } else if is_muted { "Unmute microphone" } else { "Mute microphone" @@ -375,45 +377,56 @@ impl TitleBar { }) .style(ButtonStyle::Subtle) .icon_size(IconSize::Small) - .selected(is_muted) + .selected(platform_supported && is_muted) + .disabled(!platform_supported) .selected_style(ButtonStyle::Tinted(TintColor::Negative)) .on_click(move |_, cx| { toggle_mute(&Default::default(), cx); }) .into_any_element(), ); - - children.push( - IconButton::new( - "mute-sound", - if is_deafened { - ui::IconName::AudioOff - } else { - ui::IconName::AudioOn - }, - ) - .style(ButtonStyle::Subtle) - .selected_style(ButtonStyle::Tinted(TintColor::Negative)) - .icon_size(IconSize::Small) - .selected(is_deafened) - .tooltip(move |cx| { - Tooltip::with_meta("Deafen Audio", None, "Mic will be muted", cx) - }) - .on_click(move |_, cx| toggle_deafen(&Default::default(), cx)) - .into_any_element(), - ); } - if screen_sharing_supported { + children.push( + IconButton::new( + "mute-sound", + if is_deafened { + ui::IconName::AudioOff + } else { + ui::IconName::AudioOn + }, + ) + .style(ButtonStyle::Subtle) + .selected_style(ButtonStyle::Tinted(TintColor::Negative)) + .icon_size(IconSize::Small) + .selected(is_deafened) + .disabled(!platform_supported) + .tooltip(move |cx| { + if !platform_supported { + Tooltip::text("Cannot share microphone", cx) + } else if can_use_microphone { + Tooltip::with_meta("Deafen Audio", None, "Mic will be muted", cx) + } else { + Tooltip::text("Deafen Audio", cx) + } + }) + .on_click(move |_, cx| toggle_deafen(&Default::default(), cx)) + .into_any_element(), + ); + + if can_share_projects { children.push( IconButton::new("screen-share", ui::IconName::Screen) .style(ButtonStyle::Subtle) .icon_size(IconSize::Small) .selected(is_screen_sharing) + .disabled(!platform_supported) .selected_style(ButtonStyle::Tinted(TintColor::Accent)) .tooltip(move |cx| { Tooltip::text( - if is_screen_sharing { + if !platform_supported { + "Cannot share screen" + } else if is_screen_sharing { "Stop Sharing Screen" } else { "Share Screen" diff --git a/crates/workspace/src/shared_screen.rs b/crates/workspace/src/shared_screen.rs index 285946cce0..59df859488 100644 --- a/crates/workspace/src/shared_screen.rs +++ b/crates/workspace/src/shared_screen.rs @@ -2,13 +2,16 @@ use crate::{ item::{Item, ItemEvent}, ItemNavHistory, WorkspaceId, }; -use call::{RemoteVideoTrack, RemoteVideoTrackView}; +use anyhow::Result; +use call::participant::{Frame, RemoteVideoTrack}; use client::{proto::PeerId, User}; +use futures::StreamExt; use gpui::{ - div, AppContext, EventEmitter, FocusHandle, FocusableView, InteractiveElement, ParentElement, - Render, SharedString, Styled, View, ViewContext, VisualContext, WindowContext, + div, surface, AppContext, EventEmitter, FocusHandle, FocusableView, InteractiveElement, + ParentElement, Render, SharedString, Styled, Task, View, ViewContext, VisualContext, + WindowContext, }; -use std::sync::Arc; +use std::sync::{Arc, Weak}; use ui::{prelude::*, Icon, IconName}; pub enum Event { @@ -16,30 +19,40 @@ pub enum Event { } pub struct SharedScreen { + track: Weak, + frame: Option, pub peer_id: PeerId, user: Arc, nav_history: Option, - view: View, + _maintain_frame: Task>, focus: FocusHandle, } impl SharedScreen { pub fn new( - track: RemoteVideoTrack, + track: &Arc, peer_id: PeerId, user: Arc, cx: &mut ViewContext, ) -> Self { - let view = cx.new_view(|cx| RemoteVideoTrackView::new(track.clone(), cx)); - cx.subscribe(&view, |_, _, ev, cx| match ev { - call::RemoteVideoTrackViewEvent::Close => cx.emit(Event::Close), - }) - .detach(); + cx.focus_handle(); + let mut frames = track.frames(); Self { - view, + track: Arc::downgrade(track), + frame: None, peer_id, user, nav_history: Default::default(), + _maintain_frame: cx.spawn(|this, mut cx| async move { + while let Some(frame) = frames.next().await { + this.update(&mut cx, |this, cx| { + this.frame = Some(frame); + cx.notify(); + })?; + } + this.update(&mut cx, |_, cx| cx.emit(Event::Close))?; + Ok(()) + }), focus: cx.focus_handle(), } } @@ -59,7 +72,11 @@ impl Render for SharedScreen { .track_focus(&self.focus) .key_context("SharedScreen") .size_full() - .child(self.view.clone()) + .children( + self.frame + .as_ref() + .map(|frame| surface(frame.image()).size_full()), + ) } } @@ -97,13 +114,8 @@ impl Item for SharedScreen { _workspace_id: Option, cx: &mut ViewContext, ) -> Option> { - Some(cx.new_view(|cx| Self { - view: self.view.update(cx, |view, cx| view.clone(cx)), - peer_id: self.peer_id, - user: self.user.clone(), - nav_history: Default::default(), - focus: cx.focus_handle(), - })) + let track = self.track.upgrade()?; + Some(cx.new_view(|cx| Self::new(&track, self.peer_id, self.user.clone(), cx))) } fn to_item_events(event: &Self::Event, mut f: impl FnMut(ItemEvent)) { diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 31089f7882..833a8b15a0 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -3939,17 +3939,6 @@ impl Workspace { None } - #[cfg(target_os = "windows")] - fn shared_screen_for_peer( - &self, - _peer_id: PeerId, - _pane: &View, - _cx: &mut WindowContext, - ) -> Option> { - None - } - - #[cfg(not(target_os = "windows"))] fn shared_screen_for_peer( &self, peer_id: PeerId, @@ -3968,7 +3957,7 @@ impl Workspace { } } - Some(cx.new_view(|cx| SharedScreen::new(track, peer_id, user.clone(), cx))) + Some(cx.new_view(|cx| SharedScreen::new(&track, peer_id, user.clone(), cx))) } pub fn on_window_activation_changed(&mut self, cx: &mut ViewContext) {