crazy linker: convert relocation unpacking to Android style.
[chromium-blink-merge.git] / media / audio / audio_low_latency_input_output_unittest.cc
blob26f9086c3be0fc46688fb377537a8e28a91181cd
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/basictypes.h"
6 #include "base/environment.h"
7 #include "base/files/file_util.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/path_service.h"
10 #include "base/synchronization/lock.h"
11 #include "base/test/test_timeouts.h"
12 #include "base/time/time.h"
13 #include "build/build_config.h"
14 #include "media/audio/audio_io.h"
15 #include "media/audio/audio_manager_base.h"
16 #include "media/audio/audio_unittest_util.h"
17 #include "media/audio/fake_audio_log_factory.h"
18 #include "media/base/seekable_buffer.h"
19 #include "testing/gmock/include/gmock/gmock.h"
20 #include "testing/gtest/include/gtest/gtest.h"
22 #if defined(USE_PULSEAUDIO)
23 #include "media/audio/pulse/audio_manager_pulse.h"
24 #elif defined(USE_ALSA)
25 #include "media/audio/alsa/audio_manager_alsa.h"
26 #elif defined(USE_CRAS)
27 #include "media/audio/cras/audio_manager_cras.h"
28 #elif defined(OS_MACOSX)
29 #include "media/audio/mac/audio_manager_mac.h"
30 #elif defined(OS_WIN)
31 #include "media/audio/win/audio_manager_win.h"
32 #include "media/audio/win/core_audio_util_win.h"
33 #elif defined(OS_ANDROID)
34 #include "media/audio/android/audio_manager_android.h"
35 #else
36 #include "media/audio/fake_audio_manager.h"
37 #endif
39 namespace media {
41 #if defined(USE_PULSEAUDIO)
42 typedef AudioManagerPulse AudioManagerAnyPlatform;
43 #elif defined(USE_ALSA)
44 typedef AudioManagerAlsa AudioManagerAnyPlatform;
45 #elif defined(USE_CRAS)
46 typedef AudioManagerCras AudioManagerAnyPlatform;
47 #elif defined(OS_MACOSX)
48 typedef AudioManagerMac AudioManagerAnyPlatform;
49 #elif defined(OS_WIN)
50 typedef AudioManagerWin AudioManagerAnyPlatform;
51 #elif defined(OS_ANDROID)
52 typedef AudioManagerAndroid AudioManagerAnyPlatform;
53 #else
54 typedef FakeAudioManager AudioManagerAnyPlatform;
55 #endif
57 // Limits the number of delay measurements we can store in an array and
58 // then write to file at end of the WASAPIAudioInputOutputFullDuplex test.
59 static const size_t kMaxDelayMeasurements = 1000;
61 // Name of the output text file. The output file will be stored in the
62 // directory containing media_unittests.exe.
63 // Example: \src\build\Debug\audio_delay_values_ms.txt.
64 // See comments for the WASAPIAudioInputOutputFullDuplex test for more details
65 // about the file format.
66 static const char kDelayValuesFileName[] = "audio_delay_values_ms.txt";
68 // Contains delay values which are reported during the full-duplex test.
69 // Total delay = |buffer_delay_ms| + |input_delay_ms| + |output_delay_ms|.
70 struct AudioDelayState {
71 AudioDelayState()
72 : delta_time_ms(0),
73 buffer_delay_ms(0),
74 input_delay_ms(0),
75 output_delay_ms(0) {
78 // Time in milliseconds since last delay report. Typical value is ~10 [ms].
79 int delta_time_ms;
81 // Size of internal sync buffer. Typical value is ~0 [ms].
82 int buffer_delay_ms;
84 // Reported capture/input delay. Typical value is ~10 [ms].
85 int input_delay_ms;
87 // Reported render/output delay. Typical value is ~40 [ms].
88 int output_delay_ms;
91 // This class mocks the platform specific audio manager and overrides
92 // the GetMessageLoop() method to ensure that we can run our tests on
93 // the main thread instead of the audio thread.
94 class MockAudioManager : public AudioManagerAnyPlatform {
95 public:
96 MockAudioManager() : AudioManagerAnyPlatform(&fake_audio_log_factory_) {}
97 ~MockAudioManager() override {}
99 scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner() override {
100 return base::MessageLoop::current()->message_loop_proxy();
103 private:
104 FakeAudioLogFactory fake_audio_log_factory_;
105 DISALLOW_COPY_AND_ASSIGN(MockAudioManager);
108 // Test fixture class.
109 class AudioLowLatencyInputOutputTest : public testing::Test {
110 protected:
111 AudioLowLatencyInputOutputTest() {}
113 ~AudioLowLatencyInputOutputTest() override {}
115 AudioManager* audio_manager() { return &mock_audio_manager_; }
116 base::MessageLoopForUI* message_loop() { return &message_loop_; }
118 private:
119 base::MessageLoopForUI message_loop_;
120 MockAudioManager mock_audio_manager_;
122 DISALLOW_COPY_AND_ASSIGN(AudioLowLatencyInputOutputTest);
125 // This audio source/sink implementation should be used for manual tests
126 // only since delay measurements are stored on an output text file.
127 // All incoming/recorded audio packets are stored in an intermediate media
128 // buffer which the renderer reads from when it needs audio for playout.
129 // The total effect is that recorded audio is played out in loop back using
130 // a sync buffer as temporary storage.
131 class FullDuplexAudioSinkSource
132 : public AudioInputStream::AudioInputCallback,
133 public AudioOutputStream::AudioSourceCallback {
134 public:
135 FullDuplexAudioSinkSource(int sample_rate,
136 int samples_per_packet,
137 int channels)
138 : sample_rate_(sample_rate),
139 samples_per_packet_(samples_per_packet),
140 channels_(channels),
141 input_elements_to_write_(0),
142 output_elements_to_write_(0),
143 previous_write_time_(base::TimeTicks::Now()) {
144 // Size in bytes of each audio frame (4 bytes for 16-bit stereo PCM).
145 frame_size_ = (16 / 8) * channels_;
147 // Start with the smallest possible buffer size. It will be increased
148 // dynamically during the test if required.
149 buffer_.reset(
150 new media::SeekableBuffer(0, samples_per_packet_ * frame_size_));
152 frames_to_ms_ = static_cast<double>(1000.0 / sample_rate_);
153 delay_states_.reset(new AudioDelayState[kMaxDelayMeasurements]);
156 ~FullDuplexAudioSinkSource() override {
157 // Get complete file path to output file in the directory containing
158 // media_unittests.exe. Example: src/build/Debug/audio_delay_values_ms.txt.
159 base::FilePath file_name;
160 EXPECT_TRUE(PathService::Get(base::DIR_EXE, &file_name));
161 file_name = file_name.AppendASCII(kDelayValuesFileName);
163 FILE* text_file = base::OpenFile(file_name, "wt");
164 DLOG_IF(ERROR, !text_file) << "Failed to open log file.";
165 VLOG(0) << ">> Output file " << file_name.value() << " has been created.";
167 // Write the array which contains time-stamps, buffer size and
168 // audio delays values to a text file.
169 size_t elements_written = 0;
170 while (elements_written <
171 std::min(input_elements_to_write_, output_elements_to_write_)) {
172 const AudioDelayState state = delay_states_[elements_written];
173 fprintf(text_file, "%d %d %d %d\n",
174 state.delta_time_ms,
175 state.buffer_delay_ms,
176 state.input_delay_ms,
177 state.output_delay_ms);
178 ++elements_written;
181 base::CloseFile(text_file);
184 // AudioInputStream::AudioInputCallback.
185 void OnData(AudioInputStream* stream,
186 const AudioBus* src,
187 uint32 hardware_delay_bytes,
188 double volume) override {
189 base::AutoLock lock(lock_);
191 // Update three components in the AudioDelayState for this recorded
192 // audio packet.
193 const base::TimeTicks now_time = base::TimeTicks::Now();
194 const int diff = (now_time - previous_write_time_).InMilliseconds();
195 previous_write_time_ = now_time;
196 if (input_elements_to_write_ < kMaxDelayMeasurements) {
197 delay_states_[input_elements_to_write_].delta_time_ms = diff;
198 delay_states_[input_elements_to_write_].buffer_delay_ms =
199 BytesToMilliseconds(buffer_->forward_bytes());
200 delay_states_[input_elements_to_write_].input_delay_ms =
201 BytesToMilliseconds(hardware_delay_bytes);
202 ++input_elements_to_write_;
205 // TODO(henrika): fix this and use AudioFifo instead.
206 // Store the captured audio packet in a seekable media buffer.
207 // if (!buffer_->Append(src, size)) {
208 // An attempt to write outside the buffer limits has been made.
209 // Double the buffer capacity to ensure that we have a buffer large
210 // enough to handle the current sample test scenario.
211 // buffer_->set_forward_capacity(2 * buffer_->forward_capacity());
212 // buffer_->Clear();
213 // }
216 void OnError(AudioInputStream* stream) override {}
218 // AudioOutputStream::AudioSourceCallback.
219 int OnMoreData(AudioBus* audio_bus, uint32 total_bytes_delay) override {
220 base::AutoLock lock(lock_);
222 // Update one component in the AudioDelayState for the packet
223 // which is about to be played out.
224 if (output_elements_to_write_ < kMaxDelayMeasurements) {
225 delay_states_[output_elements_to_write_].output_delay_ms =
226 BytesToMilliseconds(total_bytes_delay);
227 ++output_elements_to_write_;
230 int size;
231 const uint8* source;
232 // Read the data from the seekable media buffer which contains
233 // captured data at the same size and sample rate as the output side.
234 if (buffer_->GetCurrentChunk(&source, &size) && size > 0) {
235 EXPECT_EQ(channels_, audio_bus->channels());
236 size = std::min(audio_bus->frames() * frame_size_, size);
237 EXPECT_EQ(static_cast<size_t>(size) % sizeof(*audio_bus->channel(0)), 0U);
238 audio_bus->FromInterleaved(
239 source, size / frame_size_, frame_size_ / channels_);
240 buffer_->Seek(size);
241 return size / frame_size_;
244 return 0;
247 void OnError(AudioOutputStream* stream) override {}
249 protected:
250 // Converts from bytes to milliseconds taking the sample rate and size
251 // of an audio frame into account.
252 int BytesToMilliseconds(uint32 delay_bytes) const {
253 return static_cast<int>((delay_bytes / frame_size_) * frames_to_ms_ + 0.5);
256 private:
257 base::Lock lock_;
258 scoped_ptr<media::SeekableBuffer> buffer_;
259 int sample_rate_;
260 int samples_per_packet_;
261 int channels_;
262 int frame_size_;
263 double frames_to_ms_;
264 scoped_ptr<AudioDelayState[]> delay_states_;
265 size_t input_elements_to_write_;
266 size_t output_elements_to_write_;
267 base::TimeTicks previous_write_time_;
270 class AudioInputStreamTraits {
271 public:
272 typedef AudioInputStream StreamType;
274 static AudioParameters GetDefaultAudioStreamParameters(
275 AudioManager* audio_manager) {
276 return audio_manager->GetInputStreamParameters(
277 AudioManagerBase::kDefaultDeviceId);
280 static StreamType* CreateStream(AudioManager* audio_manager,
281 const AudioParameters& params) {
282 return audio_manager->MakeAudioInputStream(params,
283 AudioManagerBase::kDefaultDeviceId);
287 class AudioOutputStreamTraits {
288 public:
289 typedef AudioOutputStream StreamType;
291 static AudioParameters GetDefaultAudioStreamParameters(
292 AudioManager* audio_manager) {
293 return audio_manager->GetDefaultOutputStreamParameters();
296 static StreamType* CreateStream(AudioManager* audio_manager,
297 const AudioParameters& params) {
298 return audio_manager->MakeAudioOutputStream(params, std::string());
302 // Traits template holding a trait of StreamType. It encapsulates
303 // AudioInputStream and AudioOutputStream stream types.
304 template <typename StreamTraits>
305 class StreamWrapper {
306 public:
307 typedef typename StreamTraits::StreamType StreamType;
309 explicit StreamWrapper(AudioManager* audio_manager)
311 audio_manager_(audio_manager),
312 format_(AudioParameters::AUDIO_PCM_LOW_LATENCY),
313 #if defined(OS_ANDROID)
314 channel_layout_(CHANNEL_LAYOUT_MONO),
315 #else
316 channel_layout_(CHANNEL_LAYOUT_STEREO),
317 #endif
318 bits_per_sample_(16) {
319 // Use the preferred sample rate.
320 const AudioParameters& params =
321 StreamTraits::GetDefaultAudioStreamParameters(audio_manager_);
322 sample_rate_ = params.sample_rate();
324 // Use the preferred buffer size. Note that the input side uses the same
325 // size as the output side in this implementation.
326 samples_per_packet_ = params.frames_per_buffer();
329 virtual ~StreamWrapper() {}
331 // Creates an Audio[Input|Output]Stream stream object using default
332 // parameters.
333 StreamType* Create() {
334 return CreateStream();
337 int channels() const {
338 return ChannelLayoutToChannelCount(channel_layout_);
340 int bits_per_sample() const { return bits_per_sample_; }
341 int sample_rate() const { return sample_rate_; }
342 int samples_per_packet() const { return samples_per_packet_; }
344 private:
345 StreamType* CreateStream() {
346 StreamType* stream = StreamTraits::CreateStream(audio_manager_,
347 AudioParameters(format_, channel_layout_, sample_rate_,
348 bits_per_sample_, samples_per_packet_));
349 EXPECT_TRUE(stream);
350 return stream;
353 AudioManager* audio_manager_;
354 AudioParameters::Format format_;
355 ChannelLayout channel_layout_;
356 int bits_per_sample_;
357 int sample_rate_;
358 int samples_per_packet_;
361 typedef StreamWrapper<AudioInputStreamTraits> AudioInputStreamWrapper;
362 typedef StreamWrapper<AudioOutputStreamTraits> AudioOutputStreamWrapper;
364 // This test is intended for manual tests and should only be enabled
365 // when it is required to make a real-time test of audio in full duplex and
366 // at the same time create a text file which contains measured delay values.
367 // The file can later be analyzed off line using e.g. MATLAB.
368 // MATLAB example:
369 // D=load('audio_delay_values_ms.txt');
370 // x=cumsum(D(:,1));
371 // plot(x, D(:,2), x, D(:,3), x, D(:,4), x, D(:,2)+D(:,3)+D(:,4));
372 // axis([0, max(x), 0, max(D(:,2)+D(:,3)+D(:,4))+10]);
373 // legend('buffer delay','input delay','output delay','total delay');
374 // xlabel('time [msec]')
375 // ylabel('delay [msec]')
376 // title('Full-duplex audio delay measurement');
377 TEST_F(AudioLowLatencyInputOutputTest, DISABLED_FullDuplexDelayMeasurement) {
378 ABORT_AUDIO_TEST_IF_NOT(audio_manager()->HasAudioInputDevices() &&
379 audio_manager()->HasAudioOutputDevices());
381 AudioInputStreamWrapper aisw(audio_manager());
382 AudioInputStream* ais = aisw.Create();
383 EXPECT_TRUE(ais);
385 AudioOutputStreamWrapper aosw(audio_manager());
386 AudioOutputStream* aos = aosw.Create();
387 EXPECT_TRUE(aos);
389 // This test only supports identical parameters in both directions.
390 // TODO(henrika): it is possible to cut delay here by using different
391 // buffer sizes for input and output.
392 if (aisw.sample_rate() != aosw.sample_rate() ||
393 aisw.samples_per_packet() != aosw.samples_per_packet() ||
394 aisw.channels()!= aosw.channels() ||
395 aisw.bits_per_sample() != aosw.bits_per_sample()) {
396 LOG(ERROR) << "This test requires symmetric input and output parameters. "
397 "Ensure that sample rate and number of channels are identical in "
398 "both directions";
399 aos->Close();
400 ais->Close();
401 return;
404 EXPECT_TRUE(ais->Open());
405 EXPECT_TRUE(aos->Open());
407 FullDuplexAudioSinkSource full_duplex(
408 aisw.sample_rate(), aisw.samples_per_packet(), aisw.channels());
410 VLOG(0) << ">> You should now be able to hear yourself in loopback...";
411 DVLOG(0) << " sample_rate : " << aisw.sample_rate();
412 DVLOG(0) << " samples_per_packet: " << aisw.samples_per_packet();
413 DVLOG(0) << " channels : " << aisw.channels();
415 ais->Start(&full_duplex);
416 aos->Start(&full_duplex);
418 // Wait for approximately 10 seconds. The user shall hear his own voice
419 // in loop back during this time. At the same time, delay recordings are
420 // performed and stored in the output text file.
421 message_loop()->PostDelayedTask(FROM_HERE,
422 base::MessageLoop::QuitClosure(), TestTimeouts::action_timeout());
423 message_loop()->Run();
425 aos->Stop();
426 ais->Stop();
428 // All Close() operations that run on the mocked audio thread,
429 // should be synchronous and not post additional close tasks to
430 // mocked the audio thread. Hence, there is no need to call
431 // message_loop()->RunUntilIdle() after the Close() methods.
432 aos->Close();
433 ais->Close();
436 } // namespace media