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 <stdint.h>
6
7#include <sstream>
8#include <string>
9
10#include "base/bind.h"
11#include "base/bind_helpers.h"
12#include "base/memory/scoped_ptr.h"
13#include "media/base/audio_bus.h"
14#include "media/base/media.h"
15#include "media/cast/audio_sender/audio_encoder.h"
16#include "media/cast/cast_config.h"
17#include "media/cast/cast_environment.h"
18#include "media/cast/test/fake_single_thread_task_runner.h"
19#include "media/cast/test/utility/audio_utility.h"
20#include "testing/gtest/include/gtest/gtest.h"
21
22namespace media {
23namespace cast {
24
25static const int64 kStartMillisecond = INT64_C(12345678900000);
26
27namespace {
28
29class TestEncodedAudioFrameReceiver {
30 public:
31  explicit TestEncodedAudioFrameReceiver(transport::AudioCodec codec)
32      : codec_(codec), frames_received_(0), rtp_lower_bound_(0) {}
33  virtual ~TestEncodedAudioFrameReceiver() {}
34
35  int frames_received() const { return frames_received_; }
36
37  void SetCaptureTimeBounds(const base::TimeTicks& lower_bound,
38                            const base::TimeTicks& upper_bound) {
39    lower_bound_ = lower_bound;
40    upper_bound_ = upper_bound;
41  }
42
43  void FrameEncoded(scoped_ptr<transport::EncodedFrame> encoded_frame) {
44    EXPECT_EQ(encoded_frame->dependency, transport::EncodedFrame::KEY);
45    EXPECT_EQ(static_cast<uint8>(frames_received_ & 0xff),
46              encoded_frame->frame_id);
47    EXPECT_EQ(encoded_frame->frame_id, encoded_frame->referenced_frame_id);
48    // RTP timestamps should be monotonically increasing and integer multiples
49    // of the fixed frame size.
50    EXPECT_LE(rtp_lower_bound_, encoded_frame->rtp_timestamp);
51    rtp_lower_bound_ = encoded_frame->rtp_timestamp;
52    // Note: In audio_encoder.cc, 100 is the fixed audio frame rate.
53    const int kSamplesPerFrame = kDefaultAudioSamplingRate / 100;
54    EXPECT_EQ(0u, encoded_frame->rtp_timestamp % kSamplesPerFrame);
55    EXPECT_TRUE(!encoded_frame->data.empty());
56
57    EXPECT_LE(lower_bound_, encoded_frame->reference_time);
58    lower_bound_ = encoded_frame->reference_time;
59    EXPECT_GT(upper_bound_, encoded_frame->reference_time);
60
61    ++frames_received_;
62  }
63
64 private:
65  const transport::AudioCodec codec_;
66  int frames_received_;
67  uint32 rtp_lower_bound_;
68  base::TimeTicks lower_bound_;
69  base::TimeTicks upper_bound_;
70
71  DISALLOW_COPY_AND_ASSIGN(TestEncodedAudioFrameReceiver);
72};
73
74struct TestScenario {
75  const int64* durations_in_ms;
76  size_t num_durations;
77
78  TestScenario(const int64* d, size_t n)
79      : durations_in_ms(d), num_durations(n) {}
80
81  std::string ToString() const {
82    std::ostringstream out;
83    for (size_t i = 0; i < num_durations; ++i) {
84      if (i > 0)
85        out << ", ";
86      out << durations_in_ms[i];
87    }
88    return out.str();
89  }
90};
91
92}  // namespace
93
94class AudioEncoderTest : public ::testing::TestWithParam<TestScenario> {
95 public:
96  AudioEncoderTest() {
97    InitializeMediaLibraryForTesting();
98    testing_clock_ = new base::SimpleTestTickClock();
99    testing_clock_->Advance(
100        base::TimeDelta::FromMilliseconds(kStartMillisecond));
101  }
102
103  virtual void SetUp() {
104    task_runner_ = new test::FakeSingleThreadTaskRunner(testing_clock_);
105    cast_environment_ =
106        new CastEnvironment(scoped_ptr<base::TickClock>(testing_clock_).Pass(),
107                            task_runner_,
108                            task_runner_,
109                            task_runner_);
110  }
111
112  virtual ~AudioEncoderTest() {}
113
114  void RunTestForCodec(transport::AudioCodec codec) {
115    const TestScenario& scenario = GetParam();
116    SCOPED_TRACE(::testing::Message() << "Durations: " << scenario.ToString());
117
118    CreateObjectsForCodec(codec);
119
120    // Note: In audio_encoder.cc, 10 ms is the fixed frame duration.
121    const base::TimeDelta frame_duration =
122        base::TimeDelta::FromMilliseconds(10);
123
124    for (size_t i = 0; i < scenario.num_durations; ++i) {
125      const bool simulate_missing_data = scenario.durations_in_ms[i] < 0;
126      const base::TimeDelta duration = base::TimeDelta::FromMilliseconds(
127          std::abs(scenario.durations_in_ms[i]));
128      receiver_->SetCaptureTimeBounds(
129          testing_clock_->NowTicks() - frame_duration,
130          testing_clock_->NowTicks() + duration);
131      if (simulate_missing_data) {
132        task_runner_->RunTasks();
133        testing_clock_->Advance(duration);
134      } else {
135        audio_encoder_->InsertAudio(audio_bus_factory_->NextAudioBus(duration),
136                                    testing_clock_->NowTicks());
137        task_runner_->RunTasks();
138        testing_clock_->Advance(duration);
139      }
140    }
141
142    DVLOG(1) << "Received " << receiver_->frames_received()
143             << " frames for this test run: " << scenario.ToString();
144  }
145
146 private:
147  void CreateObjectsForCodec(transport::AudioCodec codec) {
148    AudioSenderConfig audio_config;
149    audio_config.codec = codec;
150    audio_config.use_external_encoder = false;
151    audio_config.frequency = kDefaultAudioSamplingRate;
152    audio_config.channels = 2;
153    audio_config.bitrate = kDefaultAudioEncoderBitrate;
154    audio_config.rtp_config.payload_type = 127;
155
156    audio_bus_factory_.reset(
157        new TestAudioBusFactory(audio_config.channels,
158                                audio_config.frequency,
159                                TestAudioBusFactory::kMiddleANoteFreq,
160                                0.5f));
161
162    receiver_.reset(new TestEncodedAudioFrameReceiver(codec));
163
164    audio_encoder_.reset(new AudioEncoder(
165        cast_environment_,
166        audio_config,
167        base::Bind(&TestEncodedAudioFrameReceiver::FrameEncoded,
168                   base::Unretained(receiver_.get()))));
169  }
170
171  base::SimpleTestTickClock* testing_clock_;  // Owned by CastEnvironment.
172  scoped_refptr<test::FakeSingleThreadTaskRunner> task_runner_;
173  scoped_ptr<TestAudioBusFactory> audio_bus_factory_;
174  scoped_ptr<TestEncodedAudioFrameReceiver> receiver_;
175  scoped_ptr<AudioEncoder> audio_encoder_;
176  scoped_refptr<CastEnvironment> cast_environment_;
177
178  DISALLOW_COPY_AND_ASSIGN(AudioEncoderTest);
179};
180
181TEST_P(AudioEncoderTest, EncodeOpus) { RunTestForCodec(transport::kOpus); }
182
183TEST_P(AudioEncoderTest, EncodePcm16) { RunTestForCodec(transport::kPcm16); }
184
185static const int64 kOneCall_3Millis[] = {3};
186static const int64 kOneCall_10Millis[] = {10};
187static const int64 kOneCall_13Millis[] = {13};
188static const int64 kOneCall_20Millis[] = {20};
189
190static const int64 kTwoCalls_3Millis[] = {3, 3};
191static const int64 kTwoCalls_10Millis[] = {10, 10};
192static const int64 kTwoCalls_Mixed1[] = {3, 10};
193static const int64 kTwoCalls_Mixed2[] = {10, 3};
194static const int64 kTwoCalls_Mixed3[] = {3, 17};
195static const int64 kTwoCalls_Mixed4[] = {17, 3};
196
197static const int64 kManyCalls_3Millis[] = {3, 3, 3, 3, 3, 3, 3, 3,
198                                           3, 3, 3, 3, 3, 3, 3};
199static const int64 kManyCalls_10Millis[] = {10, 10, 10, 10, 10, 10, 10, 10,
200                                            10, 10, 10, 10, 10, 10, 10};
201static const int64 kManyCalls_Mixed1[] = {3,  10, 3,  10, 3,  10, 3,  10, 3,
202                                          10, 3,  10, 3,  10, 3,  10, 3,  10};
203static const int64 kManyCalls_Mixed2[] = {10, 3, 10, 3, 10, 3, 10, 3, 10, 3,
204                                          10, 3, 10, 3, 10, 3, 10, 3, 10, 3};
205static const int64 kManyCalls_Mixed3[] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8,
206                                          9, 7, 9, 3, 2, 3, 8, 4, 6, 2, 6, 4};
207static const int64 kManyCalls_Mixed4[] = {31, 4, 15, 9,  26, 53, 5,  8, 9,
208                                          7,  9, 32, 38, 4,  62, 64, 3};
209static const int64 kManyCalls_Mixed5[] = {3, 14, 15, 9, 26, 53, 58, 9, 7,
210                                          9, 3,  23, 8, 4,  6,  2,  6, 43};
211
212static const int64 kOneBigUnderrun[] = {10, 10, 10, 10, -1000, 10, 10, 10};
213static const int64 kTwoBigUnderruns[] = {10, 10, 10, 10, -712, 10, 10, 10,
214                                         -1311, 10, 10, 10};
215static const int64 kMixedUnderruns[] = {31, -64, 4, 15, 9, 26, -53, 5,  8, -9,
216                                        7,  9, 32, 38, -4, 62, -64, 3};
217
218INSTANTIATE_TEST_CASE_P(
219    AudioEncoderTestScenarios,
220    AudioEncoderTest,
221    ::testing::Values(
222        TestScenario(kOneCall_3Millis, arraysize(kOneCall_3Millis)),
223        TestScenario(kOneCall_10Millis, arraysize(kOneCall_10Millis)),
224        TestScenario(kOneCall_13Millis, arraysize(kOneCall_13Millis)),
225        TestScenario(kOneCall_20Millis, arraysize(kOneCall_20Millis)),
226        TestScenario(kTwoCalls_3Millis, arraysize(kTwoCalls_3Millis)),
227        TestScenario(kTwoCalls_10Millis, arraysize(kTwoCalls_10Millis)),
228        TestScenario(kTwoCalls_Mixed1, arraysize(kTwoCalls_Mixed1)),
229        TestScenario(kTwoCalls_Mixed2, arraysize(kTwoCalls_Mixed2)),
230        TestScenario(kTwoCalls_Mixed3, arraysize(kTwoCalls_Mixed3)),
231        TestScenario(kTwoCalls_Mixed4, arraysize(kTwoCalls_Mixed4)),
232        TestScenario(kManyCalls_3Millis, arraysize(kManyCalls_3Millis)),
233        TestScenario(kManyCalls_10Millis, arraysize(kManyCalls_10Millis)),
234        TestScenario(kManyCalls_Mixed1, arraysize(kManyCalls_Mixed1)),
235        TestScenario(kManyCalls_Mixed2, arraysize(kManyCalls_Mixed2)),
236        TestScenario(kManyCalls_Mixed3, arraysize(kManyCalls_Mixed3)),
237        TestScenario(kManyCalls_Mixed4, arraysize(kManyCalls_Mixed4)),
238        TestScenario(kManyCalls_Mixed5, arraysize(kManyCalls_Mixed5)),
239        TestScenario(kOneBigUnderrun, arraysize(kOneBigUnderrun)),
240        TestScenario(kTwoBigUnderruns, arraysize(kTwoBigUnderruns)),
241        TestScenario(kMixedUnderruns, arraysize(kMixedUnderruns))));
242
243}  // namespace cast
244}  // namespace media
245