Queue TMST::AddObserver calls until SetImplementation, then notify them

Queue calls to TransferredMediaStreamTrack::AddObserver() until SetImplementation() is called, and notify the observers when this happens.

Bug: 1288839
Change-Id: Iaef5d4a94d3cd155476325c277b7555d1ec018a4
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3683263
Reviewed-by: Tony Herre <toprice@chromium.org>
Commit-Queue: Tove Petersson <tovep@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1010230}
diff --git a/third_party/blink/renderer/modules/mediastream/transferred_media_stream_track.cc b/third_party/blink/renderer/modules/mediastream/transferred_media_stream_track.cc
index a09eacf..7938b8a 100644
--- a/third_party/blink/renderer/modules/mediastream/transferred_media_stream_track.cc
+++ b/third_party/blink/renderer/modules/mediastream/transferred_media_stream_track.cc
@@ -200,6 +200,15 @@
   // Set up an EventPropagator helper to forward any events fired on track so
   // that they're re-dispatched to anything that's listening on this.
   event_propagator_ = MakeGarbageCollected<EventPropagator>(track, this);
+
+  // Observers may dispatch events which create and add new Observers. Such
+  // observers are added directly to the implementation track since track_ is
+  // now set.
+  for (auto observer : observers_) {
+    observer->TrackChangedState();
+    track_->AddObserver(observer);
+  }
+  observers_.clear();
 }
 
 void TransferredMediaStreamTrack::SetConstraints(
@@ -315,9 +324,9 @@
 void TransferredMediaStreamTrack::AddObserver(Observer* observer) {
   if (track_) {
     track_->AddObserver(observer);
+  } else {
+    observers_.insert(observer);
   }
-  // TODO(https://crbug.com/1288839): Save and forward to track_ once it's
-  // initialized.
 }
 
 TransferredMediaStreamTrack::EventPropagator::EventPropagator(
@@ -349,6 +358,7 @@
   visitor->Trace(track_);
   visitor->Trace(execution_context_);
   visitor->Trace(event_propagator_);
+  visitor->Trace(observers_);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/mediastream/transferred_media_stream_track.h b/third_party/blink/renderer/modules/mediastream/transferred_media_stream_track.h
index caacde00..7942b0f 100644
--- a/third_party/blink/renderer/modules/mediastream/transferred_media_stream_track.h
+++ b/third_party/blink/renderer/modules/mediastream/transferred_media_stream_track.h
@@ -127,6 +127,7 @@
   WeakMember<ExecutionContext> execution_context_;
   TransferredValues data_;
   Member<EventPropagator> event_propagator_;
+  HeapHashSet<WeakMember<MediaStreamTrack::Observer>> observers_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/mediastream/transferred_media_stream_track_test.cc b/third_party/blink/renderer/modules/mediastream/transferred_media_stream_track_test.cc
index 7621323..dd1e3f93f 100644
--- a/third_party/blink/renderer/modules/mediastream/transferred_media_stream_track_test.cc
+++ b/third_party/blink/renderer/modules/mediastream/transferred_media_stream_track_test.cc
@@ -17,6 +17,17 @@
 
 namespace {
 using testing::_;
+
+class TestObserver : public GarbageCollected<TestObserver>,
+                     public MediaStreamTrack::Observer {
+ public:
+  void TrackChangedState() override { observation_count_++; }
+  int ObservationCount() const { return observation_count_; }
+
+ private:
+  int observation_count_ = 0;
+};
+
 }  // namespace
 
 class TransferredMediaStreamTrackTest : public testing::Test {
@@ -172,4 +183,25 @@
   transferred_track_->applyConstraints(scope.GetScriptState(),
                                        MediaTrackConstraints::Create());
 }
+
+TEST_F(TransferredMediaStreamTrackTest, SetImplementationTriggersObservers) {
+  V8TestingScope scope;
+  CustomSetUp(scope);
+  TestObserver* testObserver = MakeGarbageCollected<TestObserver>();
+  transferred_track_->AddObserver(testObserver);
+  transferred_track_->SetImplementation(
+      MakeGarbageCollected<testing::NiceMock<MockMediaStreamTrack>>());
+  EXPECT_EQ(testObserver->ObservationCount(), 1);
+}
+
+TEST_F(TransferredMediaStreamTrackTest, ObserversAddedToImpl) {
+  V8TestingScope scope;
+  CustomSetUp(scope);
+  transferred_track_->AddObserver(MakeGarbageCollected<TestObserver>());
+  MockMediaStreamTrack* mock_impl =
+      MakeGarbageCollected<testing::NiceMock<MockMediaStreamTrack>>();
+  EXPECT_CALL(*mock_impl, AddObserver(_));
+  transferred_track_->SetImplementation(mock_impl);
+}
+
 }  // namespace blink