From 74532a5880470f854def44a862a79af012bfd395 Mon Sep 17 00:00:00 2001
From: "satish@chromium.org"
 <satish@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>
Date: Thu, 15 Jul 2010 08:34:06 +0000
Subject: Add a fake audio input stream for testing purposes. This will be used
 by unit tests in subsequent patches. BUG=none TEST=no new features added and
 nothing new to test

Review URL: http://codereview.chromium.org/2909015

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@52464 0039d316-1c4b-4281-b951-d872f2087c98
---
 media/audio/fake_audio_input_stream.cc          | 80 +++++++++++++++++++++++++
 media/audio/fake_audio_input_stream.h           | 51 ++++++++++++++++
 media/audio/fake_audio_input_stream_unittest.cc | 51 ++++++++++++++++
 media/audio/linux/audio_manager_linux.cc        |  6 ++
 media/audio/mac/audio_manager_mac.cc            |  6 ++
 media/audio/win/audio_manager_win.cc            |  5 +-
 media/media.gyp                                 |  3 +
 7 files changed, 201 insertions(+), 1 deletion(-)
 create mode 100644 media/audio/fake_audio_input_stream.cc
 create mode 100644 media/audio/fake_audio_input_stream.h
 create mode 100644 media/audio/fake_audio_input_stream_unittest.cc

(limited to 'media')

diff --git a/media/audio/fake_audio_input_stream.cc b/media/audio/fake_audio_input_stream.cc
new file mode 100644
index 0000000..9748d8e
--- /dev/null
+++ b/media/audio/fake_audio_input_stream.cc
@@ -0,0 +1,80 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/audio/fake_audio_input_stream.h"
+
+#include "base/at_exit.h"
+
+using base::Time;
+using base::TimeDelta;
+
+AudioInputStream* FakeAudioInputStream::MakeFakeStream(int channels,
+                                                       int bits_per_sample,
+                                                       int sampling_rate,
+                                                       int samples_per_packet) {
+  return new FakeAudioInputStream(channels, bits_per_sample, sampling_rate,
+                                  samples_per_packet);
+}
+
+FakeAudioInputStream::FakeAudioInputStream(int channels, int bits_per_sample,
+                                           int sampling_rate,
+                                           int samples_per_packet)
+    : callback_(NULL),
+      buffer_size_((channels * bits_per_sample * samples_per_packet) / 8),
+      thread_("FakeAudioRecordingThread"),
+      callback_interval_ms_((samples_per_packet * 1000) / sampling_rate) {
+  // This object is ref counted (so that it can be used with Thread, PostTask)
+  // but the caller expects a plain pointer. So we take a reference here and
+  // will Release() ourselves in Close().
+  AddRef();
+}
+
+bool FakeAudioInputStream::Open() {
+  buffer_.reset(new uint8[buffer_size_]);
+  memset(buffer_.get(), 0, buffer_size_);
+  return true;
+}
+
+void FakeAudioInputStream::Start(AudioInputCallback* callback)  {
+  DCHECK(!thread_.IsRunning());
+  callback_ = callback;
+  last_callback_time_ = Time::Now();
+  thread_.Start();
+  thread_.message_loop()->PostDelayedTask(
+      FROM_HERE,
+      NewRunnableMethod(this, &FakeAudioInputStream::DoCallback),
+      callback_interval_ms_);
+}
+
+void FakeAudioInputStream::DoCallback() {
+  DCHECK(callback_);
+  callback_->OnData(this, buffer_.get(), buffer_size_);
+
+  Time now = Time::Now();
+  int64 next_callback_ms = (last_callback_time_ +
+      TimeDelta::FromMilliseconds(callback_interval_ms_ * 2) -
+      now).InMilliseconds();
+  // If we are falling behind, try to catch up as much as we can in the next
+  // callback.
+  if (next_callback_ms < 0)
+    next_callback_ms = 0;
+
+  last_callback_time_ = now;
+  thread_.message_loop()->PostDelayedTask(
+      FROM_HERE,
+      NewRunnableMethod(this, &FakeAudioInputStream::DoCallback),
+      next_callback_ms);
+}
+
+void FakeAudioInputStream::Stop() {
+  thread_.Stop();
+}
+
+void FakeAudioInputStream::Close() {
+  if (callback_) {
+    callback_->OnClose(this);
+    callback_ = NULL;
+  }
+  Release();  // Destoys this object.
+}
diff --git a/media/audio/fake_audio_input_stream.h b/media/audio/fake_audio_input_stream.h
new file mode 100644
index 0000000..1cca917
--- /dev/null
+++ b/media/audio/fake_audio_input_stream.h
@@ -0,0 +1,51 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// A fake implementation of AudioInputStream, useful for testing purpose.
+
+#ifndef MEDIA_AUDIO_FAKE_AUDIO_INPUT_STREAM_H_
+#define MEDIA_AUDIO_FAKE_AUDIO_INOUT_STREAM_H_
+
+#include <vector>
+
+#include "base/ref_counted.h"
+#include "base/scoped_ptr.h"
+#include "base/thread.h"
+#include "base/time.h"
+#include "media/audio/audio_io.h"
+
+class FakeAudioInputStream :
+    public AudioInputStream,
+    public base::RefCountedThreadSafe<FakeAudioInputStream> {
+ public:
+  static AudioInputStream* MakeFakeStream(int channels, int bits_per_sample,
+                                   int sampling_rate, int samples_per_packet);
+
+  virtual bool Open();
+  virtual void Start(AudioInputCallback* callback);
+  virtual void Stop();
+  virtual void Close();
+
+ private:
+  // Give RefCountedThreadSafe access our destructor.
+  friend class base::RefCountedThreadSafe<FakeAudioInputStream>;
+
+  FakeAudioInputStream(int channels, int bits_per_sample, int sampling_rate,
+                       int samples_per_packet);
+  virtual ~FakeAudioInputStream() {}
+
+  void DoCallback();
+
+  AudioInputCallback* callback_;
+  scoped_array<uint8> buffer_;
+  int buffer_size_;
+  base::Thread thread_;
+  base::Time last_callback_time_;
+  int callback_interval_ms_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeAudioInputStream);
+};
+
+#endif  // MEDIA_AUDIO_FAKE_AUDIO_INPUT_STREAM_H_
+
diff --git a/media/audio/fake_audio_input_stream_unittest.cc b/media/audio/fake_audio_input_stream_unittest.cc
new file mode 100644
index 0000000..16e86a4
--- /dev/null
+++ b/media/audio/fake_audio_input_stream_unittest.cc
@@ -0,0 +1,51 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/basictypes.h"
+#include "base/platform_thread.h"
+#include "media/audio/audio_io.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::_;
+using ::testing::AtLeast;
+using ::testing::Exactly;
+using ::testing::NotNull;
+
+namespace {
+
+class MockAudioInputCallback : public AudioInputStream::AudioInputCallback {
+ public:
+  MockAudioInputCallback() {}
+
+  MOCK_METHOD1(OnClose, void(AudioInputStream* stream));
+  MOCK_METHOD2(OnError, void(AudioInputStream* stream, int error_code));
+  MOCK_METHOD3(OnData, void(AudioInputStream* stream, const uint8* src,
+                            uint32 size));
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockAudioInputCallback);
+};
+
+}
+
+// ============================================================================
+// Validate that the AudioManager::AUDIO_MOCK callbacks work.
+TEST(FakeAudioInputTest, BasicCallbacks) {
+  MockAudioInputCallback callback;
+  EXPECT_CALL(callback, OnData(NotNull(), _, _)).Times(AtLeast(5));
+  EXPECT_CALL(callback, OnError(NotNull(), _)).Times(Exactly(0));
+
+  AudioManager* audio_man = AudioManager::GetAudioManager();
+  ASSERT_TRUE(NULL != audio_man);
+  // Ask for one recorded packet every 50ms.
+  AudioInputStream* stream = audio_man->MakeAudioInputStream(
+      AudioManager::AUDIO_MOCK, 2, 8000, 8, 400);
+  ASSERT_TRUE(NULL != stream);
+  EXPECT_TRUE(stream->Open());
+  stream->Start(&callback);
+  PlatformThread::Sleep(340);  // Give sufficient time to receive 5 / 6 packets.
+  stream->Stop();
+  stream->Close();
+}
+
diff --git a/media/audio/linux/audio_manager_linux.cc b/media/audio/linux/audio_manager_linux.cc
index 6822c8b..17a1f74 100644
--- a/media/audio/linux/audio_manager_linux.cc
+++ b/media/audio/linux/audio_manager_linux.cc
@@ -7,6 +7,7 @@
 #include "base/at_exit.h"
 #include "base/command_line.h"
 #include "base/logging.h"
+#include "media/audio/fake_audio_input_stream.h"
 #include "media/audio/fake_audio_output_stream.h"
 #include "media/audio/linux/alsa_output.h"
 #include "media/audio/linux/alsa_wrapper.h"
@@ -35,6 +36,11 @@ AudioInputStream* AudioManagerLinux::MakeAudioInputStream(
     int sample_rate,
     char bits_per_sample,
     uint32 samples_per_packet) {
+  if (format == AUDIO_MOCK) {
+    return FakeAudioInputStream::MakeFakeStream(channels, bits_per_sample,
+                                                sample_rate,
+                                                samples_per_packet);
+  }
   // TODO(satish): implement.
   return NULL;
 }
diff --git a/media/audio/mac/audio_manager_mac.cc b/media/audio/mac/audio_manager_mac.cc
index 84f76de..312ecbb 100644
--- a/media/audio/mac/audio_manager_mac.cc
+++ b/media/audio/mac/audio_manager_mac.cc
@@ -5,6 +5,7 @@
 #include <CoreAudio/AudioHardware.h>
 
 #include "base/at_exit.h"
+#include "media/audio/fake_audio_input_stream.h"
 #include "media/audio/fake_audio_output_stream.h"
 #include "media/audio/mac/audio_manager_mac.h"
 #include "media/audio/mac/audio_output_mac.h"
@@ -38,6 +39,11 @@ AudioInputStream* AudioManagerMac::MakeAudioInputStream(
     int sample_rate,
     char bits_per_sample,
     uint32 samples_per_packet) {
+  if (format == AUDIO_MOCK) {
+    return FakeAudioInputStream::MakeFakeStream(channels, bits_per_sample,
+                                                sample_rate,
+                                                samples_per_packet);
+  }
   // TODO(satish): implement.
   return NULL;
 }
diff --git a/media/audio/win/audio_manager_win.cc b/media/audio/win/audio_manager_win.cc
index 0c42015..061d2d8 100644
--- a/media/audio/win/audio_manager_win.cc
+++ b/media/audio/win/audio_manager_win.cc
@@ -9,6 +9,7 @@
 
 #include "base/at_exit.h"
 #include "base/basictypes.h"
+#include "media/audio/fake_audio_input_stream.h"
 #include "media/audio/fake_audio_output_stream.h"
 #include "media/audio/win/audio_manager_win.h"
 #include "media/audio/win/wavein_input_win.h"
@@ -94,7 +95,9 @@ AudioInputStream* AudioManagerWin::MakeAudioInputStream(
     return NULL;
 
   if (format == AUDIO_MOCK) {
-    // TODO(satish): Add mock audio input stream.
+    return FakeAudioInputStream::MakeFakeStream(channels, bits_per_sample,
+                                                sample_rate,
+                                                samples_per_packet);
   } else if (format == AUDIO_PCM_LINEAR) {
     return new PCMWaveInAudioInputStream(this, channels, sample_rate,
                                          kNumInputBuffers, bits_per_sample,
diff --git a/media/media.gyp b/media/media.gyp
index 86966d6..554dcd1 100644
--- a/media/media.gyp
+++ b/media/media.gyp
@@ -25,6 +25,8 @@
         'audio/audio_output_controller.h',
         'audio/audio_util.cc',
         'audio/audio_util.h',
+        'audio/fake_audio_input_stream.cc',
+        'audio/fake_audio_input_stream.h',
         'audio/fake_audio_output_stream.cc',
         'audio/fake_audio_output_stream.h',
         'audio/linux/audio_manager_linux.cc',
@@ -190,6 +192,7 @@
       'sources': [
         'audio/audio_output_controller_unittest.cc',
         'audio/audio_util_unittest.cc',
+        'audio/fake_audio_input_stream_unittest.cc',
         'audio/linux/alsa_output_unittest.cc',
         'audio/mac/audio_output_mac_unittest.cc',
         'audio/simple_sources_unittest.cc',
-- 
cgit v1.1