OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (c) 2013 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 <assert.h> | |
12 #include <math.h> | |
13 | |
14 #include <iostream> | |
15 | |
16 #include "gflags/gflags.h" | |
17 #include "testing/gtest/include/gtest/gtest.h" | |
18 #include "webrtc/base/scoped_ptr.h" | |
19 #include "webrtc/common.h" | |
20 #include "webrtc/common_types.h" | |
21 #include "webrtc/engine_configurations.h" | |
22 #include "webrtc/modules/audio_coding/main/include/audio_coding_module.h" | |
23 #include "webrtc/modules/audio_coding/main/include/audio_coding_module_typedefs.
h" | |
24 #include "webrtc/modules/audio_coding/main/acm2/acm_common_defs.h" | |
25 #include "webrtc/modules/audio_coding/main/test/Channel.h" | |
26 #include "webrtc/modules/audio_coding/main/test/PCMFile.h" | |
27 #include "webrtc/modules/audio_coding/main/test/utility.h" | |
28 #include "webrtc/system_wrappers/include/event_wrapper.h" | |
29 #include "webrtc/test/testsupport/fileutils.h" | |
30 | |
31 DEFINE_string(codec, "isac", "Codec Name"); | |
32 DEFINE_int32(sample_rate_hz, 16000, "Sampling rate in Hertz."); | |
33 DEFINE_int32(num_channels, 1, "Number of Channels."); | |
34 DEFINE_string(input_file, "", "Input file, PCM16 32 kHz, optional."); | |
35 DEFINE_int32(delay, 0, "Delay in millisecond."); | |
36 DEFINE_bool(dtx, false, "Enable DTX at the sender side."); | |
37 DEFINE_bool(packet_loss, false, "Apply packet loss, c.f. Channel{.cc, .h}."); | |
38 DEFINE_bool(fec, false, "Use Forward Error Correction (FEC)."); | |
39 | |
40 namespace webrtc { | |
41 | |
42 namespace { | |
43 | |
44 struct CodecSettings { | |
45 char name[50]; | |
46 int sample_rate_hz; | |
47 int num_channels; | |
48 }; | |
49 | |
50 struct AcmSettings { | |
51 bool dtx; | |
52 bool fec; | |
53 }; | |
54 | |
55 struct TestSettings { | |
56 CodecSettings codec; | |
57 AcmSettings acm; | |
58 bool packet_loss; | |
59 }; | |
60 | |
61 } // namespace | |
62 | |
63 class DelayTest { | |
64 public: | |
65 DelayTest() | |
66 : acm_a_(AudioCodingModule::Create(0)), | |
67 acm_b_(AudioCodingModule::Create(1)), | |
68 channel_a2b_(new Channel), | |
69 test_cntr_(0), | |
70 encoding_sample_rate_hz_(8000) {} | |
71 | |
72 ~DelayTest() { | |
73 if (channel_a2b_ != NULL) { | |
74 delete channel_a2b_; | |
75 channel_a2b_ = NULL; | |
76 } | |
77 in_file_a_.Close(); | |
78 } | |
79 | |
80 void Initialize() { | |
81 test_cntr_ = 0; | |
82 std::string file_name = webrtc::test::ResourcePath( | |
83 "audio_coding/testfile32kHz", "pcm"); | |
84 if (FLAGS_input_file.size() > 0) | |
85 file_name = FLAGS_input_file; | |
86 in_file_a_.Open(file_name, 32000, "rb"); | |
87 ASSERT_EQ(0, acm_a_->InitializeReceiver()) << | |
88 "Couldn't initialize receiver.\n"; | |
89 ASSERT_EQ(0, acm_b_->InitializeReceiver()) << | |
90 "Couldn't initialize receiver.\n"; | |
91 | |
92 if (FLAGS_delay > 0) { | |
93 ASSERT_EQ(0, acm_b_->SetMinimumPlayoutDelay(FLAGS_delay)) << | |
94 "Failed to set minimum delay.\n"; | |
95 } | |
96 | |
97 int num_encoders = acm_a_->NumberOfCodecs(); | |
98 CodecInst my_codec_param; | |
99 for (int n = 0; n < num_encoders; n++) { | |
100 EXPECT_EQ(0, acm_b_->Codec(n, &my_codec_param)) << | |
101 "Failed to get codec."; | |
102 if (STR_CASE_CMP(my_codec_param.plname, "opus") == 0) | |
103 my_codec_param.channels = 1; | |
104 else if (my_codec_param.channels > 1) | |
105 continue; | |
106 if (STR_CASE_CMP(my_codec_param.plname, "CN") == 0 && | |
107 my_codec_param.plfreq == 48000) | |
108 continue; | |
109 if (STR_CASE_CMP(my_codec_param.plname, "telephone-event") == 0) | |
110 continue; | |
111 ASSERT_EQ(0, acm_b_->RegisterReceiveCodec(my_codec_param)) << | |
112 "Couldn't register receive codec.\n"; | |
113 } | |
114 | |
115 // Create and connect the channel | |
116 ASSERT_EQ(0, acm_a_->RegisterTransportCallback(channel_a2b_)) << | |
117 "Couldn't register Transport callback.\n"; | |
118 channel_a2b_->RegisterReceiverACM(acm_b_.get()); | |
119 } | |
120 | |
121 void Perform(const TestSettings* config, size_t num_tests, int duration_sec, | |
122 const char* output_prefix) { | |
123 for (size_t n = 0; n < num_tests; ++n) { | |
124 ApplyConfig(config[n]); | |
125 Run(duration_sec, output_prefix); | |
126 } | |
127 } | |
128 | |
129 private: | |
130 void ApplyConfig(const TestSettings& config) { | |
131 printf("====================================\n"); | |
132 printf("Test %d \n" | |
133 "Codec: %s, %d kHz, %d channel(s)\n" | |
134 "ACM: DTX %s, FEC %s\n" | |
135 "Channel: %s\n", | |
136 ++test_cntr_, config.codec.name, config.codec.sample_rate_hz, | |
137 config.codec.num_channels, config.acm.dtx ? "on" : "off", | |
138 config.acm.fec ? "on" : "off", | |
139 config.packet_loss ? "with packet-loss" : "no packet-loss"); | |
140 SendCodec(config.codec); | |
141 ConfigAcm(config.acm); | |
142 ConfigChannel(config.packet_loss); | |
143 } | |
144 | |
145 void SendCodec(const CodecSettings& config) { | |
146 CodecInst my_codec_param; | |
147 ASSERT_EQ(0, AudioCodingModule::Codec( | |
148 config.name, &my_codec_param, config.sample_rate_hz, | |
149 config.num_channels)) << "Specified codec is not supported.\n"; | |
150 | |
151 encoding_sample_rate_hz_ = my_codec_param.plfreq; | |
152 ASSERT_EQ(0, acm_a_->RegisterSendCodec(my_codec_param)) << | |
153 "Failed to register send-codec.\n"; | |
154 } | |
155 | |
156 void ConfigAcm(const AcmSettings& config) { | |
157 ASSERT_EQ(0, acm_a_->SetVAD(config.dtx, config.dtx, VADAggr)) << | |
158 "Failed to set VAD.\n"; | |
159 ASSERT_EQ(0, acm_a_->SetREDStatus(config.fec)) << | |
160 "Failed to set RED.\n"; | |
161 } | |
162 | |
163 void ConfigChannel(bool packet_loss) { | |
164 channel_a2b_->SetFECTestWithPacketLoss(packet_loss); | |
165 } | |
166 | |
167 void OpenOutFile(const char* output_id) { | |
168 std::stringstream file_stream; | |
169 file_stream << "delay_test_" << FLAGS_codec << "_" << FLAGS_sample_rate_hz | |
170 << "Hz" << "_" << FLAGS_delay << "ms.pcm"; | |
171 std::cout << "Output file: " << file_stream.str() << std::endl << std::endl; | |
172 std::string file_name = webrtc::test::OutputPath() + file_stream.str(); | |
173 out_file_b_.Open(file_name.c_str(), 32000, "wb"); | |
174 } | |
175 | |
176 void Run(int duration_sec, const char* output_prefix) { | |
177 OpenOutFile(output_prefix); | |
178 AudioFrame audio_frame; | |
179 uint32_t out_freq_hz_b = out_file_b_.SamplingFrequency(); | |
180 | |
181 int num_frames = 0; | |
182 int in_file_frames = 0; | |
183 uint32_t playout_ts; | |
184 uint32_t received_ts; | |
185 double average_delay = 0; | |
186 double inst_delay_sec = 0; | |
187 while (num_frames < (duration_sec * 100)) { | |
188 if (in_file_a_.EndOfFile()) { | |
189 in_file_a_.Rewind(); | |
190 } | |
191 | |
192 // Print delay information every 16 frame | |
193 if ((num_frames & 0x3F) == 0x3F) { | |
194 NetworkStatistics statistics; | |
195 acm_b_->GetNetworkStatistics(&statistics); | |
196 fprintf(stdout, "delay: min=%3d max=%3d mean=%3d median=%3d" | |
197 " ts-based average = %6.3f, " | |
198 "curr buff-lev = %4u opt buff-lev = %4u \n", | |
199 statistics.minWaitingTimeMs, statistics.maxWaitingTimeMs, | |
200 statistics.meanWaitingTimeMs, statistics.medianWaitingTimeMs, | |
201 average_delay, statistics.currentBufferSize, | |
202 statistics.preferredBufferSize); | |
203 fflush (stdout); | |
204 } | |
205 | |
206 in_file_a_.Read10MsData(audio_frame); | |
207 ASSERT_GE(acm_a_->Add10MsData(audio_frame), 0); | |
208 ASSERT_EQ(0, acm_b_->PlayoutData10Ms(out_freq_hz_b, &audio_frame)); | |
209 out_file_b_.Write10MsData( | |
210 audio_frame.data_, | |
211 audio_frame.samples_per_channel_ * audio_frame.num_channels_); | |
212 acm_b_->PlayoutTimestamp(&playout_ts); | |
213 received_ts = channel_a2b_->LastInTimestamp(); | |
214 inst_delay_sec = static_cast<uint32_t>(received_ts - playout_ts) | |
215 / static_cast<double>(encoding_sample_rate_hz_); | |
216 | |
217 if (num_frames > 10) | |
218 average_delay = 0.95 * average_delay + 0.05 * inst_delay_sec; | |
219 | |
220 ++num_frames; | |
221 ++in_file_frames; | |
222 } | |
223 out_file_b_.Close(); | |
224 } | |
225 | |
226 rtc::scoped_ptr<AudioCodingModule> acm_a_; | |
227 rtc::scoped_ptr<AudioCodingModule> acm_b_; | |
228 | |
229 Channel* channel_a2b_; | |
230 | |
231 PCMFile in_file_a_; | |
232 PCMFile out_file_b_; | |
233 int test_cntr_; | |
234 int encoding_sample_rate_hz_; | |
235 }; | |
236 | |
237 } // namespace webrtc | |
238 | |
239 int main(int argc, char* argv[]) { | |
240 google::ParseCommandLineFlags(&argc, &argv, true); | |
241 webrtc::TestSettings test_setting; | |
242 strcpy(test_setting.codec.name, FLAGS_codec.c_str()); | |
243 | |
244 if (FLAGS_sample_rate_hz != 8000 && | |
245 FLAGS_sample_rate_hz != 16000 && | |
246 FLAGS_sample_rate_hz != 32000 && | |
247 FLAGS_sample_rate_hz != 48000) { | |
248 std::cout << "Invalid sampling rate.\n"; | |
249 return 1; | |
250 } | |
251 test_setting.codec.sample_rate_hz = FLAGS_sample_rate_hz; | |
252 if (FLAGS_num_channels < 1 || FLAGS_num_channels > 2) { | |
253 std::cout << "Only mono and stereo are supported.\n"; | |
254 return 1; | |
255 } | |
256 test_setting.codec.num_channels = FLAGS_num_channels; | |
257 test_setting.acm.dtx = FLAGS_dtx; | |
258 test_setting.acm.fec = FLAGS_fec; | |
259 test_setting.packet_loss = FLAGS_packet_loss; | |
260 | |
261 webrtc::DelayTest delay_test; | |
262 delay_test.Initialize(); | |
263 delay_test.Perform(&test_setting, 1, 240, "delay_test"); | |
264 return 0; | |
265 } | |
OLD | NEW |