Home | History | Annotate | Download | only in sender
      1 // Copyright 2014 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 <stdint.h>
      6 
      7 #include <vector>
      8 
      9 #include "base/bind.h"
     10 #include "base/memory/scoped_ptr.h"
     11 #include "base/test/simple_test_tick_clock.h"
     12 #include "media/base/video_frame.h"
     13 #include "media/cast/cast_environment.h"
     14 #include "media/cast/logging/simple_event_subscriber.h"
     15 #include "media/cast/net/cast_transport_config.h"
     16 #include "media/cast/net/cast_transport_sender_impl.h"
     17 #include "media/cast/net/pacing/paced_sender.h"
     18 #include "media/cast/sender/video_sender.h"
     19 #include "media/cast/test/fake_single_thread_task_runner.h"
     20 #include "media/cast/test/fake_video_encode_accelerator.h"
     21 #include "media/cast/test/utility/default_config.h"
     22 #include "media/cast/test/utility/video_utility.h"
     23 #include "testing/gmock/include/gmock/gmock.h"
     24 #include "testing/gtest/include/gtest/gtest.h"
     25 
     26 namespace media {
     27 namespace cast {
     28 
     29 namespace {
     30 static const uint8 kPixelValue = 123;
     31 static const int kWidth = 320;
     32 static const int kHeight = 240;
     33 
     34 using testing::_;
     35 using testing::AtLeast;
     36 
     37 void CreateVideoEncodeAccelerator(
     38     const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
     39     scoped_ptr<VideoEncodeAccelerator> fake_vea,
     40     const ReceiveVideoEncodeAcceleratorCallback& callback) {
     41   callback.Run(task_runner, fake_vea.Pass());
     42 }
     43 
     44 void CreateSharedMemory(
     45     size_t size, const ReceiveVideoEncodeMemoryCallback& callback) {
     46   scoped_ptr<base::SharedMemory> shm(new base::SharedMemory());
     47   if (!shm->CreateAndMapAnonymous(size)) {
     48     NOTREACHED();
     49     return;
     50   }
     51   callback.Run(shm.Pass());
     52 }
     53 
     54 void SaveInitializationStatus(CastInitializationStatus* out_status,
     55                               CastInitializationStatus in_status) {
     56   *out_status = in_status;
     57 }
     58 
     59 class TestPacketSender : public PacketSender {
     60  public:
     61   TestPacketSender()
     62       : number_of_rtp_packets_(0),
     63         number_of_rtcp_packets_(0),
     64         paused_(false) {}
     65 
     66   // A singular packet implies a RTCP packet.
     67   virtual bool SendPacket(PacketRef packet,
     68                           const base::Closure& cb) OVERRIDE {
     69     if (paused_) {
     70       stored_packet_ = packet;
     71       callback_ = cb;
     72       return false;
     73     }
     74     if (Rtcp::IsRtcpPacket(&packet->data[0], packet->data.size())) {
     75       ++number_of_rtcp_packets_;
     76     } else {
     77       // Check that at least one RTCP packet was sent before the first RTP
     78       // packet.  This confirms that the receiver will have the necessary lip
     79       // sync info before it has to calculate the playout time of the first
     80       // frame.
     81       if (number_of_rtp_packets_ == 0)
     82         EXPECT_LE(1, number_of_rtcp_packets_);
     83       ++number_of_rtp_packets_;
     84     }
     85     return true;
     86   }
     87 
     88   virtual int64 GetBytesSent() OVERRIDE {
     89     return 0;
     90   }
     91 
     92   int number_of_rtp_packets() const { return number_of_rtp_packets_; }
     93 
     94   int number_of_rtcp_packets() const { return number_of_rtcp_packets_; }
     95 
     96   void SetPause(bool paused) {
     97     paused_ = paused;
     98     if (!paused && stored_packet_.get()) {
     99       SendPacket(stored_packet_, callback_);
    100       callback_.Run();
    101     }
    102   }
    103 
    104  private:
    105   int number_of_rtp_packets_;
    106   int number_of_rtcp_packets_;
    107   bool paused_;
    108   base::Closure callback_;
    109   PacketRef stored_packet_;
    110 
    111   DISALLOW_COPY_AND_ASSIGN(TestPacketSender);
    112 };
    113 
    114 void IgnorePlayoutDelayChanges(base::TimeDelta unused_playout_delay) {
    115 }
    116 class PeerVideoSender : public VideoSender {
    117  public:
    118   PeerVideoSender(
    119       scoped_refptr<CastEnvironment> cast_environment,
    120       const VideoSenderConfig& video_config,
    121       const CastInitializationCallback& initialization_cb,
    122       const CreateVideoEncodeAcceleratorCallback& create_vea_cb,
    123       const CreateVideoEncodeMemoryCallback& create_video_encode_mem_cb,
    124       CastTransportSender* const transport_sender)
    125       : VideoSender(cast_environment,
    126                     video_config,
    127                     initialization_cb,
    128                     create_vea_cb,
    129                     create_video_encode_mem_cb,
    130                     transport_sender,
    131                     base::Bind(&IgnorePlayoutDelayChanges)) {}
    132   using VideoSender::OnReceivedCastFeedback;
    133 };
    134 }  // namespace
    135 
    136 class VideoSenderTest : public ::testing::Test {
    137  protected:
    138   VideoSenderTest() {
    139     testing_clock_ = new base::SimpleTestTickClock();
    140     testing_clock_->Advance(base::TimeTicks::Now() - base::TimeTicks());
    141     task_runner_ = new test::FakeSingleThreadTaskRunner(testing_clock_);
    142     cast_environment_ =
    143         new CastEnvironment(scoped_ptr<base::TickClock>(testing_clock_).Pass(),
    144                             task_runner_,
    145                             task_runner_,
    146                             task_runner_);
    147     last_pixel_value_ = kPixelValue;
    148     net::IPEndPoint dummy_endpoint;
    149     transport_sender_.reset(new CastTransportSenderImpl(
    150         NULL,
    151         testing_clock_,
    152         dummy_endpoint,
    153         make_scoped_ptr(new base::DictionaryValue),
    154         base::Bind(&UpdateCastTransportStatus),
    155         BulkRawEventsCallback(),
    156         base::TimeDelta(),
    157         task_runner_,
    158         &transport_));
    159   }
    160 
    161   virtual ~VideoSenderTest() {}
    162 
    163   virtual void TearDown() OVERRIDE {
    164     video_sender_.reset();
    165     task_runner_->RunTasks();
    166   }
    167 
    168   static void UpdateCastTransportStatus(CastTransportStatus status) {
    169     EXPECT_EQ(TRANSPORT_VIDEO_INITIALIZED, status);
    170   }
    171 
    172   // If |external| is true then external video encoder (VEA) is used.
    173   // |expect_init_sucess| is true if initialization is expected to succeed.
    174   CastInitializationStatus InitEncoder(bool external,
    175                                        bool expect_init_success) {
    176     VideoSenderConfig video_config;
    177     video_config.ssrc = 1;
    178     video_config.incoming_feedback_ssrc = 2;
    179     video_config.rtp_payload_type = 127;
    180     video_config.use_external_encoder = external;
    181     video_config.width = kWidth;
    182     video_config.height = kHeight;
    183     video_config.max_bitrate = 5000000;
    184     video_config.min_bitrate = 1000000;
    185     video_config.start_bitrate = 1000000;
    186     video_config.max_qp = 56;
    187     video_config.min_qp = 0;
    188     video_config.max_frame_rate = 30;
    189     video_config.max_number_of_video_buffers_used = 1;
    190     video_config.codec = CODEC_VIDEO_VP8;
    191     CastInitializationStatus status = STATUS_VIDEO_UNINITIALIZED;
    192 
    193     if (external) {
    194       test::FakeVideoEncodeAccelerator* fake_vea =
    195           new test::FakeVideoEncodeAccelerator(
    196               task_runner_, &stored_bitrates_);
    197       fake_vea->SetWillInitializationSucceed(expect_init_success);
    198       scoped_ptr<VideoEncodeAccelerator> fake_vea_owner(fake_vea);
    199       video_sender_.reset(
    200           new PeerVideoSender(cast_environment_,
    201                               video_config,
    202                               base::Bind(&SaveInitializationStatus,
    203                                          &status),
    204                               base::Bind(&CreateVideoEncodeAccelerator,
    205                                          task_runner_,
    206                                          base::Passed(&fake_vea_owner)),
    207                               base::Bind(&CreateSharedMemory),
    208                               transport_sender_.get()));
    209     } else {
    210       video_sender_.reset(
    211           new PeerVideoSender(cast_environment_,
    212                               video_config,
    213                               base::Bind(&SaveInitializationStatus,
    214                                          &status),
    215                               CreateDefaultVideoEncodeAcceleratorCallback(),
    216                               CreateDefaultVideoEncodeMemoryCallback(),
    217                               transport_sender_.get()));
    218     }
    219     task_runner_->RunTasks();
    220     return status;
    221   }
    222 
    223   scoped_refptr<media::VideoFrame> GetNewVideoFrame() {
    224     gfx::Size size(kWidth, kHeight);
    225     scoped_refptr<media::VideoFrame> video_frame =
    226         media::VideoFrame::CreateFrame(
    227             VideoFrame::I420, size, gfx::Rect(size), size, base::TimeDelta());
    228     PopulateVideoFrame(video_frame.get(), last_pixel_value_++);
    229     return video_frame;
    230   }
    231 
    232   scoped_refptr<media::VideoFrame> GetLargeNewVideoFrame() {
    233     gfx::Size size(kWidth, kHeight);
    234     scoped_refptr<media::VideoFrame> video_frame =
    235         media::VideoFrame::CreateFrame(
    236             VideoFrame::I420, size, gfx::Rect(size), size, base::TimeDelta());
    237     PopulateVideoFrameWithNoise(video_frame.get());
    238     return video_frame;
    239   }
    240 
    241   void RunTasks(int during_ms) {
    242     task_runner_->Sleep(base::TimeDelta::FromMilliseconds(during_ms));
    243   }
    244 
    245   base::SimpleTestTickClock* testing_clock_;  // Owned by CastEnvironment.
    246   TestPacketSender transport_;
    247   scoped_ptr<CastTransportSenderImpl> transport_sender_;
    248   scoped_refptr<test::FakeSingleThreadTaskRunner> task_runner_;
    249   scoped_ptr<PeerVideoSender> video_sender_;
    250   std::vector<uint32> stored_bitrates_;
    251   scoped_refptr<CastEnvironment> cast_environment_;
    252   int last_pixel_value_;
    253 
    254   DISALLOW_COPY_AND_ASSIGN(VideoSenderTest);
    255 };
    256 
    257 TEST_F(VideoSenderTest, BuiltInEncoder) {
    258   EXPECT_EQ(STATUS_VIDEO_INITIALIZED, InitEncoder(false, true));
    259   scoped_refptr<media::VideoFrame> video_frame = GetNewVideoFrame();
    260 
    261   const base::TimeTicks capture_time = testing_clock_->NowTicks();
    262   video_sender_->InsertRawVideoFrame(video_frame, capture_time);
    263 
    264   task_runner_->RunTasks();
    265   EXPECT_LE(1, transport_.number_of_rtp_packets());
    266   EXPECT_LE(1, transport_.number_of_rtcp_packets());
    267 }
    268 
    269 TEST_F(VideoSenderTest, ExternalEncoder) {
    270   EXPECT_EQ(STATUS_VIDEO_INITIALIZED, InitEncoder(true, true));
    271 
    272   scoped_refptr<media::VideoFrame> video_frame = GetNewVideoFrame();
    273 
    274   const base::TimeTicks capture_time = testing_clock_->NowTicks();
    275   video_sender_->InsertRawVideoFrame(video_frame, capture_time);
    276   task_runner_->RunTasks();
    277   video_sender_->InsertRawVideoFrame(video_frame, capture_time);
    278   task_runner_->RunTasks();
    279   video_sender_->InsertRawVideoFrame(video_frame, capture_time);
    280   task_runner_->RunTasks();
    281 
    282   // Fixed bitrate is used for external encoder. Bitrate is only once
    283   // to the encoder.
    284   EXPECT_EQ(1u, stored_bitrates_.size());
    285   video_sender_.reset(NULL);
    286   task_runner_->RunTasks();
    287 }
    288 
    289 TEST_F(VideoSenderTest, ExternalEncoderInitFails) {
    290   EXPECT_EQ(STATUS_HW_VIDEO_ENCODER_NOT_SUPPORTED,
    291             InitEncoder(true, false));
    292   video_sender_.reset(NULL);
    293   task_runner_->RunTasks();
    294 }
    295 
    296 TEST_F(VideoSenderTest, RtcpTimer) {
    297   EXPECT_EQ(STATUS_VIDEO_INITIALIZED, InitEncoder(false, true));
    298 
    299   scoped_refptr<media::VideoFrame> video_frame = GetNewVideoFrame();
    300 
    301   const base::TimeTicks capture_time = testing_clock_->NowTicks();
    302   video_sender_->InsertRawVideoFrame(video_frame, capture_time);
    303 
    304   // Make sure that we send at least one RTCP packet.
    305   base::TimeDelta max_rtcp_timeout =
    306       base::TimeDelta::FromMilliseconds(1 + kDefaultRtcpIntervalMs * 3 / 2);
    307 
    308   RunTasks(max_rtcp_timeout.InMilliseconds());
    309   EXPECT_LE(1, transport_.number_of_rtp_packets());
    310   EXPECT_LE(1, transport_.number_of_rtcp_packets());
    311   // Build Cast msg and expect RTCP packet.
    312   RtcpCastMessage cast_feedback(1);
    313   cast_feedback.media_ssrc = 2;
    314   cast_feedback.ack_frame_id = 0;
    315   video_sender_->OnReceivedCastFeedback(cast_feedback);
    316   RunTasks(max_rtcp_timeout.InMilliseconds());
    317   EXPECT_LE(1, transport_.number_of_rtcp_packets());
    318 }
    319 
    320 TEST_F(VideoSenderTest, ResendTimer) {
    321   EXPECT_EQ(STATUS_VIDEO_INITIALIZED, InitEncoder(false, true));
    322 
    323   scoped_refptr<media::VideoFrame> video_frame = GetNewVideoFrame();
    324 
    325   const base::TimeTicks capture_time = testing_clock_->NowTicks();
    326   video_sender_->InsertRawVideoFrame(video_frame, capture_time);
    327 
    328   // ACK the key frame.
    329   RtcpCastMessage cast_feedback(1);
    330   cast_feedback.media_ssrc = 2;
    331   cast_feedback.ack_frame_id = 0;
    332   video_sender_->OnReceivedCastFeedback(cast_feedback);
    333 
    334   video_frame = GetNewVideoFrame();
    335   video_sender_->InsertRawVideoFrame(video_frame, capture_time);
    336 
    337   base::TimeDelta max_resend_timeout =
    338       base::TimeDelta::FromMilliseconds(1 + kDefaultRtpMaxDelayMs);
    339 
    340   // Make sure that we do a re-send.
    341   RunTasks(max_resend_timeout.InMilliseconds());
    342   // Should have sent at least 3 packets.
    343   EXPECT_LE(
    344       3,
    345       transport_.number_of_rtp_packets() + transport_.number_of_rtcp_packets());
    346 }
    347 
    348 TEST_F(VideoSenderTest, LogAckReceivedEvent) {
    349   EXPECT_EQ(STATUS_VIDEO_INITIALIZED, InitEncoder(false, true));
    350   SimpleEventSubscriber event_subscriber;
    351   cast_environment_->Logging()->AddRawEventSubscriber(&event_subscriber);
    352 
    353   int num_frames = 10;
    354   for (int i = 0; i < num_frames; i++) {
    355     scoped_refptr<media::VideoFrame> video_frame = GetNewVideoFrame();
    356 
    357     const base::TimeTicks capture_time = testing_clock_->NowTicks();
    358     video_sender_->InsertRawVideoFrame(video_frame, capture_time);
    359     RunTasks(33);
    360   }
    361 
    362   task_runner_->RunTasks();
    363 
    364   RtcpCastMessage cast_feedback(1);
    365   cast_feedback.ack_frame_id = num_frames - 1;
    366 
    367   video_sender_->OnReceivedCastFeedback(cast_feedback);
    368 
    369   std::vector<FrameEvent> frame_events;
    370   event_subscriber.GetFrameEventsAndReset(&frame_events);
    371 
    372   ASSERT_TRUE(!frame_events.empty());
    373   EXPECT_EQ(FRAME_ACK_RECEIVED, frame_events.rbegin()->type);
    374   EXPECT_EQ(VIDEO_EVENT, frame_events.rbegin()->media_type);
    375   EXPECT_EQ(num_frames - 1u, frame_events.rbegin()->frame_id);
    376 
    377   cast_environment_->Logging()->RemoveRawEventSubscriber(&event_subscriber);
    378 }
    379 
    380 TEST_F(VideoSenderTest, StopSendingInTheAbsenceOfAck) {
    381   EXPECT_EQ(STATUS_VIDEO_INITIALIZED, InitEncoder(false, true));
    382   // Send a stream of frames and don't ACK; by default we shouldn't have more
    383   // than 4 frames in flight.
    384   scoped_refptr<media::VideoFrame> video_frame = GetNewVideoFrame();
    385   video_sender_->InsertRawVideoFrame(video_frame, testing_clock_->NowTicks());
    386   RunTasks(33);
    387 
    388   // Send 3 more frames and record the number of packets sent.
    389   for (int i = 0; i < 3; ++i) {
    390     scoped_refptr<media::VideoFrame> video_frame = GetNewVideoFrame();
    391     video_sender_->InsertRawVideoFrame(video_frame, testing_clock_->NowTicks());
    392     RunTasks(33);
    393   }
    394   const int number_of_packets_sent = transport_.number_of_rtp_packets();
    395 
    396   // Send 3 more frames - they should not be encoded, as we have not received
    397   // any acks.
    398   for (int i = 0; i < 3; ++i) {
    399     scoped_refptr<media::VideoFrame> video_frame = GetNewVideoFrame();
    400     video_sender_->InsertRawVideoFrame(video_frame, testing_clock_->NowTicks());
    401     RunTasks(33);
    402   }
    403 
    404   // We expect a frame to be retransmitted because of duplicated ACKs.
    405   // Only one packet of the frame is re-transmitted.
    406   EXPECT_EQ(number_of_packets_sent + 1,
    407             transport_.number_of_rtp_packets());
    408 
    409   // Start acking and make sure we're back to steady-state.
    410   RtcpCastMessage cast_feedback(1);
    411   cast_feedback.media_ssrc = 2;
    412   cast_feedback.ack_frame_id = 0;
    413   video_sender_->OnReceivedCastFeedback(cast_feedback);
    414   EXPECT_LE(
    415       4,
    416       transport_.number_of_rtp_packets() + transport_.number_of_rtcp_packets());
    417 
    418   // Empty the pipeline.
    419   RunTasks(100);
    420   // Should have sent at least 7 packets.
    421   EXPECT_LE(
    422       7,
    423       transport_.number_of_rtp_packets() + transport_.number_of_rtcp_packets());
    424 }
    425 
    426 TEST_F(VideoSenderTest, DuplicateAckRetransmit) {
    427   EXPECT_EQ(STATUS_VIDEO_INITIALIZED, InitEncoder(false, true));
    428   scoped_refptr<media::VideoFrame> video_frame = GetNewVideoFrame();
    429   video_sender_->InsertRawVideoFrame(video_frame, testing_clock_->NowTicks());
    430   RunTasks(33);
    431   RtcpCastMessage cast_feedback(1);
    432   cast_feedback.media_ssrc = 2;
    433   cast_feedback.ack_frame_id = 0;
    434 
    435   // Send 3 more frames but don't ACK.
    436   for (int i = 0; i < 3; ++i) {
    437     scoped_refptr<media::VideoFrame> video_frame = GetNewVideoFrame();
    438     video_sender_->InsertRawVideoFrame(video_frame, testing_clock_->NowTicks());
    439     RunTasks(33);
    440   }
    441   const int number_of_packets_sent = transport_.number_of_rtp_packets();
    442 
    443   // Send duplicated ACKs and mix some invalid NACKs.
    444   for (int i = 0; i < 10; ++i) {
    445     RtcpCastMessage ack_feedback(1);
    446     ack_feedback.media_ssrc = 2;
    447     ack_feedback.ack_frame_id = 0;
    448     RtcpCastMessage nack_feedback(1);
    449     nack_feedback.media_ssrc = 2;
    450     nack_feedback.missing_frames_and_packets[255] = PacketIdSet();
    451     video_sender_->OnReceivedCastFeedback(ack_feedback);
    452     video_sender_->OnReceivedCastFeedback(nack_feedback);
    453   }
    454   EXPECT_EQ(number_of_packets_sent, transport_.number_of_rtp_packets());
    455 
    456   // Re-transmit one packet because of duplicated ACKs.
    457   for (int i = 0; i < 3; ++i) {
    458     RtcpCastMessage ack_feedback(1);
    459     ack_feedback.media_ssrc = 2;
    460     ack_feedback.ack_frame_id = 0;
    461     video_sender_->OnReceivedCastFeedback(ack_feedback);
    462   }
    463   EXPECT_EQ(number_of_packets_sent + 1, transport_.number_of_rtp_packets());
    464 }
    465 
    466 TEST_F(VideoSenderTest, DuplicateAckRetransmitDoesNotCancelRetransmits) {
    467   EXPECT_EQ(STATUS_VIDEO_INITIALIZED, InitEncoder(false, true));
    468   scoped_refptr<media::VideoFrame> video_frame = GetNewVideoFrame();
    469   video_sender_->InsertRawVideoFrame(video_frame, testing_clock_->NowTicks());
    470   RunTasks(33);
    471   RtcpCastMessage cast_feedback(1);
    472   cast_feedback.media_ssrc = 2;
    473   cast_feedback.ack_frame_id = 0;
    474 
    475   // Send 2 more frames but don't ACK.
    476   for (int i = 0; i < 2; ++i) {
    477     scoped_refptr<media::VideoFrame> video_frame = GetNewVideoFrame();
    478     video_sender_->InsertRawVideoFrame(video_frame, testing_clock_->NowTicks());
    479     RunTasks(33);
    480   }
    481   // Pause the transport
    482   transport_.SetPause(true);
    483 
    484   // Insert one more video frame.
    485   video_frame = GetLargeNewVideoFrame();
    486   video_sender_->InsertRawVideoFrame(video_frame, testing_clock_->NowTicks());
    487   RunTasks(33);
    488 
    489   const int number_of_packets_sent = transport_.number_of_rtp_packets();
    490 
    491   // Send duplicated ACKs and mix some invalid NACKs.
    492   for (int i = 0; i < 10; ++i) {
    493     RtcpCastMessage ack_feedback(1);
    494     ack_feedback.media_ssrc = 2;
    495     ack_feedback.ack_frame_id = 0;
    496     RtcpCastMessage nack_feedback(1);
    497     nack_feedback.media_ssrc = 2;
    498     nack_feedback.missing_frames_and_packets[255] = PacketIdSet();
    499     video_sender_->OnReceivedCastFeedback(ack_feedback);
    500     video_sender_->OnReceivedCastFeedback(nack_feedback);
    501   }
    502   EXPECT_EQ(number_of_packets_sent, transport_.number_of_rtp_packets());
    503 
    504   // Re-transmit one packet because of duplicated ACKs.
    505   for (int i = 0; i < 3; ++i) {
    506     RtcpCastMessage ack_feedback(1);
    507     ack_feedback.media_ssrc = 2;
    508     ack_feedback.ack_frame_id = 0;
    509     video_sender_->OnReceivedCastFeedback(ack_feedback);
    510   }
    511 
    512   transport_.SetPause(false);
    513   RunTasks(100);
    514   EXPECT_LT(number_of_packets_sent + 1, transport_.number_of_rtp_packets());
    515 }
    516 
    517 TEST_F(VideoSenderTest, AcksCancelRetransmits) {
    518   EXPECT_EQ(STATUS_VIDEO_INITIALIZED, InitEncoder(false, true));
    519   transport_.SetPause(true);
    520   scoped_refptr<media::VideoFrame> video_frame = GetLargeNewVideoFrame();
    521   video_sender_->InsertRawVideoFrame(video_frame, testing_clock_->NowTicks());
    522   RunTasks(33);
    523 
    524   // Frame should be in buffer, waiting. Now let's ack it.
    525   RtcpCastMessage cast_feedback(1);
    526   cast_feedback.media_ssrc = 2;
    527   cast_feedback.ack_frame_id = 0;
    528   video_sender_->OnReceivedCastFeedback(cast_feedback);
    529 
    530   transport_.SetPause(false);
    531   RunTasks(33);
    532   EXPECT_EQ(0, transport_.number_of_rtp_packets());
    533 }
    534 
    535 }  // namespace cast
    536 }  // namespace media
    537