Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / media / audio / audio_low_latency_input_output_unittest.cc
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.
4
5 #include "base/basictypes.h"
6 #include "base/environment.h"
7 #include "base/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/fake_audio_log_factory.h"
17 #include "media/base/seekable_buffer.h"
18 #include "testing/gmock/include/gmock/gmock.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20
21 #if defined(USE_ALSA)
22 #include "media/audio/alsa/audio_manager_alsa.h"
23 #elif defined(OS_MACOSX)
24 #include "media/audio/mac/audio_manager_mac.h"
25 #elif defined(OS_WIN)
26 #include "media/audio/win/audio_manager_win.h"
27 #include "media/audio/win/core_audio_util_win.h"
28 #elif defined(OS_ANDROID)
29 #include "media/audio/android/audio_manager_android.h"
30 #else
31 #include "media/audio/fake_audio_manager.h"
32 #endif
33
34 namespace media {
35
36 #if defined(USE_ALSA)
37 typedef AudioManagerAlsa AudioManagerAnyPlatform;
38 #elif defined(OS_MACOSX)
39 typedef AudioManagerMac AudioManagerAnyPlatform;
40 #elif defined(OS_WIN)
41 typedef AudioManagerWin AudioManagerAnyPlatform;
42 #elif defined(OS_ANDROID)
43 typedef AudioManagerAndroid AudioManagerAnyPlatform;
44 #else
45 typedef FakeAudioManager AudioManagerAnyPlatform;
46 #endif
47
48 // Limits the number of delay measurements we can store in an array and
49 // then write to file at end of the WASAPIAudioInputOutputFullDuplex test.
50 static const size_t kMaxDelayMeasurements = 1000;
51
52 // Name of the output text file. The output file will be stored in the
53 // directory containing media_unittests.exe.
54 // Example: \src\build\Debug\audio_delay_values_ms.txt.
55 // See comments for the WASAPIAudioInputOutputFullDuplex test for more details
56 // about the file format.
57 static const char kDelayValuesFileName[] = "audio_delay_values_ms.txt";
58
59 // Contains delay values which are reported during the full-duplex test.
60 // Total delay = |buffer_delay_ms| + |input_delay_ms| + |output_delay_ms|.
61 struct AudioDelayState {
62   AudioDelayState()
63       : delta_time_ms(0),
64         buffer_delay_ms(0),
65         input_delay_ms(0),
66         output_delay_ms(0) {
67   }
68
69   // Time in milliseconds since last delay report. Typical value is ~10 [ms].
70   int delta_time_ms;
71
72   // Size of internal sync buffer. Typical value is ~0 [ms].
73   int buffer_delay_ms;
74
75   // Reported capture/input delay. Typical value is ~10 [ms].
76   int input_delay_ms;
77
78   // Reported render/output delay. Typical value is ~40 [ms].
79   int output_delay_ms;
80 };
81
82 // This class mocks the platform specific audio manager and overrides
83 // the GetMessageLoop() method to ensure that we can run our tests on
84 // the main thread instead of the audio thread.
85 class MockAudioManager : public AudioManagerAnyPlatform {
86  public:
87   MockAudioManager() : AudioManagerAnyPlatform(&fake_audio_log_factory_) {}
88   virtual ~MockAudioManager() {}
89
90   virtual scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner() OVERRIDE {
91     return base::MessageLoop::current()->message_loop_proxy();
92   }
93
94  private:
95   FakeAudioLogFactory fake_audio_log_factory_;
96   DISALLOW_COPY_AND_ASSIGN(MockAudioManager);
97 };
98
99 // Test fixture class.
100 class AudioLowLatencyInputOutputTest : public testing::Test {
101  protected:
102   AudioLowLatencyInputOutputTest() {}
103
104   virtual ~AudioLowLatencyInputOutputTest() {}
105
106   AudioManager* audio_manager() { return &mock_audio_manager_; }
107   base::MessageLoopForUI* message_loop() { return &message_loop_; }
108
109   // Convenience method which ensures that we are not running on the build
110   // bots and that at least one valid input and output device can be found.
111   bool CanRunAudioTests() {
112     bool input = audio_manager()->HasAudioInputDevices();
113     bool output = audio_manager()->HasAudioOutputDevices();
114     LOG_IF(WARNING, !input) << "No input device detected.";
115     LOG_IF(WARNING, !output) << "No output device detected.";
116     return input && output;
117   }
118
119  private:
120   base::MessageLoopForUI message_loop_;
121   MockAudioManager mock_audio_manager_;
122
123   DISALLOW_COPY_AND_ASSIGN(AudioLowLatencyInputOutputTest);
124 };
125
126 // This audio source/sink implementation should be used for manual tests
127 // only since delay measurements are stored on an output text file.
128 // All incoming/recorded audio packets are stored in an intermediate media
129 // buffer which the renderer reads from when it needs audio for playout.
130 // The total effect is that recorded audio is played out in loop back using
131 // a sync buffer as temporary storage.
132 class FullDuplexAudioSinkSource
133     : public AudioInputStream::AudioInputCallback,
134       public AudioOutputStream::AudioSourceCallback {
135  public:
136   FullDuplexAudioSinkSource(int sample_rate,
137                             int samples_per_packet,
138                             int channels)
139     : sample_rate_(sample_rate),
140       samples_per_packet_(samples_per_packet),
141       channels_(channels),
142       input_elements_to_write_(0),
143       output_elements_to_write_(0),
144       previous_write_time_(base::TimeTicks::Now()) {
145     // Size in bytes of each audio frame (4 bytes for 16-bit stereo PCM).
146     frame_size_ = (16 / 8) * channels_;
147
148     // Start with the smallest possible buffer size. It will be increased
149     // dynamically during the test if required.
150     buffer_.reset(
151         new media::SeekableBuffer(0, samples_per_packet_ * frame_size_));
152
153     frames_to_ms_ = static_cast<double>(1000.0 / sample_rate_);
154     delay_states_.reset(new AudioDelayState[kMaxDelayMeasurements]);
155   }
156
157   virtual ~FullDuplexAudioSinkSource() {
158     // Get complete file path to output file in the directory containing
159     // media_unittests.exe. Example: src/build/Debug/audio_delay_values_ms.txt.
160     base::FilePath file_name;
161     EXPECT_TRUE(PathService::Get(base::DIR_EXE, &file_name));
162     file_name = file_name.AppendASCII(kDelayValuesFileName);
163
164     FILE* text_file = base::OpenFile(file_name, "wt");
165     DLOG_IF(ERROR, !text_file) << "Failed to open log file.";
166     VLOG(0) << ">> Output file " << file_name.value() << " has been created.";
167
168     // Write the array which contains time-stamps, buffer size and
169     // audio delays values to a text file.
170     size_t elements_written = 0;
171     while (elements_written <
172         std::min(input_elements_to_write_, output_elements_to_write_)) {
173       const AudioDelayState state = delay_states_[elements_written];
174       fprintf(text_file, "%d %d %d %d\n",
175               state.delta_time_ms,
176               state.buffer_delay_ms,
177               state.input_delay_ms,
178               state.output_delay_ms);
179       ++elements_written;
180     }
181
182     base::CloseFile(text_file);
183   }
184
185   // AudioInputStream::AudioInputCallback.
186   virtual void OnData(AudioInputStream* stream,
187                       const uint8* src, uint32 size,
188                       uint32 hardware_delay_bytes,
189                       double volume) OVERRIDE {
190     base::AutoLock lock(lock_);
191
192     // Update three components in the AudioDelayState for this recorded
193     // audio packet.
194     const base::TimeTicks now_time = base::TimeTicks::Now();
195     const int diff = (now_time - previous_write_time_).InMilliseconds();
196     previous_write_time_ = now_time;
197     if (input_elements_to_write_ < kMaxDelayMeasurements) {
198       delay_states_[input_elements_to_write_].delta_time_ms = diff;
199       delay_states_[input_elements_to_write_].buffer_delay_ms =
200           BytesToMilliseconds(buffer_->forward_bytes());
201       delay_states_[input_elements_to_write_].input_delay_ms =
202           BytesToMilliseconds(hardware_delay_bytes);
203       ++input_elements_to_write_;
204     }
205
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     }
214   }
215
216   virtual void OnError(AudioInputStream* stream) OVERRIDE {}
217
218   // AudioOutputStream::AudioSourceCallback.
219   virtual int OnMoreData(AudioBus* audio_bus,
220                          AudioBuffersState buffers_state) OVERRIDE {
221     base::AutoLock lock(lock_);
222
223     // Update one component in the AudioDelayState for the packet
224     // which is about to be played out.
225     if (output_elements_to_write_ < kMaxDelayMeasurements) {
226       int output_delay_bytes = buffers_state.hardware_delay_bytes;
227 #if defined(OS_WIN)
228       // Special fix for Windows in combination with Wave where the
229       // pending bytes field of the audio buffer state is used to
230       // report the delay.
231       if (!CoreAudioUtil::IsSupported()) {
232         output_delay_bytes = buffers_state.pending_bytes;
233       }
234 #endif
235       delay_states_[output_elements_to_write_].output_delay_ms =
236           BytesToMilliseconds(output_delay_bytes);
237       ++output_elements_to_write_;
238     }
239
240     int size;
241     const uint8* source;
242     // Read the data from the seekable media buffer which contains
243     // captured data at the same size and sample rate as the output side.
244     if (buffer_->GetCurrentChunk(&source, &size) && size > 0) {
245       EXPECT_EQ(channels_, audio_bus->channels());
246       size = std::min(audio_bus->frames() * frame_size_, size);
247       EXPECT_EQ(static_cast<size_t>(size) % sizeof(*audio_bus->channel(0)), 0U);
248       audio_bus->FromInterleaved(
249           source, size / frame_size_, frame_size_ / channels_);
250       buffer_->Seek(size);
251       return size / frame_size_;
252     }
253
254     return 0;
255   }
256
257   virtual int OnMoreIOData(AudioBus* source,
258                            AudioBus* dest,
259                            AudioBuffersState buffers_state) OVERRIDE {
260     NOTREACHED();
261     return 0;
262   }
263
264   virtual void OnError(AudioOutputStream* stream) OVERRIDE {}
265
266  protected:
267   // Converts from bytes to milliseconds taking the sample rate and size
268   // of an audio frame into account.
269   int BytesToMilliseconds(uint32 delay_bytes) const {
270     return static_cast<int>((delay_bytes / frame_size_) * frames_to_ms_ + 0.5);
271   }
272
273  private:
274   base::Lock lock_;
275   scoped_ptr<media::SeekableBuffer> buffer_;
276   int sample_rate_;
277   int samples_per_packet_;
278   int channels_;
279   int frame_size_;
280   double frames_to_ms_;
281   scoped_ptr<AudioDelayState[]> delay_states_;
282   size_t input_elements_to_write_;
283   size_t output_elements_to_write_;
284   base::TimeTicks previous_write_time_;
285 };
286
287 class AudioInputStreamTraits {
288  public:
289   typedef AudioInputStream StreamType;
290
291   static AudioParameters GetDefaultAudioStreamParameters(
292       AudioManager* audio_manager) {
293     return audio_manager->GetInputStreamParameters(
294         AudioManagerBase::kDefaultDeviceId);
295   }
296
297   static StreamType* CreateStream(AudioManager* audio_manager,
298       const AudioParameters& params) {
299     return audio_manager->MakeAudioInputStream(params,
300       AudioManagerBase::kDefaultDeviceId);
301   }
302 };
303
304 class AudioOutputStreamTraits {
305  public:
306   typedef AudioOutputStream StreamType;
307
308   static AudioParameters GetDefaultAudioStreamParameters(
309       AudioManager* audio_manager) {
310     return audio_manager->GetDefaultOutputStreamParameters();
311   }
312
313   static StreamType* CreateStream(AudioManager* audio_manager,
314       const AudioParameters& params) {
315     return audio_manager->MakeAudioOutputStream(params, std::string());
316   }
317 };
318
319 // Traits template holding a trait of StreamType. It encapsulates
320 // AudioInputStream and AudioOutputStream stream types.
321 template <typename StreamTraits>
322 class StreamWrapper {
323  public:
324   typedef typename StreamTraits::StreamType StreamType;
325
326   explicit StreamWrapper(AudioManager* audio_manager)
327       :
328         audio_manager_(audio_manager),
329         format_(AudioParameters::AUDIO_PCM_LOW_LATENCY),
330 #if defined(OS_ANDROID)
331         channel_layout_(CHANNEL_LAYOUT_MONO),
332 #else
333         channel_layout_(CHANNEL_LAYOUT_STEREO),
334 #endif
335         bits_per_sample_(16) {
336     // Use the preferred sample rate.
337     const AudioParameters& params =
338         StreamTraits::GetDefaultAudioStreamParameters(audio_manager_);
339     sample_rate_ = params.sample_rate();
340
341     // Use the preferred buffer size. Note that the input side uses the same
342     // size as the output side in this implementation.
343     samples_per_packet_ = params.frames_per_buffer();
344   }
345
346   virtual ~StreamWrapper() {}
347
348   // Creates an Audio[Input|Output]Stream stream object using default
349   // parameters.
350   StreamType* Create() {
351     return CreateStream();
352   }
353
354   int channels() const {
355     return ChannelLayoutToChannelCount(channel_layout_);
356   }
357   int bits_per_sample() const { return bits_per_sample_; }
358   int sample_rate() const { return sample_rate_; }
359   int samples_per_packet() const { return samples_per_packet_; }
360
361  private:
362   StreamType* CreateStream() {
363     StreamType* stream = StreamTraits::CreateStream(audio_manager_,
364         AudioParameters(format_, channel_layout_, sample_rate_,
365             bits_per_sample_, samples_per_packet_));
366     EXPECT_TRUE(stream);
367     return stream;
368   }
369
370   AudioManager* audio_manager_;
371   AudioParameters::Format format_;
372   ChannelLayout channel_layout_;
373   int bits_per_sample_;
374   int sample_rate_;
375   int samples_per_packet_;
376 };
377
378 typedef StreamWrapper<AudioInputStreamTraits> AudioInputStreamWrapper;
379 typedef StreamWrapper<AudioOutputStreamTraits> AudioOutputStreamWrapper;
380
381 // This test is intended for manual tests and should only be enabled
382 // when it is required to make a real-time test of audio in full duplex and
383 // at the same time create a text file which contains measured delay values.
384 // The file can later be analyzed off line using e.g. MATLAB.
385 // MATLAB example:
386 //   D=load('audio_delay_values_ms.txt');
387 //   x=cumsum(D(:,1));
388 //   plot(x, D(:,2), x, D(:,3), x, D(:,4), x, D(:,2)+D(:,3)+D(:,4));
389 //   axis([0, max(x), 0, max(D(:,2)+D(:,3)+D(:,4))+10]);
390 //   legend('buffer delay','input delay','output delay','total delay');
391 //   xlabel('time [msec]')
392 //   ylabel('delay [msec]')
393 //   title('Full-duplex audio delay measurement');
394 TEST_F(AudioLowLatencyInputOutputTest, DISABLED_FullDuplexDelayMeasurement) {
395   if (!CanRunAudioTests())
396     return;
397
398   AudioInputStreamWrapper aisw(audio_manager());
399   AudioInputStream* ais = aisw.Create();
400   EXPECT_TRUE(ais);
401
402   AudioOutputStreamWrapper aosw(audio_manager());
403   AudioOutputStream* aos = aosw.Create();
404   EXPECT_TRUE(aos);
405
406   // This test only supports identical parameters in both directions.
407   // TODO(henrika): it is possible to cut delay here by using different
408   // buffer sizes for input and output.
409   if (aisw.sample_rate() != aosw.sample_rate() ||
410       aisw.samples_per_packet() != aosw.samples_per_packet() ||
411       aisw.channels()!= aosw.channels() ||
412       aisw.bits_per_sample() != aosw.bits_per_sample()) {
413     LOG(ERROR) << "This test requires symmetric input and output parameters. "
414         "Ensure that sample rate and number of channels are identical in "
415         "both directions";
416     aos->Close();
417     ais->Close();
418     return;
419   }
420
421   EXPECT_TRUE(ais->Open());
422   EXPECT_TRUE(aos->Open());
423
424   FullDuplexAudioSinkSource full_duplex(
425       aisw.sample_rate(), aisw.samples_per_packet(), aisw.channels());
426
427   VLOG(0) << ">> You should now be able to hear yourself in loopback...";
428   DVLOG(0) << "   sample_rate       : " << aisw.sample_rate();
429   DVLOG(0) << "   samples_per_packet: " << aisw.samples_per_packet();
430   DVLOG(0) << "   channels          : " << aisw.channels();
431
432   ais->Start(&full_duplex);
433   aos->Start(&full_duplex);
434
435   // Wait for approximately 10 seconds. The user shall hear his own voice
436   // in loop back during this time. At the same time, delay recordings are
437   // performed and stored in the output text file.
438   message_loop()->PostDelayedTask(FROM_HERE,
439       base::MessageLoop::QuitClosure(), TestTimeouts::action_timeout());
440   message_loop()->Run();
441
442   aos->Stop();
443   ais->Stop();
444
445   // All Close() operations that run on the mocked audio thread,
446   // should be synchronous and not post additional close tasks to
447   // mocked the audio thread. Hence, there is no need to call
448   // message_loop()->RunUntilIdle() after the Close() methods.
449   aos->Close();
450   ais->Close();
451 }
452
453 }  // namespace media