1// Copyright 2013 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 "base/bind.h"
6#include "base/memory/ref_counted.h"
7#include "base/memory/scoped_ptr.h"
8#include "base/test/simple_test_tick_clock.h"
9#include "media/cast/audio_receiver/audio_receiver.h"
10#include "media/cast/cast_defines.h"
11#include "media/cast/cast_environment.h"
12#include "media/cast/net/pacing/mock_paced_packet_sender.h"
13#include "media/cast/rtcp/test_rtcp_packet_builder.h"
14#include "media/cast/test/fake_task_runner.h"
15#include "testing/gmock/include/gmock/gmock.h"
16
17namespace media {
18namespace cast {
19
20static const int64 kStartMillisecond = GG_INT64_C(12345678900000);
21
22namespace {
23class TestAudioEncoderCallback :
24    public base::RefCountedThreadSafe<TestAudioEncoderCallback>  {
25 public:
26  TestAudioEncoderCallback()
27      : num_called_(0) {}
28
29  void SetExpectedResult(uint8 expected_frame_id,
30                         const base::TimeTicks& expected_playout_time) {
31    expected_frame_id_ = expected_frame_id;
32    expected_playout_time_ = expected_playout_time;
33  }
34
35  void DeliverEncodedAudioFrame(scoped_ptr<EncodedAudioFrame> audio_frame,
36                                const base::TimeTicks& playout_time) {
37    EXPECT_EQ(expected_frame_id_, audio_frame->frame_id);
38    EXPECT_EQ(kPcm16, audio_frame->codec);
39    EXPECT_EQ(expected_playout_time_, playout_time);
40    num_called_++;
41  }
42
43  int number_times_called() const { return num_called_;}
44
45 protected:
46  virtual ~TestAudioEncoderCallback() {}
47
48 private:
49  friend class base::RefCountedThreadSafe<TestAudioEncoderCallback>;
50
51  int num_called_;
52  uint8 expected_frame_id_;
53  base::TimeTicks expected_playout_time_;
54};
55}  // namespace
56
57class PeerAudioReceiver : public AudioReceiver {
58 public:
59  PeerAudioReceiver(scoped_refptr<CastEnvironment> cast_environment,
60                    const AudioReceiverConfig& audio_config,
61                    PacedPacketSender* const packet_sender)
62      : AudioReceiver(cast_environment, audio_config, packet_sender) {}
63
64  using AudioReceiver::IncomingParsedRtpPacket;
65};
66
67class AudioReceiverTest : public ::testing::Test {
68 protected:
69  AudioReceiverTest() {
70    // Configure the audio receiver to use PCM16.
71    audio_config_.rtp_payload_type = 127;
72    audio_config_.frequency = 16000;
73    audio_config_.channels = 1;
74    audio_config_.codec = kPcm16;
75    audio_config_.use_external_decoder = false;
76    audio_config_.feedback_ssrc = 1234;
77    testing_clock_.Advance(
78        base::TimeDelta::FromMilliseconds(kStartMillisecond));
79    task_runner_ = new test::FakeTaskRunner(&testing_clock_);
80    cast_environment_ = new CastEnvironment(&testing_clock_, task_runner_,
81        task_runner_, task_runner_, task_runner_, task_runner_,
82        GetDefaultCastLoggingConfig());
83    test_audio_encoder_callback_ = new TestAudioEncoderCallback();
84  }
85
86  void Configure(bool use_external_decoder) {
87    audio_config_.use_external_decoder = use_external_decoder;
88    receiver_.reset(new PeerAudioReceiver(cast_environment_, audio_config_,
89                                          &mock_transport_));
90  }
91
92  virtual ~AudioReceiverTest() {}
93
94  static void DummyDeletePacket(const uint8* packet) {};
95
96  virtual void SetUp() {
97    payload_.assign(kIpPacketSize, 0);
98    rtp_header_.is_key_frame = true;
99    rtp_header_.frame_id = 0;
100    rtp_header_.packet_id = 0;
101    rtp_header_.max_packet_id = 0;
102    rtp_header_.is_reference = false;
103    rtp_header_.reference_frame_id = 0;
104    rtp_header_.webrtc.header.timestamp = 0;
105  }
106
107  AudioReceiverConfig audio_config_;
108  std::vector<uint8> payload_;
109  RtpCastHeader rtp_header_;
110  base::SimpleTestTickClock testing_clock_;
111  MockPacedPacketSender mock_transport_;
112  scoped_refptr<test::FakeTaskRunner> task_runner_;
113  scoped_ptr<PeerAudioReceiver> receiver_;
114  scoped_refptr<CastEnvironment> cast_environment_;
115  scoped_refptr<TestAudioEncoderCallback> test_audio_encoder_callback_;
116};
117
118TEST_F(AudioReceiverTest, GetOnePacketEncodedframe) {
119  Configure(true);
120  EXPECT_CALL(mock_transport_, SendRtcpPacket(testing::_)).Times(1);
121
122  receiver_->IncomingParsedRtpPacket(payload_.data(),
123      payload_.size(), rtp_header_);
124  EncodedAudioFrame audio_frame;
125  base::TimeTicks playout_time;
126  test_audio_encoder_callback_->SetExpectedResult(0, testing_clock_.NowTicks());
127
128  AudioFrameEncodedCallback frame_encoded_callback =
129      base::Bind(&TestAudioEncoderCallback::DeliverEncodedAudioFrame,
130                 test_audio_encoder_callback_.get());
131
132  receiver_->GetEncodedAudioFrame(frame_encoded_callback);
133  task_runner_->RunTasks();
134  EXPECT_EQ(1, test_audio_encoder_callback_->number_times_called());
135}
136
137TEST_F(AudioReceiverTest, MultiplePendingGetCalls) {
138  Configure(true);
139  EXPECT_CALL(mock_transport_, SendRtcpPacket(testing::_)).WillRepeatedly(
140      testing::Return(true));
141
142  AudioFrameEncodedCallback frame_encoded_callback =
143      base::Bind(&TestAudioEncoderCallback::DeliverEncodedAudioFrame,
144                 test_audio_encoder_callback_.get());
145
146  receiver_->GetEncodedAudioFrame(frame_encoded_callback);
147
148  receiver_->IncomingParsedRtpPacket(payload_.data(), payload_.size(),
149                                     rtp_header_);
150
151  EncodedAudioFrame audio_frame;
152  base::TimeTicks playout_time;
153  test_audio_encoder_callback_->SetExpectedResult(0, testing_clock_.NowTicks());
154
155  task_runner_->RunTasks();
156  EXPECT_EQ(1, test_audio_encoder_callback_->number_times_called());
157
158  TestRtcpPacketBuilder rtcp_packet;
159
160  uint32 ntp_high;
161  uint32 ntp_low;
162  ConvertTimeTicksToNtp(testing_clock_.NowTicks(), &ntp_high, &ntp_low);
163  rtcp_packet.AddSrWithNtp(audio_config_.feedback_ssrc, ntp_high, ntp_low,
164      rtp_header_.webrtc.header.timestamp);
165
166  testing_clock_.Advance(base::TimeDelta::FromMilliseconds(20));
167
168  receiver_->IncomingPacket(rtcp_packet.Packet(), rtcp_packet.Length(),
169      base::Bind(AudioReceiverTest::DummyDeletePacket, rtcp_packet.Packet()));
170
171  // Make sure that we are not continuous and that the RTP timestamp represent a
172  // time in the future.
173  rtp_header_.is_key_frame = false;
174  rtp_header_.frame_id = 2;
175  rtp_header_.is_reference = true;
176  rtp_header_.reference_frame_id = 0;
177  rtp_header_.webrtc.header.timestamp = 960;
178  test_audio_encoder_callback_->SetExpectedResult(2,
179      testing_clock_.NowTicks() + base::TimeDelta::FromMilliseconds(100));
180
181  receiver_->IncomingParsedRtpPacket(payload_.data(), payload_.size(),
182                                     rtp_header_);
183  receiver_->GetEncodedAudioFrame(frame_encoded_callback);
184  task_runner_->RunTasks();
185
186  // Frame 2 should not come out at this point in time.
187  EXPECT_EQ(1, test_audio_encoder_callback_->number_times_called());
188
189  // Through on one more pending callback.
190  receiver_->GetEncodedAudioFrame(frame_encoded_callback);
191
192  testing_clock_.Advance(base::TimeDelta::FromMilliseconds(100));
193
194  task_runner_->RunTasks();
195  EXPECT_EQ(2, test_audio_encoder_callback_->number_times_called());
196
197  test_audio_encoder_callback_->SetExpectedResult(3, testing_clock_.NowTicks());
198
199  // Through on one more pending audio frame.
200  rtp_header_.frame_id = 3;
201  rtp_header_.is_reference = false;
202  rtp_header_.reference_frame_id = 0;
203  rtp_header_.webrtc.header.timestamp = 1280;
204  receiver_->IncomingParsedRtpPacket(payload_.data(), payload_.size(),
205                                     rtp_header_);
206
207  receiver_->GetEncodedAudioFrame(frame_encoded_callback);
208  task_runner_->RunTasks();
209  EXPECT_EQ(3, test_audio_encoder_callback_->number_times_called());
210}
211
212// TODO(mikhal): Add encoded frames.
213TEST_F(AudioReceiverTest, GetRawFrame) {
214}
215
216}  // namespace cast
217}  // namespace media
218