summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoralexeypa@chromium.org <alexeypa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-12-27 22:57:49 +0000
committeralexeypa@chromium.org <alexeypa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-12-27 22:57:49 +0000
commit1c969e39e5c1813a57103d097d48bf03b0191ec8 (patch)
tree2b232cbe56bb4f1ce623207f8d9b89c3084c82f7
parent8b13223964fe8f641de74a9306ecd7dec5f55bfe (diff)
downloadchromium_src-1c969e39e5c1813a57103d097d48bf03b0191ec8.zip
chromium_src-1c969e39e5c1813a57103d097d48bf03b0191ec8.tar.gz
chromium_src-1c969e39e5c1813a57103d097d48bf03b0191ec8.tar.bz2
Added audio support to the multiprocess host.
The desktop session agent running in the user's session now captures audio and sends serialized audio packets over IPC to the network process. BUG=134694 Review URL: https://chromiumcodereview.appspot.com/11611007 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@174706 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--remoting/host/chromoting_messages.h5
-rw-r--r--remoting/host/desktop_process.cc16
-rw-r--r--remoting/host/desktop_session_agent.cc43
-rw-r--r--remoting/host/desktop_session_agent.h23
-rw-r--r--remoting/host/desktop_session_agent_posix.cc9
-rw-r--r--remoting/host/desktop_session_agent_win.cc10
-rw-r--r--remoting/host/desktop_session_proxy.cc48
-rw-r--r--remoting/host/desktop_session_proxy.h26
-rw-r--r--remoting/host/ipc_audio_capturer.cc59
-rw-r--r--remoting/host/ipc_audio_capturer.h46
-rw-r--r--remoting/host/ipc_desktop_environment.cc4
-rw-r--r--remoting/host/ipc_desktop_environment_factory.cc5
-rw-r--r--remoting/host/ipc_desktop_environment_factory.h4
-rw-r--r--remoting/host/remoting_me2me_host.cc1
-rw-r--r--remoting/remoting.gyp2
15 files changed, 290 insertions, 11 deletions
diff --git a/remoting/host/chromoting_messages.h b/remoting/host/chromoting_messages.h
index 846e440..4407f49 100644
--- a/remoting/host/chromoting_messages.h
+++ b/remoting/host/chromoting_messages.h
@@ -174,6 +174,11 @@ IPC_MESSAGE_CONTROL1(ChromotingDesktopNetworkMsg_InjectClipboardEvent,
// Requests the network process to terminate the client session.
IPC_MESSAGE_CONTROL0(ChromotingDesktopNetworkMsg_DisconnectSession)
+// Carries an audio packet from the desktop session agent to the client.
+// |serialized_packet| is a serialized AudioPacket.
+IPC_MESSAGE_CONTROL1(ChromotingDesktopNetworkMsg_AudioPacket,
+ std::string /* serialized_packet */ )
+
//-----------------------------------------------------------------------------
// Chromoting messages sent from the network to the desktop process.
diff --git a/remoting/host/desktop_process.cc b/remoting/host/desktop_process.cc
index 464b7d4..67eb7dd 100644
--- a/remoting/host/desktop_process.cc
+++ b/remoting/host/desktop_process.cc
@@ -76,6 +76,19 @@ void DesktopProcess::OnChannelError() {
bool DesktopProcess::Start() {
DCHECK(caller_task_runner_->BelongsToCurrentThread());
+ // Launch the audio capturing thread.
+ scoped_refptr<AutoThreadTaskRunner> audio_task_runner;
+#if defined(OS_WIN)
+ // On Windows the AudioCapturer requires COM, so we run a single-threaded
+ // apartment, which requires a UI thread.
+ audio_task_runner = AutoThread::CreateWithLoopAndComInitTypes(
+ "ChromotingAudioThread", caller_task_runner_, MessageLoop::TYPE_UI,
+ AutoThread::COM_INIT_STA);
+#else // !defined(OS_WIN)
+ audio_task_runner = AutoThread::CreateWithType(
+ "ChromotingAudioThread", caller_task_runner_, MessageLoop::TYPE_IO);
+#endif // !defined(OS_WIN)
+
// Launch the input thread.
scoped_refptr<AutoThreadTaskRunner> input_task_runner =
AutoThread::CreateWithType("Input thread", caller_task_runner_,
@@ -91,7 +104,8 @@ bool DesktopProcess::Start() {
AutoThread::Create("Video capture thread", caller_task_runner_);
// Create a desktop agent.
- desktop_agent_ = DesktopSessionAgent::Create(caller_task_runner_,
+ desktop_agent_ = DesktopSessionAgent::Create(audio_task_runner,
+ caller_task_runner_,
input_task_runner,
io_task_runner,
video_capture_task_runner);
diff --git a/remoting/host/desktop_session_agent.cc b/remoting/host/desktop_session_agent.cc
index a02cddb..aec9c1ea6 100644
--- a/remoting/host/desktop_session_agent.cc
+++ b/remoting/host/desktop_session_agent.cc
@@ -12,11 +12,13 @@
#include "remoting/base/constants.h"
#include "remoting/base/util.h"
#include "remoting/capturer/capture_data.h"
+#include "remoting/host/audio_capturer.h"
#include "remoting/host/chromoting_messages.h"
#include "remoting/host/disconnect_window.h"
#include "remoting/host/event_executor.h"
#include "remoting/host/local_input_monitor.h"
#include "remoting/host/remote_input_filter.h"
+#include "remoting/proto/audio.pb.h"
#include "remoting/proto/control.pb.h"
#include "remoting/proto/event.pb.h"
#include "remoting/protocol/clipboard_stub.h"
@@ -68,6 +70,7 @@ DesktopSessionAgent::Delegate::~Delegate() {
}
DesktopSessionAgent::~DesktopSessionAgent() {
+ DCHECK(!audio_capturer_);
DCHECK(!disconnect_window_);
DCHECK(!local_input_monitor_);
DCHECK(!network_channel_);
@@ -201,6 +204,10 @@ void DesktopSessionAgent::OnStartSessionAgent(
local_input_monitor_ = LocalInputMonitor::Create();
local_input_monitor_->Start(this, disconnect_session);
+ // Start the audio capturer.
+ audio_capture_task_runner()->PostTask(
+ FROM_HERE, base::Bind(&DesktopSessionAgent::StartAudioCapturer, this));
+
// Start the video capturer.
video_capture_task_runner()->PostTask(
FROM_HERE, base::Bind(&DesktopSessionAgent::StartVideoCapturer, this));
@@ -248,6 +255,18 @@ void DesktopSessionAgent::InjectClipboardEvent(
new ChromotingDesktopNetworkMsg_InjectClipboardEvent(serialized_event));
}
+void DesktopSessionAgent::ProcessAudioPacket(scoped_ptr<AudioPacket> packet) {
+ DCHECK(audio_capture_task_runner()->BelongsToCurrentThread());
+
+ std::string serialized_packet;
+ if (!packet->SerializeToString(&serialized_packet)) {
+ LOG(ERROR) << "Failed to serialize AudioPacket.";
+ return;
+ }
+
+ SendToNetwork(new ChromotingDesktopNetworkMsg_AudioPacket(serialized_packet));
+}
+
bool DesktopSessionAgent::Start(const base::WeakPtr<Delegate>& delegate,
IPC::PlatformFileForTransit* desktop_pipe_out) {
DCHECK(caller_task_runner()->BelongsToCurrentThread());
@@ -286,6 +305,10 @@ void DesktopSessionAgent::Stop() {
event_executor_.reset();
+ // Stop the audio capturer.
+ audio_capture_task_runner()->PostTask(
+ FROM_HERE, base::Bind(&DesktopSessionAgent::StopAudioCapturer, this));
+
// Stop the video capturer.
video_capture_task_runner()->PostTask(
FROM_HERE, base::Bind(&DesktopSessionAgent::StopVideoCapturer, this));
@@ -442,6 +465,22 @@ void DesktopSessionAgent::SendToNetwork(IPC::Message* message) {
}
}
+void DesktopSessionAgent::StartAudioCapturer() {
+ DCHECK(audio_capture_task_runner()->BelongsToCurrentThread());
+
+ audio_capturer_ = AudioCapturer::Create();
+ if (audio_capturer_) {
+ audio_capturer_->Start(base::Bind(&DesktopSessionAgent::ProcessAudioPacket,
+ this));
+ }
+}
+
+void DesktopSessionAgent::StopAudioCapturer() {
+ DCHECK(audio_capture_task_runner()->BelongsToCurrentThread());
+
+ audio_capturer_.reset();
+}
+
void DesktopSessionAgent::StartVideoCapturer() {
DCHECK(video_capture_task_runner()->BelongsToCurrentThread());
@@ -463,11 +502,13 @@ void DesktopSessionAgent::StopVideoCapturer() {
}
DesktopSessionAgent::DesktopSessionAgent(
+ scoped_refptr<AutoThreadTaskRunner> audio_capture_task_runner,
scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
scoped_refptr<AutoThreadTaskRunner> input_task_runner,
scoped_refptr<AutoThreadTaskRunner> io_task_runner,
scoped_refptr<AutoThreadTaskRunner> video_capture_task_runner)
- : caller_task_runner_(caller_task_runner),
+ : audio_capture_task_runner_(audio_capture_task_runner),
+ caller_task_runner_(caller_task_runner),
input_task_runner_(input_task_runner),
io_task_runner_(io_task_runner),
video_capture_task_runner_(video_capture_task_runner),
diff --git a/remoting/host/desktop_session_agent.h b/remoting/host/desktop_session_agent.h
index 916b4a5..fbb23c9 100644
--- a/remoting/host/desktop_session_agent.h
+++ b/remoting/host/desktop_session_agent.h
@@ -30,6 +30,8 @@ class Message;
namespace remoting {
+class AudioCapturer;
+class AudioPacket;
class AutoThreadTaskRunner;
class DisconnectWindow;
class EventExecutor;
@@ -62,6 +64,7 @@ class DesktopSessionAgent
};
static scoped_refptr<DesktopSessionAgent> Create(
+ scoped_refptr<AutoThreadTaskRunner> audio_capture_task_runner,
scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
scoped_refptr<AutoThreadTaskRunner> input_task_runner,
scoped_refptr<AutoThreadTaskRunner> io_task_runner,
@@ -89,6 +92,9 @@ class DesktopSessionAgent
// process.
void InjectClipboardEvent(const protocol::ClipboardEvent& event);
+ // Forwards an audio packet though the IPC channel to the network process.
+ void ProcessAudioPacket(scoped_ptr<AudioPacket> packet);
+
// Creates desktop integration components and a connected IPC channel to be
// used to access them. The client end of the channel is returned in
// the variable pointed by |desktop_pipe_out|.
@@ -100,6 +106,7 @@ class DesktopSessionAgent
protected:
DesktopSessionAgent(
+ scoped_refptr<AutoThreadTaskRunner> audio_capture_task_runner,
scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
scoped_refptr<AutoThreadTaskRunner> input_task_runner,
scoped_refptr<AutoThreadTaskRunner> io_task_runner,
@@ -140,6 +147,12 @@ class DesktopSessionAgent
// Sends a message to the network process.
void SendToNetwork(IPC::Message* message);
+ // Posted to |audio_capture_task_runner_| to start the audio capturer.
+ void StartAudioCapturer();
+
+ // Posted to |audio_capture_task_runner_| to stop the audio capturer.
+ void StopAudioCapturer();
+
// Posted to |video_capture_task_runner_| to start the video capturer.
void StartVideoCapturer();
@@ -148,6 +161,10 @@ class DesktopSessionAgent
// Getters providing access to the task runners for platform-specific derived
// classes.
+ scoped_refptr<AutoThreadTaskRunner> audio_capture_task_runner() const {
+ return audio_capture_task_runner_;
+ }
+
scoped_refptr<AutoThreadTaskRunner> caller_task_runner() const {
return caller_task_runner_;
}
@@ -169,6 +186,9 @@ class DesktopSessionAgent
}
private:
+ // Task runner dedicated to running methods of |audio_capturer_|.
+ scoped_refptr<AutoThreadTaskRunner> audio_capture_task_runner_;
+
// Task runner on which public methods of this class should be called.
scoped_refptr<AutoThreadTaskRunner> caller_task_runner_;
@@ -181,6 +201,9 @@ class DesktopSessionAgent
// Task runner dedicated to running methods of |video_capturer_|.
scoped_refptr<AutoThreadTaskRunner> video_capture_task_runner_;
+ // Captures audio output.
+ scoped_ptr<AudioCapturer> audio_capturer_;
+
base::WeakPtr<Delegate> delegate_;
// Provides a user interface allowing the local user to close the connection.
diff --git a/remoting/host/desktop_session_agent_posix.cc b/remoting/host/desktop_session_agent_posix.cc
index 0d4f8b2..b0adc27 100644
--- a/remoting/host/desktop_session_agent_posix.cc
+++ b/remoting/host/desktop_session_agent_posix.cc
@@ -23,6 +23,7 @@ namespace remoting {
class DesktopSessionAgentPosix : public DesktopSessionAgent {
public:
DesktopSessionAgentPosix(
+ scoped_refptr<AutoThreadTaskRunner> audio_capture_task_runner,
scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
scoped_refptr<AutoThreadTaskRunner> input_task_runner,
scoped_refptr<AutoThreadTaskRunner> io_task_runner,
@@ -41,11 +42,13 @@ class DesktopSessionAgentPosix : public DesktopSessionAgent {
};
DesktopSessionAgentPosix::DesktopSessionAgentPosix(
+ scoped_refptr<AutoThreadTaskRunner> audio_capture_task_runner,
scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
scoped_refptr<AutoThreadTaskRunner> input_task_runner,
scoped_refptr<AutoThreadTaskRunner> io_task_runner,
scoped_refptr<AutoThreadTaskRunner> video_capture_task_runner)
- : DesktopSessionAgent(caller_task_runner, input_task_runner, io_task_runner,
+ : DesktopSessionAgent(audio_capture_task_runner, caller_task_runner,
+ input_task_runner, io_task_runner,
video_capture_task_runner) {
}
@@ -99,12 +102,14 @@ scoped_ptr<EventExecutor> DesktopSessionAgentPosix::CreateEventExecutor() {
// static
scoped_refptr<DesktopSessionAgent> DesktopSessionAgent::Create(
+ scoped_refptr<AutoThreadTaskRunner> audio_capture_task_runner,
scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
scoped_refptr<AutoThreadTaskRunner> input_task_runner,
scoped_refptr<AutoThreadTaskRunner> io_task_runner,
scoped_refptr<AutoThreadTaskRunner> video_capture_task_runner) {
return scoped_refptr<DesktopSessionAgent>(
- new DesktopSessionAgentPosix(caller_task_runner, input_task_runner,
+ new DesktopSessionAgentPosix(audio_capture_task_runner,
+ caller_task_runner, input_task_runner,
io_task_runner, video_capture_task_runner));
}
diff --git a/remoting/host/desktop_session_agent_win.cc b/remoting/host/desktop_session_agent_win.cc
index c67343d..ac254a4 100644
--- a/remoting/host/desktop_session_agent_win.cc
+++ b/remoting/host/desktop_session_agent_win.cc
@@ -26,6 +26,7 @@ namespace remoting {
class DesktopSessionAgentWin : public DesktopSessionAgent {
public:
DesktopSessionAgentWin(
+ scoped_refptr<AutoThreadTaskRunner> audio_capture_task_runner,
scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
scoped_refptr<AutoThreadTaskRunner> input_task_runner,
scoped_refptr<AutoThreadTaskRunner> io_task_runner,
@@ -48,11 +49,13 @@ class DesktopSessionAgentWin : public DesktopSessionAgent {
};
DesktopSessionAgentWin::DesktopSessionAgentWin(
+ scoped_refptr<AutoThreadTaskRunner> audio_capture_task_runner,
scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
scoped_refptr<AutoThreadTaskRunner> input_task_runner,
scoped_refptr<AutoThreadTaskRunner> io_task_runner,
scoped_refptr<AutoThreadTaskRunner> video_capture_task_runner)
- : DesktopSessionAgent(caller_task_runner,
+ : DesktopSessionAgent(audio_capture_task_runner,
+ caller_task_runner,
input_task_runner,
io_task_runner,
video_capture_task_runner) {
@@ -114,13 +117,14 @@ void DesktopSessionAgentWin::InjectSas() {
// static
scoped_refptr<DesktopSessionAgent> DesktopSessionAgent::Create(
+ scoped_refptr<AutoThreadTaskRunner> audio_capture_task_runner,
scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
scoped_refptr<AutoThreadTaskRunner> input_task_runner,
scoped_refptr<AutoThreadTaskRunner> io_task_runner,
scoped_refptr<AutoThreadTaskRunner> video_capture_task_runner) {
return scoped_refptr<DesktopSessionAgent>(new DesktopSessionAgentWin(
- caller_task_runner, input_task_runner, io_task_runner,
- video_capture_task_runner));
+ audio_capture_task_runner, caller_task_runner, input_task_runner,
+ io_task_runner, video_capture_task_runner));
}
} // namespace remoting
diff --git a/remoting/host/desktop_session_proxy.cc b/remoting/host/desktop_session_proxy.cc
index 3f2f62f..59a567f 100644
--- a/remoting/host/desktop_session_proxy.cc
+++ b/remoting/host/desktop_session_proxy.cc
@@ -14,7 +14,9 @@
#include "remoting/host/audio_capturer.h"
#include "remoting/host/chromoting_messages.h"
#include "remoting/host/client_session.h"
+#include "remoting/host/ipc_audio_capturer.h"
#include "remoting/host/ipc_video_frame_capturer.h"
+#include "remoting/proto/audio.pb.h"
#include "remoting/proto/control.pb.h"
#include "remoting/proto/event.pb.h"
@@ -25,10 +27,13 @@
namespace remoting {
DesktopSessionProxy::DesktopSessionProxy(
+ scoped_refptr<base::SingleThreadTaskRunner> audio_capture_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> video_capture_task_runner)
- : caller_task_runner_(caller_task_runner),
+ : audio_capture_task_runner_(audio_capture_task_runner),
+ caller_task_runner_(caller_task_runner),
video_capture_task_runner_(video_capture_task_runner),
+ audio_capturer_(NULL),
pending_capture_frame_requests_(0),
video_capturer_(NULL) {
DCHECK(caller_task_runner_->BelongsToCurrentThread());
@@ -39,6 +44,8 @@ bool DesktopSessionProxy::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(DesktopSessionProxy, message)
+ IPC_MESSAGE_HANDLER(ChromotingDesktopNetworkMsg_AudioPacket,
+ OnAudioPacket)
IPC_MESSAGE_HANDLER(ChromotingDesktopNetworkMsg_CaptureCompleted,
OnCaptureCompleted)
IPC_MESSAGE_HANDLER(ChromotingDesktopNetworkMsg_CursorShapeChanged,
@@ -229,6 +236,19 @@ void DesktopSessionProxy::CaptureFrame() {
SendToDesktop(new ChromotingNetworkDesktopMsg_CaptureFrame());
}
+void DesktopSessionProxy::StartAudioCapturer(IpcAudioCapturer* audio_capturer) {
+ DCHECK(audio_capture_task_runner_->BelongsToCurrentThread());
+ DCHECK(audio_capturer_ == NULL);
+
+ audio_capturer_ = audio_capturer;
+}
+
+void DesktopSessionProxy::StopAudioCapturer() {
+ DCHECK(audio_capture_task_runner_->BelongsToCurrentThread());
+
+ audio_capturer_ = NULL;
+}
+
void DesktopSessionProxy::StartVideoCapturer(
IpcVideoFrameCapturer* video_capturer) {
DCHECK(video_capture_task_runner_->BelongsToCurrentThread());
@@ -258,6 +278,20 @@ scoped_refptr<SharedBuffer> DesktopSessionProxy::GetSharedBuffer(int id) {
}
}
+void DesktopSessionProxy::OnAudioPacket(const std::string& serialized_packet) {
+ DCHECK(caller_task_runner_->BelongsToCurrentThread());
+
+ // Parse the serialized audio packet. No further validation is done since
+ // the message was send by more privileged process.
+ scoped_ptr<AudioPacket> packet(new AudioPacket());
+ if (!packet->ParseFromString(serialized_packet)) {
+ LOG(ERROR) << "Failed to parse AudioPacket.";
+ return;
+ }
+
+ PostAudioPacket(packet.Pass());
+}
+
void DesktopSessionProxy::OnCreateSharedBuffer(
int id,
IPC::PlatformFileForTransit handle,
@@ -355,6 +389,18 @@ void DesktopSessionProxy::OnInjectClipboardEvent(
client_clipboard_->InjectClipboardEvent(event);
}
+void DesktopSessionProxy::PostAudioPacket(scoped_ptr<AudioPacket> packet) {
+ if (!audio_capture_task_runner_->BelongsToCurrentThread()) {
+ audio_capture_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&DesktopSessionProxy::PostAudioPacket,
+ this, base::Passed(&packet)));
+ return;
+ }
+
+ if (audio_capturer_)
+ audio_capturer_->OnAudioPacket(packet.Pass());
+}
+
void DesktopSessionProxy::PostCaptureCompleted(
scoped_refptr<CaptureData> capture_data) {
if (!video_capture_task_runner_->BelongsToCurrentThread()) {
diff --git a/remoting/host/desktop_session_proxy.h b/remoting/host/desktop_session_proxy.h
index 5c5dab2..fd0d0a7 100644
--- a/remoting/host/desktop_session_proxy.h
+++ b/remoting/host/desktop_session_proxy.h
@@ -36,7 +36,9 @@ struct SerializedCapturedData;
namespace remoting {
+class AudioPacket;
class ClientSession;
+class IpcAudioCapturer;
class IpcVideoFrameCapturer;
// This class routes calls to the DesktopEnvironment's stubs though the IPC
@@ -47,6 +49,7 @@ class DesktopSessionProxy
public IPC::Listener {
public:
DesktopSessionProxy(
+ scoped_refptr<base::SingleThreadTaskRunner> audio_capture_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> video_capture_task_runner);
@@ -78,6 +81,14 @@ class DesktopSessionProxy
void InvalidateRegion(const SkRegion& invalid_region);
void CaptureFrame();
+ // Stores |audio_capturer| to be used to post captured audio packets.
+ // |audio_capturer| must be valid until StopAudioCapturer() is called.
+ void StartAudioCapturer(IpcAudioCapturer* audio_capturer);
+
+ // Clears the cached pointer to the audio capturer. Any packets captured after
+ // StopAudioCapturer() has been called will be silently dropped.
+ void StopAudioCapturer();
+
// Stores |video_capturer| to be used to post captured video frames.
// |video_capturer| must be valid until StopVideoCapturer() is called.
void StartVideoCapturer(IpcVideoFrameCapturer* video_capturer);
@@ -99,6 +110,9 @@ class DesktopSessionProxy
// Returns a shared buffer from the list of known buffers.
scoped_refptr<SharedBuffer> GetSharedBuffer(int id);
+ // Handles AudioPacket notification from the desktop session agent.
+ void OnAudioPacket(const std::string& serialized_packet);
+
// Registers a new shared buffer created by the desktop process.
void OnCreateSharedBuffer(int id,
IPC::PlatformFileForTransit handle,
@@ -116,6 +130,10 @@ class DesktopSessionProxy
// Handles InjectClipboardEvent request from the desktop integration process.
void OnInjectClipboardEvent(const std::string& serialized_event);
+ // Posted to |audio_capture_task_runner_| to pass a captured audio packet back
+ // to |audio_capturer_|.
+ void PostAudioPacket(scoped_ptr<AudioPacket> packet);
+
// Posted to |video_capture_task_runner_| to pass a captured video frame back
// to |video_capturer_|.
void PostCaptureCompleted(scoped_refptr<CaptureData> capture_data);
@@ -128,13 +146,19 @@ class DesktopSessionProxy
// deleted if the channel is broken.
void SendToDesktop(IPC::Message* message);
+ // Task runner on which methods of |audio_capturer_| will be invoked.
+ scoped_refptr<base::SingleThreadTaskRunner> audio_capture_task_runner_;
+
// Task runner on which public methods of this class should be called (unless
// it is documented otherwise).
scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner_;
- // Task runner on which |video_capturer_delegate_| will be invoked.
+ // Task runner on which methods of |video_capturer_| will be invoked.
scoped_refptr<base::SingleThreadTaskRunner> video_capture_task_runner_;
+ // Points to the audio capturer receiving captured audio packets.
+ IpcAudioCapturer* audio_capturer_;
+
// Points to the client stub passed to StartEventExecutor().
scoped_ptr<protocol::ClipboardStub> client_clipboard_;
diff --git a/remoting/host/ipc_audio_capturer.cc b/remoting/host/ipc_audio_capturer.cc
new file mode 100644
index 0000000..17c478e
--- /dev/null
+++ b/remoting/host/ipc_audio_capturer.cc
@@ -0,0 +1,59 @@
+// Copyright (c) 2012 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 "remoting/host/ipc_audio_capturer.h"
+
+#include "remoting/host/desktop_session_proxy.h"
+#include "remoting/proto/audio.pb.h"
+
+namespace remoting {
+
+IpcAudioCapturer::IpcAudioCapturer(
+ scoped_refptr<DesktopSessionProxy> desktop_session_proxy)
+ : desktop_session_proxy_(desktop_session_proxy) {
+ // The audio capturer is created on the network thread while used on the audio
+ // capture thread. Detach |thread_checker_| from the current thread so that it
+ // will re-attach to the proper thread when Start() is called for the first
+ // time.
+ thread_checker_.DetachFromThread();
+}
+
+IpcAudioCapturer::~IpcAudioCapturer() {
+ DCHECK(callback_.is_null());
+}
+
+bool IpcAudioCapturer::Start(const PacketCapturedCallback& callback) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(callback_.is_null());
+ DCHECK(!callback.is_null());
+
+ callback_ = callback;
+ desktop_session_proxy_->StartAudioCapturer(this);
+
+ return true;
+}
+
+void IpcAudioCapturer::Stop() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(!callback_.is_null());
+
+ desktop_session_proxy_->StopAudioCapturer();
+ callback_.Reset();
+}
+
+bool IpcAudioCapturer::IsStarted() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ return !callback_.is_null();
+}
+
+// Called when an audio packet has been received.
+void IpcAudioCapturer::OnAudioPacket(scoped_ptr<AudioPacket> packet) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(!callback_.is_null());
+
+ callback_.Run(packet.Pass());
+}
+
+} // namespace remoting
diff --git a/remoting/host/ipc_audio_capturer.h b/remoting/host/ipc_audio_capturer.h
new file mode 100644
index 0000000..f6048b4
--- /dev/null
+++ b/remoting/host/ipc_audio_capturer.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2012 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.
+
+#ifndef REMOTING_HOST_IPC_AUDIO_CAPTURER_H_
+#define REMOTING_HOST_IPC_AUDIO_CAPTURER_H_
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/threading/thread_checker.h"
+#include "remoting/host/audio_capturer.h"
+
+namespace remoting {
+
+class AudioPacket;
+class DesktopSessionProxy;
+
+class IpcAudioCapturer : public AudioCapturer {
+ public:
+ IpcAudioCapturer(scoped_refptr<DesktopSessionProxy> desktop_session_proxy);
+ virtual ~IpcAudioCapturer();
+
+ // AudioCapturer interface.
+ virtual bool Start(const PacketCapturedCallback& callback) OVERRIDE;
+ virtual void Stop() OVERRIDE;
+ virtual bool IsStarted() OVERRIDE;
+
+ // Called by DesktopSessionProxy when an audio packet was received.
+ void OnAudioPacket(scoped_ptr<AudioPacket> packet);
+
+ private:
+ // Invoked when an audio packet was received.
+ PacketCapturedCallback callback_;
+
+ // Wraps the IPC channel to the desktop session agent.
+ scoped_refptr<DesktopSessionProxy> desktop_session_proxy_;
+
+ base::ThreadChecker thread_checker_;
+
+ DISALLOW_COPY_AND_ASSIGN(IpcAudioCapturer);
+};
+
+} // namespace remoting
+
+#endif // REMOTING_HOST_IPC_AUDIO_CAPTURER_H_
diff --git a/remoting/host/ipc_desktop_environment.cc b/remoting/host/ipc_desktop_environment.cc
index 6229adb..699f06a 100644
--- a/remoting/host/ipc_desktop_environment.cc
+++ b/remoting/host/ipc_desktop_environment.cc
@@ -19,6 +19,7 @@
#include "remoting/host/desktop_session_connector.h"
#include "remoting/host/desktop_session_proxy.h"
#include "remoting/host/event_executor.h"
+#include "remoting/host/ipc_audio_capturer.h"
#include "remoting/host/ipc_event_executor.h"
#include "remoting/host/ipc_video_frame_capturer.h"
@@ -35,7 +36,8 @@ IpcDesktopEnvironment::IpcDesktopEnvironment(
DesktopSessionConnector* desktop_session_connector,
scoped_refptr<DesktopSessionProxy> desktop_session_proxy)
: DesktopEnvironment(
- AudioCapturer::Create(),
+ scoped_ptr<AudioCapturer>(
+ new IpcAudioCapturer(desktop_session_proxy)),
scoped_ptr<EventExecutor>(
new IpcEventExecutor(desktop_session_proxy)),
scoped_ptr<VideoFrameCapturer>(
diff --git a/remoting/host/ipc_desktop_environment_factory.cc b/remoting/host/ipc_desktop_environment_factory.cc
index 2996ec5..250b4f4 100644
--- a/remoting/host/ipc_desktop_environment_factory.cc
+++ b/remoting/host/ipc_desktop_environment_factory.cc
@@ -22,12 +22,14 @@ namespace remoting {
IpcDesktopEnvironmentFactory::IpcDesktopEnvironmentFactory(
IPC::ChannelProxy* daemon_channel,
+ scoped_refptr<base::SingleThreadTaskRunner> audio_capture_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> input_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> network_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> video_capture_task_runner)
: DesktopEnvironmentFactory(input_task_runner, ui_task_runner),
daemon_channel_(daemon_channel),
+ audio_capture_task_runner_(audio_capture_task_runner),
network_task_runner_(network_task_runner),
video_capture_task_runner_(video_capture_task_runner),
next_id_(0) {
@@ -40,7 +42,8 @@ scoped_ptr<DesktopEnvironment> IpcDesktopEnvironmentFactory::Create() {
DCHECK(network_task_runner_->BelongsToCurrentThread());
scoped_refptr<DesktopSessionProxy> desktop_session_proxy(
- new DesktopSessionProxy(network_task_runner_,
+ new DesktopSessionProxy(audio_capture_task_runner_,
+ network_task_runner_,
video_capture_task_runner_));
return scoped_ptr<DesktopEnvironment>(new IpcDesktopEnvironment(
diff --git a/remoting/host/ipc_desktop_environment_factory.h b/remoting/host/ipc_desktop_environment_factory.h
index 435ea6d..17ee314 100644
--- a/remoting/host/ipc_desktop_environment_factory.h
+++ b/remoting/host/ipc_desktop_environment_factory.h
@@ -31,6 +31,7 @@ class IpcDesktopEnvironmentFactory
// relevant task runners. |daemon_channel| must outlive this object.
IpcDesktopEnvironmentFactory(
IPC::ChannelProxy* daemon_channel,
+ scoped_refptr<base::SingleThreadTaskRunner> audio_capture_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> input_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> network_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
@@ -54,6 +55,9 @@ class IpcDesktopEnvironmentFactory
// IPC channel connected to the daemon process.
IPC::ChannelProxy* daemon_channel_;
+ // Task runner used to run the audio capturer.
+ scoped_refptr<base::SingleThreadTaskRunner> audio_capture_task_runner_;
+
// Task runner used to service calls to the DesktopSessionConnector APIs.
scoped_refptr<base::SingleThreadTaskRunner> network_task_runner_;
diff --git a/remoting/host/remoting_me2me_host.cc b/remoting/host/remoting_me2me_host.cc
index 8d1d349..65bd8cc 100644
--- a/remoting/host/remoting_me2me_host.cc
+++ b/remoting/host/remoting_me2me_host.cc
@@ -570,6 +570,7 @@ void HostProcess::StartOnUiThread() {
IpcDesktopEnvironmentFactory* desktop_environment_factory =
new IpcDesktopEnvironmentFactory(
daemon_channel_.get(),
+ context_->audio_task_runner(),
context_->input_task_runner(),
context_->network_task_runner(),
context_->ui_task_runner(),
diff --git a/remoting/remoting.gyp b/remoting/remoting.gyp
index 1da423f..9b315d1 100644
--- a/remoting/remoting.gyp
+++ b/remoting/remoting.gyp
@@ -397,6 +397,8 @@
'host/host_user_interface.h',
'host/in_memory_host_config.cc',
'host/in_memory_host_config.h',
+ 'host/ipc_audio_capturer.cc',
+ 'host/ipc_audio_capturer.h',
'host/ipc_constants.cc',
'host/ipc_constants.h',
'host/ipc_desktop_environment_factory.cc',