summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--remoting/client/jni/chromoting_jni_instance.cc12
-rw-r--r--remoting/client/jni/chromoting_jni_instance.h4
-rw-r--r--remoting/client/plugin/pepper_video_renderer_3d.cc32
-rw-r--r--remoting/client/plugin/pepper_video_renderer_3d.h16
-rw-r--r--remoting/client/software_video_renderer.cc27
-rw-r--r--remoting/client/software_video_renderer.h9
-rw-r--r--remoting/protocol/client_event_dispatcher.cc8
-rw-r--r--remoting/protocol/performance_tracker.cc89
-rw-r--r--remoting/protocol/performance_tracker.h29
9 files changed, 111 insertions, 115 deletions
diff --git a/remoting/client/jni/chromoting_jni_instance.cc b/remoting/client/jni/chromoting_jni_instance.cc
index ba7672b..b12364e 100644
--- a/remoting/client/jni/chromoting_jni_instance.cc
+++ b/remoting/client/jni/chromoting_jni_instance.cc
@@ -292,18 +292,6 @@ void ChromotingJniInstance::SendClientMessage(const std::string& type,
client_->host_stub()->DeliverClientMessage(extension_message);
}
-void ChromotingJniInstance::RecordPaintTime(int64 paint_time_ms) {
- if (!jni_runtime_->network_task_runner()->BelongsToCurrentThread()) {
- jni_runtime_->network_task_runner()->PostTask(
- FROM_HERE, base::Bind(&ChromotingJniInstance::RecordPaintTime, this,
- paint_time_ms));
- return;
- }
-
- if (stats_logging_enabled_)
- perf_tracker_->RecordPaintTime(paint_time_ms);
-}
-
void ChromotingJniInstance::OnConnectionState(
protocol::ConnectionToHost::State state,
protocol::ErrorCode error) {
diff --git a/remoting/client/jni/chromoting_jni_instance.h b/remoting/client/jni/chromoting_jni_instance.h
index d87aed9..6ec4e40 100644
--- a/remoting/client/jni/chromoting_jni_instance.h
+++ b/remoting/client/jni/chromoting_jni_instance.h
@@ -93,10 +93,6 @@ class ChromotingJniInstance
void SendClientMessage(const std::string& type, const std::string& data);
- // Records paint time for statistics logging, if enabled. May be called from
- // any thread.
- void RecordPaintTime(int64 paint_time_ms);
-
// ClientUserInterface implementation.
void OnConnectionState(protocol::ConnectionToHost::State state,
protocol::ErrorCode error) override;
diff --git a/remoting/client/plugin/pepper_video_renderer_3d.cc b/remoting/client/plugin/pepper_video_renderer_3d.cc
index 83985d4..4d518b6 100644
--- a/remoting/client/plugin/pepper_video_renderer_3d.cc
+++ b/remoting/client/plugin/pepper_video_renderer_3d.cc
@@ -54,11 +54,6 @@ class PepperVideoRenderer3D::Picture {
PP_VideoPicture picture_;
};
-PepperVideoRenderer3D::FrameDecodeTimestamp::FrameDecodeTimestamp(
- uint32_t frame_id,
- base::TimeTicks decode_started_time)
- : frame_id(frame_id), decode_started_time(decode_started_time) {}
-
PepperVideoRenderer3D::PepperVideoRenderer3D() : callback_factory_(this) {}
PepperVideoRenderer3D::~PepperVideoRenderer3D() {
@@ -265,14 +260,10 @@ void PepperVideoRenderer3D::DecodeNextPacket() {
if (!initialization_finished_ || decode_pending_ || pending_packets_.empty())
return;
- ++latest_frame_id_;
- frame_decode_timestamps_.push_back(
- FrameDecodeTimestamp(latest_frame_id_, base::TimeTicks::Now()));
-
const VideoPacket* packet = pending_packets_.front()->packet();
int32_t result = video_decoder_.Decode(
- latest_frame_id_, packet->data().size(), packet->data().data(),
+ packet->frame_id(), packet->data().size(), packet->data().data(),
callback_factory_.NewCallback(&PepperVideoRenderer3D::OnDecodeDone));
CHECK_EQ(result, PP_OK_COMPLETIONPENDING);
decode_pending_ = true;
@@ -317,21 +308,7 @@ void PepperVideoRenderer3D::OnPictureReady(int32_t result,
return;
}
- CHECK(!frame_decode_timestamps_.empty());
- const FrameDecodeTimestamp& frame_timer = frame_decode_timestamps_.front();
-
- if (picture.decode_id != frame_timer.frame_id) {
- LOG(ERROR)
- << "Received a video packet that didn't contain a complete frame.";
- event_handler_->OnVideoDecodeError();
- return;
- }
-
- base::TimeDelta decode_time =
- base::TimeTicks::Now() - frame_timer.decode_started_time;
- perf_tracker_->RecordDecodeTime(decode_time.InMilliseconds());
-
- frame_decode_timestamps_.pop_front();
+ perf_tracker_->OnFrameDecoded(picture.decode_id);
next_picture_.reset(new Picture(&video_decoder_, picture));
@@ -348,7 +325,6 @@ void PepperVideoRenderer3D::PaintIfNeeded() {
current_picture_ = next_picture_.Pass();
force_repaint_ = false;
- latest_paint_started_time_ = base::TimeTicks::Now();
const PP_VideoPicture& picture = current_picture_->picture();
PP_Resource graphics_3d = graphics_.pp_resource();
@@ -409,9 +385,7 @@ void PepperVideoRenderer3D::OnPaintDone(int32_t result) {
CHECK_EQ(result, PP_OK) << "Graphics3D::SwapBuffers() failed";
paint_pending_ = false;
- base::TimeDelta paint_time =
- base::TimeTicks::Now() - latest_paint_started_time_;
- perf_tracker_->RecordPaintTime(paint_time.InMilliseconds());
+ perf_tracker_->OnFramePainted(current_picture_->picture().decode_id);
PaintIfNeeded();
}
diff --git a/remoting/client/plugin/pepper_video_renderer_3d.h b/remoting/client/plugin/pepper_video_renderer_3d.h
index a624a87..2c229b6 100644
--- a/remoting/client/plugin/pepper_video_renderer_3d.h
+++ b/remoting/client/plugin/pepper_video_renderer_3d.h
@@ -11,7 +11,6 @@
#include "base/basictypes.h"
#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
-#include "base/time/time.h"
#include "ppapi/cpp/graphics_3d.h"
#include "ppapi/cpp/instance_handle.h"
#include "ppapi/cpp/video_decoder.h"
@@ -53,13 +52,6 @@ class PepperVideoRenderer3D : public PepperVideoRenderer,
class PendingPacket;
class Picture;
- struct FrameDecodeTimestamp {
- FrameDecodeTimestamp(uint32_t frame_id,
- base::TimeTicks decode_started_time);
- uint32_t frame_id;
- base::TimeTicks decode_started_time;
- };
-
// Callback for pp::VideoDecoder::Initialize().
void OnInitialized(int32_t result);
@@ -113,15 +105,10 @@ class PepperVideoRenderer3D : public PepperVideoRenderer,
bool get_picture_pending_ = false;
bool paint_pending_ = false;
- uint32_t latest_frame_id_ = 0;
-
// Queue of packets that that have been received, but haven't been passed to
// the decoder yet.
std::deque<PendingPacket*> pending_packets_;
- // Timestamps for all frames currently being processed by the decoder.
- std::deque<FrameDecodeTimestamp> frame_decode_timestamps_;
-
// The current picture shown on the screen or being rendered. Must be deleted
// before |video_decoder_|.
scoped_ptr<Picture> current_picture_;
@@ -134,9 +121,6 @@ class PepperVideoRenderer3D : public PepperVideoRenderer,
// Set to true if the screen has been resized and needs to be repainted.
bool force_repaint_ = false;
- // Time the last paint operation was started.
- base::TimeTicks latest_paint_started_time_;
-
// The texture type for which |shader_program| was initialized. Can be either
// 0, GL_TEXTURE_2D, GL_TEXTURE_RECTANGLE_ARB or GL_TEXTURE_EXTERNAL_OES. 0
// indicates that |shader_program_| hasn't been intialized.
diff --git a/remoting/client/software_video_renderer.cc b/remoting/client/software_video_renderer.cc
index b52db3eac..8172369 100644
--- a/remoting/client/software_video_renderer.cc
+++ b/remoting/client/software_video_renderer.cc
@@ -149,25 +149,23 @@ void SoftwareVideoRenderer::ProcessVideoPacket(scoped_ptr<VideoPacket> packet,
consumer_->AllocateFrame(source_size_);
frame->set_dpi(source_dpi_);
+ int32_t frame_id = packet->frame_id();
base::PostTaskAndReplyWithResult(
decode_task_runner_.get(), FROM_HERE,
base::Bind(&DoDecodeFrame, decoder_.get(), base::Passed(&packet),
base::Passed(&frame)),
base::Bind(&SoftwareVideoRenderer::RenderFrame,
- weak_factory_.GetWeakPtr(), base::TimeTicks::Now(),
- done_runner.Release()));
+ weak_factory_.GetWeakPtr(), frame_id, done_runner.Release()));
}
void SoftwareVideoRenderer::RenderFrame(
- base::TimeTicks decode_start_time,
+ int32_t frame_id,
const base::Closure& done,
scoped_ptr<webrtc::DesktopFrame> frame) {
DCHECK(thread_checker_.CalledOnValidThread());
- if (perf_tracker_) {
- perf_tracker_->RecordDecodeTime(
- (base::TimeTicks::Now() - decode_start_time).InMilliseconds());
- }
+ if (perf_tracker_)
+ perf_tracker_->OnFrameDecoded(frame_id);
if (!frame) {
if (!done.is_null())
@@ -175,20 +173,17 @@ void SoftwareVideoRenderer::RenderFrame(
return;
}
- consumer_->DrawFrame(
- frame.Pass(),
- base::Bind(&SoftwareVideoRenderer::OnFrameRendered,
- weak_factory_.GetWeakPtr(), base::TimeTicks::Now(), done));
+ consumer_->DrawFrame(frame.Pass(),
+ base::Bind(&SoftwareVideoRenderer::OnFrameRendered,
+ weak_factory_.GetWeakPtr(), frame_id, done));
}
-void SoftwareVideoRenderer::OnFrameRendered(base::TimeTicks paint_start_time,
+void SoftwareVideoRenderer::OnFrameRendered(int32_t frame_id,
const base::Closure& done) {
DCHECK(thread_checker_.CalledOnValidThread());
- if (perf_tracker_) {
- perf_tracker_->RecordPaintTime(
- (base::TimeTicks::Now() - paint_start_time).InMilliseconds());
- }
+ if (perf_tracker_)
+ perf_tracker_->OnFramePainted(frame_id);
if (!done.is_null())
done.Run();
diff --git a/remoting/client/software_video_renderer.h b/remoting/client/software_video_renderer.h
index 318a3d8..5158e9d 100644
--- a/remoting/client/software_video_renderer.h
+++ b/remoting/client/software_video_renderer.h
@@ -55,11 +55,10 @@ class SoftwareVideoRenderer : public VideoRenderer,
const base::Closure& done) override;
private:
- void RenderFrame(base::TimeTicks decode_start_time,
- const base::Closure& done,
- scoped_ptr<webrtc::DesktopFrame> frame);
- void OnFrameRendered(base::TimeTicks paint_start_time,
- const base::Closure& done);
+ void RenderFrame(int32_t frame_id,
+ const base::Closure& done,
+ scoped_ptr<webrtc::DesktopFrame> frame);
+ void OnFrameRendered(int32_t frame_id, const base::Closure& done);
scoped_refptr<base::SingleThreadTaskRunner> decode_task_runner_;
FrameConsumer* consumer_;
diff --git a/remoting/protocol/client_event_dispatcher.cc b/remoting/protocol/client_event_dispatcher.cc
index 4f1e51e..9329227 100644
--- a/remoting/protocol/client_event_dispatcher.cc
+++ b/remoting/protocol/client_event_dispatcher.cc
@@ -25,7 +25,7 @@ void ClientEventDispatcher::InjectKeyEvent(const KeyEvent& event) {
DCHECK(event.has_usb_keycode());
DCHECK(event.has_pressed());
EventMessage message;
- message.set_timestamp(base::Time::Now().ToInternalValue());
+ message.set_timestamp(base::TimeTicks::Now().ToInternalValue());
message.mutable_key_event()->CopyFrom(event);
writer()->Write(SerializeAndFrameMessage(message), base::Closure());
}
@@ -33,21 +33,21 @@ void ClientEventDispatcher::InjectKeyEvent(const KeyEvent& event) {
void ClientEventDispatcher::InjectTextEvent(const TextEvent& event) {
DCHECK(event.has_text());
EventMessage message;
- message.set_timestamp(base::Time::Now().ToInternalValue());
+ message.set_timestamp(base::TimeTicks::Now().ToInternalValue());
message.mutable_text_event()->CopyFrom(event);
writer()->Write(SerializeAndFrameMessage(message), base::Closure());
}
void ClientEventDispatcher::InjectMouseEvent(const MouseEvent& event) {
EventMessage message;
- message.set_timestamp(base::Time::Now().ToInternalValue());
+ message.set_timestamp(base::TimeTicks::Now().ToInternalValue());
message.mutable_mouse_event()->CopyFrom(event);
writer()->Write(SerializeAndFrameMessage(message), base::Closure());
}
void ClientEventDispatcher::InjectTouchEvent(const TouchEvent& event) {
EventMessage message;
- message.set_timestamp(base::Time::Now().ToInternalValue());
+ message.set_timestamp(base::TimeTicks::Now().ToInternalValue());
message.mutable_touch_event()->CopyFrom(event);
writer()->Write(SerializeAndFrameMessage(message), base::Closure());
}
diff --git a/remoting/protocol/performance_tracker.cc b/remoting/protocol/performance_tracker.cc
index 283e59b..3ee1a4a 100644
--- a/remoting/protocol/performance_tracker.cc
+++ b/remoting/protocol/performance_tracker.cc
@@ -118,27 +118,29 @@ void PerformanceTracker::RecordVideoPacketStats(const VideoPacket& packet) {
// Record this received packet, even if it is empty.
video_packet_rate_.Record(1);
- // Record the RTT, even for empty packets, otherwise input events that
- // do not cause an on-screen change can give very large, bogus RTTs.
- if (packet.has_latest_event_timestamp() &&
- packet.latest_event_timestamp() > latest_input_event_timestamp_) {
- latest_input_event_timestamp_ = packet.latest_event_timestamp();
-
- base::TimeDelta round_trip_latency =
- base::Time::Now() -
- base::Time::FromInternalValue(packet.latest_event_timestamp());
-
- round_trip_ms_.Record(round_trip_latency.InMilliseconds());
-
- uma_custom_times_updater_.Run(
- kRoundTripLatencyHistogram, round_trip_latency.InMilliseconds(),
- kLatencyHistogramMinMs, kLatencyHistogramMaxMs,
- kLatencyHistogramBuckets);
+ FrameTimestamps timestamps;
+ timestamps.time_received = base::TimeTicks::Now();
+ if (packet.has_latest_event_timestamp()) {
+ base::TimeTicks timestamp =
+ base::TimeTicks::FromInternalValue(packet.latest_event_timestamp());
+ // Only use latest_event_timestamp field if it has changed from the
+ // previous frame.
+ if (timestamp > latest_event_timestamp_) {
+ timestamps.latest_event_timestamp = timestamp;
+ latest_event_timestamp_ = timestamp;
+ }
}
// If the packet is empty, there are no other stats to update.
- if (!packet.data().size())
+ if (!packet.data().size()) {
+ // Record the RTT, even for empty packets, otherwise input events that
+ // do not cause an on-screen change can give very large, bogus RTTs.
+ RecordRoundTripLatency(timestamps);
return;
+ }
+
+ DCHECK(packet.has_frame_id());
+ frame_timestamps_[packet.frame_id()] = timestamps;
video_frame_rate_.Record(1);
video_bandwidth_.Record(packet.data().size());
@@ -188,18 +190,55 @@ void PerformanceTracker::RecordVideoPacketStats(const VideoPacket& packet) {
}
}
-void PerformanceTracker::RecordDecodeTime(double value) {
- video_decode_ms_.Record(value);
+void PerformanceTracker::OnFrameDecoded(int32_t frame_id) {
+ FramesTimestampsMap::iterator it = frame_timestamps_.find(frame_id);
+ DCHECK(it != frame_timestamps_.end());
+ it->second.time_decoded = base::TimeTicks::Now();
+ base::TimeDelta delay = it->second.time_decoded - it->second.time_received;
+
+ video_decode_ms_.Record(delay.InMilliseconds());
uma_custom_times_updater_.Run(
- kVideoDecodeLatencyHistogram, value, kVideoActionsHistogramsMinMs,
- kVideoActionsHistogramsMaxMs, kVideoActionsHistogramsBuckets);
+ kVideoDecodeLatencyHistogram, delay.InMilliseconds(),
+ kVideoActionsHistogramsMinMs, kVideoActionsHistogramsMaxMs,
+ kVideoActionsHistogramsBuckets);
}
-void PerformanceTracker::RecordPaintTime(double value) {
- video_paint_ms_.Record(value);
+void PerformanceTracker::OnFramePainted(int32_t frame_id) {
+ base::TimeTicks now = base::TimeTicks::Now();
+
+ while (!frame_timestamps_.empty() &&
+ frame_timestamps_.begin()->first <= frame_id) {
+ FrameTimestamps& timestamps = frame_timestamps_.begin()->second;
+
+ // time_decoded may be null if OnFrameDecoded() was never called, e.g. if
+ // the frame was dropped or decoding has failed.
+ if (!timestamps.time_decoded.is_null()) {
+ base::TimeDelta delay = now - timestamps.time_decoded;
+ video_paint_ms_.Record(delay.InMilliseconds());
+ uma_custom_times_updater_.Run(
+ kVideoPaintLatencyHistogram, delay.InMilliseconds(),
+ kVideoActionsHistogramsMinMs, kVideoActionsHistogramsMaxMs,
+ kVideoActionsHistogramsBuckets);
+ }
+
+ RecordRoundTripLatency(timestamps);
+ frame_timestamps_.erase(frame_timestamps_.begin());
+ }
+}
+
+void PerformanceTracker::RecordRoundTripLatency(
+ const FrameTimestamps& timestamps) {
+ if (timestamps.latest_event_timestamp.is_null())
+ return;
+
+ base::TimeTicks now = base::TimeTicks::Now();
+ base::TimeDelta round_trip_latency =
+ now - timestamps.latest_event_timestamp;
+
+ round_trip_ms_.Record(round_trip_latency.InMilliseconds());
uma_custom_times_updater_.Run(
- kVideoPaintLatencyHistogram, value, kVideoActionsHistogramsMinMs,
- kVideoActionsHistogramsMaxMs, kVideoActionsHistogramsBuckets);
+ kRoundTripLatencyHistogram, round_trip_latency.InMilliseconds(),
+ kLatencyHistogramMinMs, kLatencyHistogramMaxMs, kLatencyHistogramBuckets);
}
void PerformanceTracker::UploadRateStatsToUma() {
diff --git a/remoting/protocol/performance_tracker.h b/remoting/protocol/performance_tracker.h
index f1d9aa0..fefb169 100644
--- a/remoting/protocol/performance_tracker.h
+++ b/remoting/protocol/performance_tracker.h
@@ -5,6 +5,8 @@
#ifndef REMOTING_PROTOCOL_PERFORMANCE_TRACKER_H_
#define REMOTING_PROTOCOL_PERFORMANCE_TRACKER_H_
+#include <map>
+
#include "base/callback.h"
#include "base/timer/timer.h"
#include "remoting/base/rate_counter.h"
@@ -53,8 +55,12 @@ class PerformanceTracker {
// Record stats for a video-packet.
void RecordVideoPacketStats(const VideoPacket& packet);
- void RecordDecodeTime(double value);
- void RecordPaintTime(double value);
+ // Helpers to track decode and paint time. If the render drops some frames
+ // before they are painted then OnFramePainted() records paint time when the
+ // following frame is rendered. OnFramePainted() may be called multiple times,
+ // in which case all calls after the first one are ignored.
+ void OnFrameDecoded(int32_t frame_id);
+ void OnFramePainted(int32_t frame_id);
// Sets callbacks in ChromotingInstance to update a UMA custom counts, custom
// times or enum histogram.
@@ -66,6 +72,18 @@ class PerformanceTracker {
void OnPauseStateChanged(bool paused);
private:
+ struct FrameTimestamps {
+ // Set to null for frames that were not sent after a fresh input event.
+ base::TimeTicks latest_event_timestamp;
+
+ base::TimeTicks time_received;
+ base::TimeTicks time_decoded;
+ };
+ typedef std::map<int32_t, FrameTimestamps> FramesTimestampsMap;
+
+ // Helper to record input roundtrip latency after a frame has been painted.
+ void RecordRoundTripLatency(const FrameTimestamps& timestamps);
+
// Updates frame-rate, packet-rate and bandwidth UMA statistics.
void UploadRateStatsToUma();
@@ -97,8 +115,11 @@ class PerformanceTracker {
UpdateUmaCustomHistogramCallback uma_custom_times_updater_;
UpdateUmaEnumHistogramCallback uma_enum_histogram_updater_;
- // The latest input timestamp that a VideoPacket was seen annotated with.
- int64_t latest_input_event_timestamp_ = 0;
+ // The latest event timestamp that a VideoPacket was seen annotated with.
+ base::TimeTicks latest_event_timestamp_;
+
+ // Stores timestamps for the frames that are currently being processed.
+ FramesTimestampsMap frame_timestamps_;
bool is_paused_ = false;