summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorhclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-02-04 19:28:53 +0000
committerhclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-02-04 19:28:53 +0000
commit8a7499e2fb2c6a80aa6a8509fa00b9cf7b6e5031 (patch)
tree9b335e29f25acfbeae49533a5a7ce0f132dfef22 /chrome
parent0e19849067bead96a0c0ca48b2b82a9682e78013 (diff)
downloadchromium_src-8a7499e2fb2c6a80aa6a8509fa00b9cf7b6e5031.zip
chromium_src-8a7499e2fb2c6a80aa6a8509fa00b9cf7b6e5031.tar.gz
chromium_src-8a7499e2fb2c6a80aa6a8509fa00b9cf7b6e5031.tar.bz2
AudioRendererHost and unit test files
AudioRendererHost provide service in browser process for AudioRenderer to access hardware in render process. There will be one AudioRendererHost for every RenderProcessHost, each one of AudioRendererHost will service multiple AudioRenderer in the related render process. The main functionality of AudioRendererHost is to group audio related services and provide access to AudioRenderer through IPC. It maps an internal stream id to the actual AudioOutputStream which most calls are delegated to. AudioRendererHost::IPCAudioSource is to implement audio data source using IPC. Review URL: http://codereview.chromium.org/21008 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@9159 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/browser.vcproj8
-rw-r--r--chrome/browser/renderer_host/audio_renderer_host.cc174
-rw-r--r--chrome/browser/renderer_host/audio_renderer_host.h132
-rw-r--r--chrome/browser/renderer_host/audio_renderer_host_unittest.cc22
-rw-r--r--chrome/test/unit/unittests.vcproj4
5 files changed, 340 insertions, 0 deletions
diff --git a/chrome/browser/browser.vcproj b/chrome/browser/browser.vcproj
index 3449e2b..0947371 100644
--- a/chrome/browser/browser.vcproj
+++ b/chrome/browser/browser.vcproj
@@ -1946,6 +1946,14 @@
>
</File>
<File
+ RelativePath=".\renderer_host\audio_renderer_host.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\renderer_host\audio_renderer_host.h"
+ >
+ </File>
+ <File
RelativePath=".\renderer_host\backing_store.cc"
>
</File>
diff --git a/chrome/browser/renderer_host/audio_renderer_host.cc b/chrome/browser/renderer_host/audio_renderer_host.cc
new file mode 100644
index 0000000..66ee9ff
--- /dev/null
+++ b/chrome/browser/renderer_host/audio_renderer_host.cc
@@ -0,0 +1,174 @@
+// Copyright (c) 2006-2009 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/message_loop.h"
+#include "base/process.h"
+#include "chrome/browser/renderer_host/audio_renderer_host.h"
+
+AudioRendererHost::IPCAudioSource::IPCAudioSource(
+ AudioRendererHost* host,
+ int32 id,
+ AudioOutputStream* stream,
+ IPC::Message::Sender* sender,
+ base::ProcessHandle process,
+ size_t packet_size)
+ : host_(host),
+ id_(id),
+ stream_(stream),
+ sender_(sender) {
+ // Make sure we can create and map the shared memory.
+ DCHECK(shared_memory_.Create(L"", false, false, packet_size) &&
+ shared_memory_.Map(packet_size));
+ // Also make sure we can create the buffer and share to render process.
+ DCHECK(shared_memory_.ShareToProcess(process, &foreign_memory_handle_));
+}
+
+AudioRendererHost::IPCAudioSource::~IPCAudioSource() {
+}
+
+size_t AudioRendererHost::IPCAudioSource::OnMoreData(AudioOutputStream* stream,
+ void* dest,
+ size_t max_size) {
+ // TODO(hclam): send an IPC message to renderer provided with a
+ // SharedMemoryHandle for audio renderer inside render process to fill in.
+ // We should sleep until we receive a notification from render process that
+ // the buffer is ready or this source is closed or an error is encountered.
+ // Stuff do there here:
+ // 1. Prepare the SharedMemory.
+ // 2. Send an IPC.
+ // 3. Wait until we receive notification.
+ return 0;
+}
+
+void AudioRendererHost::IPCAudioSource::OnClose(AudioOutputStream* stream) {
+ // TODO(hclam): should set a flag here and wakes up the thread waiting for
+ // audio buffer. Should also make sure this call come from the thread as this
+ // object is created.
+ // Stuff to do here:
+ // 1. Send an IPC to renderer about close complete.
+ // 2. Remove this object from host.
+ host_->DestroySource(id_);
+}
+
+void AudioRendererHost::IPCAudioSource::OnError(AudioOutputStream* stream,
+ int code) {
+ // TODO(hclam): make sure this method is received in the same thread as this
+ // object is created and remove this object and from the map gracefully.
+ // Stuff to do here:
+ // 1. Send an IPC to renderer about the error.
+ // 2. Close the stream so it would get closed.
+ // TODO(cpu): make sure it is safe to close() in this method.
+ stream_->Close();
+}
+
+void AudioRendererHost::IPCAudioSource::NotifyPacketReady() {
+ // TODO(hclam): wake the thread waiting for buffer.
+}
+
+AudioRendererHost::AudioRendererHost(MessageLoop* message_loop)
+ : next_id_(INVALID_ID+1),
+ message_loop_(message_loop) {
+}
+
+AudioRendererHost::~AudioRendererHost() {
+ DestroyAllStreams();
+}
+
+int AudioRendererHost::CreateStream(
+ IPC::Message::Sender* sender, base::ProcessHandle handle,
+ AudioManager::Format format, int channels, int sample_rate,
+ int bits_per_sample, size_t packet_size) {
+ DCHECK(MessageLoop::current() == message_loop_);
+
+ // Create the stream in the first place.
+ AudioOutputStream* stream = AudioManager::GetAudioManager()->MakeAudioStream(
+ format, channels, sample_rate, bits_per_sample);
+ if (!stream)
+ return INVALID_ID;
+
+ // Try to open the stream if we can create it.
+ if (stream->Open(packet_size)) {
+ // Create the containing IPCAudioSource and save it to the map.
+ IPCAudioSource* source =
+ new IPCAudioSource(this, next_id_++, stream, sender, handle,
+ packet_size);
+ sources_.AddWithID(source, source->id());
+ return source->id();
+ }
+ return INVALID_ID;
+}
+
+bool AudioRendererHost::Start(int stream_id) {
+ DCHECK(MessageLoop::current() == message_loop_);
+ IPCAudioSource* source = sources_.Lookup(stream_id);
+ if (source) {
+ source->stream()->Start(source);
+ return true;
+ }
+ return false;
+}
+
+bool AudioRendererHost::Stop(int stream_id) {
+ DCHECK(MessageLoop::current() == message_loop_);
+ IPCAudioSource* source = sources_.Lookup(stream_id);
+ if (source) {
+ source->stream()->Stop();
+ return true;
+ }
+ return false;
+}
+
+bool AudioRendererHost::Close(int stream_id) {
+ DCHECK(MessageLoop::current() == message_loop_);
+ IPCAudioSource* source = sources_.Lookup(stream_id);
+ if (source) {
+ source->stream()->Close();
+ return true;
+ }
+ return false;
+}
+
+bool AudioRendererHost::SetVolume(
+ int stream_id, double left_channel, double right_channel) {
+ DCHECK(MessageLoop::current() == message_loop_);
+ IPCAudioSource* source = sources_.Lookup(stream_id);
+ if (source) {
+ source->stream()->SetVolume(left_channel, right_channel);
+ }
+ return false;
+}
+
+bool AudioRendererHost::GetVolume(
+ int stream_id, double* left_channel, double* right_channel) {
+ DCHECK(MessageLoop::current() == message_loop_);
+ IPCAudioSource* source = sources_.Lookup(stream_id);
+ if (source) {
+ source->stream()->GetVolume(left_channel, right_channel);
+ return true;
+ }
+ return false;
+}
+
+void AudioRendererHost::NotifyPacketReady(int stream_id) {
+ DCHECK(MessageLoop::current() == message_loop_);
+ IPCAudioSource* source = sources_.Lookup(stream_id);
+ if (source) {
+ source->NotifyPacketReady();
+ }
+}
+
+void AudioRendererHost::DestroyAllStreams() {
+ DCHECK(MessageLoop::current() == message_loop_);
+ // TODO(hclam): iterate on the map, close and delete every stream, and clear
+ // the map.
+}
+
+void AudioRendererHost::DestroySource(int stream_id) {
+ DCHECK(MessageLoop::current() == message_loop_);
+ IPCAudioSource* source = sources_.Lookup(stream_id);
+ if (source) {
+ sources_.Remove(stream_id);
+ delete source;
+ }
+}
diff --git a/chrome/browser/renderer_host/audio_renderer_host.h b/chrome/browser/renderer_host/audio_renderer_host.h
new file mode 100644
index 0000000..4df24ba
--- /dev/null
+++ b/chrome/browser/renderer_host/audio_renderer_host.h
@@ -0,0 +1,132 @@
+// Copyright (c) 2006-2009 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.
+//
+// AudioRendererHost serves audio related requests from AudioRenderer which
+// lives inside the render process and provide access to audio hardware. It maps
+// an internal ID to AudioRendererHost::IPCAudioSource in a map, which is the
+// actual object providing audio packets through IPC. It creates the actual
+// AudioOutputStream object when requested by the renderer and returns an
+// internal ID. It then delegates calls to the AudioOutputStream object indexed
+// by the internal id.
+//
+// AudioRendererHost::IPCAudioSource is a container of AudioOutputStream and
+// provide audio packets to the associated AudioOutputStream through IPC. It
+// transforms the pull data model to a push model used for IPC. When asked by
+// AudioOutputStream for an audio packet, it would send a message to renderer,
+// passing a SharedMemoryHandle for filling the buffer.
+// NotifyPacketReady(|stream_id|) would be called when the buffer is filled
+// and ready to be consumed.
+
+#ifndef CHROME_BROWSER_RENDERER_HOST_AUDIO_RENDERER_HOST_H_
+#define CHROME_BROWSER_RENDERER_HOST_AUDIO_RENDERER_HOST_H_
+
+#include "base/id_map.h"
+#include "base/shared_memory.h"
+#include "chrome/common/ipc_message.h"
+#include "media/audio/audio_output.h"
+
+class AudioManager;
+class MessageLoop;
+
+class AudioRendererHost {
+ public:
+ static const int32 INVALID_ID = 0;
+
+ explicit AudioRendererHost(MessageLoop* message_loop);
+ ~AudioRendererHost();
+
+ // Creates an audio output stream with the specified format, returns the
+ // stream id if successful, otherwise INVALID_ID. If this call is successful
+ // this object would keep an internal entry of the stream about the
+ // required properties, renderer process handle and IPC channel for sending
+ // buffer request messages.
+ int32 CreateStream(IPC::Message::Sender* sender, base::ProcessHandle handle,
+ AudioManager::Format format, int channels, int sample_rate,
+ int bits_per_sample, size_t packet_size);
+
+ // Start the audio output strean, return false if stream doesn't exist or the
+ // cannot start.
+ bool Start(int32 stream_id);
+
+ // Stop the audio output stream, return false if stream doesn't exist or
+ // cannot stop.
+ bool Stop(int32 stream_id);
+
+ // Close the audio output stream, return false if stream doesn't exist or
+ // cannot close. If this call is successful, the AudioOutputStream correspond
+ // to |stream_id| would go unmanaged by this class, subsequent calls to
+ // this object with the same |stream_id| would fail.
+ bool Close(int32 stream_id);
+
+ // Set the volume for the stream specified, returns true if successful, false
+ // if stream doesn't exist or cann't set volume.
+ bool SetVolume(
+ int32 stream_id, double left_channel, double right_channel);
+
+ // Get the volume of the stream specified, returns true if successful, false
+ // is stream doesn't exist or can't get volume.
+ bool GetVolume(
+ int32 stream_id, double* left_channel, double* right_channel);
+
+ // Notify packet has been prepared for stream specified by |stream_id|. The
+ // buffer associated with |stream_id| has been filled and is ready to be
+ // consumed.
+ void NotifyPacketReady(int32 stream_id);
+
+ // Destroy all audio output streams.
+ void DestroyAllStreams();
+
+ // Destroy the stream specified by |stream_id| and remove it from map.
+ // *DO NOT* call this method other than from IPCAudioSource.
+ void DestroySource(int32 stream_id);
+
+ private:
+ // The container for AudioOutputStream and serves audio packet for it by IPC.
+ class IPCAudioSource : public AudioOutputStream::AudioSourceCallback {
+ public:
+ IPCAudioSource(AudioRendererHost* host, // Host of this source.
+ int32 id, // ID of this source.
+ AudioOutputStream* stream, // Stream associated.
+ IPC::Message::Sender* sender, // IPC sender to user.
+ base::ProcessHandle process, // Render process handle.
+ size_t packet_size); // Size of shared memory
+ // buffer for writing.
+ ~IPCAudioSource();
+
+ // AudioSourceCallback methods.
+ virtual size_t OnMoreData(AudioOutputStream* stream,
+ void* dest, size_t max_size);
+ virtual void OnClose(AudioOutputStream* stream);
+ virtual void OnError(AudioOutputStream* stream, int code);
+
+ // Notify this source that buffer has been filled and is ready to be
+ // consumed.
+ void NotifyPacketReady();
+
+ int32 id() { return id_; }
+ AudioOutputStream* stream() { return stream_; }
+
+ private:
+ AudioRendererHost* host_;
+ int32 id_;
+ AudioOutputStream* stream_;
+ IPC::Message::Sender* sender_;
+ base::SharedMemory shared_memory_;
+ base::SharedMemoryHandle foreign_memory_handle_;
+ };
+
+ // A map of id to audio sources.
+ IDMap<IPCAudioSource> sources_;
+
+ // An internal id for streams.
+ int32 next_id_;
+
+ // Only used for DCHECKs to make sure all methods calls are from the same
+ // thread as this object is created.
+ MessageLoop* message_loop_;
+
+ DISALLOW_COPY_AND_ASSIGN(AudioRendererHost);
+};
+
+#endif // CHROME_BROWSER_RENDERER_HOST_AUDIO_RENDERER_HOST_H_
diff --git a/chrome/browser/renderer_host/audio_renderer_host_unittest.cc b/chrome/browser/renderer_host/audio_renderer_host_unittest.cc
new file mode 100644
index 0000000..443966b
--- /dev/null
+++ b/chrome/browser/renderer_host/audio_renderer_host_unittest.cc
@@ -0,0 +1,22 @@
+// Copyright (c) 2009 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/message_loop.h"
+#include "base/process.h"
+#include "base/scoped_ptr.h"
+#include "chrome/browser/renderer_host/audio_renderer_host.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class AudioRendererHostTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ host_.reset(new AudioRendererHost(MessageLoop::current()));
+ }
+
+ scoped_ptr<AudioRendererHost> host_;
+};
+
+TEST_F(AudioRendererHostTest, NoTest) {
+ // TODO(hclam): come up with useful tests.
+}
diff --git a/chrome/test/unit/unittests.vcproj b/chrome/test/unit/unittests.vcproj
index fbd1da5..70c9d65 100644
--- a/chrome/test/unit/unittests.vcproj
+++ b/chrome/test/unit/unittests.vcproj
@@ -383,6 +383,10 @@
Name="browser"
>
<File
+ RelativePath="..\..\browser\renderer_host\audio_renderer_host_unittest.cc"
+ >
+ </File>
+ <File
RelativePath="..\..\browser\autocomplete\autocomplete_unittest.cc"
>
</File>