1/*
2 *  Copyright (c) 2011 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 <stdio.h>
12#include <string>
13
14#include "webrtc/call/rtc_event_log.h"
15#include "webrtc/test/test_suite.h"
16#include "webrtc/test/testsupport/fileutils.h"
17#include "webrtc/voice_engine/test/auto_test/fixtures/after_streaming_fixture.h"
18#include "webrtc/voice_engine/voice_engine_defines.h"
19
20class CodecTest : public AfterStreamingFixture {
21 protected:
22  void SetUp() {
23    memset(&codec_instance_, 0, sizeof(codec_instance_));
24  }
25
26  void SetArbitrarySendCodec() {
27    // Just grab the first codec.
28    EXPECT_EQ(0, voe_codec_->GetCodec(0, codec_instance_));
29    EXPECT_EQ(0, voe_codec_->SetSendCodec(channel_, codec_instance_));
30  }
31
32  webrtc::CodecInst codec_instance_;
33};
34
35static void SetRateIfILBC(webrtc::CodecInst* codec_instance, int packet_size) {
36  if (!_stricmp(codec_instance->plname, "ilbc")) {
37    if (packet_size == 160 || packet_size == 320) {
38      codec_instance->rate = 15200;
39    } else {
40      codec_instance->rate = 13300;
41    }
42  }
43}
44
45static bool IsNotViableSendCodec(const char* codec_name) {
46  return !_stricmp(codec_name, "CN") ||
47         !_stricmp(codec_name, "telephone-event") ||
48         !_stricmp(codec_name, "red");
49}
50
51TEST_F(CodecTest, PcmuIsDefaultCodecAndHasTheRightValues) {
52  EXPECT_EQ(0, voe_codec_->GetSendCodec(channel_, codec_instance_));
53  EXPECT_EQ(1u, codec_instance_.channels);
54  EXPECT_EQ(160, codec_instance_.pacsize);
55  EXPECT_EQ(8000, codec_instance_.plfreq);
56  EXPECT_EQ(0, codec_instance_.pltype);
57  EXPECT_EQ(64000, codec_instance_.rate);
58  EXPECT_STRCASEEQ("PCMU", codec_instance_.plname);
59}
60
61TEST_F(CodecTest, VoiceActivityDetectionIsOffByDefault) {
62  bool vad_enabled = false;
63  bool dtx_disabled = false;
64  webrtc::VadModes vad_mode = webrtc::kVadAggressiveMid;
65
66  voe_codec_->GetVADStatus(channel_, vad_enabled, vad_mode, dtx_disabled);
67
68  EXPECT_FALSE(vad_enabled);
69  EXPECT_TRUE(dtx_disabled);
70  EXPECT_EQ(webrtc::kVadConventional, vad_mode);
71}
72
73TEST_F(CodecTest, VoiceActivityDetectionCanBeEnabled) {
74  EXPECT_EQ(0, voe_codec_->SetVADStatus(channel_, true));
75
76  bool vad_enabled = false;
77  bool dtx_disabled = false;
78  webrtc::VadModes vad_mode = webrtc::kVadAggressiveMid;
79
80  voe_codec_->GetVADStatus(channel_, vad_enabled, vad_mode, dtx_disabled);
81
82  EXPECT_TRUE(vad_enabled);
83  EXPECT_EQ(webrtc::kVadConventional, vad_mode);
84  EXPECT_FALSE(dtx_disabled);
85}
86
87TEST_F(CodecTest, VoiceActivityDetectionTypeSettingsCanBeChanged) {
88  bool vad_enabled = false;
89  bool dtx_disabled = false;
90  webrtc::VadModes vad_mode = webrtc::kVadAggressiveMid;
91
92  EXPECT_EQ(0, voe_codec_->SetVADStatus(
93      channel_, true, webrtc::kVadAggressiveLow, false));
94  EXPECT_EQ(0, voe_codec_->GetVADStatus(
95      channel_, vad_enabled, vad_mode, dtx_disabled));
96  EXPECT_EQ(vad_mode, webrtc::kVadAggressiveLow);
97  EXPECT_FALSE(dtx_disabled);
98
99  EXPECT_EQ(0, voe_codec_->SetVADStatus(
100      channel_, true, webrtc::kVadAggressiveMid, false));
101  EXPECT_EQ(0, voe_codec_->GetVADStatus(
102      channel_, vad_enabled, vad_mode, dtx_disabled));
103  EXPECT_EQ(vad_mode, webrtc::kVadAggressiveMid);
104  EXPECT_FALSE(dtx_disabled);
105
106  // The fourth argument is the DTX disable flag, which is always supposed to
107  // be false.
108  EXPECT_EQ(0, voe_codec_->SetVADStatus(channel_, true,
109                                        webrtc::kVadAggressiveHigh, false));
110  EXPECT_EQ(0, voe_codec_->GetVADStatus(
111      channel_, vad_enabled, vad_mode, dtx_disabled));
112  EXPECT_EQ(vad_mode, webrtc::kVadAggressiveHigh);
113  EXPECT_FALSE(dtx_disabled);
114
115  EXPECT_EQ(0, voe_codec_->SetVADStatus(channel_, true,
116                                        webrtc::kVadConventional, false));
117  EXPECT_EQ(0, voe_codec_->GetVADStatus(
118      channel_, vad_enabled, vad_mode, dtx_disabled));
119  EXPECT_EQ(vad_mode, webrtc::kVadConventional);
120}
121
122TEST_F(CodecTest, VoiceActivityDetectionCanBeTurnedOff) {
123  EXPECT_EQ(0, voe_codec_->SetVADStatus(channel_, true));
124
125  // VAD is always on when DTX is on, so we need to turn off DTX too.
126  EXPECT_EQ(0, voe_codec_->SetVADStatus(
127      channel_, false, webrtc::kVadConventional, true));
128
129  bool vad_enabled = false;
130  bool dtx_disabled = false;
131  webrtc::VadModes vad_mode = webrtc::kVadAggressiveMid;
132
133  voe_codec_->GetVADStatus(channel_, vad_enabled, vad_mode, dtx_disabled);
134
135  EXPECT_FALSE(vad_enabled);
136  EXPECT_TRUE(dtx_disabled);
137  EXPECT_EQ(webrtc::kVadConventional, vad_mode);
138}
139
140TEST_F(CodecTest, OpusMaxPlaybackRateCanBeSet) {
141  for (int i = 0; i < voe_codec_->NumOfCodecs(); ++i) {
142    voe_codec_->GetCodec(i, codec_instance_);
143    if (_stricmp("opus", codec_instance_.plname)) {
144      continue;
145    }
146    voe_codec_->SetSendCodec(channel_, codec_instance_);
147    // SetOpusMaxPlaybackRate can handle any integer as the bandwidth. Following
148    // tests some most commonly used numbers.
149    EXPECT_EQ(0, voe_codec_->SetOpusMaxPlaybackRate(channel_, 48000));
150    EXPECT_EQ(0, voe_codec_->SetOpusMaxPlaybackRate(channel_, 32000));
151    EXPECT_EQ(0, voe_codec_->SetOpusMaxPlaybackRate(channel_, 16000));
152    EXPECT_EQ(0, voe_codec_->SetOpusMaxPlaybackRate(channel_, 8000));
153  }
154}
155
156TEST_F(CodecTest, OpusDtxCanBeSetForOpus) {
157  for (int i = 0; i < voe_codec_->NumOfCodecs(); ++i) {
158    voe_codec_->GetCodec(i, codec_instance_);
159    if (_stricmp("opus", codec_instance_.plname)) {
160      continue;
161    }
162    voe_codec_->SetSendCodec(channel_, codec_instance_);
163    EXPECT_EQ(0, voe_codec_->SetOpusDtx(channel_, false));
164    EXPECT_EQ(0, voe_codec_->SetOpusDtx(channel_, true));
165  }
166}
167
168TEST_F(CodecTest, OpusDtxCannotBeSetForNonOpus) {
169  for (int i = 0; i < voe_codec_->NumOfCodecs(); ++i) {
170    voe_codec_->GetCodec(i, codec_instance_);
171    if (!_stricmp("opus", codec_instance_.plname)) {
172      continue;
173    }
174    voe_codec_->SetSendCodec(channel_, codec_instance_);
175    EXPECT_EQ(-1, voe_codec_->SetOpusDtx(channel_, true));
176  }
177}
178
179#ifdef ENABLE_RTC_EVENT_LOG
180TEST_F(CodecTest, RtcEventLogIntegrationTest) {
181  webrtc::RtcEventLog* event_log = voe_codec_->GetEventLog();
182  ASSERT_TRUE(event_log);
183
184  // Find the name of the current test, in order to use it as a temporary
185  // filename.
186  auto test_info = ::testing::UnitTest::GetInstance()->current_test_info();
187  const std::string temp_filename = webrtc::test::OutputPath() +
188                                    test_info->test_case_name() +
189                                    test_info->name();
190  // Create a log file.
191  event_log->StartLogging(temp_filename, 1000);
192  event_log->StopLogging();
193
194  // Check if the file has been created.
195  FILE* event_file = fopen(temp_filename.c_str(), "r");
196  ASSERT_TRUE(event_file);
197  fclose(event_file);
198  // Remove the temporary file.
199  remove(temp_filename.c_str());
200}
201#endif  // ENABLE_RTC_EVENT_LOG
202
203// TODO(xians, phoglund): Re-enable when issue 372 is resolved.
204TEST_F(CodecTest, DISABLED_ManualVerifySendCodecsForAllPacketSizes) {
205  for (int i = 0; i < voe_codec_->NumOfCodecs(); ++i) {
206    voe_codec_->GetCodec(i, codec_instance_);
207    if (IsNotViableSendCodec(codec_instance_.plname)) {
208      TEST_LOG("Skipping %s.\n", codec_instance_.plname);
209      continue;
210    }
211    EXPECT_NE(-1, codec_instance_.pltype) <<
212        "The codec database should suggest a payload type.";
213
214    // Test with default packet size:
215    TEST_LOG("%s (pt=%d): default packet size(%d), accepts sizes ",
216             codec_instance_.plname, codec_instance_.pltype,
217             codec_instance_.pacsize);
218    voe_codec_->SetSendCodec(channel_, codec_instance_);
219    Sleep(CODEC_TEST_TIME);
220
221    // Now test other reasonable packet sizes:
222    bool at_least_one_succeeded = false;
223    for (int packet_size = 80; packet_size < 1000; packet_size += 80) {
224      SetRateIfILBC(&codec_instance_, packet_size);
225      codec_instance_.pacsize = packet_size;
226
227      if (voe_codec_->SetSendCodec(channel_, codec_instance_) != -1) {
228        // Note that it's fine for SetSendCodec to fail - what packet sizes
229        // it accepts depends on the codec. It should accept one at minimum.
230        TEST_LOG("%d ", packet_size);
231        TEST_LOG_FLUSH;
232        at_least_one_succeeded = true;
233        Sleep(CODEC_TEST_TIME);
234      }
235    }
236    TEST_LOG("\n");
237    EXPECT_TRUE(at_least_one_succeeded);
238  }
239}
240