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