From 2dab90b149cf05b8e67c8c41ae8f978f6c3b59f8 Mon Sep 17 00:00:00 2001 From: Alan George Date: Wed, 14 Oct 2026 20:16:35 -0600 Subject: [PATCH] Fix "local track published for unknown sid" warning --- src/ffi_client.cpp | 19 ++++++++--- src/ffi_client.h | 6 ++-- src/local_participant.cpp | 27 +++++++-------- .../test_local_track_publish_sid.cpp | 33 +++++++++++++++++++ 4 files changed, 62 insertions(+), 23 deletions(-) diff --git a/src/ffi_client.cpp b/src/ffi_client.cpp index 867eba94..2a3eba73 100644 --- a/src/ffi_client.cpp +++ b/src/ffi_client.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -694,9 +695,9 @@ std::future FfiClient::simulateScenarioAsync(uintptr_t room_handle, int sc } // Participant APIs Implementation -std::future FfiClient::publishTrackAsync(std::uint64_t local_participant_handle, - std::uint64_t track_handle, - const TrackPublishOptions& options) { +std::future FfiClient::publishTrackAsync( + std::uint64_t local_participant_handle, std::uint64_t track_handle, const TrackPublishOptions& options, + std::function on_success) { // Generate client-side async_id first const AsyncId async_id = generateAsyncId(); @@ -708,7 +709,8 @@ std::future FfiClient::publishTrackAsync(std::uint return event.has_publish_track() && event.publish_track().async_id() == async_id; }, // Handler: resolve with publication or throw error - [](const proto::FfiEvent& event, std::promise& pr) { + [on_success = std::move(on_success)](const proto::FfiEvent& event, + std::promise& pr) { const auto& cb = event.publish_track(); // Oneof message { string error = 2; OwnedTrackPublication publication = @@ -723,7 +725,14 @@ std::future FfiClient::publishTrackAsync(std::uint } const proto::OwnedTrackPublication& pub = cb.publication(); - pr.set_value(pub); + try { + if (on_success) { + on_success(pub); + } + pr.set_value(pub); + } catch (...) { + pr.set_exception(std::current_exception()); + } }); // Build and send the request diff --git a/src/ffi_client.h b/src/ffi_client.h index 0104de76..4f10b1fa 100644 --- a/src/ffi_client.h +++ b/src/ffi_client.h @@ -109,9 +109,9 @@ class LIVEKIT_INTERNAL_API FfiClient { std::future simulateScenarioAsync(uintptr_t room_handle, int scenario); // Participant APIs - std::future publishTrackAsync(std::uint64_t local_participant_handle, - std::uint64_t track_handle, - const TrackPublishOptions& options); + std::future publishTrackAsync( + std::uint64_t local_participant_handle, std::uint64_t track_handle, const TrackPublishOptions& options, + std::function on_success = {}); std::future unpublishTrackAsync(std::uint64_t local_participant_handle, const std::string& track_sid, bool stop_on_unpublish); std::future publishDataAsync(std::uint64_t local_participant_handle, const std::uint8_t* data_ptr, diff --git a/src/local_participant.cpp b/src/local_participant.cpp index 8dbc1fdc..2607963d 100644 --- a/src/local_participant.cpp +++ b/src/local_participant.cpp @@ -191,21 +191,18 @@ void LocalParticipant::publishTrack(const std::shared_ptr& track, const T if (track_handle == 0) { throw std::runtime_error("LocalParticipant::publishTrack: invalid track FFI handle"); } - auto fut = FfiClient::instance().publishTrackAsync(static_cast(participant_handle), - static_cast(track_handle), options); - - // Will throw if the async op fails (error in callback). - const proto::OwnedTrackPublication owned_pub = fut.get(); - - // Construct a LocalTrackPublication from the proto publication. - auto publication = std::make_shared(owned_pub); - - const std::string sid = publication->sid(); - { - const std::scoped_lock guard(published_tracks_mutex_); - published_tracks_by_sid_[sid] = std::weak_ptr(track); - track->setPublication(publication); - } + auto fut = FfiClient::instance().publishTrackAsync( + static_cast(participant_handle), static_cast(track_handle), options, + [this, track](const proto::OwnedTrackPublication& owned_pub) { + auto publication = std::make_shared(owned_pub); + const std::scoped_lock guard(published_tracks_mutex_); + published_tracks_by_sid_[publication->sid()] = track; + track->setPublication(publication); + }); + + // Publication state is installed on the FFI thread before this future is + // completed and before Rust can emit LocalTrackPublished. + (void)fut.get(); } std::shared_ptr LocalParticipant::publishVideoTrack(const std::string& name, diff --git a/src/tests/integration/test_local_track_publish_sid.cpp b/src/tests/integration/test_local_track_publish_sid.cpp index ee767450..21707f4b 100644 --- a/src/tests/integration/test_local_track_publish_sid.cpp +++ b/src/tests/integration/test_local_track_publish_sid.cpp @@ -17,9 +17,12 @@ #include #include +#include #include +#include #include #include +#include #include "../common/audio_utils.h" #include "../common/room_test_access.h" @@ -31,6 +34,30 @@ namespace { using namespace std::chrono_literals; +class LocalPublicationDelegate final : public RoomDelegate { +public: + void onLocalTrackPublished(Room&, const LocalTrackPublishedEvent& event) override { + if (!event.publication) { + return; + } + { + const std::scoped_lock guard(mutex_); + published_sids_.insert(event.publication->sid()); + } + cv_.notify_all(); + } + + bool waitForPublished(const std::string& sid, std::chrono::milliseconds timeout) { + std::unique_lock lock(mutex_); + return cv_.wait_for(lock, timeout, [&] { return published_sids_.count(sid) != 0; }); + } + +private: + std::mutex mutex_; + std::condition_variable cv_; + std::unordered_set published_sids_; +}; + void expectTrackSidAssigned(const Track& track, const LocalTrackPublication& publication) { const std::string& track_sid = track.sid(); const std::string& publication_sid = publication.sid(); @@ -58,6 +85,8 @@ TEST_F(LocalTrackPublishSidTest, PublishVideoTrackAssignsSid) { failIfNotConfigured(); Room room; + LocalPublicationDelegate delegate; + room.setDelegate(&delegate); const RoomOptions room_options; ASSERT_TRUE(room.connect(config_.url, config_.token_a, room_options)); @@ -69,6 +98,7 @@ TEST_F(LocalTrackPublishSidTest, PublishVideoTrackAssignsSid) { ASSERT_NE(track->publication(), nullptr); expectTrackSidAssigned(*track, *track->publication()); + EXPECT_TRUE(delegate.waitForPublished(track->sid(), 5s)); lockLocalParticipant(room)->unpublishTrack(track->publication()->sid()); } @@ -76,6 +106,8 @@ TEST_F(LocalTrackPublishSidTest, PublishAudioTrackAssignsSid) { failIfNotConfigured(); Room room; + LocalPublicationDelegate delegate; + room.setDelegate(&delegate); const RoomOptions room_options; ASSERT_TRUE(room.connect(config_.url, config_.token_a, room_options)); @@ -87,6 +119,7 @@ TEST_F(LocalTrackPublishSidTest, PublishAudioTrackAssignsSid) { ASSERT_NE(track->publication(), nullptr); expectTrackSidAssigned(*track, *track->publication()); + EXPECT_TRUE(delegate.waitForPublished(track->sid(), 5s)); lockLocalParticipant(room)->unpublishTrack(track->publication()->sid()); }