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 "chromecast/media/cma/base/buffering_state.h"
6 
7 #include <sstream>
8 
9 #include "base/logging.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "media/base/timestamp_constants.h"
12 
13 namespace chromecast {
14 namespace media {
15 
BufferingConfig(base::TimeDelta low_level_threshold,base::TimeDelta high_level_threshold)16 BufferingConfig::BufferingConfig(
17     base::TimeDelta low_level_threshold,
18     base::TimeDelta high_level_threshold)
19     : low_level_threshold_(low_level_threshold),
20       high_level_threshold_(high_level_threshold) {
21 }
22 
~BufferingConfig()23 BufferingConfig::~BufferingConfig() {
24 }
25 
BufferingState(const std::string & stream_id,const scoped_refptr<BufferingConfig> & config,const base::RepeatingClosure & state_changed_cb,const HighLevelBufferCB & high_level_buffer_cb)26 BufferingState::BufferingState(const std::string& stream_id,
27                                const scoped_refptr<BufferingConfig>& config,
28                                const base::RepeatingClosure& state_changed_cb,
29                                const HighLevelBufferCB& high_level_buffer_cb)
30     : stream_id_(stream_id),
31       config_(config),
32       state_changed_cb_(state_changed_cb),
33       high_level_buffer_cb_(high_level_buffer_cb),
34       state_(kLowLevel),
35       media_time_(::media::kNoTimestamp),
36       max_rendering_time_(::media::kNoTimestamp),
37       buffered_time_(::media::kNoTimestamp) {}
38 
~BufferingState()39 BufferingState::~BufferingState() {
40 }
41 
OnConfigChanged()42 void BufferingState::OnConfigChanged() {
43   state_ = GetBufferLevelState();
44 }
45 
SetMediaTime(base::TimeDelta media_time)46 void BufferingState::SetMediaTime(base::TimeDelta media_time) {
47   media_time_ = media_time;
48   switch (state_) {
49     case kLowLevel:
50     case kMediumLevel:
51     case kHighLevel:
52       UpdateState(GetBufferLevelState());
53       break;
54     case kEosReached:
55       break;
56   }
57 }
58 
SetMaxRenderingTime(base::TimeDelta max_rendering_time)59 void BufferingState::SetMaxRenderingTime(base::TimeDelta max_rendering_time) {
60   max_rendering_time_ = max_rendering_time;
61 }
62 
GetMaxRenderingTime() const63 base::TimeDelta BufferingState::GetMaxRenderingTime() const {
64   return max_rendering_time_;
65 }
66 
SetBufferedTime(base::TimeDelta buffered_time)67 void BufferingState::SetBufferedTime(base::TimeDelta buffered_time) {
68   buffered_time_ = buffered_time;
69   switch (state_) {
70     case kLowLevel:
71     case kMediumLevel:
72     case kHighLevel:
73       UpdateState(GetBufferLevelState());
74       break;
75     case kEosReached:
76       break;
77   }
78 }
79 
NotifyEos()80 void BufferingState::NotifyEos() {
81   UpdateState(kEosReached);
82 }
83 
NotifyMaxCapacity(base::TimeDelta buffered_time)84 void BufferingState::NotifyMaxCapacity(base::TimeDelta buffered_time) {
85   if (media_time_ == ::media::kNoTimestamp ||
86       buffered_time == ::media::kNoTimestamp) {
87     LOG(WARNING) << "Max capacity with no timestamp";
88     return;
89   }
90   base::TimeDelta buffer_duration = buffered_time - media_time_;
91   if (buffer_duration < config_->high_level())
92     high_level_buffer_cb_.Run(buffer_duration);
93 }
94 
StateToString(BufferingState::State state)95 static const char* StateToString(BufferingState::State state) {
96   switch (state) {
97     case BufferingState::kLowLevel:
98       return "kLowLevel";
99     case BufferingState::kMediumLevel:
100       return "kMediumLevel";
101     case BufferingState::kHighLevel:
102       return "kHighLevel";
103     case BufferingState::kEosReached:
104       return "kEosReached";
105     default:
106       NOTREACHED();
107   }
108   NOTREACHED();
109   return "";
110 }
111 
TimeDeltaToString(const base::TimeDelta & t)112 static std::string TimeDeltaToString(const base::TimeDelta& t) {
113   if (t == ::media::kNoTimestamp)
114     return "kNoTimestamp";
115   return base::NumberToString(t.InSecondsF());
116 }
117 
ToString() const118 std::string BufferingState::ToString() const {
119   std::ostringstream s;
120   s << stream_id_ << " state=" << StateToString(state_)
121     << " media_time=" << TimeDeltaToString(media_time_)
122     << " buffered_time=" << TimeDeltaToString(buffered_time_);
123   return s.str();
124 }
125 
GetBufferLevelState() const126 BufferingState::State BufferingState::GetBufferLevelState() const {
127   if (media_time_ == ::media::kNoTimestamp ||
128       buffered_time_ == ::media::kNoTimestamp) {
129     return kLowLevel;
130   }
131 
132   base::TimeDelta buffer_duration = buffered_time_ - media_time_;
133   if (buffer_duration <= config_->low_level())
134     return kLowLevel;
135   if (buffer_duration >= config_->high_level())
136     return kHighLevel;
137   return kMediumLevel;
138 }
139 
UpdateState(State new_state)140 void BufferingState::UpdateState(State new_state) {
141   if (new_state == state_)
142     return;
143 
144   state_ = new_state;
145   if (!state_changed_cb_.is_null())
146     state_changed_cb_.Run();
147 }
148 
149 }  // namespace media
150 }  // namespace chromecast
151