feat: Data Tracks - #1004
Conversation
|
|
Compared this against the Swift (#975), JS (#1994) and Rust implementations, looking for behavior diffs. Before merge
Public surface — cheaper to settle now
Small
|
|
Diffuse output: Base AAR cache miss. Please run the build job on main to generate the base AAR. |
|
Dependency diff: +--- com.squareup.okhttp3:okhttp:4.12.0
| \--- com.squareup.okio:okio:3.6.0
| \--- com.squareup.okio:okio-jvm:3.6.0
| \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.10
| \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.10 -> 1.9.25
-| \--- org.jetbrains:annotations:13.0
+| \--- org.jetbrains:annotations:13.0 -> 23.0.0
+--- com.github.davidliu:audioswitch:039a35aefab7747c557242fa216c9ea11743b604
-| \--- androidx.annotation:annotation:1.3.0 -> 1.7.1
-| \--- androidx.annotation:annotation-jvm:1.7.1
-| \--- org.jetbrains.kotlin:kotlin-stdlib:1.7.10 -> 1.9.25 (*)
+| \--- androidx.annotation:annotation:1.3.0 -> 1.9.0
+| \--- androidx.annotation:annotation-jvm:1.9.0
+| \--- org.jetbrains.kotlin:kotlin-stdlib:1.7.10 -> 1.9.25 (*)
-+--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0 -> 1.6.4
-| +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4
-| | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4
-| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.6.4
-| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4 (c)
-| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4 (c)
-| | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4 (c)
-| | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.6.21 -> 1.9.10 (*)
-| | \--- org.jetbrains.kotlin:kotlin-stdlib-common:1.6.21 -> 1.9.25 (*)
-| +--- org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.6.4 (*)
-| \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.6.21 -> 1.9.10 (*)
++--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0 -> 1.8.1
+| +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1
+| | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.8.1
+| | +--- org.jetbrains:annotations:23.0.0
+| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.8.1
+| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1 (c)
+| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.8.1 (c)
+| | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 (c)
+| | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.21 -> 1.9.25 (*)
+| +--- org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.8.1 (*)
+| \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.21 -> 1.9.25 (*)
-+--- com.auth0.android:jwtdecode:2.0.2
-| \--- androidx.annotation:annotation:1.1.0 -> 1.7.1 (*)
-+--- androidx.annotation:annotation:1.7.1 (*)
-\--- androidx.core:core:1.13.1
- +--- androidx.annotation:annotation:1.6.0 -> 1.7.1 (*)
- +--- androidx.collection:collection:1.0.0
- | \--- androidx.annotation:annotation:1.0.0 -> 1.7.1 (*)
- +--- androidx.concurrent:concurrent-futures:1.0.0 -> 1.1.0
- | \--- androidx.annotation:annotation:1.1.0 -> 1.7.1 (*)
- +--- androidx.interpolator:interpolator:1.0.0
- | \--- androidx.annotation:annotation:1.0.0 -> 1.7.1 (*)
- +--- androidx.lifecycle:lifecycle-runtime:2.6.2
- | +--- androidx.annotation:annotation:1.1.0 -> 1.7.1 (*)
- | +--- androidx.arch.core:core-common:2.2.0
- | | \--- androidx.annotation:annotation:1.1.0 -> 1.7.1 (*)
- | +--- androidx.arch.core:core-runtime:2.2.0
- | | \--- androidx.annotation:annotation:1.1.0 -> 1.7.1 (*)
- | +--- androidx.lifecycle:lifecycle-common:2.6.2
- | | +--- androidx.annotation:annotation:1.1.0 -> 1.7.1 (*)
- | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4 (*)
- | \--- androidx.profileinstaller:profileinstaller:1.3.0
- | +--- androidx.annotation:annotation:1.2.0 -> 1.7.1 (*)
- | \--- androidx.startup:startup-runtime:1.1.1
- | +--- androidx.annotation:annotation:1.1.0 -> 1.7.1 (*)
- | \--- androidx.tracing:tracing:1.0.0
- | \--- androidx.annotation:annotation:1.1.0 -> 1.7.1 (*)
- \--- androidx.versionedparcelable:versionedparcelable:1.1.1
- \--- androidx.annotation:annotation:1.1.0 -> 1.7.1 (*)
++--- io.livekit:livekit-uniffi-android:0.1.9
+| +--- androidx.annotation:annotation:1.9.0 (*)
+| +--- net.java.dev.jna:jna:5.16.0
+| +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 (*)
+| \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.22 -> 1.9.25 (*)
++--- com.auth0.android:jwtdecode:2.0.2
+| \--- androidx.annotation:annotation:1.1.0 -> 1.9.0 (*)
++--- androidx.annotation:annotation:1.7.1 -> 1.9.0 (*)
+\--- androidx.core:core:1.13.1
+ +--- androidx.annotation:annotation:1.6.0 -> 1.9.0 (*)
+ +--- androidx.collection:collection:1.0.0
+ | \--- androidx.annotation:annotation:1.0.0 -> 1.9.0 (*)
+ +--- androidx.concurrent:concurrent-futures:1.0.0 -> 1.1.0
+ | \--- androidx.annotation:annotation:1.1.0 -> 1.9.0 (*)
+ +--- androidx.interpolator:interpolator:1.0.0
+ | \--- androidx.annotation:annotation:1.0.0 -> 1.9.0 (*)
+ +--- androidx.lifecycle:lifecycle-runtime:2.6.2
+ | +--- androidx.annotation:annotation:1.1.0 -> 1.9.0 (*)
+ | +--- androidx.arch.core:core-common:2.2.0
+ | | \--- androidx.annotation:annotation:1.1.0 -> 1.9.0 (*)
+ | +--- androidx.arch.core:core-runtime:2.2.0
+ | | \--- androidx.annotation:annotation:1.1.0 -> 1.9.0 (*)
+ | +--- androidx.lifecycle:lifecycle-common:2.6.2
+ | | +--- androidx.annotation:annotation:1.1.0 -> 1.9.0 (*)
+ | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4 -> 1.8.1 (*)
+ | \--- androidx.profileinstaller:profileinstaller:1.3.0
+ | +--- androidx.annotation:annotation:1.2.0 -> 1.9.0 (*)
+ | \--- androidx.startup:startup-runtime:1.1.1
+ | +--- androidx.annotation:annotation:1.1.0 -> 1.9.0 (*)
+ | \--- androidx.tracing:tracing:1.0.0
+ | \--- androidx.annotation:annotation:1.1.0 -> 1.9.0 (*)
+ \--- androidx.versionedparcelable:versionedparcelable:1.1.1
+ \--- androidx.annotation:annotation:1.1.0 -> 1.9.0 (*) |
|
@pblazej can I get you to recheck? |
|
Any plan to land this PR soon ? I got pinged by the Robotic team |
| is Custom -> FfiSchemaEncoding.Custom(identifier) | ||
| } | ||
|
|
||
| internal fun toProto(): LivekitModels.DataTrackSchemaEncoding { |
There was a problem hiding this comment.
question: Why does this need to be converted to Protobuf?
| if (tracks.values.any { it === track }) { | ||
| return@synchronized false | ||
| } | ||
| tracks = tracks + (track.name to track) |
There was a problem hiding this comment.
It uses the track.name as the key ? is this correct ? any chance that two tracks from one participant sharing the same name ?
or should we use sid as key ?
| private var reliableDataChannelSub: DataChannel? = null | ||
| private var lossyDataChannel: DataChannel? = null | ||
| private var lossyDataChannelSub: DataChannel? = null | ||
| private var dataTrackDataChannelSub: DataChannel? = null |
There was a problem hiding this comment.
is this dataTrackDataChannelSub needed ? I don't see how it is used rather than assign and clear, is it intentional ?
| * | ||
| * @suppress | ||
| */ | ||
| fun interface LocalDataTrackManagerFactory { |
There was a problem hiding this comment.
These are public but their signatures are io.livekit.uniffi.* types, and that dep is implementation (build.gradle:121) — so consumers can't reference them, or the public constructors taking them, without adding it themselves. @suppress is Dokka-only, so internal is the actual fix; Dagger binds internal types fine within a module.
| /** | ||
| * Republish all tracks after a full reconnect so the SFU recognizes existing publications. | ||
| */ | ||
| fun republishTracks() { |
There was a problem hiding this comment.
This and resendSubscriptionUpdates() run from coroutineScope.launch (RTCEngine.kt:727), which is SupervisorJob() + ioDispatcher with no CoroutineExceptionHandler — so anything thrown here hits the thread's uncaught handler instead of failing the reconnect. Does uniffi throw on use-after-destroy if a concurrent disconnect() closes the manager mid-call?
pblazej
left a comment
There was a problem hiding this comment.
LGTM, added 2 non-blockers above
Adds data track support, sharing the Rust UniFFI core (
livekit-uniffi-android) with the other SDKs.Most of
room/datatrack/is a thin wrapper around that core. The Android-specific work is the WebRTC, signaling, and reconnect glue.Actual changes
RTCEngine/DataTrackFrameSender—_data_trackchannel, send backpressure, wait-for-open, reconnectSignalClient— publish / unpublish / subscriber-handle / request-response forwardingRoom,LocalParticipant,RemoteParticipant— public API, attach/park remote tracks, eventsIncomingDataTrackManager/OutgoingDataTrackManager— bridge UniFFI managers to the engineDataTrackCryptor/E2EEManager— E2EE via the existing data-packet cryptorDataChannelManager,RTCModule, test DI — channel metering and injectable factoriesSimple wrappers (FFI type/API mapping, little Android-specific logic)
LocalDataTrack,RemoteDataTrack,DataTrackStreamDataTrackFrame,DataTrackInfo,DataTrackSid,DataTrackSchema,DataTrackPublishOptions,DataTrackExceptionDataTrackManagerFactory,IncomingDataTrackEventE2E tests: https://github.com/livekit/e2e-android/pull/13