Home | History | Annotate | Download | only in test
      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 
     27 namespace webrtc {
     28 
     29 OpusTest::OpusTest()
     30     : acm_receiver_(AudioCodingModule::Create(0)),
     31       channel_a2b_(NULL),
     32       counter_(0),
     33       payload_type_(255),
     34       rtp_timestamp_(0) {}
     35 
     36 OpusTest::~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 
     59 void 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 
    208 void 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 
    368 void 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