summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--remoting/client/chromoting_client.cc110
-rw-r--r--remoting/client/chromoting_client.h39
-rw-r--r--remoting/client/plugin/chromoting_instance.cc5
-rw-r--r--remoting/client/rectangle_update_decoder.cc154
-rw-r--r--remoting/client/rectangle_update_decoder.h73
5 files changed, 206 insertions, 175 deletions
diff --git a/remoting/client/chromoting_client.cc b/remoting/client/chromoting_client.cc
index 7c05d83..3bdc7b6 100644
--- a/remoting/client/chromoting_client.cc
+++ b/remoting/client/chromoting_client.cc
@@ -22,14 +22,6 @@ namespace remoting {
using protocol::AuthenticationMethod;
-ChromotingClient::QueuedVideoPacket::QueuedVideoPacket(
- scoped_ptr<VideoPacket> packet, const base::Closure& done)
- : packet(packet.release()), done(done) {
-}
-
-ChromotingClient::QueuedVideoPacket::~QueuedVideoPacket() {
-}
-
ChromotingClient::ChromotingClient(
const ClientConfig& config,
ClientContext* client_context,
@@ -42,8 +34,6 @@ ChromotingClient::ChromotingClient(
connection_(connection),
user_interface_(user_interface),
rectangle_decoder_(rectangle_decoder),
- packet_being_processed_(false),
- last_sequence_number_(0),
weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
audio_decode_scheduler_.reset(new AudioDecodeScheduler(
client_context->main_task_runner(),
@@ -69,7 +59,8 @@ void ChromotingClient::Start(
connection_->Connect(xmpp_proxy, config_.local_jid, config_.host_jid,
config_.host_public_key, transport_factory.Pass(),
- authenticator.Pass(), this, this, this, this,
+ authenticator.Pass(), this, this, this,
+ rectangle_decoder_,
audio_decode_scheduler_.get());
}
@@ -77,11 +68,7 @@ void ChromotingClient::Stop(const base::Closure& shutdown_task) {
DCHECK(task_runner_->BelongsToCurrentThread());
// Drop all pending packets.
- while(!received_packets_.empty()) {
- delete received_packets_.front().packet;
- received_packets_.front().done.Run();
- received_packets_.pop_front();
- }
+ rectangle_decoder_->DropAllPackets();
connection_->Disconnect(base::Bind(&ChromotingClient::OnDisconnected,
weak_ptr_, shutdown_task));
@@ -93,7 +80,7 @@ void ChromotingClient::OnDisconnected(const base::Closure& shutdown_task) {
ChromotingStats* ChromotingClient::GetStats() {
DCHECK(task_runner_->BelongsToCurrentThread());
- return &stats_;
+ return rectangle_decoder_->GetStats();
}
void ChromotingClient::InjectClipboardEvent(
@@ -107,70 +94,6 @@ void ChromotingClient::SetCursorShape(
user_interface_->GetCursorShapeStub()->SetCursorShape(cursor_shape);
}
-void ChromotingClient::ProcessVideoPacket(scoped_ptr<VideoPacket> packet,
- const base::Closure& done) {
- DCHECK(task_runner_->BelongsToCurrentThread());
-
- // If the video packet is empty then drop it. Empty packets are used to
- // maintain activity on the network.
- if (!packet->has_data() || packet->data().size() == 0) {
- done.Run();
- return;
- }
-
- // Add one frame to the counter.
- stats_.video_frame_rate()->Record(1);
-
- // Record other statistics received from host.
- stats_.video_bandwidth()->Record(packet->data().size());
- if (packet->has_capture_time_ms())
- stats_.video_capture_ms()->Record(packet->capture_time_ms());
- if (packet->has_encode_time_ms())
- stats_.video_encode_ms()->Record(packet->encode_time_ms());
- if (packet->has_client_sequence_number() &&
- packet->client_sequence_number() > last_sequence_number_) {
- last_sequence_number_ = packet->client_sequence_number();
- base::TimeDelta round_trip_latency =
- base::Time::Now() -
- base::Time::FromInternalValue(packet->client_sequence_number());
- stats_.round_trip_ms()->Record(round_trip_latency.InMilliseconds());
- }
-
- received_packets_.push_back(QueuedVideoPacket(packet.Pass(), done));
- if (!packet_being_processed_)
- DispatchPacket();
-}
-
-int ChromotingClient::GetPendingVideoPackets() {
- DCHECK(task_runner_->BelongsToCurrentThread());
- return received_packets_.size();
-}
-
-void ChromotingClient::DispatchPacket() {
- DCHECK(task_runner_->BelongsToCurrentThread());
- CHECK(!packet_being_processed_);
-
- if (received_packets_.empty()) {
- // Nothing to do!
- return;
- }
-
- scoped_ptr<VideoPacket> packet(received_packets_.front().packet);
- received_packets_.front().packet = NULL;
- packet_being_processed_ = true;
-
- // Measure the latency between the last packet being received and presented.
- bool last_packet = (packet->flags() & VideoPacket::LAST_PACKET) != 0;
- base::Time decode_start;
- if (last_packet)
- decode_start = base::Time::Now();
-
- rectangle_decoder_->DecodePacket(
- packet.Pass(),
- base::Bind(&ChromotingClient::OnPacketDone, base::Unretained(this),
- last_packet, decode_start));
-}
-
void ChromotingClient::OnConnectionState(
protocol::ConnectionToHost::State state,
protocol::ErrorCode error) {
@@ -186,31 +109,6 @@ void ChromotingClient::OnConnectionReady(bool ready) {
user_interface_->OnConnectionReady(ready);
}
-void ChromotingClient::OnPacketDone(bool last_packet,
- base::Time decode_start) {
- if (!task_runner_->BelongsToCurrentThread()) {
- task_runner_->PostTask(FROM_HERE, base::Bind(
- &ChromotingClient::OnPacketDone, base::Unretained(this),
- last_packet, decode_start));
- return;
- }
-
- // Record the latency between the final packet being received and
- // presented.
- if (last_packet) {
- stats_.video_decode_ms()->Record(
- (base::Time::Now() - decode_start).InMilliseconds());
- }
-
- received_packets_.front().done.Run();
- received_packets_.pop_front();
-
- packet_being_processed_ = false;
-
- // Process the next video packet.
- DispatchPacket();
-}
-
void ChromotingClient::Initialize() {
DCHECK(task_runner_->BelongsToCurrentThread());
diff --git a/remoting/client/chromoting_client.h b/remoting/client/chromoting_client.h
index f2355f1..f826394 100644
--- a/remoting/client/chromoting_client.h
+++ b/remoting/client/chromoting_client.h
@@ -38,10 +38,8 @@ class ClientContext;
class ClientUserInterface;
class RectangleUpdateDecoder;
-// TODO(sergeyu): Move VideoStub implementation to RectangleUpdateDecoder.
class ChromotingClient : public protocol::ConnectionToHost::HostEventCallback,
- public protocol::ClientStub,
- public protocol::VideoStub {
+ public protocol::ClientStub {
public:
// Objects passed in are not owned by this class.
ChromotingClient(const ClientConfig& config,
@@ -75,32 +73,10 @@ class ChromotingClient : public protocol::ConnectionToHost::HostEventCallback,
protocol::ErrorCode error) OVERRIDE;
virtual void OnConnectionReady(bool ready) OVERRIDE;
- // VideoStub implementation.
- virtual void ProcessVideoPacket(scoped_ptr<VideoPacket> packet,
- const base::Closure& done) OVERRIDE;
- virtual int GetPendingVideoPackets() OVERRIDE;
-
private:
- struct QueuedVideoPacket {
- QueuedVideoPacket(scoped_ptr<VideoPacket> packet,
- const base::Closure& done);
- ~QueuedVideoPacket();
- VideoPacket* packet;
- base::Closure done;
- };
-
// Initializes connection.
void Initialize();
- // If a packet is not being processed, dispatches a single message from the
- // |received_packets_| queue.
- void DispatchPacket();
-
- // Callback method when a VideoPacket is processed.
- // If |last_packet| is true then |decode_start| contains the timestamp when
- // the packet will start to be processed.
- void OnPacketDone(bool last_packet, base::Time decode_start);
-
void OnDisconnected(const base::Closure& shutdown_task);
// The following are not owned by this class.
@@ -116,22 +92,9 @@ class ChromotingClient : public protocol::ConnectionToHost::HostEventCallback,
// If non-NULL, this is called when the client is done.
base::Closure client_done_;
- // Contains all video packets that have been received, but have not yet been
- // processed.
- //
- // Used to serialize sending of messages to the client.
- std::list<QueuedVideoPacket> received_packets_;
-
- // True if a message is being processed. Can be used to determine if it is
- // safe to dispatch another message.
- bool packet_being_processed_;
-
// Record the statistics of the connection.
ChromotingStats stats_;
- // Keep track of the last sequence number bounced back from the host.
- int64 last_sequence_number_;
-
// WeakPtr used to avoid tasks accessing the client after it is deleted.
base::WeakPtrFactory<ChromotingClient> weak_factory_;
base::WeakPtr<ChromotingClient> weak_ptr_;
diff --git a/remoting/client/plugin/chromoting_instance.cc b/remoting/client/plugin/chromoting_instance.cc
index f4be000..a28a8e9 100644
--- a/remoting/client/plugin/chromoting_instance.cc
+++ b/remoting/client/plugin/chromoting_instance.cc
@@ -232,8 +232,9 @@ bool ChromotingInstance::Init(uint32_t argc,
// PepperView with a ref-counted proxy object.
scoped_refptr<FrameConsumerProxy> consumer_proxy =
new FrameConsumerProxy(plugin_task_runner_);
- rectangle_decoder_ = new RectangleUpdateDecoder(
- context_.decode_task_runner(), consumer_proxy);
+ rectangle_decoder_ = new RectangleUpdateDecoder(context_.main_task_runner(),
+ context_.decode_task_runner(),
+ consumer_proxy);
view_.reset(new PepperView(this, &context_, rectangle_decoder_.get()));
consumer_proxy->Attach(view_->AsWeakPtr());
diff --git a/remoting/client/rectangle_update_decoder.cc b/remoting/client/rectangle_update_decoder.cc
index 0fb253b..c7a1404 100644
--- a/remoting/client/rectangle_update_decoder.cc
+++ b/remoting/client/rectangle_update_decoder.cc
@@ -6,7 +6,6 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
-#include "base/callback.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/message_loop_proxy.h"
@@ -24,16 +23,30 @@ using remoting::protocol::SessionConfig;
namespace remoting {
+RectangleUpdateDecoder::QueuedVideoPacket::QueuedVideoPacket(
+ scoped_ptr<VideoPacket> packet,
+ const base::Closure& done)
+ : packet(packet.release()),
+ done(done) {
+}
+
+RectangleUpdateDecoder::QueuedVideoPacket::~QueuedVideoPacket() {
+}
+
RectangleUpdateDecoder::RectangleUpdateDecoder(
- scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> decode_task_runner,
scoped_refptr<FrameConsumerProxy> consumer)
- : task_runner_(task_runner),
+ : main_task_runner_(main_task_runner),
+ decode_task_runner_(decode_task_runner),
consumer_(consumer),
source_size_(SkISize::Make(0, 0)),
source_dpi_(SkIPoint::Make(0, 0)),
view_size_(SkISize::Make(0, 0)),
clip_area_(SkIRect::MakeEmpty()),
- paint_scheduled_(false) {
+ paint_scheduled_(false),
+ packet_being_processed_(false),
+ latest_sequence_number_(0) {
}
RectangleUpdateDecoder::~RectangleUpdateDecoder() {
@@ -55,12 +68,7 @@ void RectangleUpdateDecoder::Initialize(const SessionConfig& config) {
void RectangleUpdateDecoder::DecodePacket(scoped_ptr<VideoPacket> packet,
const base::Closure& done) {
- if (!task_runner_->BelongsToCurrentThread()) {
- task_runner_->PostTask(
- FROM_HERE, base::Bind(&RectangleUpdateDecoder::DecodePacket,
- this, base::Passed(&packet), done));
- return;
- }
+ DCHECK(decode_task_runner_->BelongsToCurrentThread());
base::ScopedClosureRunner done_runner(done);
bool decoder_needs_reset = false;
@@ -109,7 +117,7 @@ void RectangleUpdateDecoder::SchedulePaint() {
if (paint_scheduled_)
return;
paint_scheduled_ = true;
- task_runner_->PostTask(
+ decode_task_runner_->PostTask(
FROM_HERE, base::Bind(&RectangleUpdateDecoder::DoPaint, this));
}
@@ -141,8 +149,8 @@ void RectangleUpdateDecoder::DoPaint() {
}
void RectangleUpdateDecoder::RequestReturnBuffers(const base::Closure& done) {
- if (!task_runner_->BelongsToCurrentThread()) {
- task_runner_->PostTask(
+ if (!decode_task_runner_->BelongsToCurrentThread()) {
+ decode_task_runner_->PostTask(
FROM_HERE, base::Bind(&RectangleUpdateDecoder::RequestReturnBuffers,
this, done));
return;
@@ -158,8 +166,8 @@ void RectangleUpdateDecoder::RequestReturnBuffers(const base::Closure& done) {
}
void RectangleUpdateDecoder::DrawBuffer(pp::ImageData* buffer) {
- if (!task_runner_->BelongsToCurrentThread()) {
- task_runner_->PostTask(
+ if (!decode_task_runner_->BelongsToCurrentThread()) {
+ decode_task_runner_->PostTask(
FROM_HERE, base::Bind(&RectangleUpdateDecoder::DrawBuffer,
this, buffer));
return;
@@ -173,8 +181,8 @@ void RectangleUpdateDecoder::DrawBuffer(pp::ImageData* buffer) {
}
void RectangleUpdateDecoder::InvalidateRegion(const SkRegion& region) {
- if (!task_runner_->BelongsToCurrentThread()) {
- task_runner_->PostTask(
+ if (!decode_task_runner_->BelongsToCurrentThread()) {
+ decode_task_runner_->PostTask(
FROM_HERE, base::Bind(&RectangleUpdateDecoder::InvalidateRegion,
this, region));
return;
@@ -188,8 +196,8 @@ void RectangleUpdateDecoder::InvalidateRegion(const SkRegion& region) {
void RectangleUpdateDecoder::SetOutputSizeAndClip(const SkISize& view_size,
const SkIRect& clip_area) {
- if (!task_runner_->BelongsToCurrentThread()) {
- task_runner_->PostTask(
+ if (!decode_task_runner_->BelongsToCurrentThread()) {
+ decode_task_runner_->PostTask(
FROM_HERE, base::Bind(&RectangleUpdateDecoder::SetOutputSizeAndClip,
this, view_size, clip_area));
return;
@@ -225,4 +233,112 @@ void RectangleUpdateDecoder::SetOutputSizeAndClip(const SkISize& view_size,
}
}
+void RectangleUpdateDecoder::ProcessVideoPacket(scoped_ptr<VideoPacket> packet,
+ const base::Closure& done) {
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
+
+ // If the video packet is empty then drop it. Empty packets are used to
+ // maintain activity on the network.
+ if (!packet->has_data() || packet->data().size() == 0) {
+ done.Run();
+ return;
+ }
+
+ // Add one frame to the counter.
+ stats_.video_frame_rate()->Record(1);
+
+ // Record other statistics received from host.
+ stats_.video_bandwidth()->Record(packet->data().size());
+ if (packet->has_capture_time_ms())
+ stats_.video_capture_ms()->Record(packet->capture_time_ms());
+ if (packet->has_encode_time_ms())
+ stats_.video_encode_ms()->Record(packet->encode_time_ms());
+ if (packet->has_client_sequence_number() &&
+ packet->client_sequence_number() > latest_sequence_number_) {
+ latest_sequence_number_ = packet->client_sequence_number();
+ base::TimeDelta round_trip_latency =
+ base::Time::Now() -
+ base::Time::FromInternalValue(packet->client_sequence_number());
+ stats_.round_trip_ms()->Record(round_trip_latency.InMilliseconds());
+ }
+
+ received_packets_.push_back(QueuedVideoPacket(packet.Pass(), done));
+ if (!packet_being_processed_)
+ ProcessNextPacket();
+}
+
+int RectangleUpdateDecoder::GetPendingVideoPackets() {
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
+ return received_packets_.size();
+}
+
+void RectangleUpdateDecoder::DropAllPackets() {
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
+
+ while(!received_packets_.empty()) {
+ delete received_packets_.front().packet;
+ received_packets_.front().done.Run();
+ received_packets_.pop_front();
+ }
+}
+
+void RectangleUpdateDecoder::ProcessNextPacket() {
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
+ CHECK(!packet_being_processed_);
+
+ if (received_packets_.empty()) {
+ // Nothing to do!
+ return;
+ }
+
+ scoped_ptr<VideoPacket> packet(received_packets_.front().packet);
+ received_packets_.front().packet = NULL;
+ packet_being_processed_ = true;
+
+ // Measure the latency between the last packet being received and presented.
+ bool last_packet = (packet->flags() & VideoPacket::LAST_PACKET) != 0;
+ base::Time decode_start;
+ if (last_packet)
+ decode_start = base::Time::Now();
+
+ base::Closure callback = base::Bind(&RectangleUpdateDecoder::OnPacketDone,
+ this,
+ last_packet,
+ decode_start);
+
+ decode_task_runner_->PostTask(FROM_HERE, base::Bind(
+ &RectangleUpdateDecoder::DecodePacket, this,
+ base::Passed(&packet), callback));
+}
+
+void RectangleUpdateDecoder::OnPacketDone(bool last_packet,
+ base::Time decode_start) {
+ if (!main_task_runner_->BelongsToCurrentThread()) {
+ main_task_runner_->PostTask(FROM_HERE, base::Bind(
+ &RectangleUpdateDecoder::OnPacketDone, this,
+ last_packet, decode_start));
+ return;
+ }
+
+ // Record the latency between the final packet being received and
+ // presented.
+ if (last_packet) {
+ stats_.video_decode_ms()->Record(
+ (base::Time::Now() - decode_start).InMilliseconds());
+ }
+
+ received_packets_.front().done.Run();
+ received_packets_.pop_front();
+
+ packet_being_processed_ = false;
+
+ // Process the next video packet.
+ ProcessNextPacket();
+}
+
+ChromotingStats* RectangleUpdateDecoder::GetStats() {
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
+ return &stats_;
+}
+
} // namespace remoting
diff --git a/remoting/client/rectangle_update_decoder.h b/remoting/client/rectangle_update_decoder.h
index 3d61b97..af91267 100644
--- a/remoting/client/rectangle_update_decoder.h
+++ b/remoting/client/rectangle_update_decoder.h
@@ -7,12 +7,14 @@
#include <list>
-#include "base/callback_forward.h"
+#include "base/callback.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "remoting/codec/video_decoder.h"
+#include "remoting/client/chromoting_stats.h"
#include "remoting/client/frame_consumer_proxy.h"
#include "remoting/client/frame_producer.h"
+#include "remoting/protocol/video_stub.h"
namespace base {
class SingleThreadTaskRunner;
@@ -24,6 +26,7 @@ class ImageData;
namespace remoting {
+class ChromotingStats;
class VideoPacket;
namespace protocol {
@@ -35,21 +38,24 @@ class SessionConfig;
// TODO(sergeyu): Rename this class.
class RectangleUpdateDecoder
: public base::RefCountedThreadSafe<RectangleUpdateDecoder>,
- public FrameProducer {
+ public FrameProducer,
+ public protocol::VideoStub {
public:
- // Creates an update decoder on |task_runner_|, outputting to |consumer|.
+ // Creates an update decoder on |main_task_runner_| and |decode_task_runner_|,
+ // outputting to |consumer|. The |main_task_runner_| is responsible for
+ // receiving and queueing packets. The |decode_task_runner_| is responsible
+ // for decoding the video packets.
// TODO(wez): Replace the ref-counted proxy with an owned FrameConsumer.
RectangleUpdateDecoder(
- scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> decode_task_runner,
scoped_refptr<FrameConsumerProxy> consumer);
// Initializes decoder with the information from the protocol config.
void Initialize(const protocol::SessionConfig& config);
- // Decodes the contents of |packet|. DecodePacket may keep a reference to
- // |packet| so the |packet| must remain alive and valid until |done| is
- // executed.
- void DecodePacket(scoped_ptr<VideoPacket> packet, const base::Closure& done);
+ // Removes all video packets in the queue.
+ void DropAllPackets();
// FrameProducer implementation. These methods may be called before we are
// Initialize()d, or we know the source screen size.
@@ -59,7 +65,23 @@ class RectangleUpdateDecoder
virtual void SetOutputSizeAndClip(const SkISize& view_size,
const SkIRect& clip_area) OVERRIDE;
+ // VideoStub implementation.
+ virtual void ProcessVideoPacket(scoped_ptr<VideoPacket> packet,
+ const base::Closure& done) OVERRIDE;
+ virtual int GetPendingVideoPackets() OVERRIDE;
+
+ // Return the stats recorded by this client.
+ ChromotingStats* GetStats();
+
private:
+ struct QueuedVideoPacket {
+ QueuedVideoPacket(scoped_ptr<VideoPacket> packet,
+ const base::Closure& done);
+ ~QueuedVideoPacket();
+ VideoPacket* packet;
+ base::Closure done;
+ };
+
friend class base::RefCountedThreadSafe<RectangleUpdateDecoder>;
virtual ~RectangleUpdateDecoder();
@@ -68,7 +90,22 @@ class RectangleUpdateDecoder
void SchedulePaint();
void DoPaint();
- scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+ // If a packet is not being processed, dispatches a single message from the
+ // |received_packets_| queue.
+ void ProcessNextPacket();
+
+ // Decodes the contents of |packet|. DecodePacket may keep a reference to
+ // |packet| so the |packet| must remain alive and valid until |done| is
+ // executed.
+ void DecodePacket(scoped_ptr<VideoPacket> packet, const base::Closure& done);
+
+ // Callback method when a VideoPacket is processed.
+ // If |last_packet| is true then |decode_start| contains the timestamp when
+ // the packet will start to be processed.
+ void OnPacketDone(bool last_packet, base::Time decode_start);
+
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
+ scoped_refptr<base::SingleThreadTaskRunner> decode_task_runner_;
scoped_refptr<FrameConsumerProxy> consumer_;
scoped_ptr<VideoDecoder> decoder_;
@@ -78,7 +115,7 @@ class RectangleUpdateDecoder
// Vertical and horizontal DPI of the remote screen.
SkIPoint source_dpi_;
- // The current dimentions of the frame consumer view.
+ // The current dimensions of the frame consumer view.
SkISize view_size_;
SkIRect clip_area_;
@@ -87,6 +124,22 @@ class RectangleUpdateDecoder
// Flag used to coalesce runs of SchedulePaint()s into a single DoPaint().
bool paint_scheduled_;
+
+ // Contains all video packets that have been received, but have not yet been
+ // processed.
+ //
+ // Used to serialize sending of messages to the client.
+ // TODO(sergeyu): Simplify this code and remove this list.
+ std::list<QueuedVideoPacket> received_packets_;
+
+ // True if a message is being processed. Can be used to determine if it is
+ // safe to dispatch another message.
+ bool packet_being_processed_;
+
+ ChromotingStats stats_;
+
+ // Keep track of the most recent sequence number bounced back from the host.
+ int64 latest_sequence_number_;
};
} // namespace remoting