Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(194)

Side by Side Diff: webrtc/modules/audio_device/ios/audio_device_unittest_ios.cc

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

Powered by Google App Engine
This is Rietveld 408576698