Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(36)

Side by Side Diff: media/cast/logging/receiver_time_offset_estimator_impl.cc

Issue 556693002: Cast: Logging estimates clock difference based on packets (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <algorithm> 5 #include <algorithm>
6 #include <utility> 6 #include <utility>
7 7
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "base/time/tick_clock.h" 9 #include "base/time/tick_clock.h"
10 #include "media/cast/logging/receiver_time_offset_estimator_impl.h" 10 #include "media/cast/logging/receiver_time_offset_estimator_impl.h"
11 11
12 namespace media { 12 namespace media {
13 namespace cast { 13 namespace cast {
14 14
15 // This should be large enough so that we can collect all 3 events before 15 ReceiverTimeOffsetEstimatorImpl::BoundCalculator::BoundCalculator()
16 // the entry gets removed from the map. 16 : has_bound_(false) {}
17 const size_t kMaxEventTimesMapSize = 100; 17 ReceiverTimeOffsetEstimatorImpl::BoundCalculator::~BoundCalculator() {}
18 18
19 ReceiverTimeOffsetEstimatorImpl::ReceiverTimeOffsetEstimatorImpl( 19 void ReceiverTimeOffsetEstimatorImpl::BoundCalculator::SetSent(
20 base::TickClock* clock) 20 uint32 rtp,
21 : bounded_(false), 21 uint32 packet_id,
22 clock_(clock), 22 bool audio,
23 offset_bounds_valid_(false), 23 base::TimeTicks t) {
24 last_reset_time_(clock_->NowTicks()) { 24 uint64 key = (static_cast<uint64>(rtp) << 32) | (packet_id << 1) | audio;
25 events_[key].first = t;
26 CheckUpdate(key);
27 }
28
29 void ReceiverTimeOffsetEstimatorImpl::BoundCalculator::SetReceived(
30 uint32 rtp,
31 uint16 packet_id,
32 bool audio,
33 base::TimeTicks t) {
34 uint64 key = (static_cast<uint64>(rtp) << 32) | (packet_id << 1) | audio;
35 events_[key].second = t;
36 CheckUpdate(key);
37 }
38
39 void ReceiverTimeOffsetEstimatorImpl::BoundCalculator::UpdateBound(
40 base::TimeTicks sent, base::TimeTicks received) {
41 base::TimeDelta delta = received - sent;
42 if (has_bound_) {
43 if (delta < bound_) {
44 bound_ = delta;
45 } else {
46 bound_ += (delta - bound_) / kClockDriftSpeed;
imcheng 2014/09/09 01:04:23 What does this do? Does it handle drifting in eith
hubbe 2014/09/09 19:06:15 Added some (hopefully helpful) comments to the cla
47 }
48 } else {
49 bound_ = delta;
50 }
51 has_bound_ = true;
52 }
53
54 void ReceiverTimeOffsetEstimatorImpl::BoundCalculator::CheckUpdate(
55 uint64 key) {
56 TimeTickPair &ticks = events_[key];
imcheng 2014/09/09 01:04:23 const?
hubbe 2014/09/09 19:06:15 Done.
57 if (!ticks.first.is_null() && !ticks.second.is_null()) {
58 UpdateBound(ticks.first, ticks.second);
59 events_.erase(key);
60 return;
61 }
62
63 if (events_.size() > kMaxEventTimesMapSize) {
64 EventMap::iterator i = ModMapOldest(&events_);
65 if (i != events_.end()) {
66 events_.erase(i);
67 }
68 }
69 }
70
71 ReceiverTimeOffsetEstimatorImpl::ReceiverTimeOffsetEstimatorImpl() {
25 } 72 }
26 73
27 ReceiverTimeOffsetEstimatorImpl::~ReceiverTimeOffsetEstimatorImpl() { 74 ReceiverTimeOffsetEstimatorImpl::~ReceiverTimeOffsetEstimatorImpl() {
28 DCHECK(thread_checker_.CalledOnValidThread()); 75 DCHECK(thread_checker_.CalledOnValidThread());
29 } 76 }
30 77
78
31 void ReceiverTimeOffsetEstimatorImpl::OnReceiveFrameEvent( 79 void ReceiverTimeOffsetEstimatorImpl::OnReceiveFrameEvent(
32 const FrameEvent& frame_event) { 80 const FrameEvent& frame_event) {
33 DCHECK(thread_checker_.CalledOnValidThread()); 81 DCHECK(thread_checker_.CalledOnValidThread());
34 82 switch (frame_event.type) {
35 if (frame_event.media_type != VIDEO_EVENT)
36 return;
37
38 CastLoggingEvent event = frame_event.type;
39 if (event != FRAME_ENCODED && event != FRAME_ACK_SENT &&
40 event != FRAME_ACK_RECEIVED)
41 return;
42
43 EventTimesMap::iterator it = event_times_map_.find(frame_event.rtp_timestamp);
44 if (it == event_times_map_.end()) {
45 EventTimes event_times;
46 it = event_times_map_.insert(std::make_pair(frame_event.rtp_timestamp,
47 event_times)).first;
48 }
49 switch (event) {
50 case FRAME_ENCODED:
51 // Encode is supposed to happen only once. If we see duplicate event,
52 // throw away the entry.
53 if (it->second.event_a_time.is_null()) {
54 it->second.event_a_time = frame_event.timestamp;
55 } else {
56 event_times_map_.erase(it);
57 return;
58 }
59 break;
60 case FRAME_ACK_SENT: 83 case FRAME_ACK_SENT:
61 if (it->second.event_b_time.is_null()) { 84 lower_bound_.SetSent(frame_event.rtp_timestamp,
62 it->second.event_b_time = frame_event.timestamp; 85 0,
63 } else if (it->second.event_b_time != frame_event.timestamp) { 86 frame_event.media_type == AUDIO_EVENT,
64 // Duplicate ack sent events are normal due to RTCP redundancy, 87 frame_event.timestamp);
65 // but they must have the same event timestamp.
66 event_times_map_.erase(it);
67 return;
68 }
69 break; 88 break;
70 case FRAME_ACK_RECEIVED: 89 case FRAME_ACK_RECEIVED:
71 // If there are duplicate ack received events, pick the one with the 90 lower_bound_.SetReceived(frame_event.rtp_timestamp,
72 // smallest event timestamp so we can get a better bound. 91 0,
73 if (it->second.event_c_time.is_null()) { 92 frame_event.media_type == AUDIO_EVENT,
74 it->second.event_c_time = frame_event.timestamp; 93 frame_event.timestamp);
75 } else {
76 it->second.event_c_time =
77 std::min(frame_event.timestamp, it->second.event_c_time);
78 }
79 break; 94 break;
80 default: 95 default:
81 NOTREACHED(); 96 // Ignored
97 break;
82 } 98 }
83
84 if (!it->second.event_a_time.is_null() &&
85 !it->second.event_b_time.is_null() &&
86 !it->second.event_c_time.is_null()) {
87 UpdateOffsetBounds(it->second);
88 event_times_map_.erase(it);
89 }
90
91 // Keep the map size at most |kMaxEventTimesMapSize|.
92 if (event_times_map_.size() > kMaxEventTimesMapSize)
93 event_times_map_.erase(event_times_map_.begin());
94 } 99 }
95 100
96 bool ReceiverTimeOffsetEstimatorImpl::GetReceiverOffsetBounds( 101 bool ReceiverTimeOffsetEstimatorImpl::GetReceiverOffsetBounds(
97 base::TimeDelta* lower_bound, 102 base::TimeDelta* lower_bound,
98 base::TimeDelta* upper_bound) { 103 base::TimeDelta* upper_bound) {
99 if (!bounded_) 104 if (!lower_bound_.has_bound() || !upper_bound_.has_bound())
100 return false; 105 return false;
101 106
102 *lower_bound = prev_offset_lower_bound_; 107 *lower_bound = -lower_bound_.bound();
103 *upper_bound = prev_offset_upper_bound_; 108 *upper_bound = upper_bound_.bound();
109
110 // Sanitize the output, we don't want the upper bound to be
111 // lower than the lower bound, make them the same.
112 if (upper_bound < lower_bound) {
113 lower_bound += (lower_bound - upper_bound) / 2;
114 upper_bound = lower_bound;
115 }
104 return true; 116 return true;
105 } 117 }
106 118
107 void ReceiverTimeOffsetEstimatorImpl::OnReceivePacketEvent( 119 void ReceiverTimeOffsetEstimatorImpl::OnReceivePacketEvent(
108 const PacketEvent& packet_event) { 120 const PacketEvent& packet_event) {
109 // Not interested in packet events.
110 DCHECK(thread_checker_.CalledOnValidThread()); 121 DCHECK(thread_checker_.CalledOnValidThread());
122 switch (packet_event.type) {
123 case PACKET_SENT_TO_NETWORK:
124 upper_bound_.SetSent(packet_event.rtp_timestamp,
125 packet_event.packet_id,
126 packet_event.media_type == AUDIO_EVENT,
127 packet_event.timestamp);
128 break;
129 case PACKET_RECEIVED:
130 upper_bound_.SetReceived(packet_event.rtp_timestamp,
131 packet_event.packet_id,
132 packet_event.media_type == AUDIO_EVENT,
133 packet_event.timestamp);
134 break;
135 default:
136 // Ignored
137 break;
138 }
111 } 139 }
112 140
113 void ReceiverTimeOffsetEstimatorImpl::UpdateOffsetBounds(
114 const EventTimes& event) {
115 base::TimeDelta lower_bound = event.event_b_time - event.event_c_time;
116 base::TimeDelta upper_bound = event.event_b_time - event.event_a_time;
117
118 if (offset_bounds_valid_) {
119 lower_bound = std::max(lower_bound, offset_lower_bound_);
120 upper_bound = std::min(upper_bound, offset_upper_bound_);
121 }
122
123 if (lower_bound > upper_bound) {
124 VLOG(2) << "Got bogus offset bound values [" << lower_bound.InMilliseconds()
125 << ", " << upper_bound.InMilliseconds() << "].";
126 return;
127 }
128
129 offset_lower_bound_ = lower_bound;
130 offset_upper_bound_ = upper_bound;
131 offset_bounds_valid_ = true;
132 if (!bounded_ ||
133 offset_upper_bound_ - offset_lower_bound_ <
134 base::TimeDelta::FromMilliseconds(20)) {
135 prev_offset_lower_bound_ = offset_lower_bound_;
136 prev_offset_upper_bound_ = offset_upper_bound_;
137 }
138
139 base::TimeTicks now = clock_->NowTicks();
140 if (now - last_reset_time_ > base::TimeDelta::FromSeconds(20)) {
141 last_reset_time_ = now;
142 offset_lower_bound_ = base::TimeDelta();
143 offset_upper_bound_ = base::TimeDelta();
144 offset_bounds_valid_ = false;
145 }
146
147 bounded_ = true;
148 }
149 141
150 } // namespace cast 142 } // namespace cast
151 } // namespace media 143 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698