Chromium Code Reviews| 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..4ef9fb4d700f0b7bc7ece6ad1bd7356152229887 100644 |
| --- a/media/cast/logging/receiver_time_offset_estimator_impl.cc |
| +++ b/media/cast/logging/receiver_time_offset_estimator_impl.cc |
| @@ -12,140 +12,132 @@ |
| 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) | 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) | 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; |
|
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
|
| + } |
| + } else { |
| + bound_ = delta; |
| + } |
| + has_bound_ = true; |
| + } |
| + |
| +void ReceiverTimeOffsetEstimatorImpl::BoundCalculator::CheckUpdate( |
| + uint64 key) { |
| + TimeTickPair &ticks = events_[key]; |
|
imcheng
2014/09/09 01:04:23
const?
hubbe
2014/09/09 19:06:15
Done.
|
| + 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 |