1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver_impl.h"
6 
7 #include <memory>
8 
9 #include "base/bind.h"
10 #include "base/logging.h"
11 #include "base/memory/ptr_util.h"
12 #include "base/memory/scoped_refptr.h"
13 #include "base/optional.h"
14 #include "base/run_loop.h"
15 #include "base/single_thread_task_runner.h"
16 #include "base/synchronization/waitable_event.h"
17 #include "build/build_config.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 #include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
20 #include "third_party/blink/public/platform/web_media_stream_source.h"
21 #include "third_party/blink/public/platform/web_string.h"
22 #include "third_party/blink/public/web/web_heap.h"
23 #include "third_party/blink/renderer/modules/peerconnection/mock_peer_connection_dependency_factory.h"
24 #include "third_party/blink/renderer/modules/peerconnection/mock_peer_connection_impl.h"
25 #include "third_party/blink/renderer/modules/peerconnection/webrtc_media_stream_track_adapter_map.h"
26 #include "third_party/blink/renderer/platform/mediastream/media_stream_audio_source.h"
27 #include "third_party/blink/renderer/platform/peerconnection/webrtc_util.h"
28 #include "third_party/blink/renderer/platform/testing/io_task_runner_testing_platform_support.h"
29 #include "third_party/webrtc/api/test/mock_rtpreceiver.h"
30 #include "third_party/webrtc/api/test/mock_rtpsender.h"
31 
32 namespace blink {
33 
34 class RTCRtpTransceiverImplTest : public ::testing::Test {
35  public:
SetUp()36   void SetUp() override {
37     dependency_factory_.reset(new blink::MockPeerConnectionDependencyFactory());
38     main_task_runner_ = blink::scheduler::GetSingleThreadTaskRunnerForTesting();
39     track_map_ = base::MakeRefCounted<blink::WebRtcMediaStreamTrackAdapterMap>(
40         dependency_factory_.get(), main_task_runner_);
41     peer_connection_ = new rtc::RefCountedObject<blink::MockPeerConnectionImpl>(
42         dependency_factory_.get(), nullptr);
43   }
44 
TearDown()45   void TearDown() override {
46     // Syncing up with the signaling thread ensures any pending operations on
47     // that thread are executed. If they post back to the main thread, such as
48     // the sender or receiver destructor traits, this is allowed to execute
49     // before the test shuts down the threads.
50     SyncWithSignalingThread();
51     blink::WebHeap::CollectAllGarbageForTesting();
52   }
53 
54   // Wait for the signaling thread to perform any queued tasks, executing tasks
55   // posted to the current thread in the meantime while waiting.
SyncWithSignalingThread() const56   void SyncWithSignalingThread() const {
57     base::RunLoop run_loop;
58     dependency_factory_->GetWebRtcSignalingTaskRunner()->PostTask(
59         FROM_HERE, run_loop.QuitClosure());
60     run_loop.Run();
61   }
62 
signaling_task_runner() const63   scoped_refptr<base::SingleThreadTaskRunner> signaling_task_runner() const {
64     return dependency_factory_->GetWebRtcSignalingTaskRunner();
65   }
66 
67   std::unique_ptr<blink::WebRtcMediaStreamTrackAdapterMap::AdapterRef>
CreateLocalTrackAndAdapter(const std::string & id)68   CreateLocalTrackAndAdapter(const std::string& id) {
69     return track_map_->GetOrCreateLocalTrackAdapter(CreateBlinkLocalTrack(id));
70   }
71 
72   std::unique_ptr<blink::WebRtcMediaStreamTrackAdapterMap::AdapterRef>
CreateRemoteTrackAndAdapter(const std::string & id)73   CreateRemoteTrackAndAdapter(const std::string& id) {
74     rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> webrtc_track =
75         blink::MockWebRtcAudioTrack::Create(id).get();
76     std::unique_ptr<blink::WebRtcMediaStreamTrackAdapterMap::AdapterRef>
77         track_ref;
78     base::RunLoop run_loop;
79     signaling_task_runner()->PostTask(
80         FROM_HERE,
81         base::BindOnce(&RTCRtpTransceiverImplTest::
82                            CreateRemoteTrackAdapterOnSignalingThread,
83                        base::Unretained(this), std::move(webrtc_track),
84                        base::Unretained(&track_ref),
85                        base::Unretained(&run_loop)));
86     run_loop.Run();
87     DCHECK(track_ref);
88     return track_ref;
89   }
90 
CreateWebRtcSender(rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track,const std::string & stream_id)91   rtc::scoped_refptr<blink::FakeRtpSender> CreateWebRtcSender(
92       rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track,
93       const std::string& stream_id) {
94     return new rtc::RefCountedObject<blink::FakeRtpSender>(
95         std::move(track), std::vector<std::string>({stream_id}));
96   }
97 
CreateWebRtcReceiver(rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track,const std::string & stream_id)98   rtc::scoped_refptr<blink::FakeRtpReceiver> CreateWebRtcReceiver(
99       rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track,
100       const std::string& stream_id) {
101     rtc::scoped_refptr<webrtc::MediaStreamInterface> remote_stream(
102         new rtc::RefCountedObject<blink::MockMediaStream>(stream_id));
103     return new rtc::RefCountedObject<blink::FakeRtpReceiver>(
104         track.get(),
105         std::vector<rtc::scoped_refptr<webrtc::MediaStreamInterface>>(
106             {remote_stream}));
107   }
108 
CreateWebRtcTransceiver(rtc::scoped_refptr<blink::FakeRtpSender> sender,rtc::scoped_refptr<blink::FakeRtpReceiver> receiver,base::Optional<std::string> mid,bool stopped,webrtc::RtpTransceiverDirection direction,base::Optional<webrtc::RtpTransceiverDirection> current_direction)109   rtc::scoped_refptr<blink::FakeRtpTransceiver> CreateWebRtcTransceiver(
110       rtc::scoped_refptr<blink::FakeRtpSender> sender,
111       rtc::scoped_refptr<blink::FakeRtpReceiver> receiver,
112       base::Optional<std::string> mid,
113       bool stopped,
114       webrtc::RtpTransceiverDirection direction,
115       base::Optional<webrtc::RtpTransceiverDirection> current_direction) {
116     DCHECK(!sender->track() ||
117            sender->track()->kind() == receiver->track()->kind());
118     return new rtc::RefCountedObject<blink::FakeRtpTransceiver>(
119         receiver->track()->kind() ==
120                 webrtc::MediaStreamTrackInterface::kAudioKind
121             ? cricket::MEDIA_TYPE_AUDIO
122             : cricket::MEDIA_TYPE_VIDEO,
123         std::move(sender), std::move(receiver), std::move(mid), stopped,
124         direction, std::move(current_direction));
125   }
126 
CreateTransceiverState(rtc::scoped_refptr<webrtc::RtpTransceiverInterface> webrtc_transceiver,std::unique_ptr<blink::WebRtcMediaStreamTrackAdapterMap::AdapterRef> sender_track_ref,std::unique_ptr<blink::WebRtcMediaStreamTrackAdapterMap::AdapterRef> receiver_track_ref)127   RtpTransceiverState CreateTransceiverState(
128       rtc::scoped_refptr<webrtc::RtpTransceiverInterface> webrtc_transceiver,
129       std::unique_ptr<blink::WebRtcMediaStreamTrackAdapterMap::AdapterRef>
130           sender_track_ref,
131       std::unique_ptr<blink::WebRtcMediaStreamTrackAdapterMap::AdapterRef>
132           receiver_track_ref) {
133     std::vector<std::string> receiver_stream_ids;
134     for (const auto& stream : webrtc_transceiver->receiver()->streams()) {
135       receiver_stream_ids.push_back(stream->id());
136     }
137     return RtpTransceiverState(
138         main_task_runner_, signaling_task_runner(), webrtc_transceiver.get(),
139         blink::RtpSenderState(main_task_runner_, signaling_task_runner(),
140                               webrtc_transceiver->sender().get(),
141                               std::move(sender_track_ref),
142                               webrtc_transceiver->sender()->stream_ids()),
143         blink::RtpReceiverState(main_task_runner_, signaling_task_runner(),
144                                 webrtc_transceiver->receiver().get(),
145                                 std::move(receiver_track_ref),
146                                 std::move(receiver_stream_ids)),
147         blink::ToBaseOptional(webrtc_transceiver->mid()),
148         webrtc_transceiver->stopped(), webrtc_transceiver->direction(),
149         blink::ToBaseOptional(webrtc_transceiver->current_direction()),
150         blink::ToBaseOptional(webrtc_transceiver->fired_direction()));
151   }
152 
153  protected:
CreateBlinkLocalTrack(const std::string & id)154   blink::WebMediaStreamTrack CreateBlinkLocalTrack(const std::string& id) {
155     blink::WebMediaStreamSource web_source;
156     web_source.Initialize(
157         blink::WebString::FromUTF8(id), blink::WebMediaStreamSource::kTypeAudio,
158         blink::WebString::FromUTF8("local_audio_track"), false);
159     blink::MediaStreamAudioSource* audio_source =
160         new blink::MediaStreamAudioSource(
161             blink::scheduler::GetSingleThreadTaskRunnerForTesting(), true);
162     // Takes ownership of |audio_source|.
163     web_source.SetPlatformSource(base::WrapUnique(audio_source));
164 
165     blink::WebMediaStreamTrack web_track;
166     web_track.Initialize(web_source.Id(), web_source);
167     audio_source->ConnectToTrack(web_track);
168     return web_track;
169   }
170 
CreateRemoteTrackAdapterOnSignalingThread(rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> webrtc_track,std::unique_ptr<blink::WebRtcMediaStreamTrackAdapterMap::AdapterRef> * track_ref,base::RunLoop * run_loop)171   void CreateRemoteTrackAdapterOnSignalingThread(
172       rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> webrtc_track,
173       std::unique_ptr<blink::WebRtcMediaStreamTrackAdapterMap::AdapterRef>*
174           track_ref,
175       base::RunLoop* run_loop) {
176     *track_ref = track_map_->GetOrCreateRemoteTrackAdapter(webrtc_track.get());
177     run_loop->Quit();
178   }
179 
180  private:
181   ScopedTestingPlatformSupport<IOTaskRunnerTestingPlatformSupport> platform_;
182 
183  protected:
184   std::unique_ptr<blink::MockPeerConnectionDependencyFactory>
185       dependency_factory_;
186   scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
187   scoped_refptr<blink::WebRtcMediaStreamTrackAdapterMap> track_map_;
188   rtc::scoped_refptr<blink::MockPeerConnectionImpl> peer_connection_;
189 };
190 
TEST_F(RTCRtpTransceiverImplTest,InitializeTransceiverState)191 TEST_F(RTCRtpTransceiverImplTest, InitializeTransceiverState) {
192   auto local_track_adapter = CreateLocalTrackAndAdapter("local_track");
193   auto remote_track_adapter = CreateRemoteTrackAndAdapter("remote_track");
194   auto webrtc_transceiver = CreateWebRtcTransceiver(
195       CreateWebRtcSender(local_track_adapter->webrtc_track(), "local_stream"),
196       CreateWebRtcReceiver(remote_track_adapter->webrtc_track(),
197                            "remote_stream"),
198       base::nullopt, false, webrtc::RtpTransceiverDirection::kSendRecv,
199       base::nullopt);
200   RtpTransceiverState transceiver_state =
201       CreateTransceiverState(webrtc_transceiver, std::move(local_track_adapter),
202                              std::move(remote_track_adapter));
203   EXPECT_FALSE(transceiver_state.is_initialized());
204   transceiver_state.Initialize();
205 
206   EXPECT_TRUE(transceiver_state.is_initialized());
207   // Inspect sender states.
208   const auto& sender_state = transceiver_state.sender_state();
209   EXPECT_TRUE(sender_state);
210   EXPECT_TRUE(sender_state->is_initialized());
211   const auto& webrtc_sender = webrtc_transceiver->sender();
212   EXPECT_EQ(sender_state->webrtc_sender().get(), webrtc_sender.get());
213   EXPECT_TRUE(sender_state->track_ref()->is_initialized());
214   EXPECT_EQ(sender_state->track_ref()->webrtc_track(),
215             webrtc_sender->track().get());
216   EXPECT_EQ(sender_state->stream_ids(), webrtc_sender->stream_ids());
217   // Inspect receiver states.
218   const auto& receiver_state = transceiver_state.receiver_state();
219   EXPECT_TRUE(receiver_state);
220   EXPECT_TRUE(receiver_state->is_initialized());
221   const auto& webrtc_receiver = webrtc_transceiver->receiver();
222   EXPECT_EQ(receiver_state->webrtc_receiver().get(), webrtc_receiver.get());
223   EXPECT_TRUE(receiver_state->track_ref()->is_initialized());
224   EXPECT_EQ(receiver_state->track_ref()->webrtc_track(),
225             webrtc_receiver->track().get());
226   std::vector<std::string> receiver_stream_ids;
227   for (const auto& stream : webrtc_receiver->streams()) {
228     receiver_stream_ids.push_back(stream->id());
229   }
230   EXPECT_EQ(receiver_state->stream_ids(), receiver_stream_ids);
231   // Inspect transceiver states.
232   EXPECT_TRUE(blink::OptionalEquals(transceiver_state.mid(),
233                                     webrtc_transceiver->mid()));
234   EXPECT_EQ(transceiver_state.stopped(), webrtc_transceiver->stopped());
235   EXPECT_TRUE(transceiver_state.direction() == webrtc_transceiver->direction());
236   EXPECT_TRUE(blink::OptionalEquals(transceiver_state.current_direction(),
237                                     webrtc_transceiver->current_direction()));
238   EXPECT_TRUE(blink::OptionalEquals(transceiver_state.fired_direction(),
239                                     webrtc_transceiver->fired_direction()));
240 }
241 
TEST_F(RTCRtpTransceiverImplTest,CreateTranceiver)242 TEST_F(RTCRtpTransceiverImplTest, CreateTranceiver) {
243   auto local_track_adapter = CreateLocalTrackAndAdapter("local_track");
244   auto remote_track_adapter = CreateRemoteTrackAndAdapter("remote_track");
245   auto webrtc_transceiver = CreateWebRtcTransceiver(
246       CreateWebRtcSender(local_track_adapter->webrtc_track(), "local_stream"),
247       CreateWebRtcReceiver(remote_track_adapter->webrtc_track(),
248                            "remote_stream"),
249       base::nullopt, false, webrtc::RtpTransceiverDirection::kSendRecv,
250       base::nullopt);
251   RtpTransceiverState transceiver_state =
252       CreateTransceiverState(webrtc_transceiver, std::move(local_track_adapter),
253                              std::move(remote_track_adapter));
254   EXPECT_FALSE(transceiver_state.is_initialized());
255   transceiver_state.Initialize();
256 
257   RTCRtpTransceiverImpl transceiver(
258       peer_connection_.get(), track_map_, std::move(transceiver_state),
259       /*force_encoded_audio_insertable_streams=*/false,
260       /*force_encoded_video_insertable_streams=*/false);
261   EXPECT_TRUE(transceiver.Mid().IsNull());
262   EXPECT_TRUE(transceiver.Sender());
263   EXPECT_TRUE(transceiver.Receiver());
264   EXPECT_FALSE(transceiver.Stopped());
265   EXPECT_EQ(transceiver.Direction(),
266             webrtc::RtpTransceiverDirection::kSendRecv);
267   EXPECT_FALSE(transceiver.CurrentDirection());
268   EXPECT_FALSE(transceiver.FiredDirection());
269 }
270 
TEST_F(RTCRtpTransceiverImplTest,ModifyTransceiver)271 TEST_F(RTCRtpTransceiverImplTest, ModifyTransceiver) {
272   auto local_track_adapter = CreateLocalTrackAndAdapter("local_track");
273   auto remote_track_adapter = CreateRemoteTrackAndAdapter("remote_track");
274   auto webrtc_sender =
275       CreateWebRtcSender(local_track_adapter->webrtc_track(), "local_stream");
276   auto webrtc_receiver = CreateWebRtcReceiver(
277       remote_track_adapter->webrtc_track(), "remote_stream");
278   auto webrtc_transceiver = CreateWebRtcTransceiver(
279       webrtc_sender, webrtc_receiver, base::nullopt, false,
280       webrtc::RtpTransceiverDirection::kSendRecv, base::nullopt);
281 
282   // Create initial state.
283   RtpTransceiverState initial_transceiver_state =
284       CreateTransceiverState(webrtc_transceiver, local_track_adapter->Copy(),
285                              remote_track_adapter->Copy());
286   EXPECT_FALSE(initial_transceiver_state.is_initialized());
287   initial_transceiver_state.Initialize();
288 
289   // Modify the webrtc transceiver and create a new state object for the
290   // modified state.
291   webrtc_transceiver->ReplaceWith(
292       *CreateWebRtcTransceiver(webrtc_sender, webrtc_receiver, "MidyMacMidface",
293                                true, webrtc::RtpTransceiverDirection::kInactive,
294                                webrtc::RtpTransceiverDirection::kSendRecv));
295   RtpTransceiverState modified_transceiver_state =
296       CreateTransceiverState(webrtc_transceiver, local_track_adapter->Copy(),
297                              remote_track_adapter->Copy());
298   EXPECT_FALSE(modified_transceiver_state.is_initialized());
299   modified_transceiver_state.Initialize();
300 
301   // Modifying the webrtc transceiver after the initial state was created should
302   // not have affected the transceiver state.
303   RTCRtpTransceiverImpl transceiver(
304       peer_connection_.get(), track_map_, std::move(initial_transceiver_state),
305       /*force_encoded_audio_insertable_streams=*/false,
306       /*force_encoded_video_insertable_streams=*/false);
307   EXPECT_TRUE(transceiver.Mid().IsNull());
308   EXPECT_TRUE(transceiver.Sender());
309   EXPECT_TRUE(transceiver.Receiver());
310   EXPECT_FALSE(transceiver.Stopped());
311   EXPECT_EQ(transceiver.Direction(),
312             webrtc::RtpTransceiverDirection::kSendRecv);
313   EXPECT_FALSE(transceiver.CurrentDirection());
314   EXPECT_FALSE(transceiver.FiredDirection());
315 
316   // Setting the state should make the transceiver state up-to-date.
317   transceiver.set_state(std::move(modified_transceiver_state),
318                         TransceiverStateUpdateMode::kAll);
319   EXPECT_EQ(transceiver.Mid(), "MidyMacMidface");
320   EXPECT_TRUE(transceiver.Sender());
321   EXPECT_TRUE(transceiver.Receiver());
322   EXPECT_TRUE(transceiver.Stopped());
323   EXPECT_EQ(transceiver.Direction(),
324             webrtc::RtpTransceiverDirection::kInactive);
325   EXPECT_TRUE(transceiver.CurrentDirection() ==
326               webrtc::RtpTransceiverDirection::kSendRecv);
327   EXPECT_FALSE(transceiver.FiredDirection());
328 }
329 
TEST_F(RTCRtpTransceiverImplTest,ShallowCopy)330 TEST_F(RTCRtpTransceiverImplTest, ShallowCopy) {
331   auto local_track_adapter = CreateLocalTrackAndAdapter("local_track");
332   auto remote_track_adapter = CreateRemoteTrackAndAdapter("remote_track");
333   auto webrtc_sender =
334       CreateWebRtcSender(local_track_adapter->webrtc_track(), "local_stream");
335   auto webrtc_receiver = CreateWebRtcReceiver(
336       remote_track_adapter->webrtc_track(), "remote_stream");
337   auto webrtc_transceiver = CreateWebRtcTransceiver(
338       webrtc_sender, webrtc_receiver, base::nullopt, false /* stopped */,
339       webrtc::RtpTransceiverDirection::kSendRecv, base::nullopt);
340 
341   std::unique_ptr<RTCRtpTransceiverImpl> transceiver;
342   // Create transceiver.
343   {
344     RtpTransceiverState transceiver_state =
345         CreateTransceiverState(webrtc_transceiver, local_track_adapter->Copy(),
346                                remote_track_adapter->Copy());
347     EXPECT_FALSE(transceiver_state.is_initialized());
348     transceiver_state.Initialize();
349     transceiver.reset(new RTCRtpTransceiverImpl(
350         peer_connection_.get(), track_map_, std::move(transceiver_state),
351         /*force_encoded_audio_insertable_streams=*/false,
352         /*force_encoded_video_insertable_streams=*/false));
353   }
354   DCHECK(transceiver);
355   EXPECT_FALSE(transceiver->Stopped());
356 
357   std::unique_ptr<RTCRtpTransceiverImpl> shallow_copy =
358       transceiver->ShallowCopy();
359   // Modifying the shallow copy should modify the original too since they have a
360   // shared internal state.
361   {
362     // Modify webrtc transceiver to be stopped.
363     webrtc_transceiver->ReplaceWith(*CreateWebRtcTransceiver(
364         webrtc_sender, webrtc_receiver, base::nullopt, true /* stopped */,
365         webrtc::RtpTransceiverDirection::kSendRecv, base::nullopt));
366     RtpTransceiverState transceiver_state =
367         CreateTransceiverState(webrtc_transceiver, local_track_adapter->Copy(),
368                                remote_track_adapter->Copy());
369     EXPECT_FALSE(transceiver_state.is_initialized());
370     transceiver_state.Initialize();
371     // Set the state of the shallow copy.
372     shallow_copy->set_state(std::move(transceiver_state),
373                             TransceiverStateUpdateMode::kAll);
374   }
375   EXPECT_TRUE(shallow_copy->Stopped());
376   EXPECT_TRUE(transceiver->Stopped());
377 }
378 
TEST_F(RTCRtpTransceiverImplTest,TransceiverStateUpdateModeSetDescription)379 TEST_F(RTCRtpTransceiverImplTest, TransceiverStateUpdateModeSetDescription) {
380   auto local_track_adapter = CreateLocalTrackAndAdapter("local_track");
381   auto remote_track_adapter = CreateRemoteTrackAndAdapter("remote_track");
382   auto webrtc_sender =
383       CreateWebRtcSender(local_track_adapter->webrtc_track(), "local_stream");
384   auto webrtc_receiver = CreateWebRtcReceiver(
385       remote_track_adapter->webrtc_track(), "remote_stream");
386   auto webrtc_transceiver = CreateWebRtcTransceiver(
387       webrtc_sender, webrtc_receiver, base::nullopt, false,
388       webrtc::RtpTransceiverDirection::kSendRecv, base::nullopt);
389 
390   // Create initial state.
391   RtpTransceiverState initial_transceiver_state =
392       CreateTransceiverState(webrtc_transceiver, local_track_adapter->Copy(),
393                              remote_track_adapter->Copy());
394   EXPECT_FALSE(initial_transceiver_state.is_initialized());
395   initial_transceiver_state.Initialize();
396 
397   // Modify the webrtc transceiver and create a new state object for the
398   // modified state.
399   webrtc_sender->SetTrack(nullptr);
400   webrtc_transceiver->ReplaceWith(
401       *CreateWebRtcTransceiver(webrtc_sender, webrtc_receiver, "MidyMacMidface",
402                                true, webrtc::RtpTransceiverDirection::kInactive,
403                                webrtc::RtpTransceiverDirection::kSendRecv));
404   RtpTransceiverState modified_transceiver_state =
405       CreateTransceiverState(webrtc_transceiver, local_track_adapter->Copy(),
406                              remote_track_adapter->Copy());
407   EXPECT_FALSE(modified_transceiver_state.is_initialized());
408   modified_transceiver_state.Initialize();
409 
410   // Construct a transceiver from the initial state.
411   RTCRtpTransceiverImpl transceiver(
412       peer_connection_.get(), track_map_, std::move(initial_transceiver_state),
413       /*force_encoded_audio_insertable_streams=*/false,
414       /*force_encoded_video_insertable_streams=*/false);
415   // Setting the state with TransceiverStateUpdateMode::kSetDescription should
416   // make the transceiver state up-to-date, except leaving
417   // "transceiver.direction" and "transceiver.sender.track" unmodified.
418   transceiver.set_state(std::move(modified_transceiver_state),
419                         TransceiverStateUpdateMode::kSetDescription);
420   EXPECT_EQ(transceiver.Mid(), "MidyMacMidface");
421   EXPECT_TRUE(transceiver.Sender());
422   EXPECT_TRUE(transceiver.Receiver());
423   EXPECT_TRUE(transceiver.Stopped());
424   EXPECT_TRUE(transceiver.CurrentDirection() ==
425               webrtc::RtpTransceiverDirection::kSendRecv);
426   EXPECT_FALSE(transceiver.FiredDirection());
427   // The sender still has a track, even though the modified state doesn't.
428   EXPECT_FALSE(transceiver.Sender()->Track().IsNull());
429   // The direction still "sendrecv", even though the modified state has
430   // "inactive".
431   EXPECT_EQ(transceiver.Direction(),
432             webrtc::RtpTransceiverDirection::kSendRecv);
433 }
434 
435 }  // namespace blink
436