OLD | NEW |
---|---|
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 |
OLD | NEW |