Index: media/cast/logging/receiver_time_offset_estimator_impl.cc |
diff --git a/media/cast/logging/receiver_time_offset_estimator_impl.cc b/media/cast/logging/receiver_time_offset_estimator_impl.cc |
index 950b3671ae8b1f3efa3519abb23c8e1271c4a744..d5116542d6bfbc08bfd4eceab9de1ab0d4f1bf63 100644 |
--- a/media/cast/logging/receiver_time_offset_estimator_impl.cc |
+++ b/media/cast/logging/receiver_time_offset_estimator_impl.cc |
@@ -12,140 +12,134 @@ |
namespace media { |
namespace cast { |
-// This should be large enough so that we can collect all 3 events before |
-// the entry gets removed from the map. |
-const size_t kMaxEventTimesMapSize = 100; |
- |
-ReceiverTimeOffsetEstimatorImpl::ReceiverTimeOffsetEstimatorImpl( |
- base::TickClock* clock) |
- : bounded_(false), |
- clock_(clock), |
- offset_bounds_valid_(false), |
- last_reset_time_(clock_->NowTicks()) { |
+ReceiverTimeOffsetEstimatorImpl::BoundCalculator::BoundCalculator() |
+ : has_bound_(false) {} |
+ReceiverTimeOffsetEstimatorImpl::BoundCalculator::~BoundCalculator() {} |
+ |
+void ReceiverTimeOffsetEstimatorImpl::BoundCalculator::SetSent( |
+ uint32 rtp, |
+ uint32 packet_id, |
+ bool audio, |
+ base::TimeTicks t) { |
+ uint64 key = (static_cast<uint64>(rtp) << 32) | (packet_id << 1) | |
+ static_cast<uint64>(audio); |
+ events_[key].first = t; |
+ CheckUpdate(key); |
+} |
+ |
+void ReceiverTimeOffsetEstimatorImpl::BoundCalculator::SetReceived( |
+ uint32 rtp, |
+ uint16 packet_id, |
+ bool audio, |
+ base::TimeTicks t) { |
+ uint64 key = (static_cast<uint64>(rtp) << 32) | (packet_id << 1) | |
+ static_cast<uint64>(audio); |
+ events_[key].second = t; |
+ CheckUpdate(key); |
+} |
+ |
+void ReceiverTimeOffsetEstimatorImpl::BoundCalculator::UpdateBound( |
+ base::TimeTicks sent, base::TimeTicks received) { |
+ base::TimeDelta delta = received - sent; |
+ if (has_bound_) { |
+ if (delta < bound_) { |
+ bound_ = delta; |
+ } else { |
+ bound_ += (delta - bound_) / kClockDriftSpeed; |
+ } |
+ } else { |
+ bound_ = delta; |
+ } |
+ has_bound_ = true; |
+ } |
+ |
+void ReceiverTimeOffsetEstimatorImpl::BoundCalculator::CheckUpdate( |
+ uint64 key) { |
+ const TimeTickPair& ticks = events_[key]; |
+ if (!ticks.first.is_null() && !ticks.second.is_null()) { |
+ UpdateBound(ticks.first, ticks.second); |
+ events_.erase(key); |
+ return; |
+ } |
+ |
+ if (events_.size() > kMaxEventTimesMapSize) { |
+ EventMap::iterator i = ModMapOldest(&events_); |
+ if (i != events_.end()) { |
+ events_.erase(i); |
+ } |
+ } |
+} |
+ |
+ReceiverTimeOffsetEstimatorImpl::ReceiverTimeOffsetEstimatorImpl() { |
} |
ReceiverTimeOffsetEstimatorImpl::~ReceiverTimeOffsetEstimatorImpl() { |
DCHECK(thread_checker_.CalledOnValidThread()); |
} |
+ |
void ReceiverTimeOffsetEstimatorImpl::OnReceiveFrameEvent( |
const FrameEvent& frame_event) { |
DCHECK(thread_checker_.CalledOnValidThread()); |
- |
- if (frame_event.media_type != VIDEO_EVENT) |
- return; |
- |
- CastLoggingEvent event = frame_event.type; |
- if (event != FRAME_ENCODED && event != FRAME_ACK_SENT && |
- event != FRAME_ACK_RECEIVED) |
- return; |
- |
- EventTimesMap::iterator it = event_times_map_.find(frame_event.rtp_timestamp); |
- if (it == event_times_map_.end()) { |
- EventTimes event_times; |
- it = event_times_map_.insert(std::make_pair(frame_event.rtp_timestamp, |
- event_times)).first; |
- } |
- switch (event) { |
- case FRAME_ENCODED: |
- // Encode is supposed to happen only once. If we see duplicate event, |
- // throw away the entry. |
- if (it->second.event_a_time.is_null()) { |
- it->second.event_a_time = frame_event.timestamp; |
- } else { |
- event_times_map_.erase(it); |
- return; |
- } |
- break; |
+ switch (frame_event.type) { |
case FRAME_ACK_SENT: |
- if (it->second.event_b_time.is_null()) { |
- it->second.event_b_time = frame_event.timestamp; |
- } else if (it->second.event_b_time != frame_event.timestamp) { |
- // Duplicate ack sent events are normal due to RTCP redundancy, |
- // but they must have the same event timestamp. |
- event_times_map_.erase(it); |
- return; |
- } |
+ lower_bound_.SetSent(frame_event.rtp_timestamp, |
+ 0, |
+ frame_event.media_type == AUDIO_EVENT, |
+ frame_event.timestamp); |
break; |
case FRAME_ACK_RECEIVED: |
- // If there are duplicate ack received events, pick the one with the |
- // smallest event timestamp so we can get a better bound. |
- if (it->second.event_c_time.is_null()) { |
- it->second.event_c_time = frame_event.timestamp; |
- } else { |
- it->second.event_c_time = |
- std::min(frame_event.timestamp, it->second.event_c_time); |
- } |
+ lower_bound_.SetReceived(frame_event.rtp_timestamp, |
+ 0, |
+ frame_event.media_type == AUDIO_EVENT, |
+ frame_event.timestamp); |
break; |
default: |
- NOTREACHED(); |
- } |
- |
- if (!it->second.event_a_time.is_null() && |
- !it->second.event_b_time.is_null() && |
- !it->second.event_c_time.is_null()) { |
- UpdateOffsetBounds(it->second); |
- event_times_map_.erase(it); |
+ // Ignored |
+ break; |
} |
- |
- // Keep the map size at most |kMaxEventTimesMapSize|. |
- if (event_times_map_.size() > kMaxEventTimesMapSize) |
- event_times_map_.erase(event_times_map_.begin()); |
} |
bool ReceiverTimeOffsetEstimatorImpl::GetReceiverOffsetBounds( |
base::TimeDelta* lower_bound, |
base::TimeDelta* upper_bound) { |
- if (!bounded_) |
+ if (!lower_bound_.has_bound() || !upper_bound_.has_bound()) |
return false; |
- *lower_bound = prev_offset_lower_bound_; |
- *upper_bound = prev_offset_upper_bound_; |
+ *lower_bound = -lower_bound_.bound(); |
+ *upper_bound = upper_bound_.bound(); |
+ |
+ // Sanitize the output, we don't want the upper bound to be |
+ // lower than the lower bound, make them the same. |
+ if (upper_bound < lower_bound) { |
+ lower_bound += (lower_bound - upper_bound) / 2; |
+ upper_bound = lower_bound; |
+ } |
return true; |
} |
void ReceiverTimeOffsetEstimatorImpl::OnReceivePacketEvent( |
const PacketEvent& packet_event) { |
- // Not interested in packet events. |
DCHECK(thread_checker_.CalledOnValidThread()); |
-} |
- |
-void ReceiverTimeOffsetEstimatorImpl::UpdateOffsetBounds( |
- const EventTimes& event) { |
- base::TimeDelta lower_bound = event.event_b_time - event.event_c_time; |
- base::TimeDelta upper_bound = event.event_b_time - event.event_a_time; |
- |
- if (offset_bounds_valid_) { |
- lower_bound = std::max(lower_bound, offset_lower_bound_); |
- upper_bound = std::min(upper_bound, offset_upper_bound_); |
- } |
- |
- if (lower_bound > upper_bound) { |
- VLOG(2) << "Got bogus offset bound values [" << lower_bound.InMilliseconds() |
- << ", " << upper_bound.InMilliseconds() << "]."; |
- return; |
- } |
- |
- offset_lower_bound_ = lower_bound; |
- offset_upper_bound_ = upper_bound; |
- offset_bounds_valid_ = true; |
- if (!bounded_ || |
- offset_upper_bound_ - offset_lower_bound_ < |
- base::TimeDelta::FromMilliseconds(20)) { |
- prev_offset_lower_bound_ = offset_lower_bound_; |
- prev_offset_upper_bound_ = offset_upper_bound_; |
- } |
- |
- base::TimeTicks now = clock_->NowTicks(); |
- if (now - last_reset_time_ > base::TimeDelta::FromSeconds(20)) { |
- last_reset_time_ = now; |
- offset_lower_bound_ = base::TimeDelta(); |
- offset_upper_bound_ = base::TimeDelta(); |
- offset_bounds_valid_ = false; |
+ switch (packet_event.type) { |
+ case PACKET_SENT_TO_NETWORK: |
+ upper_bound_.SetSent(packet_event.rtp_timestamp, |
+ packet_event.packet_id, |
+ packet_event.media_type == AUDIO_EVENT, |
+ packet_event.timestamp); |
+ break; |
+ case PACKET_RECEIVED: |
+ upper_bound_.SetReceived(packet_event.rtp_timestamp, |
+ packet_event.packet_id, |
+ packet_event.media_type == AUDIO_EVENT, |
+ packet_event.timestamp); |
+ break; |
+ default: |
+ // Ignored |
+ break; |
} |
- |
- bounded_ = true; |
} |
+ |
} // namespace cast |
} // namespace media |