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