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