Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
3c87f5f
feat: commit initial data streams v2 implementation
1egoman Jun 26, 2026
f135aa5
fix: Create data_streams_v2.md
1egoman Jun 26, 2026
b330aea
fix: remove ClientCapability from prelude
1egoman Jul 1, 2026
2888a0a
feat: allow data stream compress option to be toggled via livekit-ffi
1egoman Jul 1, 2026
02df9da
fix: run cargo fmt
1egoman Jul 1, 2026
5e38e18
generated protobuf
github-actions[bot] Jul 1, 2026
4321e31
fix: address toc-tou issue with decompressor state
1egoman Jul 1, 2026
61c6c9e
fix: cleanup data stream v2 test fixture initialization
1egoman Jul 1, 2026
6209bc7
feat: make client capabilities proto deserialization use TryFrom
1egoman Jul 1, 2026
2c85219
fix: run cargo fmt
1egoman Jul 1, 2026
28e7b77
fix: remove dead code
1egoman Jul 1, 2026
040b0e6
generated protobuf
github-actions[bot] Jul 1, 2026
cf79cc6
fix: downgrade protocol to before data track schema metadata
1egoman Jul 1, 2026
9a87b66
refactor: convert data stream open tuple to struct and add is_compres…
1egoman Jul 1, 2026
3630dbe
feat: add is_compressed / is_inline to ByteStreamInfo / TextStreamInfo
1egoman Jul 1, 2026
1d29c7c
Revert "refactor: convert data stream open tuple to struct and add is…
1egoman Jul 1, 2026
1f31fb5
feat: explicitly check is_compressed / is_inline in e2e tests
1egoman Jul 1, 2026
1c94ab5
fix: add e2e test that tests compress=false path
1egoman Jul 1, 2026
434ae6f
feat: add e2e feature on compressed / inline fields
1egoman Jul 1, 2026
f6dcba9
feat: get random bytes e2e test to pass by using much higher quality …
1egoman Jul 1, 2026
043342a
refactor: move RemoteParticipantRegistry to participant/registry.rs
1egoman Jul 2, 2026
96427be
refactor: restructure send_text / send_bytes
1egoman Jul 2, 2026
a9517db
feat: throw error when remove participant disconnects halfway through…
1egoman Jul 2, 2026
8017b70
fix: adjust send_text / send_bytes to make the disambiguation between…
1egoman Jul 2, 2026
cbc3d1e
fix: clean up incoming stream manager
1egoman Jul 2, 2026
9ae07ee
fix: preload buffer length
1egoman Jul 2, 2026
b16440d
fix: add reason labels on e2e test assertions
1egoman Jul 2, 2026
7d9c827
refactor: depend on livekit_common::RemoteParticipantRegistry
1egoman Jul 2, 2026
ec2f0c7
fix: remove arc wrapping around reserved_topics
1egoman Jul 6, 2026
4d96df6
refactor: rename is_topic_internal -> is_internal_topic, is_stream_in…
1egoman Jul 6, 2026
1e0f40b
refactor: split up livekit-data-stream crate into multiple smaller mo…
1egoman Jul 6, 2026
9dbf2a1
fix: run cargo fmt
1egoman Jul 6, 2026
880dda1
fix: add missing OperationType reexport
1egoman Jul 6, 2026
1cf1a34
refactor: make pseudo_random_text easier to understand
1egoman Jul 6, 2026
1ea2ccf
fix: run cargo fmt
1egoman Jul 6, 2026
5c166f8
fix: drop recv_reader
1egoman Jul 6, 2026
67cb6a3
fix: add MaybeCompressed docstring
1egoman Jul 6, 2026
d0cbfc3
refactor: reformat somewhat_compressible to use rand
1egoman Jul 6, 2026
b0ffd9e
Revert "refactor: drop unused ClientCapability, RemoteParticipantRegi…
1egoman Jul 8, 2026
73e7afd
Revert "refactor: merge livekit-data-stream __e2e-test feature into t…
1egoman Jul 8, 2026
ad00257
fix: drop duplicate outgoing test helpers introduced by rebase merge
1egoman Jul 8, 2026
1902c2a
refactor: use livekit_common::enum_dispatch in data-stream info dispatch
1egoman Jul 8, 2026
7960420
feat: add async-compression and thread it through via the new MaybeCo…
1egoman Jul 8, 2026
cffaf36
feat: add new local struct / enum layer in livekit-data-stream mirror…
1egoman Jul 9, 2026
c95bd3f
refactor: port outgoing data stream manager to use new packet types
1egoman Jul 9, 2026
0df6add
feat: convert incoming data stream manager to actor
1egoman Jul 9, 2026
05ad3b5
fix: address typos in test only data stream fields
1egoman Jul 9, 2026
44c6bce
refactor: rename {Incoming,Outgoing}StreamManager -> *DataStreamManager
1egoman Jul 9, 2026
2552a56
fix: run cargo fmt
1egoman Jul 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .changeset/data_streams_v2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
livekit: patch
livekit-api: patch
livekit-datatrack: patch
livekit-ffi: patch
livekit-protocol: patch
livekit-uniffi: patch
---

Add data streams v2 - #1192 (@1egoman)
41 changes: 37 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 12 additions & 5 deletions livekit-api/src/signal_client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,21 @@
pub const PROTOCOL_VERSION: u32 = 17;

/// Capabilities the Rust SDK advertises to the SFU at connect time.
const CLIENT_CAPABILITIES: &[proto::client_info::Capability] =
&[proto::client_info::Capability::CapPacketTrailer];

pub use livekit_common::{CLIENT_PROTOCOL_DATA_STREAM_RPC, CLIENT_PROTOCOL_DEFAULT};
///
/// `CapCompressionDeflateRaw` is always advertised because the SDK's deflate-raw codec
/// (flate2/miniz_oxide) is pure-Rust and compiled in unconditionally.
const CLIENT_CAPABILITIES: &[proto::client_info::Capability] = &[
proto::client_info::Capability::CapPacketTrailer,
proto::client_info::Capability::CapCompressionDeflateRaw,
];

pub use livekit_common::{
CLIENT_PROTOCOL_DATA_STREAM_RPC, CLIENT_PROTOCOL_DATA_STREAM_V2, CLIENT_PROTOCOL_DEFAULT,
};

/// The client protocol which is sent to other clients and indicates the set of apis that other
/// clients should assume this client supports.
const CLIENT_PROTOCOL_VERSION: i32 = CLIENT_PROTOCOL_DATA_STREAM_RPC;
const CLIENT_PROTOCOL_VERSION: i32 = CLIENT_PROTOCOL_DATA_STREAM_V2;

#[derive(Error, Debug)]
pub enum SignalError {
Expand Down Expand Up @@ -1013,7 +1020,7 @@
/// in `send`. The stream slot is None so any actual write would be dropped,
/// which is fine — these tests only assert which side of the queue each
/// message lands on.
fn make_stub_inner() -> Arc<SignalInner> {

Check warning on line 1023 in livekit-api/src/signal_client/mod.rs

View workflow job for this annotation

GitHub Actions / livekit-api (signal-client (async), cargo test -p livekit-api --no-default-features --features si...

function `make_stub_inner` is never used
Arc::new(SignalInner {
stream: AsyncRwLock::new(None),
token: Mutex::new(String::new()),
Expand Down
69 changes: 68 additions & 1 deletion livekit-common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
// limitations under the License.

//! Foundational types shared across LiveKit crates: participant identities, the
//! encryption enum, and client-protocol constants.
//! encryption/capability enums, client-protocol constants, and the remote-participant
//! registry trait consulted by the data-stream and RPC send paths.

use std::fmt::Display;

Expand All @@ -31,6 +32,9 @@ pub const CLIENT_PROTOCOL_DEFAULT: i32 = 0;
/// RPC v2 (see RPC spec).
pub const CLIENT_PROTOCOL_DATA_STREAM_RPC: i32 = 1;

/// Understands inline single-packet data streams (data streams v2).
pub const CLIENT_PROTOCOL_DATA_STREAM_V2: i32 = 2;

// -------------------------------------------------------------------------------------------------
// ParticipantIdentity
// -------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -109,3 +113,66 @@ impl From<EncryptionType> for i32 {
}
}
}

// -------------------------------------------------------------------------------------------------
// ClientCapability
// -------------------------------------------------------------------------------------------------

/// A capability a participant's client advertises, mirroring the `ClientInfo.Capability` protobuf
/// enum.
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
#[non_exhaustive]
pub enum ClientCapability {
Unused,
PacketTrailer,
CompressionDeflateRaw,
}

impl TryFrom<i32> for ClientCapability {
type Error = &'static str;

fn try_from(value: i32) -> Result<Self, Self::Error> {
match proto::client_info::Capability::try_from(value) {
Ok(proto::client_info::Capability::CapPacketTrailer) => Ok(Self::PacketTrailer),
Ok(proto::client_info::Capability::CapCompressionDeflateRaw) => {
Ok(Self::CompressionDeflateRaw)
}
Ok(proto::client_info::Capability::CapUnused) => Ok(Self::Unused),
Err(_) => Err("unknown client capability"),
}
}
}

impl From<ClientCapability> for i32 {
fn from(value: ClientCapability) -> Self {
match value {
ClientCapability::Unused => proto::client_info::Capability::CapUnused as i32,
ClientCapability::PacketTrailer => {
proto::client_info::Capability::CapPacketTrailer as i32
}
ClientCapability::CompressionDeflateRaw => {
proto::client_info::Capability::CapCompressionDeflateRaw as i32
}
}
}
}

// -------------------------------------------------------------------------------------------------
// RemoteParticipantRegistry
// -------------------------------------------------------------------------------------------------

/// Read access to remote participants' advertised protocol and capabilities.
///
/// Used by downstream modules like the the RPC transport (v1/v2 transport selection) and
/// the data-stream send path (inline / compression eligibility) to determine what level of support
/// a participant has for protocol level features.
pub trait RemoteParticipantRegistry: Send + Sync {
/// A remote participant's `client_protocol`, or `CLIENT_PROTOCOL_DEFAULT` (0) if unknown.
fn remote_client_protocol(&self, identity: &ParticipantIdentity) -> i32;

/// A remote participant's advertised capabilities, or empty if unknown.
fn remote_capabilities(&self, identity: &ParticipantIdentity) -> Vec<ClientCapability>;

/// The identities of every remote participant, used to resolve a broadcast send.
fn remote_identities(&self) -> Vec<ParticipantIdentity>;
}
14 changes: 11 additions & 3 deletions livekit-data-stream/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ edition.workspace = true
repository.workspace = true

[features]
# Exposes test-only hooks used by downstream crates' test suites (e.g.
# `TextStreamReader::new_for_test`). Forwarded from the `livekit` crate's `__lk-e2e-test` feature.
# End-to-end testing hooks (exposes is_compressed/is_inline on stream info). Forwarded from
# the `livekit` crate's `__lk-e2e-test` feature.
__e2e-test = []
# Exposes constructors used by downstream crates' test suites (e.g. `TextStreamReader::new_for_test`).
test-utils = []

[dependencies]
Expand All @@ -20,12 +22,18 @@ thiserror = { workspace = true }
parking_lot = { workspace = true }
bytes = { workspace = true }
tokio = { workspace = true, default-features = false, features = ["sync", "fs", "io-util", "rt"] }
futures-util = { workspace = true, default-features = false, features = ["sink"] }
futures-util = { workspace = true, default-features = false, features = ["sink", "io"] }
prost = "0.12"
chrono = "0.4.38"
# Still used by the streaming file-compression path (`send_file`/`write_file`) and the test
# suite's cross-implementation interop check. The in-memory (de)compression paths use
# `async-compression` instead.
flate2 = "1"
bmrng = "0.5.2"
uuid = { version = "1", features = ["v4"] }
async-compression = { version = "0.4.42", features = ["deflate", "futures-io"] }
from_variants.workspace = true

[dev-dependencies]
tokio = { workspace = true, default-features = false, features = ["macros", "rt", "rt-multi-thread", "time"] }
rand = { workspace = true }
Loading
Loading