OLD | NEW |
(Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include <algorithm> |
| 6 #include <utility> |
| 7 |
| 8 #include "base/logging.h" |
| 9 #include "media/cast/logging/receiver_time_offset_estimator_impl.h" |
| 10 |
| 11 namespace media { |
| 12 namespace cast { |
| 13 |
| 14 // This should be large enough so that we can collect all 3 events before |
| 15 // the entry gets removed from the map. |
| 16 const size_t kMaxEventTimesMapSize = 100; |
| 17 |
| 18 ReceiverTimeOffsetEstimatorImpl::ReceiverTimeOffsetEstimatorImpl() |
| 19 : bounded_(false) {} |
| 20 |
| 21 ReceiverTimeOffsetEstimatorImpl::~ReceiverTimeOffsetEstimatorImpl() { |
| 22 DCHECK(thread_checker_.CalledOnValidThread()); |
| 23 } |
| 24 |
| 25 void ReceiverTimeOffsetEstimatorImpl::OnReceiveFrameEvent( |
| 26 const FrameEvent& frame_event) { |
| 27 DCHECK(thread_checker_.CalledOnValidThread()); |
| 28 CastLoggingEvent event = frame_event.type; |
| 29 if (event != kVideoFrameEncoded && event != kVideoAckSent && |
| 30 event != kVideoAckReceived) |
| 31 return; |
| 32 |
| 33 EventTimesMap::iterator it = event_times_map_.find(frame_event.rtp_timestamp); |
| 34 if (it == event_times_map_.end()) { |
| 35 EventTimes event_times; |
| 36 it = event_times_map_.insert(std::make_pair(frame_event.rtp_timestamp, |
| 37 event_times)).first; |
| 38 } |
| 39 switch (event) { |
| 40 case kVideoFrameEncoded: |
| 41 // Encode is supposed to happen only once. If we see duplicate event, |
| 42 // throw away the entry. |
| 43 if (it->second.event_a_time.is_null()) { |
| 44 it->second.event_a_time = frame_event.timestamp; |
| 45 } else { |
| 46 event_times_map_.erase(it); |
| 47 return; |
| 48 } |
| 49 break; |
| 50 case kVideoAckSent: |
| 51 if (it->second.event_b_time.is_null()) { |
| 52 it->second.event_b_time = frame_event.timestamp; |
| 53 } else if (it->second.event_b_time != frame_event.timestamp) { |
| 54 // Duplicate ack sent events are normal due to RTCP redundancy, |
| 55 // but they must have the same event timestamp. |
| 56 event_times_map_.erase(it); |
| 57 return; |
| 58 } |
| 59 break; |
| 60 case kVideoAckReceived: |
| 61 // If there are duplicate ack received events, pick the one with the |
| 62 // smallest event timestamp so we can get a better bound. |
| 63 if (it->second.event_c_time.is_null()) { |
| 64 it->second.event_c_time = frame_event.timestamp; |
| 65 } else { |
| 66 it->second.event_c_time = |
| 67 std::min(frame_event.timestamp, it->second.event_c_time); |
| 68 } |
| 69 break; |
| 70 default: |
| 71 NOTREACHED(); |
| 72 } |
| 73 |
| 74 if (!it->second.event_a_time.is_null() && |
| 75 !it->second.event_b_time.is_null() && |
| 76 !it->second.event_c_time.is_null()) { |
| 77 UpdateOffsetBounds(it->second); |
| 78 event_times_map_.erase(it); |
| 79 } |
| 80 |
| 81 // Keep the map size at most |kMaxEventTimesMapSize|. |
| 82 if (event_times_map_.size() > kMaxEventTimesMapSize) |
| 83 event_times_map_.erase(event_times_map_.begin()); |
| 84 } |
| 85 |
| 86 bool ReceiverTimeOffsetEstimatorImpl::GetReceiverOffsetBounds( |
| 87 base::TimeDelta* lower_bound, |
| 88 base::TimeDelta* upper_bound) { |
| 89 if (!bounded_) |
| 90 return false; |
| 91 |
| 92 *lower_bound = offset_lower_bound_; |
| 93 *upper_bound = offset_upper_bound_; |
| 94 return true; |
| 95 } |
| 96 |
| 97 void ReceiverTimeOffsetEstimatorImpl::OnReceivePacketEvent( |
| 98 const PacketEvent& packet_event) { |
| 99 // Not interested in packet events. |
| 100 DCHECK(thread_checker_.CalledOnValidThread()); |
| 101 } |
| 102 |
| 103 void ReceiverTimeOffsetEstimatorImpl::UpdateOffsetBounds( |
| 104 const EventTimes& event) { |
| 105 base::TimeDelta lower_bound = event.event_b_time - event.event_c_time; |
| 106 base::TimeDelta upper_bound = event.event_b_time - event.event_a_time; |
| 107 |
| 108 if (bounded_) { |
| 109 lower_bound = std::max(lower_bound, offset_lower_bound_); |
| 110 upper_bound = std::min(upper_bound, offset_upper_bound_); |
| 111 } |
| 112 |
| 113 if (lower_bound > upper_bound) { |
| 114 VLOG(2) << "Got bogus offset bound values [" << lower_bound.InMilliseconds() |
| 115 << ", " << upper_bound.InMilliseconds() << "]."; |
| 116 return; |
| 117 } |
| 118 |
| 119 offset_lower_bound_ = lower_bound; |
| 120 offset_upper_bound_ = upper_bound; |
| 121 bounded_ = true; |
| 122 } |
| 123 |
| 124 } // namespace cast |
| 125 } // namespace media |
OLD | NEW |