[MediaRouter] Update MR-2-Extension's PostMessage to return boolean.
[chromium-blink-merge.git] / chromecast / media / cma / pipeline / av_pipeline_impl.cc
blob5c6c69538a2fd87cca39c2c0ddeb21d6157c864c
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/av_pipeline_impl.h"
7 #include "base/bind.h"
8 #include "base/location.h"
9 #include "base/single_thread_task_runner.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/thread_task_runner_handle.h"
12 #include "chromecast/media/base/decrypt_context.h"
13 #include "chromecast/media/cdm/browser_cdm_cast.h"
14 #include "chromecast/media/cma/backend/media_clock_device.h"
15 #include "chromecast/media/cma/backend/media_component_device.h"
16 #include "chromecast/media/cma/base/buffering_frame_provider.h"
17 #include "chromecast/media/cma/base/buffering_state.h"
18 #include "chromecast/media/cma/base/cma_logging.h"
19 #include "chromecast/media/cma/base/coded_frame_provider.h"
20 #include "chromecast/media/cma/base/decoder_buffer_base.h"
21 #include "chromecast/media/cma/pipeline/decrypt_util.h"
22 #include "media/base/audio_decoder_config.h"
23 #include "media/base/bind_to_current_loop.h"
24 #include "media/base/decrypt_config.h"
26 namespace chromecast {
27 namespace media {
29 namespace {
31 const int kNoCallbackId = -1;
33 } // namespace
35 AvPipelineImpl::AvPipelineImpl(
36 MediaComponentDevice* media_component_device,
37 const UpdateConfigCB& update_config_cb)
38 : update_config_cb_(update_config_cb),
39 media_component_device_(media_component_device),
40 state_(kUninitialized),
41 buffered_time_(::media::kNoTimestamp()),
42 playable_buffered_time_(::media::kNoTimestamp()),
43 enable_feeding_(false),
44 pending_read_(false),
45 pending_push_(false),
46 enable_time_update_(false),
47 pending_time_update_task_(false),
48 media_keys_(NULL),
49 media_keys_callback_id_(kNoCallbackId),
50 weak_factory_(this) {
51 DCHECK(media_component_device);
52 weak_this_ = weak_factory_.GetWeakPtr();
53 thread_checker_.DetachFromThread();
56 AvPipelineImpl::~AvPipelineImpl() {
57 DCHECK(thread_checker_.CalledOnValidThread());
58 media_component_device_->SetClient(MediaComponentDevice::Client());
60 if (media_keys_ && media_keys_callback_id_ != kNoCallbackId)
61 media_keys_->UnregisterPlayer(media_keys_callback_id_);
64 void AvPipelineImpl::TransitionToState(State state) {
65 DCHECK(thread_checker_.CalledOnValidThread());
66 state_ = state;
69 void AvPipelineImpl::SetCodedFrameProvider(
70 scoped_ptr<CodedFrameProvider> frame_provider,
71 size_t max_buffer_size,
72 size_t max_frame_size) {
73 DCHECK_EQ(state_, kUninitialized);
74 DCHECK(frame_provider);
76 // Wrap the incoming frame provider to add some buffering capabilities.
77 frame_provider_.reset(
78 new BufferingFrameProvider(
79 frame_provider.Pass(),
80 max_buffer_size,
81 max_frame_size,
82 base::Bind(&AvPipelineImpl::OnFrameBuffered, weak_this_)));
85 void AvPipelineImpl::SetClient(const AvPipelineClient& client) {
86 DCHECK(thread_checker_.CalledOnValidThread());
87 DCHECK_EQ(state_, kUninitialized);
88 client_ = client;
91 bool AvPipelineImpl::Initialize() {
92 DCHECK(thread_checker_.CalledOnValidThread());
93 DCHECK_EQ(state_, kUninitialized);
95 MediaComponentDevice::Client client;
96 client.eos_cb = base::Bind(&AvPipelineImpl::OnEos, weak_this_);
97 media_component_device_->SetClient(client);
98 if (!media_component_device_->SetState(MediaComponentDevice::kStateIdle))
99 return false;
101 return true;
104 bool AvPipelineImpl::StartPlayingFrom(
105 base::TimeDelta time,
106 const scoped_refptr<BufferingState>& buffering_state) {
107 DCHECK(thread_checker_.CalledOnValidThread());
108 DCHECK_EQ(state_, kFlushed);
110 // Media time where rendering should start
111 // and switch to a state where the audio device accepts incoming buffers.
112 if (!media_component_device_->SetStartPts(time) ||
113 !media_component_device_->SetState(MediaComponentDevice::kStatePaused)) {
114 return false;
117 // Buffering related initialization.
118 DCHECK(frame_provider_);
119 buffering_state_ = buffering_state;
120 if (buffering_state_.get())
121 buffering_state_->SetMediaTime(time);
123 if (!media_component_device_->SetState(MediaComponentDevice::kStateRunning))
124 return false;
126 // Start feeding the pipeline.
127 enable_feeding_ = true;
128 base::ThreadTaskRunnerHandle::Get()->PostTask(
129 FROM_HERE, base::Bind(&AvPipelineImpl::FetchBufferIfNeeded, weak_this_));
131 return true;
134 void AvPipelineImpl::Flush(const base::Closure& done_cb) {
135 DCHECK(thread_checker_.CalledOnValidThread());
136 DCHECK_EQ(state_, kFlushing);
137 DCHECK_EQ(
138 media_component_device_->GetState(), MediaComponentDevice::kStateRunning);
139 // Note: returning to idle state aborts any pending frame push.
140 media_component_device_->SetState(MediaComponentDevice::kStateIdle);
141 pending_push_ = false;
143 // Break the feeding loop.
144 enable_feeding_ = false;
146 // Remove any pending buffer.
147 pending_buffer_ = scoped_refptr<DecoderBufferBase>();
149 // Finally, remove any frames left in the frame provider.
150 pending_read_ = false;
151 buffered_time_ = ::media::kNoTimestamp();
152 playable_buffered_time_ = ::media::kNoTimestamp();
153 non_playable_frames_.clear();
154 frame_provider_->Flush(done_cb);
157 void AvPipelineImpl::Stop() {
158 DCHECK(thread_checker_.CalledOnValidThread());
160 // Stop can be called from any state.
161 if (state_ == kUninitialized || state_ == kStopped)
162 return;
164 // Stop feeding the pipeline.
165 enable_feeding_ = false;
167 // Release hardware resources on Stop.
168 if (media_component_device_->GetState() ==
169 MediaComponentDevice::kStatePaused ||
170 media_component_device_->GetState() ==
171 MediaComponentDevice::kStateRunning) {
172 media_component_device_->SetState(MediaComponentDevice::kStateIdle);
174 if (media_component_device_->GetState() == MediaComponentDevice::kStateIdle) {
175 media_component_device_->SetState(
176 MediaComponentDevice::kStateUninitialized);
180 void AvPipelineImpl::SetCdm(BrowserCdmCast* media_keys) {
181 DCHECK(thread_checker_.CalledOnValidThread());
182 DCHECK(media_keys);
184 if (media_keys_ && media_keys_callback_id_ != kNoCallbackId)
185 media_keys_->UnregisterPlayer(media_keys_callback_id_);
187 media_keys_ = media_keys;
188 media_keys_callback_id_ = media_keys_->RegisterPlayer(
189 base::Bind(&AvPipelineImpl::OnCdmStateChanged, weak_this_),
190 base::Bind(&AvPipelineImpl::OnCdmDestroyed, weak_this_));
193 void AvPipelineImpl::OnEos() {
194 DCHECK(thread_checker_.CalledOnValidThread());
195 CMALOG(kLogControl) << __FUNCTION__;
196 if (state_ != kPlaying)
197 return;
199 if (!client_.eos_cb.is_null())
200 client_.eos_cb.Run();
203 void AvPipelineImpl::FetchBufferIfNeeded() {
204 DCHECK(thread_checker_.CalledOnValidThread());
205 if (!enable_feeding_)
206 return;
208 if (pending_read_ || pending_buffer_.get())
209 return;
211 pending_read_ = true;
212 frame_provider_->Read(
213 base::Bind(&AvPipelineImpl::OnNewFrame, weak_this_));
216 void AvPipelineImpl::OnNewFrame(
217 const scoped_refptr<DecoderBufferBase>& buffer,
218 const ::media::AudioDecoderConfig& audio_config,
219 const ::media::VideoDecoderConfig& video_config) {
220 DCHECK(thread_checker_.CalledOnValidThread());
221 pending_read_ = false;
223 if (audio_config.IsValidConfig() || video_config.IsValidConfig())
224 update_config_cb_.Run(buffer->stream_id(), audio_config, video_config);
226 pending_buffer_ = buffer;
227 ProcessPendingBuffer();
229 base::ThreadTaskRunnerHandle::Get()->PostTask(
230 FROM_HERE, base::Bind(&AvPipelineImpl::FetchBufferIfNeeded, weak_this_));
233 void AvPipelineImpl::ProcessPendingBuffer() {
234 if (!enable_feeding_)
235 return;
237 // Initiate a read if there isn't already one.
238 if (!pending_buffer_.get() && !pending_read_) {
239 base::ThreadTaskRunnerHandle::Get()->PostTask(
240 FROM_HERE,
241 base::Bind(&AvPipelineImpl::FetchBufferIfNeeded, weak_this_));
242 return;
245 if (!pending_buffer_.get() || pending_push_)
246 return;
248 // Break the feeding loop when the end of stream is reached.
249 if (pending_buffer_->end_of_stream()) {
250 CMALOG(kLogControl) << __FUNCTION__ << ": EOS reached, stopped feeding";
251 enable_feeding_ = false;
254 scoped_refptr<DecryptContext> decrypt_context;
255 if (!pending_buffer_->end_of_stream() &&
256 pending_buffer_->decrypt_config()) {
257 // Verify that CDM has the key ID.
258 // Should not send the frame if the key ID is not available yet.
259 std::string key_id(pending_buffer_->decrypt_config()->key_id());
260 if (!media_keys_) {
261 CMALOG(kLogControl) << "No CDM for frame: pts="
262 << pending_buffer_->timestamp().InMilliseconds();
263 return;
265 decrypt_context = media_keys_->GetDecryptContext(key_id);
266 if (!decrypt_context.get()) {
267 CMALOG(kLogControl) << "frame(pts="
268 << pending_buffer_->timestamp().InMilliseconds()
269 << "): waiting for key id "
270 << base::HexEncode(&key_id[0], key_id.size());
271 return;
274 // If we do have the clear key, decrypt the pending buffer
275 // and reset the decryption context (not needed anymore).
276 crypto::SymmetricKey* key = decrypt_context->GetKey();
277 if (key != NULL) {
278 pending_buffer_ = DecryptDecoderBuffer(pending_buffer_, key);
279 decrypt_context = scoped_refptr<DecryptContext>();
283 if (!pending_buffer_->end_of_stream() && buffering_state_.get()) {
284 base::TimeDelta timestamp = pending_buffer_->timestamp();
285 if (timestamp != ::media::kNoTimestamp())
286 buffering_state_->SetMaxRenderingTime(timestamp);
289 MediaComponentDevice::FrameStatus status = media_component_device_->PushFrame(
290 decrypt_context,
291 pending_buffer_,
292 base::Bind(&AvPipelineImpl::OnFramePushed, weak_this_));
293 pending_buffer_ = scoped_refptr<DecoderBufferBase>();
295 pending_push_ = (status == MediaComponentDevice::kFramePending);
296 if (!pending_push_)
297 OnFramePushed(status);
300 void AvPipelineImpl::OnFramePushed(MediaComponentDevice::FrameStatus status) {
301 DCHECK(thread_checker_.CalledOnValidThread());
302 pending_push_ = false;
303 if (status == MediaComponentDevice::kFrameFailed) {
304 LOG(WARNING) << "AvPipelineImpl: PushFrame failed";
305 enable_feeding_ = false;
306 state_ = kError;
307 return;
309 base::ThreadTaskRunnerHandle::Get()->PostTask(
310 FROM_HERE, base::Bind(&AvPipelineImpl::ProcessPendingBuffer, weak_this_));
313 void AvPipelineImpl::OnCdmStateChanged() {
314 DCHECK(thread_checker_.CalledOnValidThread());
316 // Update the buffering state if needed.
317 if (buffering_state_.get())
318 UpdatePlayableFrames();
320 // Process the pending buffer in case the CDM now has the frame key id.
321 ProcessPendingBuffer();
324 void AvPipelineImpl::OnCdmDestroyed() {
325 DCHECK(thread_checker_.CalledOnValidThread());
326 media_keys_ = NULL;
329 void AvPipelineImpl::OnFrameBuffered(
330 const scoped_refptr<DecoderBufferBase>& buffer,
331 bool is_at_max_capacity) {
332 DCHECK(thread_checker_.CalledOnValidThread());
334 if (!buffering_state_.get())
335 return;
337 if (!buffer->end_of_stream() &&
338 (buffered_time_ == ::media::kNoTimestamp() ||
339 buffered_time_ < buffer->timestamp())) {
340 buffered_time_ = buffer->timestamp();
343 if (is_at_max_capacity)
344 buffering_state_->NotifyMaxCapacity(buffered_time_);
346 // No need to update the list of playable frames,
347 // if we are already blocking on a frame.
348 bool update_playable_frames = non_playable_frames_.empty();
349 non_playable_frames_.push_back(buffer);
350 if (update_playable_frames)
351 UpdatePlayableFrames();
354 void AvPipelineImpl::UpdatePlayableFrames() {
355 while (!non_playable_frames_.empty()) {
356 const scoped_refptr<DecoderBufferBase>& non_playable_frame =
357 non_playable_frames_.front();
359 if (non_playable_frame->end_of_stream()) {
360 buffering_state_->NotifyEos();
361 } else {
362 const ::media::DecryptConfig* decrypt_config =
363 non_playable_frame->decrypt_config();
364 if (decrypt_config &&
365 !(media_keys_ &&
366 media_keys_->GetDecryptContext(decrypt_config->key_id()).get())) {
367 // The frame is still not playable. All the following are thus not
368 // playable.
369 break;
372 if (playable_buffered_time_ == ::media::kNoTimestamp() ||
373 playable_buffered_time_ < non_playable_frame->timestamp()) {
374 playable_buffered_time_ = non_playable_frame->timestamp();
375 buffering_state_->SetBufferedTime(playable_buffered_time_);
379 // The frame is playable: remove it from the list of non playable frames.
380 non_playable_frames_.pop_front();
384 } // namespace media
385 } // namespace chromecast