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