[MediaRouter] Update MR-2-Extension's PostMessage to return boolean.
[chromium-blink-merge.git] / chromecast / media / cma / pipeline / media_pipeline_impl.cc
blobfe5a2ebd10d58c661e0ab0b8f83973d17fad4c2a
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.
5 #include "chromecast/media/cma/pipeline/media_pipeline_impl.h"
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/callback_helpers.h"
10 #include "base/location.h"
11 #include "base/logging.h"
12 #include "base/single_thread_task_runner.h"
13 #include "base/thread_task_runner_handle.h"
14 #include "base/time/time.h"
15 #include "chromecast/media/cdm/browser_cdm_cast.h"
16 #include "chromecast/media/cma/backend/media_clock_device.h"
17 #include "chromecast/media/cma/backend/media_pipeline_device.h"
18 #include "chromecast/media/cma/base/buffering_controller.h"
19 #include "chromecast/media/cma/base/buffering_state.h"
20 #include "chromecast/media/cma/base/cma_logging.h"
21 #include "chromecast/media/cma/base/coded_frame_provider.h"
22 #include "chromecast/media/cma/pipeline/audio_pipeline_impl.h"
23 #include "chromecast/media/cma/pipeline/video_pipeline_impl.h"
24 #include "media/base/buffers.h"
26 namespace chromecast {
27 namespace media {
29 namespace {
31 // Buffering parameters when load_type is kLoadTypeUrl.
32 const base::TimeDelta kLowBufferThresholdURL(
33 base::TimeDelta::FromMilliseconds(2000));
34 const base::TimeDelta kHighBufferThresholdURL(
35 base::TimeDelta::FromMilliseconds(6000));
37 // Buffering parameters when load_type is kLoadTypeMediaSource.
38 const base::TimeDelta kLowBufferThresholdMediaSource(
39 base::TimeDelta::FromMilliseconds(0));
40 const base::TimeDelta kHighBufferThresholdMediaSource(
41 base::TimeDelta::FromMilliseconds(300));
43 // Interval between two updates of the media time.
44 const base::TimeDelta kTimeUpdateInterval(
45 base::TimeDelta::FromMilliseconds(250));
47 // Interval between two updates of the statistics is equal to:
48 // kTimeUpdateInterval * kStatisticsUpdatePeriod.
49 const int kStatisticsUpdatePeriod = 4;
51 } // namespace
53 MediaPipelineImpl::MediaPipelineImpl()
54 : has_audio_(false),
55 has_video_(false),
56 target_playback_rate_(0.0),
57 enable_time_update_(false),
58 pending_time_update_task_(false),
59 statistics_rolling_counter_(0),
60 weak_factory_(this) {
61 CMALOG(kLogControl) << __FUNCTION__;
62 weak_this_ = weak_factory_.GetWeakPtr();
63 thread_checker_.DetachFromThread();
66 MediaPipelineImpl::~MediaPipelineImpl() {
67 CMALOG(kLogControl) << __FUNCTION__;
68 DCHECK(thread_checker_.CalledOnValidThread());
71 void MediaPipelineImpl::Initialize(
72 LoadType load_type,
73 scoped_ptr<MediaPipelineDevice> media_pipeline_device) {
74 CMALOG(kLogControl) << __FUNCTION__;
75 DCHECK(thread_checker_.CalledOnValidThread());
76 media_pipeline_device_.reset(media_pipeline_device.release());
77 clock_device_ = media_pipeline_device_->GetMediaClockDevice();
79 if (load_type == kLoadTypeURL || load_type == kLoadTypeMediaSource) {
80 base::TimeDelta low_threshold(kLowBufferThresholdURL);
81 base::TimeDelta high_threshold(kHighBufferThresholdURL);
82 if (load_type == kLoadTypeMediaSource) {
83 low_threshold = kLowBufferThresholdMediaSource;
84 high_threshold = kHighBufferThresholdMediaSource;
86 scoped_refptr<BufferingConfig> buffering_config(
87 new BufferingConfig(low_threshold, high_threshold));
88 buffering_controller_.reset(new BufferingController(
89 buffering_config,
90 base::Bind(&MediaPipelineImpl::OnBufferingNotification, weak_this_)));
93 audio_pipeline_.reset(new AudioPipelineImpl(
94 media_pipeline_device_->GetAudioPipelineDevice()));
96 video_pipeline_.reset(new VideoPipelineImpl(
97 media_pipeline_device_->GetVideoPipelineDevice()));
100 void MediaPipelineImpl::SetClient(const MediaPipelineClient& client) {
101 DCHECK(thread_checker_.CalledOnValidThread());
102 DCHECK(!client.error_cb.is_null());
103 DCHECK(!client.time_update_cb.is_null());
104 DCHECK(!client.buffering_state_cb.is_null());
105 client_ = client;
108 void MediaPipelineImpl::SetCdm(int cdm_id) {
109 CMALOG(kLogControl) << __FUNCTION__ << " cdm_id=" << cdm_id;
110 DCHECK(thread_checker_.CalledOnValidThread());
111 NOTIMPLEMENTED();
112 // TODO(gunsch): SetCdm(int) is not implemented.
113 // One possibility would be a GetCdmByIdCB that's passed in.
116 void MediaPipelineImpl::SetCdm(BrowserCdmCast* cdm) {
117 CMALOG(kLogControl) << __FUNCTION__;
118 DCHECK(thread_checker_.CalledOnValidThread());
119 audio_pipeline_->SetCdm(cdm);
120 video_pipeline_->SetCdm(cdm);
123 AudioPipeline* MediaPipelineImpl::GetAudioPipeline() const {
124 return audio_pipeline_.get();
127 VideoPipeline* MediaPipelineImpl::GetVideoPipeline() const {
128 return video_pipeline_.get();
131 void MediaPipelineImpl::InitializeAudio(
132 const ::media::AudioDecoderConfig& config,
133 scoped_ptr<CodedFrameProvider> frame_provider,
134 const ::media::PipelineStatusCB& status_cb) {
135 DCHECK(thread_checker_.CalledOnValidThread());
136 DCHECK(!has_audio_);
137 if (clock_device_->GetState() == MediaClockDevice::kStateUninitialized &&
138 !clock_device_->SetState(MediaClockDevice::kStateIdle)) {
139 status_cb.Run(::media::PIPELINE_ERROR_INITIALIZATION_FAILED);
140 return;
142 has_audio_ = true;
143 audio_pipeline_->Initialize(config, frame_provider.Pass(), status_cb);
146 void MediaPipelineImpl::InitializeVideo(
147 const std::vector<::media::VideoDecoderConfig>& configs,
148 scoped_ptr<CodedFrameProvider> frame_provider,
149 const ::media::PipelineStatusCB& status_cb) {
150 DCHECK(thread_checker_.CalledOnValidThread());
151 DCHECK(!has_video_);
152 if (clock_device_->GetState() == MediaClockDevice::kStateUninitialized &&
153 !clock_device_->SetState(MediaClockDevice::kStateIdle)) {
154 status_cb.Run(::media::PIPELINE_ERROR_INITIALIZATION_FAILED);
155 return;
157 has_video_ = true;
158 video_pipeline_->Initialize(configs, frame_provider.Pass(), status_cb);
161 void MediaPipelineImpl::StartPlayingFrom(base::TimeDelta time) {
162 CMALOG(kLogControl) << __FUNCTION__ << " t0=" << time.InMilliseconds();
163 DCHECK(thread_checker_.CalledOnValidThread());
164 DCHECK(has_audio_ || has_video_);
165 DCHECK(!pending_flush_callbacks_);
167 // Reset the start of the timeline.
168 DCHECK_EQ(clock_device_->GetState(), MediaClockDevice::kStateIdle);
169 clock_device_->ResetTimeline(time);
171 // Start the clock. If the playback rate is 0, then the clock is started
172 // but does not increase.
173 if (!clock_device_->SetState(MediaClockDevice::kStateRunning)) {
174 OnError(::media::PIPELINE_ERROR_ABORT);
175 return;
178 // Enable time updates.
179 enable_time_update_ = true;
180 statistics_rolling_counter_ = 0;
181 if (!pending_time_update_task_) {
182 pending_time_update_task_ = true;
183 base::ThreadTaskRunnerHandle::Get()->PostTask(
184 FROM_HERE, base::Bind(&MediaPipelineImpl::UpdateMediaTime, weak_this_));
187 // Setup the audio and video pipeline for the new timeline.
188 if (has_audio_) {
189 scoped_refptr<BufferingState> buffering_state;
190 if (buffering_controller_)
191 buffering_state = buffering_controller_->AddStream("audio");
192 if (!audio_pipeline_->StartPlayingFrom(time, buffering_state)) {
193 OnError(::media::PIPELINE_ERROR_ABORT);
194 return;
197 if (has_video_) {
198 scoped_refptr<BufferingState> buffering_state;
199 if (buffering_controller_)
200 buffering_state = buffering_controller_->AddStream("video");
201 if (!video_pipeline_->StartPlayingFrom(time, buffering_state)) {
202 OnError(::media::PIPELINE_ERROR_ABORT);
203 return;
208 void MediaPipelineImpl::Flush(const ::media::PipelineStatusCB& status_cb) {
209 CMALOG(kLogControl) << __FUNCTION__;
210 DCHECK(thread_checker_.CalledOnValidThread());
211 DCHECK(has_audio_ || has_video_);
212 DCHECK(!pending_flush_callbacks_);
214 // No need to update media time anymore.
215 enable_time_update_ = false;
217 buffering_controller_->Reset();
219 // The clock should return to idle.
220 if (!clock_device_->SetState(MediaClockDevice::kStateIdle)) {
221 status_cb.Run(::media::PIPELINE_ERROR_ABORT);
222 return;
225 // Flush both the audio and video pipeline.
226 ::media::SerialRunner::Queue bound_fns;
227 if (has_audio_) {
228 bound_fns.Push(base::Bind(
229 &AudioPipelineImpl::Flush,
230 base::Unretained(audio_pipeline_.get())));
232 if (has_video_) {
233 bound_fns.Push(base::Bind(
234 &VideoPipelineImpl::Flush,
235 base::Unretained(video_pipeline_.get())));
237 ::media::PipelineStatusCB transition_cb =
238 base::Bind(&MediaPipelineImpl::StateTransition, weak_this_, status_cb);
239 pending_flush_callbacks_ =
240 ::media::SerialRunner::Run(bound_fns, transition_cb);
243 void MediaPipelineImpl::Stop() {
244 CMALOG(kLogControl) << __FUNCTION__;
245 DCHECK(thread_checker_.CalledOnValidThread());
246 DCHECK(has_audio_ || has_video_);
248 // Cancel pending flush callbacks since we are about to stop/shutdown
249 // audio/video pipelines. This will ensure A/V Flush won't happen in
250 // stopped state.
251 pending_flush_callbacks_.reset();
253 // No need to update media time anymore.
254 enable_time_update_ = false;
256 // Release hardware resources on Stop.
257 // Note: Stop can be called from any state.
258 if (clock_device_->GetState() == MediaClockDevice::kStateRunning)
259 clock_device_->SetState(MediaClockDevice::kStateIdle);
260 if (clock_device_->GetState() == MediaClockDevice::kStateIdle)
261 clock_device_->SetState(MediaClockDevice::kStateUninitialized);
263 // Stop both the audio and video pipeline.
264 if (has_audio_)
265 audio_pipeline_->Stop();
266 if (has_video_)
267 video_pipeline_->Stop();
270 void MediaPipelineImpl::SetPlaybackRate(double rate) {
271 CMALOG(kLogControl) << __FUNCTION__ << " rate=" << rate;
272 DCHECK(thread_checker_.CalledOnValidThread());
273 target_playback_rate_ = rate;
274 if (!buffering_controller_ || !buffering_controller_->IsBuffering())
275 media_pipeline_device_->GetMediaClockDevice()->SetRate(rate);
278 AudioPipelineImpl* MediaPipelineImpl::GetAudioPipelineImpl() const {
279 return audio_pipeline_.get();
282 VideoPipelineImpl* MediaPipelineImpl::GetVideoPipelineImpl() const {
283 return video_pipeline_.get();
286 void MediaPipelineImpl::StateTransition(
287 const ::media::PipelineStatusCB& status_cb,
288 ::media::PipelineStatus status) {
289 pending_flush_callbacks_.reset();
290 status_cb.Run(status);
293 void MediaPipelineImpl::OnBufferingNotification(bool is_buffering) {
294 CMALOG(kLogControl) << __FUNCTION__ << " is_buffering=" << is_buffering;
295 DCHECK(thread_checker_.CalledOnValidThread());
296 DCHECK(buffering_controller_);
298 if (!client_.buffering_state_cb.is_null()) {
299 ::media::BufferingState buffering_state = is_buffering ?
300 ::media::BUFFERING_HAVE_NOTHING : ::media::BUFFERING_HAVE_ENOUGH;
301 client_.buffering_state_cb.Run(buffering_state);
304 if (media_pipeline_device_->GetMediaClockDevice()->GetState() ==
305 MediaClockDevice::kStateUninitialized) {
306 return;
309 if (is_buffering) {
310 // Do not consume data in a rebuffering phase.
311 media_pipeline_device_->GetMediaClockDevice()->SetRate(0.0);
312 } else {
313 media_pipeline_device_->GetMediaClockDevice()->SetRate(
314 target_playback_rate_);
318 void MediaPipelineImpl::UpdateMediaTime() {
319 pending_time_update_task_ = false;
320 if (!enable_time_update_)
321 return;
323 if (statistics_rolling_counter_ == 0) {
324 audio_pipeline_->UpdateStatistics();
325 video_pipeline_->UpdateStatistics();
327 statistics_rolling_counter_ =
328 (statistics_rolling_counter_ + 1) % kStatisticsUpdatePeriod;
330 base::TimeDelta media_time(clock_device_->GetTime());
331 if (media_time == ::media::kNoTimestamp()) {
332 pending_time_update_task_ = true;
333 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
334 FROM_HERE, base::Bind(&MediaPipelineImpl::UpdateMediaTime, weak_this_),
335 kTimeUpdateInterval);
336 return;
338 base::TimeTicks stc = base::TimeTicks::Now();
340 base::TimeDelta max_rendering_time = media_time;
341 if (buffering_controller_) {
342 buffering_controller_->SetMediaTime(media_time);
344 // Receiving the same time twice in a row means playback isn't moving,
345 // so don't interpolate ahead.
346 if (media_time != last_media_time_) {
347 max_rendering_time = buffering_controller_->GetMaxRenderingTime();
348 if (max_rendering_time == ::media::kNoTimestamp())
349 max_rendering_time = media_time;
351 // Cap interpolation time to avoid interpolating too far ahead.
352 max_rendering_time =
353 std::min(max_rendering_time, media_time + 2 * kTimeUpdateInterval);
357 last_media_time_ = media_time;
358 if (!client_.time_update_cb.is_null())
359 client_.time_update_cb.Run(media_time, max_rendering_time, stc);
361 pending_time_update_task_ = true;
362 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
363 FROM_HERE, base::Bind(&MediaPipelineImpl::UpdateMediaTime, weak_this_),
364 kTimeUpdateInterval);
367 void MediaPipelineImpl::OnError(::media::PipelineStatus error) {
368 DCHECK(thread_checker_.CalledOnValidThread());
369 DCHECK_NE(error, ::media::PIPELINE_OK) << "PIPELINE_OK is not an error!";
370 if (!client_.error_cb.is_null())
371 client_.error_cb.Run(error);
374 } // namespace media
375 } // namespace chromecast