15f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <algorithm>
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <utility>
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h"
95f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/time/tick_clock.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/cast/logging/receiver_time_offset_estimator_impl.h"
115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)namespace media {
135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)namespace cast {
145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)ReceiverTimeOffsetEstimatorImpl::BoundCalculator::BoundCalculator()
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : has_bound_(false) {}
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ReceiverTimeOffsetEstimatorImpl::BoundCalculator::~BoundCalculator() {}
185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void ReceiverTimeOffsetEstimatorImpl::BoundCalculator::SetSent(
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    uint32 rtp,
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    uint32 packet_id,
225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    bool audio,
235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    base::TimeTicks t) {
245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  uint64 key = (static_cast<uint64>(rtp) << 32) | (packet_id << 1) |
255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      static_cast<uint64>(audio);
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  events_[key].first = t;
275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  CheckUpdate(key);
285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ReceiverTimeOffsetEstimatorImpl::BoundCalculator::SetReceived(
315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    uint32 rtp,
325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    uint16 packet_id,
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool audio,
345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    base::TimeTicks t) {
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  uint64 key = (static_cast<uint64>(rtp) << 32) | (packet_id << 1) |
365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      static_cast<uint64>(audio);
375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  events_[key].second = t;
385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  CheckUpdate(key);
395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ReceiverTimeOffsetEstimatorImpl::BoundCalculator::UpdateBound(
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    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
56void 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
73ReceiverTimeOffsetEstimatorImpl::ReceiverTimeOffsetEstimatorImpl() {
74}
75
76ReceiverTimeOffsetEstimatorImpl::~ReceiverTimeOffsetEstimatorImpl() {
77  DCHECK(thread_checker_.CalledOnValidThread());
78}
79
80
81void 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
103bool 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
121void 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