1/*
2 *  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
3 *
4 *  Use of this source code is governed by a BSD-style license
5 *  that can be found in the LICENSE file in the root of the source
6 *  tree. An additional intellectual property rights grant can be found
7 *  in the file PATENTS.  All contributing project authors may
8 *  be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "testing/gtest/include/gtest/gtest.h"
12#include "webrtc/base/random.h"
13#include "webrtc/base/scoped_ptr.h"
14#include "webrtc/base/timeutils.h"
15#include "webrtc/system_wrappers/include/sleep.h"
16#include "webrtc/test/channel_transport/channel_transport.h"
17#include "webrtc/test/testsupport/fileutils.h"
18#include "webrtc/voice_engine/test/auto_test/voe_standard_test.h"
19
20namespace {
21
22const char kIp[] = "127.0.0.1";
23const int kPort = 1234;
24const webrtc::CodecInst kCodecInst = {120, "opus", 48000, 960, 2, 64000};
25
26}  // namespace
27
28namespace voetest {
29
30using webrtc::Random;
31using webrtc::test::VoiceChannelTransport;
32
33// This test allows a check on the output signal in an end-to-end call.
34class OutputTest {
35 public:
36  OutputTest(int16_t lower_bound, int16_t upper_bound);
37  ~OutputTest();
38
39  void Start();
40
41  void EnableOutputCheck();
42  void DisableOutputCheck();
43  void SetOutputBound(int16_t lower_bound, int16_t upper_bound);
44  void Mute();
45  void Unmute();
46  void SetBitRate(int rate);
47
48 private:
49  // This class checks all output values and count the number of samples that
50  // go out of a defined range.
51  class VoEOutputCheckMediaProcess : public VoEMediaProcess {
52   public:
53    VoEOutputCheckMediaProcess(int16_t lower_bound, int16_t upper_bound);
54
55    void set_enabled(bool enabled) { enabled_ = enabled; }
56    void Process(int channel,
57                 ProcessingTypes type,
58                 int16_t audio10ms[],
59                 size_t length,
60                 int samplingFreq,
61                 bool isStereo) override;
62
63   private:
64    bool enabled_;
65    int16_t lower_bound_;
66    int16_t upper_bound_;
67  };
68
69  VoETestManager manager_;
70  VoEOutputCheckMediaProcess output_checker_;
71
72  int channel_;
73};
74
75OutputTest::OutputTest(int16_t lower_bound, int16_t upper_bound)
76    : output_checker_(lower_bound, upper_bound) {
77  EXPECT_TRUE(manager_.Init());
78  manager_.GetInterfaces();
79
80  VoEBase* base = manager_.BasePtr();
81  VoECodec* codec = manager_.CodecPtr();
82  VoENetwork* network = manager_.NetworkPtr();
83
84  EXPECT_EQ(0, base->Init());
85
86  channel_ = base->CreateChannel();
87
88  // |network| will take care of the life time of |transport|.
89  VoiceChannelTransport* transport =
90      new VoiceChannelTransport(network, channel_);
91
92  EXPECT_EQ(0, transport->SetSendDestination(kIp, kPort));
93  EXPECT_EQ(0, transport->SetLocalReceiver(kPort));
94
95  EXPECT_EQ(0, codec->SetSendCodec(channel_, kCodecInst));
96  EXPECT_EQ(0, codec->SetOpusDtx(channel_, true));
97
98  EXPECT_EQ(0, manager_.VolumeControlPtr()->SetSpeakerVolume(255));
99
100  manager_.ExternalMediaPtr()->RegisterExternalMediaProcessing(
101      channel_, ProcessingTypes::kPlaybackPerChannel, output_checker_);
102}
103
104OutputTest::~OutputTest() {
105  EXPECT_EQ(0, manager_.NetworkPtr()->DeRegisterExternalTransport(channel_));
106  EXPECT_EQ(0, manager_.ReleaseInterfaces());
107}
108
109void OutputTest::Start() {
110  const std::string file_name =
111      webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm");
112  const webrtc::FileFormats kInputFormat = webrtc::kFileFormatPcm32kHzFile;
113
114  ASSERT_EQ(0, manager_.FilePtr()->StartPlayingFileAsMicrophone(
115      channel_, file_name.c_str(), true, false, kInputFormat, 1.0));
116
117  VoEBase* base = manager_.BasePtr();
118  ASSERT_EQ(0, base->StartPlayout(channel_));
119  ASSERT_EQ(0, base->StartSend(channel_));
120}
121
122void OutputTest::EnableOutputCheck() {
123  output_checker_.set_enabled(true);
124}
125
126void OutputTest::DisableOutputCheck() {
127  output_checker_.set_enabled(false);
128}
129
130void OutputTest::Mute() {
131  manager_.VolumeControlPtr()->SetInputMute(channel_, true);
132}
133
134void OutputTest::Unmute() {
135  manager_.VolumeControlPtr()->SetInputMute(channel_, false);
136}
137
138void OutputTest::SetBitRate(int rate) {
139  manager_.CodecPtr()->SetBitRate(channel_, rate);
140}
141
142OutputTest::VoEOutputCheckMediaProcess::VoEOutputCheckMediaProcess(
143    int16_t lower_bound, int16_t upper_bound)
144    : enabled_(false),
145      lower_bound_(lower_bound),
146      upper_bound_(upper_bound) {}
147
148void OutputTest::VoEOutputCheckMediaProcess::Process(int channel,
149                                                     ProcessingTypes type,
150                                                     int16_t* audio10ms,
151                                                     size_t length,
152                                                     int samplingFreq,
153                                                     bool isStereo) {
154  if (!enabled_)
155    return;
156  const int num_channels = isStereo ? 2 : 1;
157  for (size_t i = 0; i < length; ++i) {
158    for (int c = 0; c < num_channels; ++c) {
159      ASSERT_GE(audio10ms[i * num_channels + c], lower_bound_);
160      ASSERT_LE(audio10ms[i * num_channels + c], upper_bound_);
161    }
162  }
163}
164
165// This test checks if the Opus does not produce high noise (noise pump) when
166// DTX is enabled. The microphone is toggled on and off, and values of the
167// output signal during muting should be bounded.
168// We do not run this test on bots. Developers that want to see the result
169// and/or listen to sound quality can run this test manually.
170TEST(OutputTest, DISABLED_OpusDtxHasNoNoisePump) {
171  const int kRuntimeMs = 20000;
172  const uint32_t kUnmuteTimeMs = 1000;
173  const int kCheckAfterMute = 2000;
174  const uint32_t kCheckTimeMs = 2000;
175  const int kMinOpusRate = 6000;
176  const int kMaxOpusRate = 64000;
177
178#if defined(OPUS_FIXED_POINT)
179  const int16_t kDtxBoundForSilence = 20;
180#else
181  const int16_t kDtxBoundForSilence = 2;
182#endif
183
184  OutputTest test(-kDtxBoundForSilence, kDtxBoundForSilence);
185  Random random(1234ull);
186
187  uint32_t start_time = rtc::Time();
188  test.Start();
189  while (rtc::TimeSince(start_time) < kRuntimeMs) {
190    webrtc::SleepMs(random.Rand(kUnmuteTimeMs - kUnmuteTimeMs / 10,
191                                kUnmuteTimeMs + kUnmuteTimeMs / 10));
192    test.Mute();
193    webrtc::SleepMs(kCheckAfterMute);
194    test.EnableOutputCheck();
195    webrtc::SleepMs(random.Rand(kCheckTimeMs - kCheckTimeMs / 10,
196                                kCheckTimeMs + kCheckTimeMs / 10));
197    test.DisableOutputCheck();
198    test.SetBitRate(random.Rand(kMinOpusRate, kMaxOpusRate));
199    test.Unmute();
200  }
201}
202
203}  // namespace voetest
204