• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "modules/audio_coding/test/opus_test.h"
12 
13 #include <string>
14 
15 #include "api/audio_codecs/builtin_audio_decoder_factory.h"
16 #include "modules/audio_coding/codecs/opus/opus_interface.h"
17 #include "modules/audio_coding/include/audio_coding_module_typedefs.h"
18 #include "modules/audio_coding/test/TestStereo.h"
19 #include "test/gtest.h"
20 #include "test/testsupport/file_utils.h"
21 
22 namespace webrtc {
23 
OpusTest()24 OpusTest::OpusTest()
25     : acm_receiver_(AudioCodingModule::Create(
26           AudioCodingModule::Config(CreateBuiltinAudioDecoderFactory()))),
27       channel_a2b_(NULL),
28       counter_(0),
29       payload_type_(255),
30       rtp_timestamp_(0) {}
31 
~OpusTest()32 OpusTest::~OpusTest() {
33   if (channel_a2b_ != NULL) {
34     delete channel_a2b_;
35     channel_a2b_ = NULL;
36   }
37   if (opus_mono_encoder_ != NULL) {
38     WebRtcOpus_EncoderFree(opus_mono_encoder_);
39     opus_mono_encoder_ = NULL;
40   }
41   if (opus_stereo_encoder_ != NULL) {
42     WebRtcOpus_EncoderFree(opus_stereo_encoder_);
43     opus_stereo_encoder_ = NULL;
44   }
45   if (opus_mono_decoder_ != NULL) {
46     WebRtcOpus_DecoderFree(opus_mono_decoder_);
47     opus_mono_decoder_ = NULL;
48   }
49   if (opus_stereo_decoder_ != NULL) {
50     WebRtcOpus_DecoderFree(opus_stereo_decoder_);
51     opus_stereo_decoder_ = NULL;
52   }
53 }
54 
Perform()55 void OpusTest::Perform() {
56 #ifndef WEBRTC_CODEC_OPUS
57   // Opus isn't defined, exit.
58   return;
59 #else
60   uint16_t frequency_hz;
61   size_t audio_channels;
62   int16_t test_cntr = 0;
63 
64   // Open both mono and stereo test files in 32 kHz.
65   const std::string file_name_stereo =
66       webrtc::test::ResourcePath("audio_coding/teststereo32kHz", "pcm");
67   const std::string file_name_mono =
68       webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm");
69   frequency_hz = 32000;
70   in_file_stereo_.Open(file_name_stereo, frequency_hz, "rb");
71   in_file_stereo_.ReadStereo(true);
72   in_file_mono_.Open(file_name_mono, frequency_hz, "rb");
73   in_file_mono_.ReadStereo(false);
74 
75   // Create Opus encoders for mono and stereo.
76   ASSERT_GT(WebRtcOpus_EncoderCreate(&opus_mono_encoder_, 1, 0, 48000), -1);
77   ASSERT_GT(WebRtcOpus_EncoderCreate(&opus_stereo_encoder_, 2, 1, 48000), -1);
78 
79   // Create Opus decoders for mono and stereo for stand-alone testing of Opus.
80   ASSERT_GT(WebRtcOpus_DecoderCreate(&opus_mono_decoder_, 1, 48000), -1);
81   ASSERT_GT(WebRtcOpus_DecoderCreate(&opus_stereo_decoder_, 2, 48000), -1);
82   WebRtcOpus_DecoderInit(opus_mono_decoder_);
83   WebRtcOpus_DecoderInit(opus_stereo_decoder_);
84 
85   ASSERT_TRUE(acm_receiver_.get() != NULL);
86   EXPECT_EQ(0, acm_receiver_->InitializeReceiver());
87 
88   // Register Opus stereo as receiving codec.
89   constexpr int kOpusPayloadType = 120;
90   const SdpAudioFormat kOpusFormatStereo("opus", 48000, 2, {{"stereo", "1"}});
91   payload_type_ = kOpusPayloadType;
92   acm_receiver_->SetReceiveCodecs({{kOpusPayloadType, kOpusFormatStereo}});
93 
94   // Create and connect the channel.
95   channel_a2b_ = new TestPackStereo;
96   channel_a2b_->RegisterReceiverACM(acm_receiver_.get());
97 
98   //
99   // Test Stereo.
100   //
101 
102   channel_a2b_->set_codec_mode(kStereo);
103   audio_channels = 2;
104   test_cntr++;
105   OpenOutFile(test_cntr);
106 
107   // Run Opus with 2.5 ms frame size.
108   Run(channel_a2b_, audio_channels, 64000, 120);
109 
110   // Run Opus with 5 ms frame size.
111   Run(channel_a2b_, audio_channels, 64000, 240);
112 
113   // Run Opus with 10 ms frame size.
114   Run(channel_a2b_, audio_channels, 64000, 480);
115 
116   // Run Opus with 20 ms frame size.
117   Run(channel_a2b_, audio_channels, 64000, 960);
118 
119   // Run Opus with 40 ms frame size.
120   Run(channel_a2b_, audio_channels, 64000, 1920);
121 
122   // Run Opus with 60 ms frame size.
123   Run(channel_a2b_, audio_channels, 64000, 2880);
124 
125   out_file_.Close();
126   out_file_standalone_.Close();
127 
128   //
129   // Test Opus stereo with packet-losses.
130   //
131 
132   test_cntr++;
133   OpenOutFile(test_cntr);
134 
135   // Run Opus with 20 ms frame size, 1% packet loss.
136   Run(channel_a2b_, audio_channels, 64000, 960, 1);
137 
138   // Run Opus with 20 ms frame size, 5% packet loss.
139   Run(channel_a2b_, audio_channels, 64000, 960, 5);
140 
141   // Run Opus with 20 ms frame size, 10% packet loss.
142   Run(channel_a2b_, audio_channels, 64000, 960, 10);
143 
144   out_file_.Close();
145   out_file_standalone_.Close();
146 
147   //
148   // Test Mono.
149   //
150   channel_a2b_->set_codec_mode(kMono);
151   audio_channels = 1;
152   test_cntr++;
153   OpenOutFile(test_cntr);
154 
155   // Register Opus mono as receiving codec.
156   const SdpAudioFormat kOpusFormatMono("opus", 48000, 2);
157   acm_receiver_->SetReceiveCodecs({{kOpusPayloadType, kOpusFormatMono}});
158 
159   // Run Opus with 2.5 ms frame size.
160   Run(channel_a2b_, audio_channels, 32000, 120);
161 
162   // Run Opus with 5 ms frame size.
163   Run(channel_a2b_, audio_channels, 32000, 240);
164 
165   // Run Opus with 10 ms frame size.
166   Run(channel_a2b_, audio_channels, 32000, 480);
167 
168   // Run Opus with 20 ms frame size.
169   Run(channel_a2b_, audio_channels, 32000, 960);
170 
171   // Run Opus with 40 ms frame size.
172   Run(channel_a2b_, audio_channels, 32000, 1920);
173 
174   // Run Opus with 60 ms frame size.
175   Run(channel_a2b_, audio_channels, 32000, 2880);
176 
177   out_file_.Close();
178   out_file_standalone_.Close();
179 
180   //
181   // Test Opus mono with packet-losses.
182   //
183   test_cntr++;
184   OpenOutFile(test_cntr);
185 
186   // Run Opus with 20 ms frame size, 1% packet loss.
187   Run(channel_a2b_, audio_channels, 64000, 960, 1);
188 
189   // Run Opus with 20 ms frame size, 5% packet loss.
190   Run(channel_a2b_, audio_channels, 64000, 960, 5);
191 
192   // Run Opus with 20 ms frame size, 10% packet loss.
193   Run(channel_a2b_, audio_channels, 64000, 960, 10);
194 
195   // Close the files.
196   in_file_stereo_.Close();
197   in_file_mono_.Close();
198   out_file_.Close();
199   out_file_standalone_.Close();
200 #endif
201 }
202 
Run(TestPackStereo * channel,size_t channels,int bitrate,size_t frame_length,int percent_loss)203 void OpusTest::Run(TestPackStereo* channel,
204                    size_t channels,
205                    int bitrate,
206                    size_t frame_length,
207                    int percent_loss) {
208   AudioFrame audio_frame;
209   int32_t out_freq_hz_b = out_file_.SamplingFrequency();
210   const size_t kBufferSizeSamples = 480 * 12 * 2;  // 120 ms stereo audio.
211   int16_t audio[kBufferSizeSamples];
212   int16_t out_audio[kBufferSizeSamples];
213   int16_t audio_type;
214   size_t written_samples = 0;
215   size_t read_samples = 0;
216   size_t decoded_samples = 0;
217   bool first_packet = true;
218   uint32_t start_time_stamp = 0;
219 
220   channel->reset_payload_size();
221   counter_ = 0;
222 
223   // Set encoder rate.
224   EXPECT_EQ(0, WebRtcOpus_SetBitRate(opus_mono_encoder_, bitrate));
225   EXPECT_EQ(0, WebRtcOpus_SetBitRate(opus_stereo_encoder_, bitrate));
226 
227 #if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS) || defined(WEBRTC_ARCH_ARM)
228   // If we are on Android, iOS and/or ARM, use a lower complexity setting as
229   // default.
230   const int kOpusComplexity5 = 5;
231   EXPECT_EQ(0, WebRtcOpus_SetComplexity(opus_mono_encoder_, kOpusComplexity5));
232   EXPECT_EQ(0,
233             WebRtcOpus_SetComplexity(opus_stereo_encoder_, kOpusComplexity5));
234 #endif
235 
236   // Fast-forward 1 second (100 blocks) since the files start with silence.
237   in_file_stereo_.FastForward(100);
238   in_file_mono_.FastForward(100);
239 
240   // Limit the runtime to 1000 blocks of 10 ms each.
241   for (size_t audio_length = 0; audio_length < 1000; audio_length += 10) {
242     bool lost_packet = false;
243 
244     // Get 10 msec of audio.
245     if (channels == 1) {
246       if (in_file_mono_.EndOfFile()) {
247         break;
248       }
249       in_file_mono_.Read10MsData(audio_frame);
250     } else {
251       if (in_file_stereo_.EndOfFile()) {
252         break;
253       }
254       in_file_stereo_.Read10MsData(audio_frame);
255     }
256 
257     // If input audio is sampled at 32 kHz, resampling to 48 kHz is required.
258     EXPECT_EQ(480, resampler_.Resample10Msec(
259                        audio_frame.data(), audio_frame.sample_rate_hz_, 48000,
260                        channels, kBufferSizeSamples - written_samples,
261                        &audio[written_samples]));
262     written_samples += 480 * channels;
263 
264     // Sometimes we need to loop over the audio vector to produce the right
265     // number of packets.
266     size_t loop_encode =
267         (written_samples - read_samples) / (channels * frame_length);
268 
269     if (loop_encode > 0) {
270       const size_t kMaxBytes = 1000;  // Maximum number of bytes for one packet.
271       size_t bitstream_len_byte;
272       uint8_t bitstream[kMaxBytes];
273       for (size_t i = 0; i < loop_encode; i++) {
274         int bitstream_len_byte_int = WebRtcOpus_Encode(
275             (channels == 1) ? opus_mono_encoder_ : opus_stereo_encoder_,
276             &audio[read_samples], frame_length, kMaxBytes, bitstream);
277         ASSERT_GE(bitstream_len_byte_int, 0);
278         bitstream_len_byte = static_cast<size_t>(bitstream_len_byte_int);
279 
280         // Simulate packet loss by setting |packet_loss_| to "true" in
281         // |percent_loss| percent of the loops.
282         // TODO(tlegrand): Move handling of loss simulation to TestPackStereo.
283         if (percent_loss > 0) {
284           if (counter_ == floor((100 / percent_loss) + 0.5)) {
285             counter_ = 0;
286             lost_packet = true;
287             channel->set_lost_packet(true);
288           } else {
289             lost_packet = false;
290             channel->set_lost_packet(false);
291           }
292           counter_++;
293         }
294 
295         // Run stand-alone Opus decoder, or decode PLC.
296         if (channels == 1) {
297           if (!lost_packet) {
298             decoded_samples += WebRtcOpus_Decode(
299                 opus_mono_decoder_, bitstream, bitstream_len_byte,
300                 &out_audio[decoded_samples * channels], &audio_type);
301           } else {
302             // Call decoder PLC.
303             constexpr int kPlcDurationMs = 10;
304             constexpr int kPlcSamples = 48 * kPlcDurationMs;
305             size_t total_plc_samples = 0;
306             while (total_plc_samples < frame_length) {
307               int ret = WebRtcOpus_Decode(
308                   opus_mono_decoder_, NULL, 0,
309                   &out_audio[decoded_samples * channels], &audio_type);
310               EXPECT_EQ(ret, kPlcSamples);
311               decoded_samples += ret;
312               total_plc_samples += ret;
313             }
314             EXPECT_EQ(total_plc_samples, frame_length);
315           }
316         } else {
317           if (!lost_packet) {
318             decoded_samples += WebRtcOpus_Decode(
319                 opus_stereo_decoder_, bitstream, bitstream_len_byte,
320                 &out_audio[decoded_samples * channels], &audio_type);
321           } else {
322             // Call decoder PLC.
323             constexpr int kPlcDurationMs = 10;
324             constexpr int kPlcSamples = 48 * kPlcDurationMs;
325             size_t total_plc_samples = 0;
326             while (total_plc_samples < frame_length) {
327               int ret = WebRtcOpus_Decode(
328                   opus_stereo_decoder_, NULL, 0,
329                   &out_audio[decoded_samples * channels], &audio_type);
330               EXPECT_EQ(ret, kPlcSamples);
331               decoded_samples += ret;
332               total_plc_samples += ret;
333             }
334             EXPECT_EQ(total_plc_samples, frame_length);
335           }
336         }
337 
338         // Send data to the channel. "channel" will handle the loss simulation.
339         channel->SendData(AudioFrameType::kAudioFrameSpeech, payload_type_,
340                           rtp_timestamp_, bitstream, bitstream_len_byte, 0);
341         if (first_packet) {
342           first_packet = false;
343           start_time_stamp = rtp_timestamp_;
344         }
345         rtp_timestamp_ += static_cast<uint32_t>(frame_length);
346         read_samples += frame_length * channels;
347       }
348       if (read_samples == written_samples) {
349         read_samples = 0;
350         written_samples = 0;
351       }
352     }
353 
354     // Run received side of ACM.
355     bool muted;
356     ASSERT_EQ(
357         0, acm_receiver_->PlayoutData10Ms(out_freq_hz_b, &audio_frame, &muted));
358     ASSERT_FALSE(muted);
359 
360     // Write output speech to file.
361     out_file_.Write10MsData(
362         audio_frame.data(),
363         audio_frame.samples_per_channel_ * audio_frame.num_channels_);
364 
365     // Write stand-alone speech to file.
366     out_file_standalone_.Write10MsData(out_audio, decoded_samples * channels);
367 
368     if (audio_frame.timestamp_ > start_time_stamp) {
369       // Number of channels should be the same for both stand-alone and
370       // ACM-decoding.
371       EXPECT_EQ(audio_frame.num_channels_, channels);
372     }
373 
374     decoded_samples = 0;
375   }
376 
377   if (in_file_mono_.EndOfFile()) {
378     in_file_mono_.Rewind();
379   }
380   if (in_file_stereo_.EndOfFile()) {
381     in_file_stereo_.Rewind();
382   }
383   // Reset in case we ended with a lost packet.
384   channel->set_lost_packet(false);
385 }
386 
OpenOutFile(int test_number)387 void OpusTest::OpenOutFile(int test_number) {
388   std::string file_name;
389   std::stringstream file_stream;
390   file_stream << webrtc::test::OutputPath() << "opustest_out_" << test_number
391               << ".pcm";
392   file_name = file_stream.str();
393   out_file_.Open(file_name, 48000, "wb");
394   file_stream.str("");
395   file_name = file_stream.str();
396   file_stream << webrtc::test::OutputPath() << "opusstandalone_out_"
397               << test_number << ".pcm";
398   file_name = file_stream.str();
399   out_file_standalone_.Open(file_name, 48000, "wb");
400 }
401 
402 }  // namespace webrtc
403