Index: chromecast/media/cma/pipeline/av_pipeline_impl.cc |
diff --git a/chromecast/media/cma/pipeline/av_pipeline_impl.cc b/chromecast/media/cma/pipeline/av_pipeline_impl.cc |
index 2e2da54facea855610ce4925b4979c3927d82fbb..6c415c7fc2e51701458518263fec2a3794a99680 100644 |
--- a/chromecast/media/cma/pipeline/av_pipeline_impl.cc |
+++ b/chromecast/media/cma/pipeline/av_pipeline_impl.cc |
@@ -45,10 +45,8 @@ AvPipelineImpl::AvPipelineImpl( |
enable_time_update_(false), |
pending_time_update_task_(false), |
media_keys_(NULL), |
- media_keys_callback_id_(kNoCallbackId), |
- weak_factory_(this) { |
+ media_keys_callback_id_(kNoCallbackId) { |
DCHECK(media_component_device); |
- weak_this_ = weak_factory_.GetWeakPtr(); |
thread_checker_.DetachFromThread(); |
} |
@@ -58,8 +56,11 @@ AvPipelineImpl::~AvPipelineImpl() { |
DCHECK(thread_checker_.CalledOnValidThread()); |
media_component_device_->SetClient(MediaComponentDevice::Client()); |
- if (media_keys_ && media_keys_callback_id_ != kNoCallbackId) |
- media_keys_->UnregisterPlayer(media_keys_callback_id_); |
+ { |
+ base::AutoLock lock(media_keys_lock_); |
+ if (media_keys_ && media_keys_callback_id_ != kNoCallbackId) |
+ media_keys_->UnregisterPlayer(media_keys_callback_id_); |
+ } |
} |
void AvPipelineImpl::TransitionToState(State state) { |
@@ -80,7 +81,7 @@ void AvPipelineImpl::SetCodedFrameProvider( |
frame_provider.Pass(), |
max_buffer_size, |
max_frame_size, |
- base::Bind(&AvPipelineImpl::OnFrameBuffered, weak_this_))); |
+ base::Bind(&AvPipelineImpl::OnFrameBuffered, this))); |
} |
void AvPipelineImpl::SetClient(const AvPipelineClient& client) { |
@@ -94,7 +95,7 @@ bool AvPipelineImpl::Initialize() { |
DCHECK_EQ(state_, kUninitialized); |
MediaComponentDevice::Client client; |
- client.eos_cb = base::Bind(&AvPipelineImpl::OnEos, weak_this_); |
+ client.eos_cb = base::Bind(&AvPipelineImpl::OnEos, this); |
media_component_device_->SetClient(client); |
if (!media_component_device_->SetState(MediaComponentDevice::kStateIdle)) |
return false; |
@@ -128,7 +129,7 @@ bool AvPipelineImpl::StartPlayingFrom( |
enable_feeding_ = true; |
base::MessageLoopProxy::current()->PostTask( |
FROM_HERE, |
- base::Bind(&AvPipelineImpl::FetchBufferIfNeeded, weak_this_)); |
+ base::Bind(&AvPipelineImpl::FetchBufferIfNeeded, this)); |
return true; |
} |
@@ -183,15 +184,21 @@ void AvPipelineImpl::SetCdm(BrowserCdmCast* media_keys) { |
DCHECK(thread_checker_.CalledOnValidThread()); |
DCHECK(media_keys); |
- if (media_keys_ && media_keys_callback_id_ != kNoCallbackId) |
- media_keys_->UnregisterPlayer(media_keys_callback_id_); |
- |
- media_keys_ = media_keys; |
- media_keys_callback_id_ = media_keys_->RegisterPlayer( |
- ::media::BindToCurrentLoop( |
- base::Bind(&AvPipelineImpl::OnCdmStateChanged, weak_this_)), |
- ::media::BindToCurrentLoop( |
- base::Bind(&AvPipelineImpl::OnCdmDestroyed, weak_this_))); |
+ { |
+ base::AutoLock lock(media_keys_lock_); |
+ if (media_keys_ && media_keys_callback_id_ != kNoCallbackId) |
+ media_keys_->UnregisterPlayer(media_keys_callback_id_); |
+ |
+ media_keys_ = media_keys; |
+ media_keys_callback_id_ = media_keys_->RegisterPlayer( |
+ ::media::BindToCurrentLoop( |
+ base::Bind(&AvPipelineImpl::OnCdmStateChanged, this)), |
+ // Note: this callback gets invoked in ~BrowserCdmCast. Posting |
+ // OnCdmDestroyed to the media thread results in a race condition |
+ // with media_keys_ accesses. This callback must run synchronously, |
+ // otherwise media_keys_ access might occur after it is deleted. |
+ base::Bind(&AvPipelineImpl::OnCdmDestroyed, this)); |
+ } |
} |
void AvPipelineImpl::OnEos() { |
@@ -214,7 +221,7 @@ void AvPipelineImpl::FetchBufferIfNeeded() { |
pending_read_ = true; |
frame_provider_->Read( |
- base::Bind(&AvPipelineImpl::OnNewFrame, weak_this_)); |
+ base::Bind(&AvPipelineImpl::OnNewFrame, this)); |
} |
void AvPipelineImpl::OnNewFrame( |
@@ -232,7 +239,7 @@ void AvPipelineImpl::OnNewFrame( |
base::MessageLoopProxy::current()->PostTask( |
FROM_HERE, |
- base::Bind(&AvPipelineImpl::FetchBufferIfNeeded, weak_this_)); |
+ base::Bind(&AvPipelineImpl::FetchBufferIfNeeded, this)); |
} |
void AvPipelineImpl::ProcessPendingBuffer() { |
@@ -243,7 +250,7 @@ void AvPipelineImpl::ProcessPendingBuffer() { |
if (!pending_buffer_.get() && !pending_read_) { |
base::MessageLoopProxy::current()->PostTask( |
FROM_HERE, |
- base::Bind(&AvPipelineImpl::FetchBufferIfNeeded, weak_this_)); |
+ base::Bind(&AvPipelineImpl::FetchBufferIfNeeded, this)); |
return; |
} |
@@ -262,12 +269,15 @@ void AvPipelineImpl::ProcessPendingBuffer() { |
// Verify that CDM has the key ID. |
// Should not send the frame if the key ID is not available yet. |
std::string key_id(pending_buffer_->decrypt_config()->key_id()); |
- if (!media_keys_) { |
- CMALOG(kLogControl) << "No CDM for frame: pts=" |
- << pending_buffer_->timestamp().InMilliseconds(); |
- return; |
+ { |
+ base::AutoLock lock(media_keys_lock_); |
+ if (!media_keys_) { |
+ CMALOG(kLogControl) << "No CDM for frame: pts=" |
+ << pending_buffer_->timestamp().InMilliseconds(); |
+ return; |
+ } |
+ decrypt_context = media_keys_->GetDecryptContext(key_id); |
} |
- decrypt_context = media_keys_->GetDecryptContext(key_id); |
if (!decrypt_context.get()) { |
CMALOG(kLogControl) << "frame(pts=" |
<< pending_buffer_->timestamp().InMilliseconds() |
@@ -294,7 +304,7 @@ void AvPipelineImpl::ProcessPendingBuffer() { |
MediaComponentDevice::FrameStatus status = media_component_device_->PushFrame( |
decrypt_context, |
pending_buffer_, |
- base::Bind(&AvPipelineImpl::OnFramePushed, weak_this_)); |
+ base::Bind(&AvPipelineImpl::OnFramePushed, this)); |
pending_buffer_ = scoped_refptr<DecoderBufferBase>(); |
pending_push_ = (status == MediaComponentDevice::kFramePending); |
@@ -313,7 +323,7 @@ void AvPipelineImpl::OnFramePushed(MediaComponentDevice::FrameStatus status) { |
} |
base::MessageLoopProxy::current()->PostTask( |
FROM_HERE, |
- base::Bind(&AvPipelineImpl::ProcessPendingBuffer, weak_this_)); |
+ base::Bind(&AvPipelineImpl::ProcessPendingBuffer, this)); |
} |
void AvPipelineImpl::OnCdmStateChanged() { |
@@ -328,7 +338,7 @@ void AvPipelineImpl::OnCdmStateChanged() { |
} |
void AvPipelineImpl::OnCdmDestroyed() { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
+ base::AutoLock lock(media_keys_lock_); |
media_keys_ = NULL; |
} |