This source file includes following definitions.
- ClearData
 
- had_error_
 
- OnMoreData
 
- OnMoreIOData
 
- OnError
 
- callback_count
 
- had_error
 
- set_error
 
- lag_in_ms_
 
- OnMoreData
 
- size_
 
- is_valid
 
- size
 
- GetChunkAt
 
- TEST
 
- TEST
 
- TEST
 
- TEST
 
- TEST
 
- TEST
 
- TEST
 
- TEST
 
- TEST
 
- TEST
 
- TEST
 
- TEST
 
- OnMoreData
 
- OnMoreIOData
 
- OnError
 
- SyncSocketThread
 
- TEST
 
#include <windows.h>
#include <mmsystem.h>
#include "base/basictypes.h"
#include "base/base_paths.h"
#include "base/memory/aligned_memory.h"
#include "base/path_service.h"
#include "base/sync_socket.h"
#include "base/win/scoped_com_initializer.h"
#include "base/win/windows_version.h"
#include "media/base/limits.h"
#include "media/audio/audio_io.h"
#include "media/audio/audio_manager.h"
#include "media/audio/mock_audio_source_callback.h"
#include "media/audio/simple_sources.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::_;
using ::testing::AnyNumber;
using ::testing::DoAll;
using ::testing::Field;
using ::testing::Invoke;
using ::testing::InSequence;
using ::testing::NiceMock;
using ::testing::NotNull;
using ::testing::Return;
using base::win::ScopedCOMInitializer;
namespace media {
static const wchar_t kAudioFile1_16b_m_16K[]
    = L"media\\test\\data\\sweep02_16b_mono_16KHz.raw";
static int ClearData(AudioBus* audio_bus, AudioBuffersState buffers_state) {
  audio_bus->Zero();
  return audio_bus->frames();
}
class TestSourceBasic : public AudioOutputStream::AudioSourceCallback {
 public:
  explicit TestSourceBasic()
      : callback_count_(0),
        had_error_(0) {
  }
  
  virtual int OnMoreData(AudioBus* audio_bus,
                         AudioBuffersState buffers_state) {
    ++callback_count_;
    
    audio_bus->Zero();
    return audio_bus->frames();
  }
  virtual int OnMoreIOData(AudioBus* source,
                           AudioBus* dest,
                           AudioBuffersState buffers_state) {
    NOTREACHED();
    return 0;
  }
  
  virtual void OnError(AudioOutputStream* stream) {
    ++had_error_;
  }
  
  int callback_count() const {
    return callback_count_;
  }
  
  int had_error() const {
    return had_error_;
  }
  void set_error(bool error) {
    had_error_ += error ? 1 : 0;
  }
 private:
  int callback_count_;
  int had_error_;
};
const int kMaxNumBuffers = 3;
class TestSourceLaggy : public TestSourceBasic {
 public:
  TestSourceLaggy(int laggy_after_buffer, int lag_in_ms)
      : laggy_after_buffer_(laggy_after_buffer), lag_in_ms_(lag_in_ms) {
  }
  virtual int OnMoreData(AudioBus* audio_bus,
                         AudioBuffersState buffers_state) {
    
    TestSourceBasic::OnMoreData(audio_bus, buffers_state);
    if (callback_count() > kMaxNumBuffers) {
      ::Sleep(lag_in_ms_);
    }
    return audio_bus->frames();
  }
 private:
  int laggy_after_buffer_;
  int lag_in_ms_;
};
class ReadOnlyMappedFile {
 public:
  explicit ReadOnlyMappedFile(const wchar_t* file_name)
      : fmap_(NULL), start_(NULL), size_(0) {
    HANDLE file = ::CreateFileW(file_name, GENERIC_READ, FILE_SHARE_READ, NULL,
                                OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (INVALID_HANDLE_VALUE == file)
      return;
    fmap_ = ::CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
    ::CloseHandle(file);
    if (!fmap_)
      return;
    start_ = reinterpret_cast<char*>(::MapViewOfFile(fmap_, FILE_MAP_READ,
                                                     0, 0, 0));
    if (!start_)
      return;
    MEMORY_BASIC_INFORMATION mbi = {0};
    ::VirtualQuery(start_, &mbi, sizeof(mbi));
    size_ = mbi.RegionSize;
  }
  ~ReadOnlyMappedFile() {
    if (start_) {
      ::UnmapViewOfFile(start_);
      ::CloseHandle(fmap_);
    }
  }
  
  bool is_valid() const {
    return ((start_ > 0) && (size_ > 0));
  }
  
  uint32 size() const {
    return size_;
  }
  
  const void* GetChunkAt(uint32 offset) {
    return &start_[offset];
  }
 private:
  HANDLE fmap_;
  char* start_;
  uint32 size_;
};
TEST(WinAudioTest, PCMWaveStreamGetAndClose) {
  scoped_ptr<AudioManager> audio_man(AudioManager::CreateForTesting());
  if (!audio_man->HasAudioOutputDevices()) {
    LOG(WARNING) << "No output device detected.";
    return;
  }
  AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
      AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO,
                      8000, 16, 256),
      std::string());
  ASSERT_TRUE(NULL != oas);
  oas->Close();
}
TEST(WinAudioTest, SanityOnMakeParams) {
  scoped_ptr<AudioManager> audio_man(AudioManager::CreateForTesting());
  if (!audio_man->HasAudioOutputDevices()) {
    LOG(WARNING) << "No output device detected.";
    return;
  }
  AudioParameters::Format fmt = AudioParameters::AUDIO_PCM_LINEAR;
  EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
      AudioParameters(fmt, CHANNEL_LAYOUT_UNSUPPORTED, 8000, 16, 256),
      std::string()));
  EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
      AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 1024 * 1024, 16, 256),
      std::string()));
  EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
      AudioParameters(fmt, CHANNEL_LAYOUT_STEREO, 8000, 80, 256),
      std::string()));
  EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
      AudioParameters(fmt, CHANNEL_LAYOUT_UNSUPPORTED, 8000, 16, 256),
      std::string()));
  EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
      AudioParameters(fmt, CHANNEL_LAYOUT_STEREO, -8000, 16, 256),
      std::string()));
  EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
      AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 8000, 16, -100),
      std::string()));
  EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
      AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 8000, 16, 0),
      std::string()));
  EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
      AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 8000, 16,
                      media::limits::kMaxSamplesPerPacket + 1),
      std::string()));
}
TEST(WinAudioTest, PCMWaveStreamOpenAndClose) {
  scoped_ptr<AudioManager> audio_man(AudioManager::CreateForTesting());
  if (!audio_man->HasAudioOutputDevices()) {
    LOG(WARNING) << "No output device detected.";
    return;
  }
  AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
      AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO,
                      8000, 16, 256),
      std::string());
  ASSERT_TRUE(NULL != oas);
  EXPECT_TRUE(oas->Open());
  oas->Close();
}
TEST(WinAudioTest, PCMWaveStreamOpenLimit) {
  scoped_ptr<AudioManager> audio_man(AudioManager::CreateForTesting());
  if (!audio_man->HasAudioOutputDevices()) {
    LOG(WARNING) << "No output device detected.";
    return;
  }
  AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
      AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO,
                      8000, 16, 1024 * 1024 * 1024),
      std::string());
  EXPECT_TRUE(NULL == oas);
  if (oas)
    oas->Close();
}
TEST(WinAudioTest, PCMWaveSlowSource) {
  scoped_ptr<AudioManager> audio_man(AudioManager::CreateForTesting());
  if (!audio_man->HasAudioOutputDevices()) {
    LOG(WARNING) << "No output device detected.";
    return;
  }
  AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
      AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
                      16000, 16, 256),
      std::string());
  ASSERT_TRUE(NULL != oas);
  TestSourceLaggy test_laggy(2, 90);
  EXPECT_TRUE(oas->Open());
  
  
  oas->Start(&test_laggy);
  ::Sleep(500);
  EXPECT_GT(test_laggy.callback_count(), 2);
  EXPECT_FALSE(test_laggy.had_error());
  oas->Stop();
  ::Sleep(500);
  oas->Close();
}
TEST(WinAudioTest, PCMWaveStreamPlaySlowLoop) {
  scoped_ptr<AudioManager> audio_man(AudioManager::CreateForTesting());
  if (!audio_man->HasAudioOutputDevices()) {
    LOG(WARNING) << "No output device detected.";
    return;
  }
  uint32 samples_100_ms = AudioParameters::kAudioCDSampleRate / 10;
  AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
      AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
                      AudioParameters::kAudioCDSampleRate, 16, samples_100_ms),
      std::string());
  ASSERT_TRUE(NULL != oas);
  SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate);
  EXPECT_TRUE(oas->Open());
  oas->SetVolume(1.0);
  for (int ix = 0; ix != 5; ++ix) {
    oas->Start(&source);
    ::Sleep(10);
    oas->Stop();
  }
  oas->Close();
}
TEST(WinAudioTest, PCMWaveStreamPlay200HzTone44Kss) {
  scoped_ptr<AudioManager> audio_man(AudioManager::CreateForTesting());
  if (!audio_man->HasAudioOutputDevices()) {
    LOG(WARNING) << "No output device detected.";
    return;
  }
  uint32 samples_100_ms = AudioParameters::kAudioCDSampleRate / 10;
  AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
      AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
                      AudioParameters::kAudioCDSampleRate, 16, samples_100_ms),
      std::string());
  ASSERT_TRUE(NULL != oas);
  SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate);
  EXPECT_TRUE(oas->Open());
  oas->SetVolume(1.0);
  oas->Start(&source);
  ::Sleep(500);
  oas->Stop();
  oas->Close();
}
TEST(WinAudioTest, PCMWaveStreamPlay200HzTone22Kss) {
  scoped_ptr<AudioManager> audio_man(AudioManager::CreateForTesting());
  if (!audio_man->HasAudioOutputDevices()) {
    LOG(WARNING) << "No output device detected.";
    return;
  }
  uint32 samples_100_ms = AudioParameters::kAudioCDSampleRate / 20;
  AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
      AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
                      AudioParameters::kAudioCDSampleRate / 2, 16,
                      samples_100_ms),
      std::string());
  ASSERT_TRUE(NULL != oas);
  SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate/2);
  EXPECT_TRUE(oas->Open());
  oas->SetVolume(0.5);
  oas->Start(&source);
  ::Sleep(500);
  
  double volume = 0.0;
  oas->GetVolume(&volume);
  EXPECT_LT(volume, 0.51);
  EXPECT_GT(volume, 0.49);
  oas->Stop();
  oas->Close();
}
TEST(WinAudioTest, PushSourceFile16KHz)  {
  scoped_ptr<AudioManager> audio_man(AudioManager::CreateForTesting());
  if (!audio_man->HasAudioOutputDevices()) {
    LOG(WARNING) << "No output device detected.";
    return;
  }
  static const int kSampleRate = 16000;
  SineWaveAudioSource source(1, 200.0, kSampleRate);
  
  const uint32 kSamples100ms = (kSampleRate / 1000) * 100;
  
  source.CapSamples(kSamples100ms);
  AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
      AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
                      kSampleRate, 16, kSamples100ms),
      std::string());
  ASSERT_TRUE(NULL != oas);
  EXPECT_TRUE(oas->Open());
  oas->SetVolume(1.0);
  oas->Start(&source);
  
  
  
  for (uint32 ix = 0; ix != 100; ++ix) {
    ::Sleep(10);
    source.Reset();
  }
  
  ::Sleep(500);
  oas->Stop();
  oas->Close();
}
TEST(WinAudioTest, PCMWaveStreamPlayTwice200HzTone44Kss) {
  scoped_ptr<AudioManager> audio_man(AudioManager::CreateForTesting());
  if (!audio_man->HasAudioOutputDevices()) {
    LOG(WARNING) << "No output device detected.";
    return;
  }
  uint32 samples_100_ms = AudioParameters::kAudioCDSampleRate / 10;
  AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
      AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
                      AudioParameters::kAudioCDSampleRate, 16, samples_100_ms),
      std::string());
  ASSERT_TRUE(NULL != oas);
  SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate);
  EXPECT_TRUE(oas->Open());
  oas->SetVolume(1.0);
  
  oas->Start(&source);
  ::Sleep(500);
  oas->Stop();
  
  ::Sleep(250);
  
  oas->Start(&source);
  ::Sleep(500);
  oas->Stop();
  oas->Close();
}
TEST(WinAudioTest, PCMWaveStreamPlay200HzToneLowLatency) {
  scoped_ptr<AudioManager> audio_man(AudioManager::CreateForTesting());
  if (!audio_man->HasAudioOutputDevices()) {
    LOG(WARNING) << "No output device detected.";
    return;
  }
  
  ScopedCOMInitializer com_init(ScopedCOMInitializer::kMTA);
  
  
  const AudioParameters params = audio_man->GetDefaultOutputStreamParameters();
  int sample_rate = params.sample_rate();
  uint32 samples_10_ms = sample_rate / 100;
  int n = 1;
  (base::win::GetVersion() <= base::win::VERSION_XP) ? n = 5 : n = 1;
  AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
      AudioParameters(AudioParameters::AUDIO_PCM_LOW_LATENCY,
                      CHANNEL_LAYOUT_MONO, sample_rate,
                      16, n * samples_10_ms),
      std::string());
  ASSERT_TRUE(NULL != oas);
  SineWaveAudioSource source(1, 200, sample_rate);
  bool opened = oas->Open();
  if (!opened) {
    
    
    LOG(WARNING) << "Mono is not supported. Skipping test.";
    oas->Close();
    return;
  }
  oas->SetVolume(1.0);
  
  oas->Start(&source);
  ::Sleep(800);
  oas->Stop();
  oas->Close();
}
TEST(WinAudioTest, PCMWaveStreamPendingBytes) {
  scoped_ptr<AudioManager> audio_man(AudioManager::CreateForTesting());
  if (!audio_man->HasAudioOutputDevices()) {
    LOG(WARNING) << "No output device detected.";
    return;
  }
  uint32 samples_100_ms = AudioParameters::kAudioCDSampleRate / 10;
  AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
      AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
                      AudioParameters::kAudioCDSampleRate, 16, samples_100_ms),
      std::string());
  ASSERT_TRUE(NULL != oas);
  NiceMock<MockAudioSourceCallback> source;
  EXPECT_TRUE(oas->Open());
  uint32 bytes_100_ms = samples_100_ms * 2;
  
  
  
  
  
  
  InSequence s;
  EXPECT_CALL(source, OnMoreData(NotNull(),
                                 Field(&AudioBuffersState::pending_bytes, 0)))
      .WillOnce(Invoke(ClearData));
  
  
  EXPECT_CALL(source, OnMoreData(NotNull(),
                                 Field(&AudioBuffersState::pending_bytes,
                                       bytes_100_ms)))
      .WillOnce(Invoke(ClearData));
  EXPECT_CALL(source, OnMoreData(NotNull(),
                                 Field(&AudioBuffersState::pending_bytes,
                                       2 * bytes_100_ms)))
      .WillOnce(Invoke(ClearData));
  EXPECT_CALL(source, OnMoreData(NotNull(),
                                 Field(&AudioBuffersState::pending_bytes,
                                       2 * bytes_100_ms)))
      .Times(AnyNumber())
      .WillRepeatedly(Return(0));
  EXPECT_CALL(source, OnMoreData(NotNull(),
                                 Field(&AudioBuffersState::pending_bytes,
                                       bytes_100_ms)))
      .Times(AnyNumber())
      .WillRepeatedly(Return(0));
  EXPECT_CALL(source, OnMoreData(NotNull(),
                                 Field(&AudioBuffersState::pending_bytes, 0)))
      .Times(AnyNumber())
      .WillRepeatedly(Return(0));
  oas->Start(&source);
  ::Sleep(500);
  oas->Stop();
  oas->Close();
}
class SyncSocketSource : public AudioOutputStream::AudioSourceCallback {
 public:
  SyncSocketSource(base::SyncSocket* socket, const AudioParameters& params)
      : socket_(socket) {
    
    data_size_ = AudioBus::CalculateMemorySize(params);
    data_.reset(static_cast<float*>(
        base::AlignedAlloc(data_size_, AudioBus::kChannelAlignment)));
    audio_bus_ = AudioBus::WrapMemory(params, data_.get());
  }
  ~SyncSocketSource() {}
  
  virtual int OnMoreData(AudioBus* audio_bus,
                         AudioBuffersState buffers_state) {
    socket_->Send(&buffers_state, sizeof(buffers_state));
    uint32 size = socket_->Receive(data_.get(), data_size_);
    DCHECK_EQ(static_cast<size_t>(size) % sizeof(*audio_bus_->channel(0)), 0U);
    audio_bus_->CopyTo(audio_bus);
    return audio_bus_->frames();
  }
  virtual int OnMoreIOData(AudioBus* source,
                           AudioBus* dest,
                           AudioBuffersState buffers_state) {
    NOTREACHED();
    return 0;
  }
  
  virtual void OnError(AudioOutputStream* stream) {
  }
 private:
  base::SyncSocket* socket_;
  int data_size_;
  scoped_ptr<float, base::AlignedFreeDeleter> data_;
  scoped_ptr<AudioBus> audio_bus_;
};
struct SyncThreadContext {
  base::SyncSocket* socket;
  int sample_rate;
  int channels;
  int frames;
  double sine_freq;
  uint32 packet_size_bytes;
};
DWORD __stdcall SyncSocketThread(void* context) {
  SyncThreadContext& ctx = *(reinterpret_cast<SyncThreadContext*>(context));
  
  scoped_ptr<float, base::AlignedFreeDeleter> data(static_cast<float*>(
      base::AlignedAlloc(ctx.packet_size_bytes, AudioBus::kChannelAlignment)));
  scoped_ptr<AudioBus> audio_bus = AudioBus::WrapMemory(
      ctx.channels, ctx.frames, data.get());
  SineWaveAudioSource sine(1, ctx.sine_freq, ctx.sample_rate);
  const int kTwoSecFrames = ctx.sample_rate * 2;
  AudioBuffersState buffers_state;
  int times = 0;
  for (int ix = 0; ix < kTwoSecFrames; ix += ctx.frames) {
    if (ctx.socket->Receive(&buffers_state, sizeof(buffers_state)) == 0)
      break;
    if ((times > 0) && (buffers_state.pending_bytes < 1000)) __debugbreak();
    sine.OnMoreData(audio_bus.get(), buffers_state);
    ctx.socket->Send(data.get(), ctx.packet_size_bytes);
    ++times;
  }
  return 0;
}
TEST(WinAudioTest, SyncSocketBasic) {
  scoped_ptr<AudioManager> audio_man(AudioManager::CreateForTesting());
  if (!audio_man->HasAudioOutputDevices()) {
    LOG(WARNING) << "No output device detected.";
    return;
  }
  static const int sample_rate = AudioParameters::kAudioCDSampleRate;
  static const uint32 kSamples20ms = sample_rate / 50;
  AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
                         CHANNEL_LAYOUT_MONO, sample_rate, 16, kSamples20ms);
  AudioOutputStream* oas = audio_man->MakeAudioOutputStream(params,
      std::string());
  ASSERT_TRUE(NULL != oas);
  ASSERT_TRUE(oas->Open());
  base::SyncSocket sockets[2];
  ASSERT_TRUE(base::SyncSocket::CreatePair(&sockets[0], &sockets[1]));
  SyncSocketSource source(&sockets[0], params);
  SyncThreadContext thread_context;
  thread_context.sample_rate = params.sample_rate();
  thread_context.sine_freq = 200.0;
  thread_context.packet_size_bytes = AudioBus::CalculateMemorySize(params);
  thread_context.frames = params.frames_per_buffer();
  thread_context.channels = params.channels();
  thread_context.socket = &sockets[1];
  HANDLE thread = ::CreateThread(NULL, 0, SyncSocketThread,
                                 &thread_context, 0, NULL);
  oas->Start(&source);
  ::WaitForSingleObject(thread, INFINITE);
  ::CloseHandle(thread);
  oas->Stop();
  oas->Close();
}
}