Data tracks UniFFI#1034
Conversation
|
@davidliu tagging you as it would be great to get some approval before the actual "0.1" release. Let's make sure the DTOs etc. look fine at least on 2 platforms, the async things work, etc. |
|
@pblazej looks good, got it compiled for Android and played around with the API. Seems like everything would integrate fairly seamlessly into the Android SDK. @ladvoc I did have to add the "macros" feature to this line in the Cargo.toml to get it building: I'm not sure if this is android specific or affects other builds as well. |
Previously made builder fields public to allow direct export as remote type.
6c06943 to
de6198f
Compare
0.31.2's Swift backend emits `nonisolated(unsafe) static let` for callback-interface vtables (Swift 6 strict-concurrency clean) and supports methods on records/enums. 0.30.0 required consumers to compile the generated bindings in Swift 5 language mode. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
UniFFI drives exported async functions from the foreign bindings' executor, on a thread with no tokio runtime. Anything that reaches a reactor — `publish_track` via `tokio::time::timeout`, the receive path (`subscribe`/`DataTrackStream::next`) via `livekit_runtime::timeout` in the depacketizer — then panics "there is no reactor running". Annotate the data track impl blocks with `#[uniffi::export(async_runtime = "tokio")]`, which wraps each future in `async_compat::Compat` so it is polled within a tokio runtime context. Applied uniformly, since which exports reach a reactor is not locally auditable. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
cargo-swift mispackages a UniFFI library with more than one component (livekit-uniffi + livekit-datatrack): wrong xcframework name and unimportable framework modules. Pin the swift-xcframework task to the fork branch that fixes this (https://github.com/livekit/cargo-swift/tree/fix/multi-crate-framework), and drop `--debug-symbols` since that branch is based on main without the dSYM-embedding support. Add a swift-workarounds task that drops the duplicate `Bytes` FfiConverter from livekit_datatrack.swift — the `Bytes` custom type is registered in both crates, so UniFFI emits it in both component files and they collide ("invalid redeclaration of 'Bytes'") when compiled into one Swift module. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
46759f4 to
8bd470c
Compare
The fork's fix/multi-crate-framework branch was rebased onto cargo-swift main as a single commit (open upstream as antoniusnaumann/cargo-swift#101) and no longer carries the uniffi_bindgen 0.31.2 bump — that went to its own PR (antoniusnaumann/cargo-swift#102). Re-pin the swift-xcframework task to the new revision. Without that bindgen bump the generated callback-interface vtables are plain `static let`, which the Swift 6 language mode rejects, so restore `swiftLanguageModes: [.v5]` in the package templates until cargo-swift ships uniffi 0.31.2. Give livekit-datatrack a uniffi.toml setting ffi_module_name = "RustLiveKitDataTrack" so its generated FFI header matches the RustLiveKitUniFFI naming instead of the default livekit_datatrackFFI. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Wiring up the Swift SDK — hit two gaps in the binding surface for join/reconnect @ladvoc @1egoman: Join-time tracks. No join handler on Quick-reconnect sync state. No way to build Caveats: no released livekit-server (incl. 1.13.2) fills |
Query tracks is now used internally and not exported
Makes sense, I implemented the latter in 4f18c9c. This replaces the |
Rust has these additional helpers to keep the interface between the rest of the client SDK and the data tracks managers as uniform as possible; instead of caring about specific fields in each response type, you hand over the whole response, and the logic of how the required information is extracted is kept as an implementation detail. A few other advantages:
I implemented |
Data tracks is fully released in OSS and Cloud now so this would be unexpected. Do you have any repro steps for this? |
No repro — false alarm on my side. The join does carry That RAII-on-drop is really the last open question: should FFI consumers mirror Rust's semantics (drop = unpublish) or go "publication-like" (JS keeps the publication in its manager until an explicit unpublish)? We went publication-like on the Swift side so callers aren't forced to retain the handle — this diff shows it: livekit/client-sdk-swift@3e3043e Framing it as "what should the convention be" rather than "should Rust change": the core's RAII is correct/idiomatic for Rust consumers — the divergence is about what the FFI bindings present. JS and (now) Swift both land on publication-like, so there's a de-facto convention worth making explicit. For concreteness, the Swift lifecycle surface:
|
Add subscribe_with_options on RemoteDataTrack and a DataTrackSubscribeOptions record (buffer_size) so foreign consumers can tune the internal frame buffer, matching the core and JS subscribe APIs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
pblazej
left a comment
There was a problem hiding this comment.
I don't see any functional gaps here preventing Swift integration
The rest is mostly consumer-side discussion (like the RAII pattern mentioned above).
Before merging please update both SPM_SIZE_LIMIT_BYTES and ANDROID_SIZE_LIMIT_BYTES with the final sizes.
Approximate sizes @ the latest commit:
SPM_SIZE_LIMIT_BYTES = 1152136ANDROID_SIZE_LIMIT_BYTES = 1250710
Summary of changes:
livekit-uniffiResolves CLT-2472