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