Shaka Player Embedded
pipeline_manager.cc
Go to the documentation of this file.
1 // Copyright 2017 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
16 
17 #include <algorithm>
18 #include <cmath>
19 #include <utility>
20 
21 #include "src/util/utils.h"
22 
23 namespace shaka {
24 namespace media {
25 
27  std::function<void(VideoPlaybackState)> on_status_changed,
28  std::function<void()> on_seek, const util::Clock* clock)
29  : mutex_("PipelineManager"),
30  on_status_changed_(std::move(on_status_changed)),
31  on_seek_(std::move(on_seek)),
32  clock_(clock) {
33  Reset();
34 }
35 
37 
39  std::unique_lock<SharedMutex> lock(mutex_);
41  prev_media_time_ = 0;
42  prev_wall_time_ = clock_->GetMonotonicTime();
43  playback_rate_ = 1;
44  duration_ = NAN;
45  will_play_ = false;
46 }
47 
49  VideoPlaybackState new_status;
50  {
51  std::unique_lock<SharedMutex> lock(mutex_);
52  if (status_ == VideoPlaybackState::Errored)
53  return;
54  DCHECK(status_ == VideoPlaybackState::Initializing);
55  if (will_play_) {
56  new_status = status_ = VideoPlaybackState::Buffering;
57  } else {
58  new_status = status_ = VideoPlaybackState::Paused;
59  }
60  }
61  on_status_changed_(new_status);
62 }
63 
65  util::shared_lock<SharedMutex> lock(mutex_);
66  return status_;
67 }
68 
70  util::shared_lock<SharedMutex> lock(mutex_);
71  return duration_;
72 }
73 
74 void PipelineManager::SetDuration(double duration) {
76  {
77  std::unique_lock<SharedMutex> lock(mutex_);
78  duration_ = duration;
79 
80  // Seek to duration if current time is past the new duration.
81  const uint64_t wall_time = clock_->GetMonotonicTime();
82  if (!std::isnan(duration) && GetTimeFor(wall_time) > duration) {
83  {
84  util::Unlocker<SharedMutex> unlock(&lock);
85  on_seek_();
86  }
87 
88  prev_media_time_ = duration;
89  prev_wall_time_ = wall_time;
90  if (status_ == VideoPlaybackState::Playing ||
91  status_ == VideoPlaybackState::Buffering ||
93  will_play_ = true;
94  new_status = status_ = VideoPlaybackState::Seeking;
95  } else if (status_ == VideoPlaybackState::Paused ||
96  status_ == VideoPlaybackState::Ended) {
97  will_play_ = false;
98  new_status = status_ = VideoPlaybackState::Seeking;
99  }
100  }
101  }
102  if (new_status != VideoPlaybackState::Initializing)
103  on_status_changed_(new_status);
104 }
105 
107  util::shared_lock<SharedMutex> lock(mutex_);
108  return GetTimeFor(clock_->GetMonotonicTime());
109 }
110 
113  {
114  std::unique_lock<SharedMutex> lock(mutex_);
115  if (status_ != VideoPlaybackState::Initializing) {
116  {
117  util::Unlocker<SharedMutex> unlock(&lock);
118  on_seek_();
119  }
120 
121  prev_media_time_ =
122  std::isnan(duration_) ? time : std::min(duration_, time);
123  prev_wall_time_ = clock_->GetMonotonicTime();
124  switch (status_) {
128  will_play_ = true;
129  new_status = status_ = VideoPlaybackState::Seeking;
130  break;
133  will_play_ = false;
134  new_status = status_ = VideoPlaybackState::Seeking;
135  break;
136  default: // Ignore remaining enum values.
137  break;
138  }
139  }
140  }
141  if (new_status != VideoPlaybackState::Initializing)
142  on_status_changed_(new_status);
143 }
144 
146  util::shared_lock<SharedMutex> lock(mutex_);
147  return playback_rate_;
148 }
149 
151  std::unique_lock<SharedMutex> lock(mutex_);
152  SyncPoint();
153  playback_rate_ = rate;
154 }
155 
158  {
159  std::unique_lock<SharedMutex> lock(mutex_);
160  SyncPoint();
161  will_play_ = true;
162  if (status_ == VideoPlaybackState::Paused) {
163  // Assume we are stalled; we will transition to Playing quickly if not.
164  new_status = status_ = VideoPlaybackState::Buffering;
165  } else if (status_ == VideoPlaybackState::Ended) {
166  {
167  util::Unlocker<SharedMutex> unlock(&lock);
168  on_seek_();
169  }
170 
171  prev_media_time_ = 0;
172  new_status = status_ = VideoPlaybackState::Seeking;
173  }
174  }
175  if (new_status != VideoPlaybackState::Initializing)
176  on_status_changed_(new_status);
177 }
178 
181  {
182  std::unique_lock<SharedMutex> lock(mutex_);
183  SyncPoint();
184  will_play_ = false;
185  if (status_ == VideoPlaybackState::Playing ||
186  status_ == VideoPlaybackState::Buffering ||
188  new_status = status_ = VideoPlaybackState::Paused;
189  }
190  }
191  if (new_status != VideoPlaybackState::Initializing)
192  on_status_changed_(new_status);
193 }
194 
196  bool status_changed = false;
197  {
198  std::unique_lock<SharedMutex> lock(mutex_);
199  if (status_ == VideoPlaybackState::Playing) {
200  SyncPoint();
202  status_changed = true;
203  }
204  }
205  if (status_changed)
206  on_status_changed_(VideoPlaybackState::Buffering);
207 }
208 
211  {
212  std::unique_lock<SharedMutex> lock(mutex_);
213  SyncPoint();
214  if (status_ == VideoPlaybackState::Buffering ||
216  status_ == VideoPlaybackState::Seeking) {
217  if (will_play_)
218  new_status = status_ = VideoPlaybackState::Playing;
219  else
220  new_status = status_ = VideoPlaybackState::Paused;
221  }
222  }
223  if (new_status != VideoPlaybackState::Initializing)
224  on_status_changed_(new_status);
225 }
226 
229  {
230  std::unique_lock<SharedMutex> lock(mutex_);
231  if (status_ != VideoPlaybackState::Ended &&
232  status_ != VideoPlaybackState::Errored) {
233  const uint64_t wall_time = clock_->GetMonotonicTime();
234  DCHECK(!std::isnan(duration_));
235  prev_wall_time_ = wall_time;
236  prev_media_time_ = duration_;
237  new_status = status_ = VideoPlaybackState::Ended;
238  }
239  }
240  if (new_status != VideoPlaybackState::Initializing)
241  on_status_changed_(new_status);
242 }
243 
245  bool fire_event = false;
246  {
247  std::unique_lock<SharedMutex> lock(mutex_);
248  if (status_ != VideoPlaybackState::Errored) {
249  SyncPoint();
250  status_ = VideoPlaybackState::Errored;
251  fire_event = true;
252  }
253  }
254  if (fire_event)
255  on_status_changed_(VideoPlaybackState::Errored);
256 }
257 
258 double PipelineManager::GetTimeFor(uint64_t wall_time) const {
259  if (status_ != VideoPlaybackState::Playing)
260  return prev_media_time_;
261 
262  const uint64_t wall_diff = wall_time - prev_wall_time_;
263  const double time = prev_media_time_ + (wall_diff * playback_rate_ / 1000.0);
264  return std::isnan(duration_) ? time : std::min(duration_, time);
265 }
266 
267 void PipelineManager::SyncPoint() {
268  const uint64_t wall_time = clock_->GetMonotonicTime();
269  prev_media_time_ = GetTimeFor(wall_time);
270  prev_wall_time_ = wall_time;
271 }
272 
273 } // namespace media
274 } // namespace shaka
virtual VideoPlaybackState GetPlaybackState() const
PipelineManager(std::function< void(VideoPlaybackState)> on_status_changed, std::function< void()> on_seek, const util::Clock *clock)
virtual void SetCurrentTime(double time)
virtual double GetCurrentTime() const
virtual void SetDuration(double duration)
virtual void SetPlaybackRate(double rate)
virtual double GetPlaybackRate() const
virtual uint64_t GetMonotonicTime() const
Definition: clock.cc:29
virtual double GetDuration() const