Skip to content

BugFix: Bot-343, DataTracks return from subscribe() and read() from rust sdk#119

Open
stephen-derosa wants to merge 5 commits intolivekit:mainfrom
stephen-derosa:sderosa/BOT-343-float-up-DT-error
Open

BugFix: Bot-343, DataTracks return from subscribe() and read() from rust sdk#119
stephen-derosa wants to merge 5 commits intolivekit:mainfrom
stephen-derosa:sderosa/BOT-343-float-up-DT-error

Conversation

@stephen-derosa
Copy link
Copy Markdown
Contributor

@stephen-derosa stephen-derosa commented May 6, 2026

aligns with changes here:
livekit/rust-sdks#1057

Depends on:

Copy link
Copy Markdown
Contributor

@alan-george-lk alan-george-lk left a comment

Choose a reason for hiding this comment

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

Looks great, love the bundled unit test

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR aligns the C++ SDK’s remote DataTrack streaming behavior with the Rust SDK update (rust-sdks#1057) by preserving and surfacing terminal subscription errors delivered via the FFI stream EOS, and by exercising that behavior in unit tests.

Changes:

  • Add DataTrackStream::terminalError() and store an optional terminal subscription error when EOS arrives with an error payload.
  • Log terminal subscription errors when the data reader thread exits after read() ends.
  • Add unit tests validating that normal EOS produces no terminal error, while subscribe-failure EOS records a typed error.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.

Show a summary per file
File Description
include/livekit/data_track_stream.h Exposes terminalError() and stores an optional terminal subscription error; adds test-only friend access.
src/data_track_stream.cpp Parses EOS error payload from FFI events and persists it as a terminal error; clears it on local close before EOS.
src/subscription_thread_dispatcher.cpp Logs terminal subscription errors after the data read loop ends.
src/tests/unit/test_data_track_stream.cpp New unit tests covering terminal error behavior for normal EOS vs subscribe-failure EOS.
src/tests/CMakeLists.txt Links protobuf for unit tests across platforms (supports protobuf usage in new unit test and static-link scenarios).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Copy Markdown
Contributor

@ladvoc ladvoc left a comment

Choose a reason for hiding this comment

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

LGTM, just the one question. Also, have you tested this against the Rust branch?

LK_LOG_ERROR("Data frame callback exception: {}", e.what());
}
}
const auto &error = stream->terminalError();
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.

question: Is the user able to access the error reason when using the thread dispatcher?

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.

no in the current implementation

Comment thread src/data_track_stream.cpp Outdated
}
subscription_handle_.reset();
listener_id = listener_id_;
listener_id_ = 0;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

just found out this might be a potential bug for double RemoveListener(listener_id);

when a close() is called, it will set listener_id_ = 0;
and you will do
if (listener_id != -1) {
FfiClient::instance().RemoveListener(listener_id);
}

That says, if close() is called twice, we will call FfiClient::instance().RemoveListener(0); which might be wrong

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.

good callout. listener_id_ should be -1. updated.

And we protect against superfluous close() calls with:

    if (closed_) {
      return;
    }

Comment thread src/data_track_stream.cpp

std::optional<SubscribeDataTrackError> DataTrackStream::terminalError() const {
const std::scoped_lock<std::mutex> lock(mutex_);
return terminal_error_;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

suggestion

Is it intentional that terminal_error_ will still be return after close() ? or it should be valid only before calling close() ?

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.

Yes, intentional. terminalError() is meant to be readable as post-stream state. If the stream has already reached EOS with an FFI-reported terminal error, close() preserves it. If close() is called locally before EOS, we clear terminal_error_ because the stream ended by local cancellation, not by a remote/FFI terminal failure.

I added a small comment here

Copy link
Copy Markdown
Collaborator

@xianshijing-lk xianshijing-lk left a comment

Choose a reason for hiding this comment

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

lgtm if you address the comments

Comment thread src/tests/unit/test_data_track_stream.cpp
… unpublishes before subscribing, then asserts the stream ends via read() == false with terminalError().code == SubscribeDataTrackErrorCode::UNPUBLISHED and a non-empty message.
Comment thread src/tests/CMakeLists.txt
livekit
spdlog::spdlog
$<$<PLATFORM_ID:Windows>:${LIVEKIT_PROTOBUF_TARGET}>
${LIVEKIT_PROTOBUF_TARGET}
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.

not sure why copilot thought this needed

@stephen-derosa stephen-derosa requested a review from Copilot May 7, 2026 02:03
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Comment on lines +727 to +733
const auto &error = stream->terminalError();
if (error.has_value()) {
LK_LOG_ERROR(
"Data reader stream ended with subscription error for \"{}\" from "
"\"{}\": code={} message={}",
track_name, identity, static_cast<std::uint32_t>(error->code),
error->message);
Comment thread src/data_track_stream.cpp
void DataTrackStream::pushEos(std::optional<SubscribeDataTrackError> error) {
{
const std::scoped_lock<std::mutex> lock(mutex_);
if (eof_) {
@stephen-derosa stephen-derosa changed the title fix DataTracks return from subscribe() and read() from rust sdk BugFix: Bot-343, DataTracks return from subscribe() and read() from rust sdk May 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants