Skip to content

Data tracks: subscribing - #992

Merged
ladvoc merged 26 commits into
ladvoc/data-track-publishingfrom
ladvoc/data-track-subscribing
Oct 21, 2026
Merged

ladvoc merged 26 commits into
ladvoc/data-track-publishingfrom
ladvoc/data-track-subscribing

Conversation

@ladvoc

@ladvoc ladvoc commented Sep 3, 2026 •

Copy link
Copy Markdown
Contributor

Adds support for subscribing to data tracks.

Architecture and public API closely match Rust and JS clients:

  • When a remote participant publishes a data track, the user receives an OnDataTrackPublished event to receive the track object which they can then use to subscribe if desired.
    • Multiple application-level subscriptions are supported for a single track; internally, packets are still only received and processed once and will be fanned out.
  • A RemoteManager is owned by the room to manage internal state and transitions for all remote data tracks.

Closes BOT-541

@ladvoc
ladvoc force-pushed the ladvoc/data-track-subscribing branch from ce38d1d to a1d1643 Compare September 4, 2026 16:04
@ladvoc
ladvoc force-pushed the ladvoc/data-track-subscribing branch from a1d1643 to bee8224 Compare September 4, 2026 22:57
@ladvoc
ladvoc force-pushed the ladvoc/data-track-subscribing branch from bee8224 to 2fd1c9b Compare September 8, 2026 21:55
@ladvoc
ladvoc requested a review from boks1971 September 8, 2026 22:15
@ladvoc
ladvoc marked this pull request as ready for review September 8, 2026 22:15
@ladvoc
ladvoc requested a review from a team as a code owner September 8, 2026 22:15

@devin-ai-integration devin-ai-integration Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

Newer findings are available below. Devin Review posted a newer report on this PR, in addition to the findings presented here.

Devin Review found 5 potential issues.

2 flags not posted on this PR by your GitHub settings — view them in Devin Review. (Configure)

Devin Review

Comment thread room.go Outdated
Comment thread datatrack/remote.go Outdated
Comment thread room.go
Comment thread remotedatatracktransport.go Outdated
// Subscribe, without stalling signal handling.
func (t remoteDataTrackTransport) OnTrackPublished(track *datatrack.RemoteTrack) {
rp := t.room.GetParticipantByIdentity(track.PublisherIdentity())
go func() {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Publication callbacks arrive reversed

Each event starts an independent goroutine, so rapid publication and removal can run OnDataTrackUnpublished first. Applications observe removal before discovery or subscribe after removal.

Prompt for agents
Dispatch data-track lifecycle callbacks asynchronously but in publication order. The two remoteDataTrackTransport methods currently launch independent goroutines, allowing publish and unpublish events for the same track to overtake each other. Use a serialized room-level or per-track callback queue that does not block signal handling, while retaining participant-before-room callback ordering.
Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Valid concern. Am guessing the media track has the same pattern?

Comment thread internal/datatrack/remote.go Outdated
Comment thread datatrack/remote.go Outdated
Comment thread datatrack/remote.go Outdated
Comment thread internal/datatrack/remote.go
Comment thread datatrack/remote.go Outdated
@ladvoc
ladvoc force-pushed the ladvoc/data-track-subscribing branch from 2fd1c9b to b7920b9 Compare September 14, 2026 21:40
@ladvoc
ladvoc force-pushed the ladvoc/data-track-subscribing branch from b7920b9 to 282a381 Compare September 14, 2026 22:27
@ladvoc
ladvoc force-pushed the ladvoc/data-track-subscribing branch from 9b0d4c1 to 95db271 Compare September 22, 2026 16:46
@ladvoc
ladvoc force-pushed the ladvoc/data-track-subscribing branch from 95db271 to f187427 Compare September 22, 2026 20:53

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

4 flags not posted on this PR by your GitHub settings — view them in Devin Review. (Configure)

Devin Review

Comment thread internal/datatrack/remote.go Outdated
@ladvoc ladvoc changed the title Data track subscribing Data tracks: subscribing Sep 22, 2026

@cnderrauber cnderrauber left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, thank you!

@boks1971 boks1971 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have not reviewed remote.go and remote_test.go yet. But, I am stopping here for some comments and pick it up later after your response.

Some notes

  1. I think remoteDataTracks should be distributed in RemoteParticipantif possible. It should just follow the media track pattern. At room level, I don't think it should be dealing with tracks. It should be dealing with only participants and tracks should live at participant. We should look at it more closely if that is not possible for some reason (I left the same comment in the publish PR where local tracks if possible should be managed inside the LocalParticipant)
  2. Because I have not fully ready the above files, I am not sure of the RemoteManager (and similarly LocalManager's roles). But for abstraction and making things private, you can do something like
type RemoteManager interface {
     // only publicly needed methods here
}

type remoteManager struct {
     // the implementation which is package private
}

var _ RemoteManager = (*remoteManager)(nil) // compiler trick to ensure that remoteManager implements the RemoteManager interface.

func NewRemoteManager() RemoteManager{
}

Comment thread examples/datatrack/subscriber/main.go Outdated
callback := &lksdk.RoomCallback{
ParticipantCallback: lksdk.ParticipantCallback{
OnDataTrackPublished: func(track *datatrack.RemoteTrack, rp *lksdk.RemoteParticipant) {
subscribe(ctx, track)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not remember if all these callbacks can happen in the same goroutine. If so, doing go subscribe would be the right thing to ensure that subscribes are spawned off to their own goroutine and callbacks do not block.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like for media tracks OnTrackPublished/OnTrackUnpublished are invoked synchronously on the signal goroutine (see remoteparticipant.go). Should we do the same here?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that should be fine, but also depends on what the callbacks do. Those are emitted to the app. This one is doing some internal operation. Just have to make sure that it does not block. Sending it synchronously to app level is probably more risky potentially, but it is existing. I think synchronous should be fine, but just wanted to flag.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 9919be6.

Comment thread examples/datatrack/subscriber/main.go Outdated
Comment thread examples/datatrack/subscriber/main.go Outdated
Comment thread room.go
Comment thread room.go
Comment thread remotedatatracktransport.go Outdated
// Subscribe, without stalling signal handling.
func (t remoteDataTrackTransport) OnTrackPublished(track *datatrack.RemoteTrack) {
rp := t.room.GetParticipantByIdentity(track.PublisherIdentity())
go func() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Valid concern. Am guessing the media track has the same pattern?

Comment thread remotedatatracktransport.go
@ladvoc
ladvoc force-pushed the ladvoc/data-track-subscribing branch from 1ab44ed to da6b831 Compare October 5, 2026 22:15
Comment thread internal/datatrack/remote_test.go Outdated
Comment thread internal/datatrack/remote_test.go
Comment thread internal/datatrack/remote.go
Comment thread internal/datatrack/remote.go Outdated
Comment thread internal/datatrack/remote.go Outdated
Comment thread internal/datatrack/remote.go Outdated
@ladvoc
ladvoc force-pushed the ladvoc/data-track-subscribing branch 2 times, most recently from 262c34b to 4441c27 Compare October 19, 2026 20:05
@ladvoc
ladvoc force-pushed the ladvoc/data-track-subscribing branch from 9919be6 to 3944765 Compare October 20, 2026 22:17
Fixes `TestDataTrack_SubscriberSideFault/full_reconnect` E2E case
@ladvoc
ladvoc merged commit 76fd42e into main Oct 21, 2026
7 checks passed
@ladvoc
ladvoc deleted the ladvoc/data-track-subscribing branch October 21, 2026 00:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants