summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkxing@chromium.org <kxing@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-07-02 23:24:21 +0000
committerkxing@chromium.org <kxing@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-07-02 23:24:21 +0000
commitf8705114c9171db859e1884cc8b6f9e7f5d7f411 (patch)
treebebca04a58a7af42be4bf1994bbd978d135f8b2c
parentb53913c4601229c87fe010aafbb20d258198e2db (diff)
downloadchromium_src-f8705114c9171db859e1884cc8b6f9e7f5d7f411.zip
chromium_src-f8705114c9171db859e1884cc8b6f9e7f5d7f411.tar.gz
chromium_src-f8705114c9171db859e1884cc8b6f9e7f5d7f411.tar.bz2
Client code for playing back audio
Review URL: https://chromiumcodereview.appspot.com/10699030 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@145217 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--remoting/client/audio_player.h38
-rw-r--r--remoting/client/chromoting_client.cc10
-rw-r--r--remoting/client/chromoting_client.h7
-rw-r--r--remoting/client/plugin/chromoting_instance.cc5
-rw-r--r--remoting/client/plugin/chromoting_instance.h2
-rw-r--r--remoting/client/plugin/pepper_audio_player.cc113
-rw-r--r--remoting/client/plugin/pepper_audio_player.h67
-rw-r--r--remoting/remoting.gyp3
8 files changed, 241 insertions, 4 deletions
diff --git a/remoting/client/audio_player.h b/remoting/client/audio_player.h
new file mode 100644
index 0000000..eed8786
--- /dev/null
+++ b/remoting/client/audio_player.h
@@ -0,0 +1,38 @@
+// 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_CLIENT_AUDIO_PLAYER_H_
+#define REMOTING_CLIENT_AUDIO_PLAYER_H_
+
+#include "base/memory/scoped_ptr.h"
+
+namespace pp {
+class Instance;
+} // namespace pp
+
+namespace remoting {
+
+class AudioPacket;
+
+class AudioPlayer {
+ public:
+ virtual ~AudioPlayer() {}
+
+ // Returns true if successful, false otherwise.
+ virtual bool Start() = 0;
+
+ virtual void ProcessAudioPacket(scoped_ptr<AudioPacket> packet) = 0;
+
+ virtual bool IsRunning() const = 0;
+
+ protected:
+ AudioPlayer() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AudioPlayer);
+};
+
+} // namespace remoting
+
+#endif // REMOTING_CLIENT_AUDIO_PLAYER_H_
diff --git a/remoting/client/chromoting_client.cc b/remoting/client/chromoting_client.cc
index f118667..9d9df67 100644
--- a/remoting/client/chromoting_client.cc
+++ b/remoting/client/chromoting_client.cc
@@ -5,10 +5,12 @@
#include "remoting/client/chromoting_client.h"
#include "base/bind.h"
+#include "remoting/client/audio_player.h"
#include "remoting/client/chromoting_view.h"
#include "remoting/client/client_context.h"
#include "remoting/client/rectangle_update_decoder.h"
#include "remoting/proto/audio.pb.h"
+#include "remoting/proto/video.pb.h"
#include "remoting/protocol/authentication_method.h"
#include "remoting/protocol/connection_to_host.h"
#include "remoting/protocol/negotiating_authenticator.h"
@@ -32,12 +34,14 @@ ChromotingClient::ChromotingClient(
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
protocol::ConnectionToHost* connection,
ChromotingView* view,
- RectangleUpdateDecoder* rectangle_decoder)
+ RectangleUpdateDecoder* rectangle_decoder,
+ AudioPlayer* audio_player)
: config_(config),
task_runner_(task_runner),
connection_(connection),
view_(view),
rectangle_decoder_(rectangle_decoder),
+ audio_player_(audio_player),
packet_being_processed_(false),
last_sequence_number_(0),
weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
@@ -143,7 +147,9 @@ int ChromotingClient::GetPendingVideoPackets() {
void ChromotingClient::ProcessAudioPacket(scoped_ptr<AudioPacket> packet,
const base::Closure& done) {
- // TODO(kxing): Playback audio.
+ audio_player_->ProcessAudioPacket(packet.Pass());
+ if (!audio_player_->IsRunning() && connection_->config().is_audio_enabled())
+ audio_player_->Start();
done.Run();
}
diff --git a/remoting/client/chromoting_client.h b/remoting/client/chromoting_client.h
index 03ef41c..d15073f 100644
--- a/remoting/client/chromoting_client.h
+++ b/remoting/client/chromoting_client.h
@@ -10,6 +10,7 @@
#include <list>
#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/time.h"
#include "remoting/client/client_config.h"
@@ -33,6 +34,7 @@ namespace protocol {
class TransportFactory;
} // namespace protocol
+class AudioPlayer;
class RectangleUpdateDecoder;
// TODO(sergeyu): Move VideoStub implementation to RectangleUpdateDecoder.
@@ -46,7 +48,9 @@ class ChromotingClient : public protocol::ConnectionToHost::HostEventCallback,
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
protocol::ConnectionToHost* connection,
ChromotingView* view,
- RectangleUpdateDecoder* rectangle_decoder);
+ RectangleUpdateDecoder* rectangle_decoder,
+ AudioPlayer* audio_player);
+
virtual ~ChromotingClient();
// Start/stop the client. Must be called on the main thread.
@@ -108,6 +112,7 @@ class ChromotingClient : public protocol::ConnectionToHost::HostEventCallback,
protocol::ConnectionToHost* connection_;
ChromotingView* view_;
RectangleUpdateDecoder* rectangle_decoder_;
+ AudioPlayer* audio_player_;
// If non-NULL, this is called when the client is done.
base::Closure client_done_;
diff --git a/remoting/client/plugin/chromoting_instance.cc b/remoting/client/plugin/chromoting_instance.cc
index fb3da91..77cd55f 100644
--- a/remoting/client/plugin/chromoting_instance.cc
+++ b/remoting/client/plugin/chromoting_instance.cc
@@ -31,6 +31,7 @@
#include "remoting/client/client_config.h"
#include "remoting/client/chromoting_client.h"
#include "remoting/client/frame_consumer_proxy.h"
+#include "remoting/client/plugin/pepper_audio_player.h"
#include "remoting/client/plugin/pepper_input_handler.h"
#include "remoting/client/plugin/pepper_port_allocator.h"
#include "remoting/client/plugin/pepper_view.h"
@@ -207,6 +208,7 @@ bool ChromotingInstance::Init(uint32_t argc,
context_.decode_task_runner(), consumer_proxy);
view_.reset(new PepperView(this, &context_, rectangle_decoder_.get()));
consumer_proxy->Attach(view_->AsWeakPtr());
+ audio_player_.reset(new PepperAudioPlayer(this));
return true;
}
@@ -379,7 +381,8 @@ void ChromotingInstance::Connect(const ClientConfig& config) {
host_connection_.reset(new protocol::ConnectionToHost(true));
client_.reset(new ChromotingClient(config, context_.main_task_runner(),
host_connection_.get(), view_.get(),
- rectangle_decoder_.get()));
+ rectangle_decoder_.get(),
+ audio_player_.get()));
// Construct the input pipeline
mouse_input_filter_.reset(
diff --git a/remoting/client/plugin/chromoting_instance.h b/remoting/client/plugin/chromoting_instance.h
index 5c8fa487..dbc840d 100644
--- a/remoting/client/plugin/chromoting_instance.h
+++ b/remoting/client/plugin/chromoting_instance.h
@@ -55,6 +55,7 @@ class ChromotingClient;
class ChromotingStats;
class ClientContext;
class FrameConsumerProxy;
+class PepperAudioPlayer;
class PepperInputHandler;
class PepperView;
class PepperXmppProxy;
@@ -211,6 +212,7 @@ class ChromotingInstance :
#endif
KeyEventMapper key_mapper_;
scoped_ptr<PepperInputHandler> input_handler_;
+ scoped_ptr<PepperAudioPlayer> audio_player_;
scoped_ptr<ChromotingClient> client_;
// XmppProxy is a refcounted interface used to perform thread-switching and
diff --git a/remoting/client/plugin/pepper_audio_player.cc b/remoting/client/plugin/pepper_audio_player.cc
new file mode 100644
index 0000000..bf67436
--- /dev/null
+++ b/remoting/client/plugin/pepper_audio_player.cc
@@ -0,0 +1,113 @@
+// 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/client/plugin/pepper_audio_player.h"
+
+#include <algorithm>
+
+#include "base/stl_util.h"
+#include "remoting/proto/audio.pb.h"
+
+namespace {
+// Constants used to create an audio configuration resource.
+// The sample count we will request from the browser.
+const uint32_t kSampleFrameCount = 4096u;
+// The number of channels in the audio stream (only supporting stereo audio
+// for now).
+const uint32_t kChannels = 2u;
+const int kSampleSizeBytes = 2;
+} // namespace
+
+namespace remoting {
+
+bool PepperAudioPlayer::IsRunning() const {
+ return running_;
+}
+
+PepperAudioPlayer::PepperAudioPlayer(pp::Instance* instance)
+ : samples_per_frame_(kSampleFrameCount),
+ bytes_consumed_(0),
+ running_(false) {
+ // Ask the browser/device for an appropriate sample frame count size.
+ samples_per_frame_ =
+ pp::AudioConfig::RecommendSampleFrameCount(instance,
+ PP_AUDIOSAMPLERATE_44100,
+ kSampleFrameCount);
+
+ // Create an audio configuration resource.
+ pp::AudioConfig audio_config = pp::AudioConfig(instance,
+ PP_AUDIOSAMPLERATE_44100,
+ samples_per_frame_);
+
+ // Create an audio resource.
+ audio_ = pp::Audio(instance, audio_config, PepperAudioPlayerCallback, this);
+}
+
+PepperAudioPlayer::~PepperAudioPlayer() { }
+
+bool PepperAudioPlayer::Start() {
+ running_ = audio_.StartPlayback();
+ return running_;
+}
+
+void PepperAudioPlayer::ProcessAudioPacket(scoped_ptr<AudioPacket> packet) {
+ // TODO(kxing): Limit the size of the queue so that latency doesn't grow
+ // too large.
+ if (packet->data().size() % (kChannels * kSampleSizeBytes) != 0) {
+ LOG(WARNING) << "Received corrupted packet.";
+ return;
+ }
+ base::AutoLock auto_lock(lock_);
+
+ queued_packets_.push_back(packet.release());
+}
+
+// static
+void PepperAudioPlayer::PepperAudioPlayerCallback(void* samples,
+ uint32_t buffer_size,
+ void* data) {
+ PepperAudioPlayer* audio_player = static_cast<PepperAudioPlayer*>(data);
+ audio_player->FillWithSamples(samples, buffer_size);
+}
+
+void PepperAudioPlayer::FillWithSamples(void* samples, uint32_t buffer_size) {
+ base::AutoLock auto_lock(lock_);
+
+ const size_t bytes_needed = kChannels * samples_per_frame_ *
+ kSampleSizeBytes;
+
+ // Make sure we don't overrun the buffer.
+ CHECK_EQ(buffer_size, bytes_needed);
+
+ char* next_sample = static_cast<char*>(samples);
+ size_t bytes_extracted = 0;
+
+ while (bytes_extracted < bytes_needed) {
+ // Check if we've run out of samples for this packet.
+ if (queued_packets_.empty()) {
+ memset(next_sample, 0, bytes_needed - bytes_extracted);
+ return;
+ }
+
+ // Pop off the packet if we've already consumed all its bytes.
+ if (queued_packets_.front()->data().size() == bytes_consumed_) {
+ delete queued_packets_.front();
+ queued_packets_.pop_front();
+ bytes_consumed_ = 0;
+ continue;
+ }
+
+ const std::string& packet_data = queued_packets_.front()->data();
+ size_t bytes_to_copy = std::min(
+ packet_data.size() - bytes_consumed_,
+ bytes_needed - bytes_extracted);
+ memcpy(next_sample, packet_data.data() + bytes_consumed_, bytes_to_copy);
+
+ next_sample += bytes_to_copy;
+ bytes_consumed_ += bytes_to_copy;
+ bytes_extracted += bytes_to_copy;
+ }
+}
+
+} // namespace remoting
diff --git a/remoting/client/plugin/pepper_audio_player.h b/remoting/client/plugin/pepper_audio_player.h
new file mode 100644
index 0000000..925b0dc
--- /dev/null
+++ b/remoting/client/plugin/pepper_audio_player.h
@@ -0,0 +1,67 @@
+// 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_CLIENT_PLUGIN_PEPPER_AUDIO_PLAYER_H_
+#define REMOTING_CLIENT_PLUGIN_PEPPER_AUDIO_PLAYER_H_
+
+#include <list>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/ref_counted.h"
+#include "base/synchronization/lock.h"
+#include "ppapi/cpp/audio.h"
+#include "ppapi/cpp/instance.h"
+#include "remoting/client/audio_player.h"
+
+namespace remoting {
+
+class AudioPacket;
+
+class PepperAudioPlayer : public AudioPlayer {
+ public:
+ explicit PepperAudioPlayer(pp::Instance* instance);
+ virtual ~PepperAudioPlayer();
+
+ // Returns true if successful, false otherwise.
+ virtual bool Start() OVERRIDE;
+
+ virtual void ProcessAudioPacket(scoped_ptr<AudioPacket> packet) OVERRIDE;
+
+ virtual bool IsRunning() const OVERRIDE;
+
+ private:
+ typedef std::list<AudioPacket*> AudioPacketQueue;
+
+ // Function called by the browser when it needs more audio samples.
+ static void PepperAudioPlayerCallback(void* samples,
+ uint32_t buffer_size,
+ void* data);
+
+ void FillWithSamples(void* samples, uint32_t buffer_size);
+
+ pp::Audio audio_;
+
+ // The count of sample frames per channel in an audio buffer.
+ uint32_t samples_per_frame_;
+
+ // Protects |queued_packets_| and |bytes_consumed_|.
+ // This is necessary to prevent races,
+ // because Pepper will callback on a separate thread.
+ base::Lock lock_;
+
+ AudioPacketQueue queued_packets_;
+
+ // The number of bytes from |queued_packets_| that have been consumed.
+ size_t bytes_consumed_;
+
+ bool running_;
+
+ DISALLOW_COPY_AND_ASSIGN(PepperAudioPlayer);
+};
+
+} // namespace remoting
+
+#endif // REMOTING_CLIENT_PLUGIN_PEPPER_AUDIO_PLAYER_H_
diff --git a/remoting/remoting.gyp b/remoting/remoting.gyp
index 4a8d8064..fddc6d1 100644
--- a/remoting/remoting.gyp
+++ b/remoting/remoting.gyp
@@ -833,6 +833,8 @@
'client/plugin/chromoting_instance.h',
'client/plugin/mac_key_event_processor.cc',
'client/plugin/mac_key_event_processor.h',
+ 'client/plugin/pepper_audio_player.cc',
+ 'client/plugin/pepper_audio_player.h',
'client/plugin/pepper_entrypoints.cc',
'client/plugin/pepper_entrypoints.h',
'client/plugin/pepper_input_handler.cc',
@@ -1288,6 +1290,7 @@
'remoting_protocol',
],
'sources': [
+ 'client/audio_player.h',
'client/chromoting_client.cc',
'client/chromoting_client.h',
'client/chromoting_stats.cc',