• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2014 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 "webrtc/modules/audio_coding/codecs/opus/opus_interface.h"
12 #include "webrtc/modules/audio_coding/codecs/opus/opus_inst.h"
13 #include "webrtc/modules/audio_coding/neteq/tools/neteq_quality_test.h"
14 
15 using google::RegisterFlagValidator;
16 using google::ParseCommandLineFlags;
17 using std::string;
18 using testing::InitGoogleTest;
19 
20 namespace webrtc {
21 namespace test {
22 namespace {
23 
24 static const int kOpusBlockDurationMs = 20;
25 static const int kOpusSamplingKhz = 48;
26 
27 // Define switch for bit rate.
ValidateBitRate(const char * flagname,int32_t value)28 static bool ValidateBitRate(const char* flagname, int32_t value) {
29   if (value >= 6 && value <= 510)
30     return true;
31   printf("Invalid bit rate, should be between 6 and 510 kbps.");
32   return false;
33 }
34 
35 DEFINE_int32(bit_rate_kbps, 32, "Target bit rate (kbps).");
36 
37 static const bool bit_rate_dummy =
38     RegisterFlagValidator(&FLAGS_bit_rate_kbps, &ValidateBitRate);
39 
40 // Define switch for complexity.
ValidateComplexity(const char * flagname,int32_t value)41 static bool ValidateComplexity(const char* flagname, int32_t value) {
42   if (value >= -1 && value <= 10)
43     return true;
44   printf("Invalid complexity setting, should be between 0 and 10.");
45   return false;
46 }
47 
48 DEFINE_int32(complexity, 10, "Complexity: 0 ~ 10 -- defined as in Opus"
49     "specification.");
50 
51 static const bool complexity_dummy =
52     RegisterFlagValidator(&FLAGS_complexity, &ValidateComplexity);
53 
54 // Define switch for maxplaybackrate
55 DEFINE_int32(maxplaybackrate, 48000, "Maximum playback rate (Hz).");
56 
57 // Define switch for application mode.
ValidateApplication(const char * flagname,int32_t value)58 static bool ValidateApplication(const char* flagname, int32_t value) {
59   if (value != 0 && value != 1) {
60     printf("Invalid application mode, should be 0 or 1.");
61     return false;
62   }
63   return true;
64 }
65 
66 DEFINE_int32(application, 0, "Application mode: 0 -- VOIP, 1 -- Audio.");
67 
68 static const bool application_dummy =
69     RegisterFlagValidator(&FLAGS_application, &ValidateApplication);
70 
71 // Define switch for reported packet loss rate.
ValidatePacketLossRate(const char * flagname,int32_t value)72 static bool ValidatePacketLossRate(const char* flagname, int32_t value) {
73   if (value >= 0 && value <= 100)
74     return true;
75   printf("Invalid packet loss percentile, should be between 0 and 100.");
76   return false;
77 }
78 
79 DEFINE_int32(reported_loss_rate, 10, "Reported percentile of packet loss.");
80 
81 static const bool reported_loss_rate_dummy =
82     RegisterFlagValidator(&FLAGS_reported_loss_rate, &ValidatePacketLossRate);
83 
84 DEFINE_bool(fec, false, "Enable FEC for encoding (-nofec to disable).");
85 
86 DEFINE_bool(dtx, false, "Enable DTX for encoding (-nodtx to disable).");
87 
88 // Define switch for number of sub packets to repacketize.
ValidateSubPackets(const char * flagname,int32_t value)89 static bool ValidateSubPackets(const char* flagname, int32_t value) {
90   if (value >= 1 && value <= 3)
91     return true;
92   printf("Invalid number of sub packets, should be between 1 and 3.");
93   return false;
94 }
95 DEFINE_int32(sub_packets, 1, "Number of sub packets to repacketize.");
96 static const bool sub_packets_dummy =
97     RegisterFlagValidator(&FLAGS_sub_packets, &ValidateSubPackets);
98 
99 }  // namepsace
100 
101 class NetEqOpusQualityTest : public NetEqQualityTest {
102  protected:
103   NetEqOpusQualityTest();
104   void SetUp() override;
105   void TearDown() override;
106   virtual int EncodeBlock(int16_t* in_data, size_t block_size_samples,
107                           uint8_t* payload, size_t max_bytes);
108  private:
109   WebRtcOpusEncInst* opus_encoder_;
110   OpusRepacketizer* repacketizer_;
111   size_t sub_block_size_samples_;
112   int bit_rate_kbps_;
113   bool fec_;
114   bool dtx_;
115   int complexity_;
116   int maxplaybackrate_;
117   int target_loss_rate_;
118   int sub_packets_;
119   int application_;
120 };
121 
NetEqOpusQualityTest()122 NetEqOpusQualityTest::NetEqOpusQualityTest()
123     : NetEqQualityTest(kOpusBlockDurationMs * FLAGS_sub_packets,
124                        kOpusSamplingKhz,
125                        kOpusSamplingKhz,
126                        NetEqDecoder::kDecoderOpus),
127       opus_encoder_(NULL),
128       repacketizer_(NULL),
129       sub_block_size_samples_(
130           static_cast<size_t>(kOpusBlockDurationMs * kOpusSamplingKhz)),
131       bit_rate_kbps_(FLAGS_bit_rate_kbps),
132       fec_(FLAGS_fec),
133       dtx_(FLAGS_dtx),
134       complexity_(FLAGS_complexity),
135       maxplaybackrate_(FLAGS_maxplaybackrate),
136       target_loss_rate_(FLAGS_reported_loss_rate),
137       sub_packets_(FLAGS_sub_packets) {
138   // Redefine decoder type if input is stereo.
139   if (channels_ > 1) {
140     decoder_type_ = NetEqDecoder::kDecoderOpus_2ch;
141   }
142   application_ = FLAGS_application;
143 }
144 
SetUp()145 void NetEqOpusQualityTest::SetUp() {
146   // Create encoder memory.
147   WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_);
148   ASSERT_TRUE(opus_encoder_);
149 
150   // Create repacketizer.
151   repacketizer_ = opus_repacketizer_create();
152   ASSERT_TRUE(repacketizer_);
153 
154   // Set bitrate.
155   EXPECT_EQ(0, WebRtcOpus_SetBitRate(opus_encoder_, bit_rate_kbps_ * 1000));
156   if (fec_) {
157     EXPECT_EQ(0, WebRtcOpus_EnableFec(opus_encoder_));
158   }
159   if (dtx_) {
160     EXPECT_EQ(0, WebRtcOpus_EnableDtx(opus_encoder_));
161   }
162   EXPECT_EQ(0, WebRtcOpus_SetComplexity(opus_encoder_, complexity_));
163   EXPECT_EQ(0, WebRtcOpus_SetMaxPlaybackRate(opus_encoder_, maxplaybackrate_));
164   EXPECT_EQ(0, WebRtcOpus_SetPacketLossRate(opus_encoder_,
165                                             target_loss_rate_));
166   NetEqQualityTest::SetUp();
167 }
168 
TearDown()169 void NetEqOpusQualityTest::TearDown() {
170   // Free memory.
171   EXPECT_EQ(0, WebRtcOpus_EncoderFree(opus_encoder_));
172   opus_repacketizer_destroy(repacketizer_);
173   NetEqQualityTest::TearDown();
174 }
175 
EncodeBlock(int16_t * in_data,size_t block_size_samples,uint8_t * payload,size_t max_bytes)176 int NetEqOpusQualityTest::EncodeBlock(int16_t* in_data,
177                                       size_t block_size_samples,
178                                       uint8_t* payload, size_t max_bytes) {
179   EXPECT_EQ(block_size_samples, sub_block_size_samples_ * sub_packets_);
180   int16_t* pointer = in_data;
181   int value;
182   opus_repacketizer_init(repacketizer_);
183   for (int idx = 0; idx < sub_packets_; idx++) {
184     value = WebRtcOpus_Encode(opus_encoder_, pointer, sub_block_size_samples_,
185                               max_bytes, payload);
186     Log() << "Encoded a frame with Opus mode "
187           << (value == 0 ? 0 : payload[0] >> 3)
188           << std::endl;
189     if (OPUS_OK != opus_repacketizer_cat(repacketizer_, payload, value)) {
190       opus_repacketizer_init(repacketizer_);
191       // If the repacketization fails, we discard this frame.
192       return 0;
193     }
194     pointer += sub_block_size_samples_ * channels_;
195   }
196   value = opus_repacketizer_out(repacketizer_, payload,
197                                 static_cast<opus_int32>(max_bytes));
198   EXPECT_GE(value, 0);
199   return value;
200 }
201 
TEST_F(NetEqOpusQualityTest,Test)202 TEST_F(NetEqOpusQualityTest, Test) {
203   Simulate();
204 }
205 
206 }  // namespace test
207 }  // namespace webrtc
208