1/* 2 * Copyright (c) 2015 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 <algorithm> 12#include <limits> 13#include <list> 14#include <numeric> 15#include <string> 16#include <vector> 17 18#include "testing/gmock/include/gmock/gmock.h" 19#include "testing/gtest/include/gtest/gtest.h" 20#include "webrtc/base/arraysize.h" 21#include "webrtc/base/criticalsection.h" 22#include "webrtc/base/format_macros.h" 23#include "webrtc/base/logging.h" 24#include "webrtc/base/scoped_ptr.h" 25#include "webrtc/base/scoped_ref_ptr.h" 26#include "webrtc/modules/audio_device/audio_device_impl.h" 27#include "webrtc/modules/audio_device/include/audio_device.h" 28#include "webrtc/modules/audio_device/ios/audio_device_ios.h" 29#include "webrtc/system_wrappers/include/clock.h" 30#include "webrtc/system_wrappers/include/event_wrapper.h" 31#include "webrtc/system_wrappers/include/sleep.h" 32#include "webrtc/test/testsupport/fileutils.h" 33 34using std::cout; 35using std::endl; 36using ::testing::_; 37using ::testing::AtLeast; 38using ::testing::Gt; 39using ::testing::Invoke; 40using ::testing::NiceMock; 41using ::testing::NotNull; 42using ::testing::Return; 43 44// #define ENABLE_DEBUG_PRINTF 45#ifdef ENABLE_DEBUG_PRINTF 46#define PRINTD(...) fprintf(stderr, __VA_ARGS__); 47#else 48#define PRINTD(...) ((void)0) 49#endif 50#define PRINT(...) fprintf(stderr, __VA_ARGS__); 51 52namespace webrtc { 53 54// Number of callbacks (input or output) the tests waits for before we set 55// an event indicating that the test was OK. 56static const size_t kNumCallbacks = 10; 57// Max amount of time we wait for an event to be set while counting callbacks. 58static const int kTestTimeOutInMilliseconds = 10 * 1000; 59// Number of bits per PCM audio sample. 60static const size_t kBitsPerSample = 16; 61// Number of bytes per PCM audio sample. 62static const size_t kBytesPerSample = kBitsPerSample / 8; 63// Average number of audio callbacks per second assuming 10ms packet size. 64static const size_t kNumCallbacksPerSecond = 100; 65// Play out a test file during this time (unit is in seconds). 66static const int kFilePlayTimeInSec = 15; 67// Run the full-duplex test during this time (unit is in seconds). 68// Note that first |kNumIgnoreFirstCallbacks| are ignored. 69static const int kFullDuplexTimeInSec = 10; 70// Wait for the callback sequence to stabilize by ignoring this amount of the 71// initial callbacks (avoids initial FIFO access). 72// Only used in the RunPlayoutAndRecordingInFullDuplex test. 73static const size_t kNumIgnoreFirstCallbacks = 50; 74// Sets the number of impulses per second in the latency test. 75// TODO(henrika): fine tune this setting for iOS. 76static const int kImpulseFrequencyInHz = 1; 77// Length of round-trip latency measurements. Number of transmitted impulses 78// is kImpulseFrequencyInHz * kMeasureLatencyTimeInSec - 1. 79// TODO(henrika): fine tune this setting for iOS. 80static const int kMeasureLatencyTimeInSec = 5; 81// Utilized in round-trip latency measurements to avoid capturing noise samples. 82// TODO(henrika): fine tune this setting for iOS. 83static const int kImpulseThreshold = 50; 84static const char kTag[] = "[..........] "; 85 86enum TransportType { 87 kPlayout = 0x1, 88 kRecording = 0x2, 89}; 90 91// Interface for processing the audio stream. Real implementations can e.g. 92// run audio in loopback, read audio from a file or perform latency 93// measurements. 94class AudioStreamInterface { 95 public: 96 virtual void Write(const void* source, size_t num_frames) = 0; 97 virtual void Read(void* destination, size_t num_frames) = 0; 98 99 protected: 100 virtual ~AudioStreamInterface() {} 101}; 102 103// Reads audio samples from a PCM file where the file is stored in memory at 104// construction. 105class FileAudioStream : public AudioStreamInterface { 106 public: 107 FileAudioStream(size_t num_callbacks, 108 const std::string& file_name, 109 int sample_rate) 110 : file_size_in_bytes_(0), sample_rate_(sample_rate), file_pos_(0) { 111 file_size_in_bytes_ = test::GetFileSize(file_name); 112 sample_rate_ = sample_rate; 113 EXPECT_GE(file_size_in_callbacks(), num_callbacks) 114 << "Size of test file is not large enough to last during the test."; 115 const size_t num_16bit_samples = 116 test::GetFileSize(file_name) / kBytesPerSample; 117 file_.reset(new int16_t[num_16bit_samples]); 118 FILE* audio_file = fopen(file_name.c_str(), "rb"); 119 EXPECT_NE(audio_file, nullptr); 120 size_t num_samples_read = 121 fread(file_.get(), sizeof(int16_t), num_16bit_samples, audio_file); 122 EXPECT_EQ(num_samples_read, num_16bit_samples); 123 fclose(audio_file); 124 } 125 126 // AudioStreamInterface::Write() is not implemented. 127 void Write(const void* source, size_t num_frames) override {} 128 129 // Read samples from file stored in memory (at construction) and copy 130 // |num_frames| (<=> 10ms) to the |destination| byte buffer. 131 void Read(void* destination, size_t num_frames) override { 132 memcpy(destination, static_cast<int16_t*>(&file_[file_pos_]), 133 num_frames * sizeof(int16_t)); 134 file_pos_ += num_frames; 135 } 136 137 int file_size_in_seconds() const { 138 return static_cast<int>( 139 file_size_in_bytes_ / (kBytesPerSample * sample_rate_)); 140 } 141 size_t file_size_in_callbacks() const { 142 return file_size_in_seconds() * kNumCallbacksPerSecond; 143 } 144 145 private: 146 size_t file_size_in_bytes_; 147 int sample_rate_; 148 rtc::scoped_ptr<int16_t[]> file_; 149 size_t file_pos_; 150}; 151 152// Simple first in first out (FIFO) class that wraps a list of 16-bit audio 153// buffers of fixed size and allows Write and Read operations. The idea is to 154// store recorded audio buffers (using Write) and then read (using Read) these 155// stored buffers with as short delay as possible when the audio layer needs 156// data to play out. The number of buffers in the FIFO will stabilize under 157// normal conditions since there will be a balance between Write and Read calls. 158// The container is a std::list container and access is protected with a lock 159// since both sides (playout and recording) are driven by its own thread. 160class FifoAudioStream : public AudioStreamInterface { 161 public: 162 explicit FifoAudioStream(size_t frames_per_buffer) 163 : frames_per_buffer_(frames_per_buffer), 164 bytes_per_buffer_(frames_per_buffer_ * sizeof(int16_t)), 165 fifo_(new AudioBufferList), 166 largest_size_(0), 167 total_written_elements_(0), 168 write_count_(0) { 169 EXPECT_NE(fifo_.get(), nullptr); 170 } 171 172 ~FifoAudioStream() { Flush(); } 173 174 // Allocate new memory, copy |num_frames| samples from |source| into memory 175 // and add pointer to the memory location to end of the list. 176 // Increases the size of the FIFO by one element. 177 void Write(const void* source, size_t num_frames) override { 178 ASSERT_EQ(num_frames, frames_per_buffer_); 179 PRINTD("+"); 180 if (write_count_++ < kNumIgnoreFirstCallbacks) { 181 return; 182 } 183 int16_t* memory = new int16_t[frames_per_buffer_]; 184 memcpy(static_cast<int16_t*>(&memory[0]), source, bytes_per_buffer_); 185 rtc::CritScope lock(&lock_); 186 fifo_->push_back(memory); 187 const size_t size = fifo_->size(); 188 if (size > largest_size_) { 189 largest_size_ = size; 190 PRINTD("(%" PRIuS ")", largest_size_); 191 } 192 total_written_elements_ += size; 193 } 194 195 // Read pointer to data buffer from front of list, copy |num_frames| of stored 196 // data into |destination| and delete the utilized memory allocation. 197 // Decreases the size of the FIFO by one element. 198 void Read(void* destination, size_t num_frames) override { 199 ASSERT_EQ(num_frames, frames_per_buffer_); 200 PRINTD("-"); 201 rtc::CritScope lock(&lock_); 202 if (fifo_->empty()) { 203 memset(destination, 0, bytes_per_buffer_); 204 } else { 205 int16_t* memory = fifo_->front(); 206 fifo_->pop_front(); 207 memcpy(destination, static_cast<int16_t*>(&memory[0]), bytes_per_buffer_); 208 delete memory; 209 } 210 } 211 212 size_t size() const { return fifo_->size(); } 213 214 size_t largest_size() const { return largest_size_; } 215 216 size_t average_size() const { 217 return (total_written_elements_ == 0) 218 ? 0.0 219 : 0.5 + 220 static_cast<float>(total_written_elements_) / 221 (write_count_ - kNumIgnoreFirstCallbacks); 222 } 223 224 private: 225 void Flush() { 226 for (auto it = fifo_->begin(); it != fifo_->end(); ++it) { 227 delete *it; 228 } 229 fifo_->clear(); 230 } 231 232 using AudioBufferList = std::list<int16_t*>; 233 rtc::CriticalSection lock_; 234 const size_t frames_per_buffer_; 235 const size_t bytes_per_buffer_; 236 rtc::scoped_ptr<AudioBufferList> fifo_; 237 size_t largest_size_; 238 size_t total_written_elements_; 239 size_t write_count_; 240}; 241 242// Inserts periodic impulses and measures the latency between the time of 243// transmission and time of receiving the same impulse. 244// Usage requires a special hardware called Audio Loopback Dongle. 245// See http://source.android.com/devices/audio/loopback.html for details. 246class LatencyMeasuringAudioStream : public AudioStreamInterface { 247 public: 248 explicit LatencyMeasuringAudioStream(size_t frames_per_buffer) 249 : clock_(Clock::GetRealTimeClock()), 250 frames_per_buffer_(frames_per_buffer), 251 bytes_per_buffer_(frames_per_buffer_ * sizeof(int16_t)), 252 play_count_(0), 253 rec_count_(0), 254 pulse_time_(0) {} 255 256 // Insert periodic impulses in first two samples of |destination|. 257 void Read(void* destination, size_t num_frames) override { 258 ASSERT_EQ(num_frames, frames_per_buffer_); 259 if (play_count_ == 0) { 260 PRINT("["); 261 } 262 play_count_++; 263 memset(destination, 0, bytes_per_buffer_); 264 if (play_count_ % (kNumCallbacksPerSecond / kImpulseFrequencyInHz) == 0) { 265 if (pulse_time_ == 0) { 266 pulse_time_ = clock_->TimeInMilliseconds(); 267 } 268 PRINT("."); 269 const int16_t impulse = std::numeric_limits<int16_t>::max(); 270 int16_t* ptr16 = static_cast<int16_t*>(destination); 271 for (size_t i = 0; i < 2; ++i) { 272 ptr16[i] = impulse; 273 } 274 } 275 } 276 277 // Detect received impulses in |source|, derive time between transmission and 278 // detection and add the calculated delay to list of latencies. 279 void Write(const void* source, size_t num_frames) override { 280 ASSERT_EQ(num_frames, frames_per_buffer_); 281 rec_count_++; 282 if (pulse_time_ == 0) { 283 // Avoid detection of new impulse response until a new impulse has 284 // been transmitted (sets |pulse_time_| to value larger than zero). 285 return; 286 } 287 const int16_t* ptr16 = static_cast<const int16_t*>(source); 288 std::vector<int16_t> vec(ptr16, ptr16 + num_frames); 289 // Find max value in the audio buffer. 290 int max = *std::max_element(vec.begin(), vec.end()); 291 // Find index (element position in vector) of the max element. 292 int index_of_max = 293 std::distance(vec.begin(), std::find(vec.begin(), vec.end(), max)); 294 if (max > kImpulseThreshold) { 295 PRINTD("(%d,%d)", max, index_of_max); 296 int64_t now_time = clock_->TimeInMilliseconds(); 297 int extra_delay = IndexToMilliseconds(static_cast<double>(index_of_max)); 298 PRINTD("[%d]", static_cast<int>(now_time - pulse_time_)); 299 PRINTD("[%d]", extra_delay); 300 // Total latency is the difference between transmit time and detection 301 // tome plus the extra delay within the buffer in which we detected the 302 // received impulse. It is transmitted at sample 0 but can be received 303 // at sample N where N > 0. The term |extra_delay| accounts for N and it 304 // is a value between 0 and 10ms. 305 latencies_.push_back(now_time - pulse_time_ + extra_delay); 306 pulse_time_ = 0; 307 } else { 308 PRINTD("-"); 309 } 310 } 311 312 size_t num_latency_values() const { return latencies_.size(); } 313 314 int min_latency() const { 315 if (latencies_.empty()) 316 return 0; 317 return *std::min_element(latencies_.begin(), latencies_.end()); 318 } 319 320 int max_latency() const { 321 if (latencies_.empty()) 322 return 0; 323 return *std::max_element(latencies_.begin(), latencies_.end()); 324 } 325 326 int average_latency() const { 327 if (latencies_.empty()) 328 return 0; 329 return 0.5 + 330 static_cast<double>( 331 std::accumulate(latencies_.begin(), latencies_.end(), 0)) / 332 latencies_.size(); 333 } 334 335 void PrintResults() const { 336 PRINT("] "); 337 for (auto it = latencies_.begin(); it != latencies_.end(); ++it) { 338 PRINT("%d ", *it); 339 } 340 PRINT("\n"); 341 PRINT("%s[min, max, avg]=[%d, %d, %d] ms\n", kTag, min_latency(), 342 max_latency(), average_latency()); 343 } 344 345 int IndexToMilliseconds(double index) const { 346 return 10.0 * (index / frames_per_buffer_) + 0.5; 347 } 348 349 private: 350 Clock* clock_; 351 const size_t frames_per_buffer_; 352 const size_t bytes_per_buffer_; 353 size_t play_count_; 354 size_t rec_count_; 355 int64_t pulse_time_; 356 std::vector<int> latencies_; 357}; 358// Mocks the AudioTransport object and proxies actions for the two callbacks 359// (RecordedDataIsAvailable and NeedMorePlayData) to different implementations 360// of AudioStreamInterface. 361class MockAudioTransport : public AudioTransport { 362 public: 363 explicit MockAudioTransport(int type) 364 : num_callbacks_(0), 365 type_(type), 366 play_count_(0), 367 rec_count_(0), 368 audio_stream_(nullptr) {} 369 370 virtual ~MockAudioTransport() {} 371 372 MOCK_METHOD10(RecordedDataIsAvailable, 373 int32_t(const void* audioSamples, 374 const size_t nSamples, 375 const size_t nBytesPerSample, 376 const size_t nChannels, 377 const uint32_t samplesPerSec, 378 const uint32_t totalDelayMS, 379 const int32_t clockDrift, 380 const uint32_t currentMicLevel, 381 const bool keyPressed, 382 uint32_t& newMicLevel)); 383 MOCK_METHOD8(NeedMorePlayData, 384 int32_t(const size_t nSamples, 385 const size_t nBytesPerSample, 386 const size_t nChannels, 387 const uint32_t samplesPerSec, 388 void* audioSamples, 389 size_t& nSamplesOut, 390 int64_t* elapsed_time_ms, 391 int64_t* ntp_time_ms)); 392 393 // Set default actions of the mock object. We are delegating to fake 394 // implementations (of AudioStreamInterface) here. 395 void HandleCallbacks(EventWrapper* test_is_done, 396 AudioStreamInterface* audio_stream, 397 size_t num_callbacks) { 398 test_is_done_ = test_is_done; 399 audio_stream_ = audio_stream; 400 num_callbacks_ = num_callbacks; 401 if (play_mode()) { 402 ON_CALL(*this, NeedMorePlayData(_, _, _, _, _, _, _, _)) 403 .WillByDefault( 404 Invoke(this, &MockAudioTransport::RealNeedMorePlayData)); 405 } 406 if (rec_mode()) { 407 ON_CALL(*this, RecordedDataIsAvailable(_, _, _, _, _, _, _, _, _, _)) 408 .WillByDefault( 409 Invoke(this, &MockAudioTransport::RealRecordedDataIsAvailable)); 410 } 411 } 412 413 int32_t RealRecordedDataIsAvailable(const void* audioSamples, 414 const size_t nSamples, 415 const size_t nBytesPerSample, 416 const size_t nChannels, 417 const uint32_t samplesPerSec, 418 const uint32_t totalDelayMS, 419 const int32_t clockDrift, 420 const uint32_t currentMicLevel, 421 const bool keyPressed, 422 uint32_t& newMicLevel) { 423 EXPECT_TRUE(rec_mode()) << "No test is expecting these callbacks."; 424 rec_count_++; 425 // Process the recorded audio stream if an AudioStreamInterface 426 // implementation exists. 427 if (audio_stream_) { 428 audio_stream_->Write(audioSamples, nSamples); 429 } 430 if (ReceivedEnoughCallbacks()) { 431 if (test_is_done_) { 432 test_is_done_->Set(); 433 } 434 } 435 return 0; 436 } 437 438 int32_t RealNeedMorePlayData(const size_t nSamples, 439 const size_t nBytesPerSample, 440 const size_t nChannels, 441 const uint32_t samplesPerSec, 442 void* audioSamples, 443 size_t& nSamplesOut, 444 int64_t* elapsed_time_ms, 445 int64_t* ntp_time_ms) { 446 EXPECT_TRUE(play_mode()) << "No test is expecting these callbacks."; 447 play_count_++; 448 nSamplesOut = nSamples; 449 // Read (possibly processed) audio stream samples to be played out if an 450 // AudioStreamInterface implementation exists. 451 if (audio_stream_) { 452 audio_stream_->Read(audioSamples, nSamples); 453 } 454 if (ReceivedEnoughCallbacks()) { 455 if (test_is_done_) { 456 test_is_done_->Set(); 457 } 458 } 459 return 0; 460 } 461 462 bool ReceivedEnoughCallbacks() { 463 bool recording_done = false; 464 if (rec_mode()) 465 recording_done = rec_count_ >= num_callbacks_; 466 else 467 recording_done = true; 468 469 bool playout_done = false; 470 if (play_mode()) 471 playout_done = play_count_ >= num_callbacks_; 472 else 473 playout_done = true; 474 475 return recording_done && playout_done; 476 } 477 478 bool play_mode() const { return type_ & kPlayout; } 479 bool rec_mode() const { return type_ & kRecording; } 480 481 private: 482 EventWrapper* test_is_done_; 483 size_t num_callbacks_; 484 int type_; 485 size_t play_count_; 486 size_t rec_count_; 487 AudioStreamInterface* audio_stream_; 488}; 489 490// AudioDeviceTest test fixture. 491class AudioDeviceTest : public ::testing::Test { 492 protected: 493 AudioDeviceTest() : test_is_done_(EventWrapper::Create()) { 494 old_sev_ = rtc::LogMessage::GetLogToDebug(); 495 // Set suitable logging level here. Change to rtc::LS_INFO for more verbose 496 // output. See webrtc/base/logging.h for complete list of options. 497 rtc::LogMessage::LogToDebug(rtc::LS_INFO); 498 // Add extra logging fields here (timestamps and thread id). 499 // rtc::LogMessage::LogTimestamps(); 500 rtc::LogMessage::LogThreads(); 501 // Creates an audio device using a default audio layer. 502 audio_device_ = CreateAudioDevice(AudioDeviceModule::kPlatformDefaultAudio); 503 EXPECT_NE(audio_device_.get(), nullptr); 504 EXPECT_EQ(0, audio_device_->Init()); 505 EXPECT_EQ(0, 506 audio_device()->GetPlayoutAudioParameters(&playout_parameters_)); 507 EXPECT_EQ(0, audio_device()->GetRecordAudioParameters(&record_parameters_)); 508 } 509 virtual ~AudioDeviceTest() { 510 EXPECT_EQ(0, audio_device_->Terminate()); 511 rtc::LogMessage::LogToDebug(old_sev_); 512 } 513 514 int playout_sample_rate() const { return playout_parameters_.sample_rate(); } 515 int record_sample_rate() const { return record_parameters_.sample_rate(); } 516 int playout_channels() const { return playout_parameters_.channels(); } 517 int record_channels() const { return record_parameters_.channels(); } 518 size_t playout_frames_per_10ms_buffer() const { 519 return playout_parameters_.frames_per_10ms_buffer(); 520 } 521 size_t record_frames_per_10ms_buffer() const { 522 return record_parameters_.frames_per_10ms_buffer(); 523 } 524 525 rtc::scoped_refptr<AudioDeviceModule> audio_device() const { 526 return audio_device_; 527 } 528 529 AudioDeviceModuleImpl* audio_device_impl() const { 530 return static_cast<AudioDeviceModuleImpl*>(audio_device_.get()); 531 } 532 533 AudioDeviceBuffer* audio_device_buffer() const { 534 return audio_device_impl()->GetAudioDeviceBuffer(); 535 } 536 537 rtc::scoped_refptr<AudioDeviceModule> CreateAudioDevice( 538 AudioDeviceModule::AudioLayer audio_layer) { 539 rtc::scoped_refptr<AudioDeviceModule> module( 540 AudioDeviceModuleImpl::Create(0, audio_layer)); 541 return module; 542 } 543 544 // Returns file name relative to the resource root given a sample rate. 545 std::string GetFileName(int sample_rate) { 546 EXPECT_TRUE(sample_rate == 48000 || sample_rate == 44100 || 547 sample_rate == 16000); 548 char fname[64]; 549 snprintf(fname, sizeof(fname), "audio_device/audio_short%d", 550 sample_rate / 1000); 551 std::string file_name(webrtc::test::ResourcePath(fname, "pcm")); 552 EXPECT_TRUE(test::FileExists(file_name)); 553#ifdef ENABLE_DEBUG_PRINTF 554 PRINTD("file name: %s\n", file_name.c_str()); 555 const size_t bytes = test::GetFileSize(file_name); 556 PRINTD("file size: %" PRIuS " [bytes]\n", bytes); 557 PRINTD("file size: %" PRIuS " [samples]\n", bytes / kBytesPerSample); 558 const int seconds = 559 static_cast<int>(bytes / (sample_rate * kBytesPerSample)); 560 PRINTD("file size: %d [secs]\n", seconds); 561 PRINTD("file size: %" PRIuS " [callbacks]\n", 562 seconds * kNumCallbacksPerSecond); 563#endif 564 return file_name; 565 } 566 567 void StartPlayout() { 568 EXPECT_FALSE(audio_device()->PlayoutIsInitialized()); 569 EXPECT_FALSE(audio_device()->Playing()); 570 EXPECT_EQ(0, audio_device()->InitPlayout()); 571 EXPECT_TRUE(audio_device()->PlayoutIsInitialized()); 572 EXPECT_EQ(0, audio_device()->StartPlayout()); 573 EXPECT_TRUE(audio_device()->Playing()); 574 } 575 576 void StopPlayout() { 577 EXPECT_EQ(0, audio_device()->StopPlayout()); 578 EXPECT_FALSE(audio_device()->Playing()); 579 EXPECT_FALSE(audio_device()->PlayoutIsInitialized()); 580 } 581 582 void StartRecording() { 583 EXPECT_FALSE(audio_device()->RecordingIsInitialized()); 584 EXPECT_FALSE(audio_device()->Recording()); 585 EXPECT_EQ(0, audio_device()->InitRecording()); 586 EXPECT_TRUE(audio_device()->RecordingIsInitialized()); 587 EXPECT_EQ(0, audio_device()->StartRecording()); 588 EXPECT_TRUE(audio_device()->Recording()); 589 } 590 591 void StopRecording() { 592 EXPECT_EQ(0, audio_device()->StopRecording()); 593 EXPECT_FALSE(audio_device()->Recording()); 594 } 595 596 rtc::scoped_ptr<EventWrapper> test_is_done_; 597 rtc::scoped_refptr<AudioDeviceModule> audio_device_; 598 AudioParameters playout_parameters_; 599 AudioParameters record_parameters_; 600 rtc::LoggingSeverity old_sev_; 601}; 602 603TEST_F(AudioDeviceTest, ConstructDestruct) { 604 // Using the test fixture to create and destruct the audio device module. 605} 606 607TEST_F(AudioDeviceTest, InitTerminate) { 608 // Initialization is part of the test fixture. 609 EXPECT_TRUE(audio_device()->Initialized()); 610 EXPECT_EQ(0, audio_device()->Terminate()); 611 EXPECT_FALSE(audio_device()->Initialized()); 612} 613 614// Tests that playout can be initiated, started and stopped. No audio callback 615// is registered in this test. 616TEST_F(AudioDeviceTest, StartStopPlayout) { 617 StartPlayout(); 618 StopPlayout(); 619 StartPlayout(); 620 StopPlayout(); 621} 622 623// Tests that recording can be initiated, started and stopped. No audio callback 624// is registered in this test. 625TEST_F(AudioDeviceTest, StartStopRecording) { 626 StartRecording(); 627 StopRecording(); 628 StartRecording(); 629 StopRecording(); 630} 631 632// Verify that calling StopPlayout() will leave us in an uninitialized state 633// which will require a new call to InitPlayout(). This test does not call 634// StartPlayout() while being uninitialized since doing so will hit a 635// RTC_DCHECK. 636TEST_F(AudioDeviceTest, StopPlayoutRequiresInitToRestart) { 637 EXPECT_EQ(0, audio_device()->InitPlayout()); 638 EXPECT_EQ(0, audio_device()->StartPlayout()); 639 EXPECT_EQ(0, audio_device()->StopPlayout()); 640 EXPECT_FALSE(audio_device()->PlayoutIsInitialized()); 641} 642 643// Verify that we can create two ADMs and start playing on the second ADM. 644// Only the first active instance shall activate an audio session and the 645// last active instance shall deactivate the audio session. The test does not 646// explicitly verify correct audio session calls but instead focuses on 647// ensuring that audio starts for both ADMs. 648TEST_F(AudioDeviceTest, StartPlayoutOnTwoInstances) { 649 // Create and initialize a second/extra ADM instance. The default ADM is 650 // created by the test harness. 651 rtc::scoped_refptr<AudioDeviceModule> second_audio_device = 652 CreateAudioDevice(AudioDeviceModule::kPlatformDefaultAudio); 653 EXPECT_NE(second_audio_device.get(), nullptr); 654 EXPECT_EQ(0, second_audio_device->Init()); 655 656 // Start playout for the default ADM but don't wait here. Instead use the 657 // upcoming second stream for that. We set the same expectation on number 658 // of callbacks as for the second stream. 659 NiceMock<MockAudioTransport> mock(kPlayout); 660 mock.HandleCallbacks(nullptr, nullptr, 0); 661 EXPECT_CALL( 662 mock, NeedMorePlayData(playout_frames_per_10ms_buffer(), kBytesPerSample, 663 playout_channels(), playout_sample_rate(), 664 NotNull(), _, _, _)) 665 .Times(AtLeast(kNumCallbacks)); 666 EXPECT_EQ(0, audio_device()->RegisterAudioCallback(&mock)); 667 StartPlayout(); 668 669 // Initialize playout for the second ADM. If all is OK, the second ADM shall 670 // reuse the audio session activated when the first ADM started playing. 671 // This call will also ensure that we avoid a problem related to initializing 672 // two different audio unit instances back to back (see webrtc:5166 for 673 // details). 674 EXPECT_EQ(0, second_audio_device->InitPlayout()); 675 EXPECT_TRUE(second_audio_device->PlayoutIsInitialized()); 676 677 // Start playout for the second ADM and verify that it starts as intended. 678 // Passing this test ensures that initialization of the second audio unit 679 // has been done successfully and that there is no conflict with the already 680 // playing first ADM. 681 MockAudioTransport mock2(kPlayout); 682 mock2.HandleCallbacks(test_is_done_.get(), nullptr, kNumCallbacks); 683 EXPECT_CALL( 684 mock2, NeedMorePlayData(playout_frames_per_10ms_buffer(), kBytesPerSample, 685 playout_channels(), playout_sample_rate(), 686 NotNull(), _, _, _)) 687 .Times(AtLeast(kNumCallbacks)); 688 EXPECT_EQ(0, second_audio_device->RegisterAudioCallback(&mock2)); 689 EXPECT_EQ(0, second_audio_device->StartPlayout()); 690 EXPECT_TRUE(second_audio_device->Playing()); 691 test_is_done_->Wait(kTestTimeOutInMilliseconds); 692 EXPECT_EQ(0, second_audio_device->StopPlayout()); 693 EXPECT_FALSE(second_audio_device->Playing()); 694 EXPECT_FALSE(second_audio_device->PlayoutIsInitialized()); 695 696 EXPECT_EQ(0, second_audio_device->Terminate()); 697} 698 699// Start playout and verify that the native audio layer starts asking for real 700// audio samples to play out using the NeedMorePlayData callback. 701TEST_F(AudioDeviceTest, StartPlayoutVerifyCallbacks) { 702 MockAudioTransport mock(kPlayout); 703 mock.HandleCallbacks(test_is_done_.get(), nullptr, kNumCallbacks); 704 EXPECT_CALL(mock, NeedMorePlayData(playout_frames_per_10ms_buffer(), 705 kBytesPerSample, playout_channels(), 706 playout_sample_rate(), NotNull(), _, _, _)) 707 .Times(AtLeast(kNumCallbacks)); 708 EXPECT_EQ(0, audio_device()->RegisterAudioCallback(&mock)); 709 StartPlayout(); 710 test_is_done_->Wait(kTestTimeOutInMilliseconds); 711 StopPlayout(); 712} 713 714// Start recording and verify that the native audio layer starts feeding real 715// audio samples via the RecordedDataIsAvailable callback. 716TEST_F(AudioDeviceTest, StartRecordingVerifyCallbacks) { 717 MockAudioTransport mock(kRecording); 718 mock.HandleCallbacks(test_is_done_.get(), nullptr, kNumCallbacks); 719 EXPECT_CALL(mock, 720 RecordedDataIsAvailable( 721 NotNull(), record_frames_per_10ms_buffer(), kBytesPerSample, 722 record_channels(), record_sample_rate(), 723 _, // TODO(henrika): fix delay 724 0, 0, false, _)).Times(AtLeast(kNumCallbacks)); 725 726 EXPECT_EQ(0, audio_device()->RegisterAudioCallback(&mock)); 727 StartRecording(); 728 test_is_done_->Wait(kTestTimeOutInMilliseconds); 729 StopRecording(); 730} 731 732// Start playout and recording (full-duplex audio) and verify that audio is 733// active in both directions. 734TEST_F(AudioDeviceTest, StartPlayoutAndRecordingVerifyCallbacks) { 735 MockAudioTransport mock(kPlayout | kRecording); 736 mock.HandleCallbacks(test_is_done_.get(), nullptr, kNumCallbacks); 737 EXPECT_CALL(mock, NeedMorePlayData(playout_frames_per_10ms_buffer(), 738 kBytesPerSample, playout_channels(), 739 playout_sample_rate(), NotNull(), _, _, _)) 740 .Times(AtLeast(kNumCallbacks)); 741 EXPECT_CALL(mock, 742 RecordedDataIsAvailable( 743 NotNull(), record_frames_per_10ms_buffer(), kBytesPerSample, 744 record_channels(), record_sample_rate(), 745 _, // TODO(henrika): fix delay 746 0, 0, false, _)).Times(AtLeast(kNumCallbacks)); 747 EXPECT_EQ(0, audio_device()->RegisterAudioCallback(&mock)); 748 StartPlayout(); 749 StartRecording(); 750 test_is_done_->Wait(kTestTimeOutInMilliseconds); 751 StopRecording(); 752 StopPlayout(); 753} 754 755// Start playout and read audio from an external PCM file when the audio layer 756// asks for data to play out. Real audio is played out in this test but it does 757// not contain any explicit verification that the audio quality is perfect. 758TEST_F(AudioDeviceTest, RunPlayoutWithFileAsSource) { 759 // TODO(henrika): extend test when mono output is supported. 760 EXPECT_EQ(1, playout_channels()); 761 NiceMock<MockAudioTransport> mock(kPlayout); 762 const int num_callbacks = kFilePlayTimeInSec * kNumCallbacksPerSecond; 763 std::string file_name = GetFileName(playout_sample_rate()); 764 rtc::scoped_ptr<FileAudioStream> file_audio_stream( 765 new FileAudioStream(num_callbacks, file_name, playout_sample_rate())); 766 mock.HandleCallbacks(test_is_done_.get(), file_audio_stream.get(), 767 num_callbacks); 768 // SetMaxPlayoutVolume(); 769 EXPECT_EQ(0, audio_device()->RegisterAudioCallback(&mock)); 770 StartPlayout(); 771 test_is_done_->Wait(kTestTimeOutInMilliseconds); 772 StopPlayout(); 773} 774 775TEST_F(AudioDeviceTest, Devices) { 776 // Device enumeration is not supported. Verify fixed values only. 777 EXPECT_EQ(1, audio_device()->PlayoutDevices()); 778 EXPECT_EQ(1, audio_device()->RecordingDevices()); 779} 780 781// Start playout and recording and store recorded data in an intermediate FIFO 782// buffer from which the playout side then reads its samples in the same order 783// as they were stored. Under ideal circumstances, a callback sequence would 784// look like: ...+-+-+-+-+-+-+-..., where '+' means 'packet recorded' and '-' 785// means 'packet played'. Under such conditions, the FIFO would only contain 786// one packet on average. However, under more realistic conditions, the size 787// of the FIFO will vary more due to an unbalance between the two sides. 788// This test tries to verify that the device maintains a balanced callback- 789// sequence by running in loopback for ten seconds while measuring the size 790// (max and average) of the FIFO. The size of the FIFO is increased by the 791// recording side and decreased by the playout side. 792// TODO(henrika): tune the final test parameters after running tests on several 793// different devices. 794TEST_F(AudioDeviceTest, RunPlayoutAndRecordingInFullDuplex) { 795 EXPECT_EQ(record_channels(), playout_channels()); 796 EXPECT_EQ(record_sample_rate(), playout_sample_rate()); 797 NiceMock<MockAudioTransport> mock(kPlayout | kRecording); 798 rtc::scoped_ptr<FifoAudioStream> fifo_audio_stream( 799 new FifoAudioStream(playout_frames_per_10ms_buffer())); 800 mock.HandleCallbacks(test_is_done_.get(), fifo_audio_stream.get(), 801 kFullDuplexTimeInSec * kNumCallbacksPerSecond); 802 // SetMaxPlayoutVolume(); 803 EXPECT_EQ(0, audio_device()->RegisterAudioCallback(&mock)); 804 StartRecording(); 805 StartPlayout(); 806 test_is_done_->Wait( 807 std::max(kTestTimeOutInMilliseconds, 1000 * kFullDuplexTimeInSec)); 808 StopPlayout(); 809 StopRecording(); 810 EXPECT_LE(fifo_audio_stream->average_size(), 10u); 811 EXPECT_LE(fifo_audio_stream->largest_size(), 20u); 812} 813 814// Measures loopback latency and reports the min, max and average values for 815// a full duplex audio session. 816// The latency is measured like so: 817// - Insert impulses periodically on the output side. 818// - Detect the impulses on the input side. 819// - Measure the time difference between the transmit time and receive time. 820// - Store time differences in a vector and calculate min, max and average. 821// This test requires a special hardware called Audio Loopback Dongle. 822// See http://source.android.com/devices/audio/loopback.html for details. 823TEST_F(AudioDeviceTest, DISABLED_MeasureLoopbackLatency) { 824 EXPECT_EQ(record_channels(), playout_channels()); 825 EXPECT_EQ(record_sample_rate(), playout_sample_rate()); 826 NiceMock<MockAudioTransport> mock(kPlayout | kRecording); 827 rtc::scoped_ptr<LatencyMeasuringAudioStream> latency_audio_stream( 828 new LatencyMeasuringAudioStream(playout_frames_per_10ms_buffer())); 829 mock.HandleCallbacks(test_is_done_.get(), latency_audio_stream.get(), 830 kMeasureLatencyTimeInSec * kNumCallbacksPerSecond); 831 EXPECT_EQ(0, audio_device()->RegisterAudioCallback(&mock)); 832 // SetMaxPlayoutVolume(); 833 // DisableBuiltInAECIfAvailable(); 834 StartRecording(); 835 StartPlayout(); 836 test_is_done_->Wait( 837 std::max(kTestTimeOutInMilliseconds, 1000 * kMeasureLatencyTimeInSec)); 838 StopPlayout(); 839 StopRecording(); 840 // Verify that the correct number of transmitted impulses are detected. 841 EXPECT_EQ(latency_audio_stream->num_latency_values(), 842 static_cast<size_t>( 843 kImpulseFrequencyInHz * kMeasureLatencyTimeInSec - 1)); 844 latency_audio_stream->PrintResults(); 845} 846 847} // namespace webrtc 848