audio_output_win_unittest.cc revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
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 <windows.h>
6#include <mmsystem.h>
7
8#include "base/basictypes.h"
9#include "base/base_paths.h"
10#include "base/memory/aligned_memory.h"
11#include "base/path_service.h"
12#include "base/sync_socket.h"
13#include "base/win/scoped_com_initializer.h"
14#include "base/win/windows_version.h"
15#include "media/base/limits.h"
16#include "media/audio/audio_io.h"
17#include "media/audio/audio_manager.h"
18#include "media/audio/simple_sources.h"
19#include "testing/gmock/include/gmock/gmock.h"
20#include "testing/gtest/include/gtest/gtest.h"
21
22using ::testing::_;
23using ::testing::AnyNumber;
24using ::testing::DoAll;
25using ::testing::Field;
26using ::testing::Invoke;
27using ::testing::InSequence;
28using ::testing::NiceMock;
29using ::testing::NotNull;
30using ::testing::Return;
31
32using base::win::ScopedCOMInitializer;
33
34namespace media {
35
36static const wchar_t kAudioFile1_16b_m_16K[]
37    = L"media\\test\\data\\sweep02_16b_mono_16KHz.raw";
38
39// This class allows to find out if the callbacks are occurring as
40// expected and if any error has been reported.
41class TestSourceBasic : public AudioOutputStream::AudioSourceCallback {
42 public:
43  explicit TestSourceBasic()
44      : callback_count_(0),
45        had_error_(0) {
46  }
47  // AudioSourceCallback::OnMoreData implementation:
48  virtual int OnMoreData(AudioBus* audio_bus,
49                         AudioBuffersState buffers_state) {
50    ++callback_count_;
51    // Touch the channel memory value to make sure memory is good.
52    audio_bus->Zero();
53    return audio_bus->frames();
54  }
55  virtual int OnMoreIOData(AudioBus* source,
56                           AudioBus* dest,
57                           AudioBuffersState buffers_state) {
58    NOTREACHED();
59    return 0;
60  }
61  // AudioSourceCallback::OnError implementation:
62  virtual void OnError(AudioOutputStream* stream) {
63    ++had_error_;
64  }
65  // Returns how many times OnMoreData() has been called.
66  int callback_count() const {
67    return callback_count_;
68  }
69  // Returns how many times the OnError callback was called.
70  int had_error() const {
71    return had_error_;
72  }
73
74  void set_error(bool error) {
75    had_error_ += error ? 1 : 0;
76  }
77
78 private:
79  int callback_count_;
80  int had_error_;
81};
82
83const int kMaxNumBuffers = 3;
84// Specializes TestSourceBasic to simulate a source that blocks for some time
85// in the OnMoreData callback.
86class TestSourceLaggy : public TestSourceBasic {
87 public:
88  TestSourceLaggy(int laggy_after_buffer, int lag_in_ms)
89      : laggy_after_buffer_(laggy_after_buffer), lag_in_ms_(lag_in_ms) {
90  }
91  virtual int OnMoreData(AudioBus* audio_bus,
92                         AudioBuffersState buffers_state) {
93    // Call the base, which increments the callback_count_.
94    TestSourceBasic::OnMoreData(audio_bus, buffers_state);
95    if (callback_count() > kMaxNumBuffers) {
96      ::Sleep(lag_in_ms_);
97    }
98    return audio_bus->frames();
99  }
100 private:
101  int laggy_after_buffer_;
102  int lag_in_ms_;
103};
104
105class MockAudioSource : public AudioOutputStream::AudioSourceCallback {
106 public:
107  MOCK_METHOD2(OnMoreData, int(AudioBus* audio_bus,
108                               AudioBuffersState buffers_state));
109  MOCK_METHOD3(OnMoreIOData, int(AudioBus* source,
110                                 AudioBus* dest,
111                                 AudioBuffersState buffers_state));
112  MOCK_METHOD1(OnError, void(AudioOutputStream* stream));
113
114  static int ClearData(AudioBus* audio_bus, AudioBuffersState buffers_state) {
115    audio_bus->Zero();
116    return audio_bus->frames();
117  }
118};
119
120// Helper class to memory map an entire file. The mapping is read-only. Don't
121// use for gigabyte-sized files. Attempts to write to this memory generate
122// memory access violations.
123class ReadOnlyMappedFile {
124 public:
125  explicit ReadOnlyMappedFile(const wchar_t* file_name)
126      : fmap_(NULL), start_(NULL), size_(0) {
127    HANDLE file = ::CreateFileW(file_name, GENERIC_READ, FILE_SHARE_READ, NULL,
128                                OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
129    if (INVALID_HANDLE_VALUE == file)
130      return;
131    fmap_ = ::CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
132    ::CloseHandle(file);
133    if (!fmap_)
134      return;
135    start_ = reinterpret_cast<char*>(::MapViewOfFile(fmap_, FILE_MAP_READ,
136                                                     0, 0, 0));
137    if (!start_)
138      return;
139    MEMORY_BASIC_INFORMATION mbi = {0};
140    ::VirtualQuery(start_, &mbi, sizeof(mbi));
141    size_ = mbi.RegionSize;
142  }
143  ~ReadOnlyMappedFile() {
144    if (start_) {
145      ::UnmapViewOfFile(start_);
146      ::CloseHandle(fmap_);
147    }
148  }
149  // Returns true if the file was successfully mapped.
150  bool is_valid() const {
151    return ((start_ > 0) && (size_ > 0));
152  }
153  // Returns the size in bytes of the mapped memory.
154  uint32 size() const {
155    return size_;
156  }
157  // Returns the memory backing the file.
158  const void* GetChunkAt(uint32 offset) {
159    return &start_[offset];
160  }
161
162 private:
163  HANDLE fmap_;
164  char* start_;
165  uint32 size_;
166};
167
168// ===========================================================================
169// Validation of AudioManager::AUDIO_PCM_LINEAR
170//
171// NOTE:
172// The tests can fail on the build bots when somebody connects to them via
173// remote-desktop and the rdp client installs an audio device that fails to open
174// at some point, possibly when the connection goes idle.
175
176// Test that can it be created and closed.
177TEST(WinAudioTest, PCMWaveStreamGetAndClose) {
178  scoped_ptr<AudioManager> audio_man(AudioManager::Create());
179  if (!audio_man->HasAudioOutputDevices()) {
180    LOG(WARNING) << "No output device detected.";
181    return;
182  }
183
184  AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
185      AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO,
186                      8000, 16, 256),
187      std::string(), std::string());
188  ASSERT_TRUE(NULL != oas);
189  oas->Close();
190}
191
192// Test that can it be cannot be created with invalid parameters.
193TEST(WinAudioTest, SanityOnMakeParams) {
194  scoped_ptr<AudioManager> audio_man(AudioManager::Create());
195  if (!audio_man->HasAudioOutputDevices()) {
196    LOG(WARNING) << "No output device detected.";
197    return;
198  }
199
200  AudioParameters::Format fmt = AudioParameters::AUDIO_PCM_LINEAR;
201  EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
202      AudioParameters(fmt, CHANNEL_LAYOUT_UNSUPPORTED, 8000, 16, 256),
203      std::string(), std::string()));
204  EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
205      AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 1024 * 1024, 16, 256),
206      std::string(), std::string()));
207  EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
208      AudioParameters(fmt, CHANNEL_LAYOUT_STEREO, 8000, 80, 256),
209      std::string(), std::string()));
210  EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
211      AudioParameters(fmt, CHANNEL_LAYOUT_UNSUPPORTED, 8000, 16, 256),
212      std::string(), std::string()));
213  EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
214      AudioParameters(fmt, CHANNEL_LAYOUT_STEREO, -8000, 16, 256),
215      std::string(), std::string()));
216  EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
217      AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 8000, 16, -100),
218      std::string(), std::string()));
219  EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
220      AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 8000, 16, 0),
221      std::string(), std::string()));
222  EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
223      AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 8000, 16,
224                      media::limits::kMaxSamplesPerPacket + 1),
225      std::string(), std::string()));
226}
227
228// Test that it can be opened and closed.
229TEST(WinAudioTest, PCMWaveStreamOpenAndClose) {
230  scoped_ptr<AudioManager> audio_man(AudioManager::Create());
231  if (!audio_man->HasAudioOutputDevices()) {
232    LOG(WARNING) << "No output device detected.";
233    return;
234  }
235
236  AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
237      AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO,
238                      8000, 16, 256),
239      std::string(), std::string());
240  ASSERT_TRUE(NULL != oas);
241  EXPECT_TRUE(oas->Open());
242  oas->Close();
243}
244
245// Test that it has a maximum packet size.
246TEST(WinAudioTest, PCMWaveStreamOpenLimit) {
247  scoped_ptr<AudioManager> audio_man(AudioManager::Create());
248  if (!audio_man->HasAudioOutputDevices()) {
249    LOG(WARNING) << "No output device detected.";
250    return;
251  }
252
253  AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
254      AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO,
255                      8000, 16, 1024 * 1024 * 1024),
256      std::string(), std::string());
257  EXPECT_TRUE(NULL == oas);
258  if (oas)
259    oas->Close();
260}
261
262// Test potential deadlock situation if the source is slow or blocks for some
263// time. The actual EXPECT_GT are mostly meaningless and the real test is that
264// the test completes in reasonable time.
265TEST(WinAudioTest, PCMWaveSlowSource) {
266  scoped_ptr<AudioManager> audio_man(AudioManager::Create());
267  if (!audio_man->HasAudioOutputDevices()) {
268    LOG(WARNING) << "No output device detected.";
269    return;
270  }
271
272  AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
273      AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
274                      16000, 16, 256),
275      std::string(), std::string());
276  ASSERT_TRUE(NULL != oas);
277  TestSourceLaggy test_laggy(2, 90);
278  EXPECT_TRUE(oas->Open());
279  // The test parameters cause a callback every 32 ms and the source is
280  // sleeping for 90 ms, so it is guaranteed that we run out of ready buffers.
281  oas->Start(&test_laggy);
282  ::Sleep(500);
283  EXPECT_GT(test_laggy.callback_count(), 2);
284  EXPECT_FALSE(test_laggy.had_error());
285  oas->Stop();
286  ::Sleep(500);
287  oas->Close();
288}
289
290// Test another potential deadlock situation if the thread that calls Start()
291// gets paused. This test is best when run over RDP with audio enabled. See
292// bug 19276 for more details.
293TEST(WinAudioTest, PCMWaveStreamPlaySlowLoop) {
294  scoped_ptr<AudioManager> audio_man(AudioManager::Create());
295  if (!audio_man->HasAudioOutputDevices()) {
296    LOG(WARNING) << "No output device detected.";
297    return;
298  }
299
300  uint32 samples_100_ms = AudioParameters::kAudioCDSampleRate / 10;
301  AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
302      AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
303                      AudioParameters::kAudioCDSampleRate, 16, samples_100_ms),
304      std::string(), std::string());
305  ASSERT_TRUE(NULL != oas);
306
307  SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate);
308
309  EXPECT_TRUE(oas->Open());
310  oas->SetVolume(1.0);
311
312  for (int ix = 0; ix != 5; ++ix) {
313    oas->Start(&source);
314    ::Sleep(10);
315    oas->Stop();
316  }
317  oas->Close();
318}
319
320
321// This test produces actual audio for .5 seconds on the default wave
322// device at 44.1K s/sec. Parameters have been chosen carefully so you should
323// not hear pops or noises while the sound is playing.
324TEST(WinAudioTest, PCMWaveStreamPlay200HzTone44Kss) {
325  scoped_ptr<AudioManager> audio_man(AudioManager::Create());
326  if (!audio_man->HasAudioOutputDevices()) {
327    LOG(WARNING) << "No output device detected.";
328    return;
329  }
330
331  uint32 samples_100_ms = AudioParameters::kAudioCDSampleRate / 10;
332  AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
333      AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
334                      AudioParameters::kAudioCDSampleRate, 16, samples_100_ms),
335      std::string(), std::string());
336  ASSERT_TRUE(NULL != oas);
337
338  SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate);
339
340  EXPECT_TRUE(oas->Open());
341  oas->SetVolume(1.0);
342  oas->Start(&source);
343  ::Sleep(500);
344  oas->Stop();
345  oas->Close();
346}
347
348// This test produces actual audio for for .5 seconds on the default wave
349// device at 22K s/sec. Parameters have been chosen carefully so you should
350// not hear pops or noises while the sound is playing. The audio also should
351// sound with a lower volume than PCMWaveStreamPlay200HzTone44Kss.
352TEST(WinAudioTest, PCMWaveStreamPlay200HzTone22Kss) {
353  scoped_ptr<AudioManager> audio_man(AudioManager::Create());
354  if (!audio_man->HasAudioOutputDevices()) {
355    LOG(WARNING) << "No output device detected.";
356    return;
357  }
358
359  uint32 samples_100_ms = AudioParameters::kAudioCDSampleRate / 20;
360  AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
361      AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
362                      AudioParameters::kAudioCDSampleRate / 2, 16,
363                      samples_100_ms),
364      std::string(), std::string());
365  ASSERT_TRUE(NULL != oas);
366
367  SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate/2);
368
369  EXPECT_TRUE(oas->Open());
370
371  oas->SetVolume(0.5);
372  oas->Start(&source);
373  ::Sleep(500);
374
375  // Test that the volume is within the set limits.
376  double volume = 0.0;
377  oas->GetVolume(&volume);
378  EXPECT_LT(volume, 0.51);
379  EXPECT_GT(volume, 0.49);
380  oas->Stop();
381  oas->Close();
382}
383
384// Uses a restricted source to play ~2 seconds of audio for about 5 seconds. We
385// try hard to generate situation where the two threads are accessing the
386// object roughly at the same time.
387TEST(WinAudioTest, PushSourceFile16KHz)  {
388  scoped_ptr<AudioManager> audio_man(AudioManager::Create());
389  if (!audio_man->HasAudioOutputDevices()) {
390    LOG(WARNING) << "No output device detected.";
391    return;
392  }
393
394  static const int kSampleRate = 16000;
395  SineWaveAudioSource source(1, 200.0, kSampleRate);
396  // Compute buffer size for 100ms of audio.
397  const uint32 kSamples100ms = (kSampleRate / 1000) * 100;
398  // Restrict SineWaveAudioSource to 100ms of samples.
399  source.CapSamples(kSamples100ms);
400
401  AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
402      AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
403                      kSampleRate, 16, kSamples100ms),
404      std::string(), std::string());
405  ASSERT_TRUE(NULL != oas);
406
407  EXPECT_TRUE(oas->Open());
408
409  oas->SetVolume(1.0);
410  oas->Start(&source);
411
412  // We buffer and play at the same time, buffering happens every ~10ms and the
413  // consuming of the buffer happens every ~100ms. We do 100 buffers which
414  // effectively wrap around the file more than once.
415  for (uint32 ix = 0; ix != 100; ++ix) {
416    ::Sleep(10);
417    source.Reset();
418  }
419
420  // Play a little bit more of the file.
421  ::Sleep(500);
422
423  oas->Stop();
424  oas->Close();
425}
426
427// This test is to make sure an AudioOutputStream can be started after it was
428// stopped. You will here two .5 seconds wave signal separated by 0.5 seconds
429// of silence.
430TEST(WinAudioTest, PCMWaveStreamPlayTwice200HzTone44Kss) {
431  scoped_ptr<AudioManager> audio_man(AudioManager::Create());
432  if (!audio_man->HasAudioOutputDevices()) {
433    LOG(WARNING) << "No output device detected.";
434    return;
435  }
436
437  uint32 samples_100_ms = AudioParameters::kAudioCDSampleRate / 10;
438  AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
439      AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
440                      AudioParameters::kAudioCDSampleRate, 16, samples_100_ms),
441      std::string(), std::string());
442  ASSERT_TRUE(NULL != oas);
443
444  SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate);
445  EXPECT_TRUE(oas->Open());
446  oas->SetVolume(1.0);
447
448  // Play the wave for .5 seconds.
449  oas->Start(&source);
450  ::Sleep(500);
451  oas->Stop();
452
453  // Sleep to give silence after stopping the AudioOutputStream.
454  ::Sleep(250);
455
456  // Start again and play for .5 seconds.
457  oas->Start(&source);
458  ::Sleep(500);
459  oas->Stop();
460
461  oas->Close();
462}
463
464// With the low latency mode, WASAPI is utilized by default for Vista and
465// higher and Wave is used for XP and lower. It is possible to utilize a
466// smaller buffer size for WASAPI than for Wave.
467TEST(WinAudioTest, PCMWaveStreamPlay200HzToneLowLatency) {
468  scoped_ptr<AudioManager> audio_man(AudioManager::Create());
469  if (!audio_man->HasAudioOutputDevices()) {
470    LOG(WARNING) << "No output device detected.";
471    return;
472  }
473
474  // The WASAPI API requires a correct COM environment.
475  ScopedCOMInitializer com_init(ScopedCOMInitializer::kMTA);
476
477  // Use 10 ms buffer size for WASAPI and 50 ms buffer size for Wave.
478  // Take the existing native sample rate into account.
479  const AudioParameters params = audio_man->GetDefaultOutputStreamParameters();
480  int sample_rate = params.sample_rate();
481  uint32 samples_10_ms = sample_rate / 100;
482  int n = 1;
483  (base::win::GetVersion() <= base::win::VERSION_XP) ? n = 5 : n = 1;
484  AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
485      AudioParameters(AudioParameters::AUDIO_PCM_LOW_LATENCY,
486                      CHANNEL_LAYOUT_MONO, sample_rate,
487                      16, n * samples_10_ms),
488      std::string(), std::string());
489  ASSERT_TRUE(NULL != oas);
490
491  SineWaveAudioSource source(1, 200, sample_rate);
492
493  bool opened = oas->Open();
494  if (!opened) {
495    // It was not possible to open this audio device in mono.
496    // No point in continuing the test so let's break here.
497    LOG(WARNING) << "Mono is not supported. Skipping test.";
498    oas->Close();
499    return;
500  }
501  oas->SetVolume(1.0);
502
503  // Play the wave for .8 seconds.
504  oas->Start(&source);
505  ::Sleep(800);
506  oas->Stop();
507  oas->Close();
508}
509
510// Check that the pending bytes value is correct what the stream starts.
511TEST(WinAudioTest, PCMWaveStreamPendingBytes) {
512  scoped_ptr<AudioManager> audio_man(AudioManager::Create());
513  if (!audio_man->HasAudioOutputDevices()) {
514    LOG(WARNING) << "No output device detected.";
515    return;
516  }
517
518  uint32 samples_100_ms = AudioParameters::kAudioCDSampleRate / 10;
519  AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
520      AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
521                      AudioParameters::kAudioCDSampleRate, 16, samples_100_ms),
522      std::string(), std::string());
523  ASSERT_TRUE(NULL != oas);
524
525  NiceMock<MockAudioSource> source;
526  EXPECT_TRUE(oas->Open());
527
528  uint32 bytes_100_ms = samples_100_ms * 2;
529
530  // Audio output stream has either a double or triple buffer scheme.
531  // We expect the amount of pending bytes will reaching up to 2 times of
532  // |bytes_100_ms| depending on number of buffers used.
533  // From that it would decrease as we are playing the data but not providing
534  // new one. And then we will try to provide zero data so the amount of
535  // pending bytes will go down and eventually read zero.
536  InSequence s;
537
538  EXPECT_CALL(source, OnMoreData(NotNull(),
539                                 Field(&AudioBuffersState::pending_bytes, 0)))
540      .WillOnce(Invoke(MockAudioSource::ClearData));
541
542  // Note: If AudioManagerWin::NumberOfWaveOutBuffers() ever changes, or if this
543  // test is run on Vista, these expectations will fail.
544  EXPECT_CALL(source, OnMoreData(NotNull(),
545                                 Field(&AudioBuffersState::pending_bytes,
546                                       bytes_100_ms)))
547      .WillOnce(Invoke(MockAudioSource::ClearData));
548  EXPECT_CALL(source, OnMoreData(NotNull(),
549                                 Field(&AudioBuffersState::pending_bytes,
550                                       2 * bytes_100_ms)))
551      .WillOnce(Invoke(MockAudioSource::ClearData));
552  EXPECT_CALL(source, OnMoreData(NotNull(),
553                                 Field(&AudioBuffersState::pending_bytes,
554                                       2 * bytes_100_ms)))
555      .Times(AnyNumber())
556      .WillRepeatedly(Return(0));
557  EXPECT_CALL(source, OnMoreData(NotNull(),
558                                 Field(&AudioBuffersState::pending_bytes,
559                                       bytes_100_ms)))
560      .Times(AnyNumber())
561      .WillRepeatedly(Return(0));
562  EXPECT_CALL(source, OnMoreData(NotNull(),
563                                 Field(&AudioBuffersState::pending_bytes, 0)))
564      .Times(AnyNumber())
565      .WillRepeatedly(Return(0));
566
567  oas->Start(&source);
568  ::Sleep(500);
569  oas->Stop();
570  oas->Close();
571}
572
573// Simple source that uses a SyncSocket to retrieve the audio data
574// from a potentially remote thread.
575class SyncSocketSource : public AudioOutputStream::AudioSourceCallback {
576 public:
577  SyncSocketSource(base::SyncSocket* socket, const AudioParameters& params)
578      : socket_(socket) {
579    // Setup AudioBus wrapping data we'll receive over the sync socket.
580    data_size_ = AudioBus::CalculateMemorySize(params);
581    data_.reset(static_cast<float*>(
582        base::AlignedAlloc(data_size_, AudioBus::kChannelAlignment)));
583    audio_bus_ = AudioBus::WrapMemory(params, data_.get());
584  }
585  ~SyncSocketSource() {}
586
587  // AudioSourceCallback::OnMoreData implementation:
588  virtual int OnMoreData(AudioBus* audio_bus,
589                         AudioBuffersState buffers_state) {
590    socket_->Send(&buffers_state, sizeof(buffers_state));
591    uint32 size = socket_->Receive(data_.get(), data_size_);
592    DCHECK_EQ(static_cast<size_t>(size) % sizeof(*audio_bus_->channel(0)), 0U);
593    audio_bus_->CopyTo(audio_bus);
594    return audio_bus_->frames();
595  }
596  virtual int OnMoreIOData(AudioBus* source,
597                           AudioBus* dest,
598                           AudioBuffersState buffers_state) {
599    NOTREACHED();
600    return 0;
601  }
602  // AudioSourceCallback::OnError implementation:
603  virtual void OnError(AudioOutputStream* stream) {
604  }
605
606 private:
607  base::SyncSocket* socket_;
608  int data_size_;
609  scoped_ptr_malloc<float, base::ScopedPtrAlignedFree> data_;
610  scoped_ptr<AudioBus> audio_bus_;
611};
612
613struct SyncThreadContext {
614  base::SyncSocket* socket;
615  int sample_rate;
616  int channels;
617  int frames;
618  double sine_freq;
619  uint32 packet_size_bytes;
620};
621
622// This thread provides the data that the SyncSocketSource above needs
623// using the other end of a SyncSocket. The protocol is as follows:
624//
625// SyncSocketSource ---send 4 bytes ------------> SyncSocketThread
626//                  <--- audio packet ----------
627//
628DWORD __stdcall SyncSocketThread(void* context) {
629  SyncThreadContext& ctx = *(reinterpret_cast<SyncThreadContext*>(context));
630
631  // Setup AudioBus wrapping data we'll pass over the sync socket.
632  scoped_ptr_malloc<float, base::ScopedPtrAlignedFree> data(static_cast<float*>(
633      base::AlignedAlloc(ctx.packet_size_bytes, AudioBus::kChannelAlignment)));
634  scoped_ptr<AudioBus> audio_bus = AudioBus::WrapMemory(
635      ctx.channels, ctx.frames, data.get());
636
637  SineWaveAudioSource sine(1, ctx.sine_freq, ctx.sample_rate);
638  const int kTwoSecFrames = ctx.sample_rate * 2;
639
640  AudioBuffersState buffers_state;
641  int times = 0;
642  for (int ix = 0; ix < kTwoSecFrames; ix += ctx.frames) {
643    if (ctx.socket->Receive(&buffers_state, sizeof(buffers_state)) == 0)
644      break;
645    if ((times > 0) && (buffers_state.pending_bytes < 1000)) __debugbreak();
646    sine.OnMoreData(audio_bus.get(), buffers_state);
647    ctx.socket->Send(data.get(), ctx.packet_size_bytes);
648    ++times;
649  }
650
651  return 0;
652}
653
654// Test the basic operation of AudioOutputStream used with a SyncSocket.
655// The emphasis is to verify that it is possible to feed data to the audio
656// layer using a source based on SyncSocket. In a real situation we would
657// go for the low-latency version in combination with SyncSocket, but to keep
658// the test more simple, AUDIO_PCM_LINEAR is utilized instead. The main
659// principle of the test still remains and we avoid the additional complexity
660// related to the two different audio-layers for AUDIO_PCM_LOW_LATENCY.
661// In this test you should hear a continuous 200Hz tone for 2 seconds.
662TEST(WinAudioTest, SyncSocketBasic) {
663  scoped_ptr<AudioManager> audio_man(AudioManager::Create());
664  if (!audio_man->HasAudioOutputDevices()) {
665    LOG(WARNING) << "No output device detected.";
666    return;
667  }
668
669  static const int sample_rate = AudioParameters::kAudioCDSampleRate;
670  static const uint32 kSamples20ms = sample_rate / 50;
671  AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
672                         CHANNEL_LAYOUT_MONO, sample_rate, 16, kSamples20ms);
673
674
675  AudioOutputStream* oas = audio_man->MakeAudioOutputStream(params,
676      std::string(), std::string());
677  ASSERT_TRUE(NULL != oas);
678
679  ASSERT_TRUE(oas->Open());
680
681  base::SyncSocket sockets[2];
682  ASSERT_TRUE(base::SyncSocket::CreatePair(&sockets[0], &sockets[1]));
683
684  SyncSocketSource source(&sockets[0], params);
685
686  SyncThreadContext thread_context;
687  thread_context.sample_rate = params.sample_rate();
688  thread_context.sine_freq = 200.0;
689  thread_context.packet_size_bytes = AudioBus::CalculateMemorySize(params);
690  thread_context.frames = params.frames_per_buffer();
691  thread_context.channels = params.channels();
692  thread_context.socket = &sockets[1];
693
694  HANDLE thread = ::CreateThread(NULL, 0, SyncSocketThread,
695                                 &thread_context, 0, NULL);
696
697  oas->Start(&source);
698
699  ::WaitForSingleObject(thread, INFINITE);
700  ::CloseHandle(thread);
701
702  oas->Stop();
703  oas->Close();
704}
705
706}  // namespace media
707