OLD | NEW |
---|---|
(Empty) | |
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 <cmath> | |
12 #include <sstream> | |
13 #include <vector> | |
14 | |
15 #include "testing/gtest/include/gtest/gtest.h" | |
16 #include "webrtc/base/buffer.h" | |
17 #include "webrtc/base/checks.h" | |
18 #include "webrtc/modules/audio_coding/codecs/isac/fix/interface/audio_encoder_is acfix.h" | |
19 #include "webrtc/modules/audio_coding/codecs/isac/main/interface/audio_encoder_i sac.h" | |
20 #include "webrtc/test/testsupport/fileutils.h" | |
21 | |
22 namespace webrtc { | |
23 | |
24 namespace { | |
25 | |
26 std::vector<int16_t> LoadSpeechData() { | |
hlundin-webrtc
2015/06/26 10:35:15
Consider using webrtc::test::InputAudioFile instea
kwiberg-webrtc
2015/06/28 03:17:41
Done.
| |
27 static const int kIsacNumberOfSamples = 32 * 60; // 60 ms at 32 kHz | |
28 const std::string file_name = | |
29 webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm"); | |
30 FILE* input_file = fopen(file_name.c_str(), "rb"); | |
31 CHECK(input_file); | |
32 std::vector<int16_t> speech_data(kIsacNumberOfSamples); | |
33 CHECK_EQ(kIsacNumberOfSamples, | |
34 static_cast<int32_t>(fread(speech_data.data(), sizeof(int16_t), | |
35 kIsacNumberOfSamples, input_file))); | |
36 CHECK_EQ(0, fclose(input_file)); | |
37 #ifndef WEBRTC_ARCH_LITTLE_ENDIAN | |
38 #error "Need to convert samples from little-endian" | |
39 #endif | |
40 return speech_data; | |
41 } | |
42 | |
43 template <typename T> | |
44 IsacBandwidthInfo GetBwInfo(typename T::instance_type* inst) { | |
45 IsacBandwidthInfo bi; | |
46 T::GetBandwidthInfo(inst, &bi); | |
47 CHECK(bi.in_use); | |
48 return bi; | |
49 } | |
50 | |
51 std::string Str(const IsacBandwidthInfo& bi) { | |
hlundin-webrtc
2015/06/26 10:35:14
The function name is a bit too compact. Consider T
kwiberg-webrtc
2015/06/28 03:17:41
Done.
| |
52 CHECK(bi.in_use); | |
53 std::ostringstream o; | |
54 o << "(send_bw_avg: " << bi.send_bw_avg << ", " | |
55 << "send_max_delay_avg: " << bi.send_max_delay_avg << ", " | |
56 << "bottleneck_idx: " << bi.bottleneck_idx << ", " | |
57 << "jitter_info: " << bi.jitter_info << ")"; | |
58 return o.str(); | |
59 } | |
60 | |
61 // Is the distance between a and b dist or less, and the relative distance | |
62 // rdist or less? | |
63 bool AlmostEqual(int a, int b, unsigned dist, double rdist) { | |
64 // d = |a-b|, because casting n-bit signed to n-bit unsigned leaves a value | |
65 // unchanged mod 2^n. | |
66 unsigned d = a > b ? static_cast<unsigned>(a) - static_cast<unsigned>(b) | |
67 : static_cast<unsigned>(b) - static_cast<unsigned>(a); | |
68 return d <= dist && d <= rdist * std::min(std::abs(a), std::abs(b)); | |
69 } | |
70 | |
71 // Returns true if the two arguments are similar enough. | |
72 bool Similar(const IsacBandwidthInfo& a, const IsacBandwidthInfo& b) { | |
73 return AlmostEqual(a.send_bw_avg, b.send_bw_avg, 1000, 0.07) && | |
74 a.send_max_delay_avg == b.send_max_delay_avg && | |
75 AlmostEqual(a.bottleneck_idx, b.bottleneck_idx, 1, 0.1) && | |
76 a.jitter_info == b.jitter_info; | |
77 } | |
78 | |
79 // Count the number of elements in the range [lower,upper). | |
80 template <typename T> | |
81 int CountRange(std::multiset<T> s, T lower, T upper) { | |
82 return std::distance(s.lower_bound(lower), s.lower_bound(upper)); | |
83 } | |
84 | |
85 template <typename T> | |
86 rtc::Buffer Encode60Ms(typename T::instance_type* inst, | |
87 const IsacBandwidthInfo* bi, | |
88 const int16_t* speech_data) { | |
89 rtc::Buffer output(1000); | |
90 for (int i = 0;; ++i) { | |
91 if (bi) | |
92 T::SetBandwidthInfo(inst, bi); | |
93 int encoded_bytes = T::Encode(inst, speech_data, output.data()); | |
hlundin-webrtc
2015/06/26 10:35:15
What if encoded_bytes is too large for output?
kwiberg-webrtc
2015/06/28 03:17:41
It shouldn't be. And some sanitizer bot would comp
| |
94 if (i == 5) { | |
95 output.SetSize(encoded_bytes); | |
96 return output; | |
97 } | |
98 CHECK_EQ(0, encoded_bytes); | |
hlundin-webrtc
2015/06/26 10:35:14
CHECK is quite aggressive here. Consider using EXP
kwiberg-webrtc
2015/06/28 03:17:41
OK. Although I sort of doubt the rest of the run w
hlundin-webrtc
2015/06/29 08:42:18
Right. But a CHECK will kill the test binary, in t
kwiberg-webrtc
2015/06/29 11:53:48
Mmmm, I didn't think things through enough to real
| |
99 } | |
100 } | |
101 | |
102 template <typename T> | |
103 void TestGetSetBandwidthInfo(const int16_t* speech_data) { | |
104 // Conjoined encoder/decoder pair: | |
105 typename T::instance_type* encdec; | |
106 EXPECT_EQ(0, T::Create(&encdec)); | |
hlundin-webrtc
2015/06/26 10:35:15
All the create and init calls should be ASSERT_EQ
kwiberg-webrtc
2015/06/28 03:17:41
Done.
| |
107 EXPECT_EQ(0, T::EncoderInit(encdec, 0 /* adaptive mode */)); | |
108 EXPECT_EQ(0, T::DecoderInit(encdec)); | |
109 | |
110 // Disjoint encoder/decoder pair: | |
111 typename T::instance_type* enc; | |
112 EXPECT_EQ(0, T::Create(&enc)); | |
113 EXPECT_EQ(0, T::EncoderInit(enc, 0 /* adaptive mode */)); | |
114 typename T::instance_type* dec; | |
115 EXPECT_EQ(0, T::Create(&dec)); | |
116 EXPECT_EQ(0, T::DecoderInit(dec)); | |
117 | |
118 const int kSamplesPerPacket = 960; | |
119 std::multiset<int> send_bw_avg, bottleneck_idx; | |
120 for (int i = 0; i < 250; ++i) { | |
121 std::ostringstream ss; | |
122 ss << "i = " << i; | |
123 SCOPED_TRACE(ss.str()); | |
124 | |
125 // 1. Get BW info from decoders, and make sure they're similar enough. | |
126 auto bi1 = GetBwInfo<T>(encdec); | |
127 auto bi2 = GetBwInfo<T>(dec); | |
128 EXPECT_TRUE(Similar(bi1, bi2)) << "Not similar enough:\n " << Str(bi1) | |
129 << "\n " << Str(bi2); | |
130 send_bw_avg.insert(bi2.send_bw_avg); | |
131 bottleneck_idx.insert(bi2.bottleneck_idx); | |
132 | |
133 // 2. Encode 6 * 10 ms. The separate encoder is given the BW info before | |
134 // each encode call. | |
135 auto bitstream1 = Encode60Ms<T>(encdec, nullptr, speech_data); | |
136 auto bitstream2 = Encode60Ms<T>(enc, &bi2, speech_data); | |
137 | |
138 // 3. Deliver the encoded data to the decoders (but don't actually ask them | |
139 // to decode it; that's not necessary). | |
140 const int send_time = i * kSamplesPerPacket; | |
141 const int receive_time = send_time + kSamplesPerPacket / 10; // 6 ms delay | |
142 EXPECT_EQ( | |
143 0, T::UpdateBwEstimate(encdec, bitstream1.data(), bitstream1.size(), 1, | |
144 send_time, receive_time)); | |
145 EXPECT_EQ(0, T::UpdateBwEstimate(dec, bitstream2.data(), bitstream2.size(), | |
146 1, send_time, receive_time)); | |
kwiberg-webrtc
2015/06/25 14:52:43
If I've understood correctly, this means that each
hlundin-webrtc
2015/06/26 10:35:15
I'm not so sure. The receive time should just be t
kwiberg-webrtc
2015/06/27 23:43:43
But I do get some action. First it keeps the bitra
hlundin-webrtc
2015/06/29 08:42:18
Hmm. I still think that the BWE should ignore this
| |
147 } | |
148 | |
149 // Check that we see a good spread of send_bw_avg numbers. | |
150 EXPECT_EQ(CountRange(send_bw_avg, std::numeric_limits<int>::min(), 10000), 0); | |
hlundin-webrtc
2015/06/26 10:35:15
EXPECT_EQ should have swapped parameters; expected
kwiberg-webrtc
2015/06/28 03:17:41
Done. For symmetry, I also swapped the EXPECT_GEs.
| |
151 EXPECT_GE(CountRange(send_bw_avg, 10000, 11000), 37); | |
152 EXPECT_GE(CountRange(send_bw_avg, 11000, 12000), 14); | |
153 EXPECT_GE(CountRange(send_bw_avg, 12000, 13000), 14); | |
154 EXPECT_GE(CountRange(send_bw_avg, 13000, 14000), 10); | |
155 EXPECT_GE(CountRange(send_bw_avg, 14000, 15000), 15); | |
156 EXPECT_GE(CountRange(send_bw_avg, 15000, 16000), 12); | |
157 EXPECT_GE(CountRange(send_bw_avg, 16000, 17000), 10); | |
158 EXPECT_GE(CountRange(send_bw_avg, 17000, 18000), 12); | |
159 EXPECT_GE(CountRange(send_bw_avg, 18000, 19000), 7); | |
160 EXPECT_GE(CountRange(send_bw_avg, 19000, 20000), 40); | |
161 EXPECT_GE(CountRange(send_bw_avg, 20000, 21000), 34); | |
162 EXPECT_EQ(CountRange(send_bw_avg, 21000, std::numeric_limits<int>::max()), 0); | |
163 | |
164 // Check that we see a good spread of bottleneck_idx numbers. | |
165 EXPECT_EQ(bottleneck_idx.count(7), 1u); | |
166 EXPECT_EQ(CountRange(bottleneck_idx, std::numeric_limits<int>::min(), 12), 1); | |
167 EXPECT_GE(bottleneck_idx.count(12), 37u); | |
168 EXPECT_GE(bottleneck_idx.count(13), 18u); | |
169 EXPECT_GE(bottleneck_idx.count(14), 18u); | |
170 EXPECT_GE(bottleneck_idx.count(15), 18u); | |
171 EXPECT_GE(bottleneck_idx.count(16), 20u); | |
172 EXPECT_GE(bottleneck_idx.count(17), 19u); | |
173 EXPECT_GE(bottleneck_idx.count(18), 40u); | |
174 EXPECT_GE(bottleneck_idx.count(19), 32u); | |
175 EXPECT_EQ(CountRange(bottleneck_idx, 20, std::numeric_limits<int>::max()), 0); | |
176 } | |
177 | |
178 } // namespace | |
179 | |
180 TEST(IsacCommonTest, GetSetBandwidthInfoFloat) { | |
181 TestGetSetBandwidthInfo<IsacFloat>(LoadSpeechData().data()); | |
182 } | |
183 | |
184 TEST(IsacCommonTest, GetSetBandwidthInfoFix) { | |
185 TestGetSetBandwidthInfo<IsacFix>(LoadSpeechData().data()); | |
186 } | |
187 | |
188 } // namespace webrtc | |
OLD | NEW |