Skip to content

Data track publishing - #991

Open
ladvoc wants to merge 5 commits into
ladvoc/data-track-corefrom
ladvoc/data-track-publishing
Open

Data track publishing#991
ladvoc wants to merge 5 commits into
ladvoc/data-track-corefrom
ladvoc/data-track-publishing

Conversation

@ladvoc

@ladvoc ladvoc commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Add support for publishing data tracks.

Architecture and public API closely match Rust and JS clients:

  • The user publishes data tracks using the LocalParticipant.PublishDataTrack API.
  • A LocalManager is owned by the room to manage internal state and transitions for all local data tracks.

Areas to review:

  • Some APIs meant for internal use (e.g., LocalManager) are currently public. Would like to understand if there is a better way to organize packages to avoid this.
  • The LocalManager is currently owned by LocalParticipant, but I am not sure this is the right place for it to live.

Closes BOT-541

@ladvoc
ladvoc force-pushed the ladvoc/data-track-publishing branch from 5db4c9f to 8a5d82c Compare September 3, 2026 22:23
@ladvoc
ladvoc force-pushed the ladvoc/data-track-publishing branch 2 times, most recently from 6bf5d50 to ba27476 Compare September 4, 2026 22:57
@ladvoc
ladvoc force-pushed the ladvoc/data-track-publishing branch from ba27476 to 45535a7 Compare September 8, 2026 21:55
@ladvoc
ladvoc requested a review from boks1971 September 8, 2026 21:59
@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.

Devin Review found 3 potential issues.

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

Devin Review

Comment thread datatrack/local.go
Comment on lines +196 to +197
case isActive && response.err != nil:
m.params.Logger.Warnw("republish failed for data track", response.err, "handle", response.handle)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Failed republish permanently blocks frames

When a reconnect publish request fails, the track remains in stateRepublishing. Rejections and transport errors only log the failure. Every later TryPush returns ErrQueueFull, even after connectivity recovers.

Prompt for agents
Handle every failed republish attempt in datatrack/local.go instead of leaving LocalTrack in stateRepublishing. Both an SFU rejection in LocalManager.resolvePublish and a LocalTransport.SendPublishRequest error in LocalManager.RepublishTracks currently only log. Transition the affected track to a terminal or retryable state, keep LocalManager.active consistent, and ensure callers do not receive ErrQueueFull forever. Add tests for both rejection and transport-send failure after beginRepublish.
Devin Review

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

Comment thread datatrack/local.go
Comment on lines +369 to +382
switch publishState(t.state.Load()) {
case stateRepublishing:
return ErrQueueFull
case stateUnpublished:
return ErrUnpublished
}

t.mu.Lock()
packets, err := t.pipeline.processFrame(frame)
t.mu.Unlock()
if err != nil {
return err
}
t.manager.params.Transport.SendFrame(packets)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Concurrent unpublish leaks a final frame

When Unpublish races with TryPush, the push can pass its state check before unpublication. markUnpublished does not synchronize with frame processing. The frame is then queued after unpublication while TryPush reports success.

Prompt for agents
Synchronize LocalTrack state transitions with TryPush in datatrack/local.go. The current atomic check occurs before pipeline processing, while markUnpublished and beginRepublish can change state concurrently without taking the track mutex. Ensure no frame can be processed or handed to LocalTransport after an unpublish or republish transition wins, while preserving safe concurrent calls and avoiding lock-order inversions with LocalManager.mu.
Devin Review

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

Comment thread datatrack/local.go
schema: options.Schema,
frameEncoding: options.FrameEncoding,
}
if err := m.params.Transport.SendPublishRequest(request.toProto()); err != nil {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Cancellation cannot interrupt connection waits

PublishDataTrack with a short deadline can remain blocked in SendPublishRequest until the engine connection timeout. The transport receives no context, so Publish observes cancellation only after that call returns.

Prompt for agents
Make the publication send path context-aware. LocalManager.Publish currently calls LocalTransport.SendPublishRequest synchronously before waiting on ctx, and localDataTrackTransport waits in RTCEngine.ensurePublisherConnected with the engine timeout. Propagate the caller context through the transport or restructure the connection wait so cancellation and shorter deadlines stop PublishDataTrack promptly without leaving an untracked request. Cover an unavailable publisher with a context deadline shorter than ConnectTimeout.
Devin Review

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

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.

1 participant