| 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) | |
| 25 static_cast<uint64>(audio); |
| 26 events_[key].first = t; |
| 27 CheckUpdate(key); |
| 28 } |
| 29 |
| 30 void ReceiverTimeOffsetEstimatorImpl::BoundCalculator::SetReceived( |
| 31 uint32 rtp, |
| 32 uint16 packet_id, |
| 33 bool audio, |
| 34 base::TimeTicks t) { |
| 35 uint64 key = (static_cast<uint64>(rtp) << 32) | (packet_id << 1) | |
| 36 static_cast<uint64>(audio); |
| 37 events_[key].second = t; |
| 38 CheckUpdate(key); |
| 39 } |
| 40 |
| 41 void ReceiverTimeOffsetEstimatorImpl::BoundCalculator::UpdateBound( |
| 42 base::TimeTicks sent, base::TimeTicks received) { |
| 43 base::TimeDelta delta = received - sent; |
| 44 if (has_bound_) { |
| 45 if (delta < bound_) { |
| 46 bound_ = delta; |
| 47 } else { |
| 48 bound_ += (delta - bound_) / kClockDriftSpeed; |
| 49 } |
| 50 } else { |
| 51 bound_ = delta; |
| 52 } |
| 53 has_bound_ = true; |
| 54 } |
| 55 |
| 56 void ReceiverTimeOffsetEstimatorImpl::BoundCalculator::CheckUpdate( |
| 57 uint64 key) { |
| 58 const TimeTickPair& ticks = events_[key]; |
| 59 if (!ticks.first.is_null() && !ticks.second.is_null()) { |
| 60 UpdateBound(ticks.first, ticks.second); |
| 61 events_.erase(key); |
| 62 return; |
| 63 } |
| 64 |
| 65 if (events_.size() > kMaxEventTimesMapSize) { |
| 66 EventMap::iterator i = ModMapOldest(&events_); |
| 67 if (i != events_.end()) { |
| 68 events_.erase(i); |
| 69 } |
| 70 } |
| 71 } |
| 72 |
| 73 ReceiverTimeOffsetEstimatorImpl::ReceiverTimeOffsetEstimatorImpl() { |
| 25 } | 74 } |
| 26 | 75 |
| 27 ReceiverTimeOffsetEstimatorImpl::~ReceiverTimeOffsetEstimatorImpl() { | 76 ReceiverTimeOffsetEstimatorImpl::~ReceiverTimeOffsetEstimatorImpl() { |
| 28 DCHECK(thread_checker_.CalledOnValidThread()); | 77 DCHECK(thread_checker_.CalledOnValidThread()); |
| 29 } | 78 } |
| 30 | 79 |
| 80 |
| 31 void ReceiverTimeOffsetEstimatorImpl::OnReceiveFrameEvent( | 81 void ReceiverTimeOffsetEstimatorImpl::OnReceiveFrameEvent( |
| 32 const FrameEvent& frame_event) { | 82 const FrameEvent& frame_event) { |
| 33 DCHECK(thread_checker_.CalledOnValidThread()); | 83 DCHECK(thread_checker_.CalledOnValidThread()); |
| 34 | 84 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: | 85 case FRAME_ACK_SENT: |
| 61 if (it->second.event_b_time.is_null()) { | 86 lower_bound_.SetSent(frame_event.rtp_timestamp, |
| 62 it->second.event_b_time = frame_event.timestamp; | 87 0, |
| 63 } else if (it->second.event_b_time != frame_event.timestamp) { | 88 frame_event.media_type == AUDIO_EVENT, |
| 64 // Duplicate ack sent events are normal due to RTCP redundancy, | 89 frame_event.timestamp); |
| 65 // but they must have the same event timestamp. | |
| 66 event_times_map_.erase(it); | |
| 67 return; | |
| 68 } | |
| 69 break; | 90 break; |
| 70 case FRAME_ACK_RECEIVED: | 91 case FRAME_ACK_RECEIVED: |
| 71 // If there are duplicate ack received events, pick the one with the | 92 lower_bound_.SetReceived(frame_event.rtp_timestamp, |
| 72 // smallest event timestamp so we can get a better bound. | 93 0, |
| 73 if (it->second.event_c_time.is_null()) { | 94 frame_event.media_type == AUDIO_EVENT, |
| 74 it->second.event_c_time = frame_event.timestamp; | 95 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; | 96 break; |
| 80 default: | 97 default: |
| 81 NOTREACHED(); | 98 // Ignored |
| 99 break; |
| 82 } | 100 } |
| 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 } | 101 } |
| 95 | 102 |
| 96 bool ReceiverTimeOffsetEstimatorImpl::GetReceiverOffsetBounds( | 103 bool ReceiverTimeOffsetEstimatorImpl::GetReceiverOffsetBounds( |
| 97 base::TimeDelta* lower_bound, | 104 base::TimeDelta* lower_bound, |
| 98 base::TimeDelta* upper_bound) { | 105 base::TimeDelta* upper_bound) { |
| 99 if (!bounded_) | 106 if (!lower_bound_.has_bound() || !upper_bound_.has_bound()) |
| 100 return false; | 107 return false; |
| 101 | 108 |
| 102 *lower_bound = prev_offset_lower_bound_; | 109 *lower_bound = -lower_bound_.bound(); |
| 103 *upper_bound = prev_offset_upper_bound_; | 110 *upper_bound = upper_bound_.bound(); |
| 111 |
| 112 // Sanitize the output, we don't want the upper bound to be |
| 113 // lower than the lower bound, make them the same. |
| 114 if (upper_bound < lower_bound) { |
| 115 lower_bound += (lower_bound - upper_bound) / 2; |
| 116 upper_bound = lower_bound; |
| 117 } |
| 104 return true; | 118 return true; |
| 105 } | 119 } |
| 106 | 120 |
| 107 void ReceiverTimeOffsetEstimatorImpl::OnReceivePacketEvent( | 121 void ReceiverTimeOffsetEstimatorImpl::OnReceivePacketEvent( |
| 108 const PacketEvent& packet_event) { | 122 const PacketEvent& packet_event) { |
| 109 // Not interested in packet events. | |
| 110 DCHECK(thread_checker_.CalledOnValidThread()); | 123 DCHECK(thread_checker_.CalledOnValidThread()); |
| 124 switch (packet_event.type) { |
| 125 case PACKET_SENT_TO_NETWORK: |
| 126 upper_bound_.SetSent(packet_event.rtp_timestamp, |
| 127 packet_event.packet_id, |
| 128 packet_event.media_type == AUDIO_EVENT, |
| 129 packet_event.timestamp); |
| 130 break; |
| 131 case PACKET_RECEIVED: |
| 132 upper_bound_.SetReceived(packet_event.rtp_timestamp, |
| 133 packet_event.packet_id, |
| 134 packet_event.media_type == AUDIO_EVENT, |
| 135 packet_event.timestamp); |
| 136 break; |
| 137 default: |
| 138 // Ignored |
| 139 break; |
| 140 } |
| 111 } | 141 } |
| 112 | 142 |
| 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 | 143 |
| 150 } // namespace cast | 144 } // namespace cast |
| 151 } // namespace media | 145 } // namespace media |
| OLD | NEW |