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 "base/time/tick_clock.h" 10 #include "media/cast/logging/receiver_time_offset_estimator_impl.h" 11 12 namespace media { 13 namespace cast { 14 15 ReceiverTimeOffsetEstimatorImpl::BoundCalculator::BoundCalculator() 16 : has_bound_(false) {} 17 ReceiverTimeOffsetEstimatorImpl::BoundCalculator::~BoundCalculator() {} 18 19 void ReceiverTimeOffsetEstimatorImpl::BoundCalculator::SetSent( 20 uint32 rtp, 21 uint32 packet_id, 22 bool audio, 23 base::TimeTicks t) { 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() { 74 } 75 76 ReceiverTimeOffsetEstimatorImpl::~ReceiverTimeOffsetEstimatorImpl() { 77 DCHECK(thread_checker_.CalledOnValidThread()); 78 } 79 80 81 void ReceiverTimeOffsetEstimatorImpl::OnReceiveFrameEvent( 82 const FrameEvent& frame_event) { 83 DCHECK(thread_checker_.CalledOnValidThread()); 84 switch (frame_event.type) { 85 case FRAME_ACK_SENT: 86 lower_bound_.SetSent(frame_event.rtp_timestamp, 87 0, 88 frame_event.media_type == AUDIO_EVENT, 89 frame_event.timestamp); 90 break; 91 case FRAME_ACK_RECEIVED: 92 lower_bound_.SetReceived(frame_event.rtp_timestamp, 93 0, 94 frame_event.media_type == AUDIO_EVENT, 95 frame_event.timestamp); 96 break; 97 default: 98 // Ignored 99 break; 100 } 101 } 102 103 bool ReceiverTimeOffsetEstimatorImpl::GetReceiverOffsetBounds( 104 base::TimeDelta* lower_bound, 105 base::TimeDelta* upper_bound) { 106 if (!lower_bound_.has_bound() || !upper_bound_.has_bound()) 107 return false; 108 109 *lower_bound = -lower_bound_.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 } 118 return true; 119 } 120 121 void ReceiverTimeOffsetEstimatorImpl::OnReceivePacketEvent( 122 const PacketEvent& packet_event) { 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 } 141 } 142 143 144 } // namespace cast 145 } // namespace media 146