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