// Copyright 2016 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chromecast/media/base/media_resource_tracker.h" #include "base/callback_helpers.h" #include "base/command_line.h" #include "chromecast/base/bind_to_task_runner.h" #include "chromecast/public/cast_media_shlib.h" namespace chromecast { namespace media { MediaResourceTracker::MediaResourceTracker( const scoped_refptr& ui_task_runner, const scoped_refptr& media_task_runner) : delegate_(nullptr), media_use_count_(0), media_lib_initialized_(false), delete_on_finalize_(false), ui_task_runner_(ui_task_runner), media_task_runner_(media_task_runner) { DCHECK(ui_task_runner); DCHECK(media_task_runner); DCHECK(ui_task_runner_->BelongsToCurrentThread()); } MediaResourceTracker::~MediaResourceTracker() {} void MediaResourceTracker::SetDelegate(Delegate* delegate) { DCHECK(ui_task_runner_->BelongsToCurrentThread()); delegate_ = delegate; } void MediaResourceTracker::InitializeMediaLib() { DCHECK(ui_task_runner_->BelongsToCurrentThread()); media_task_runner_->PostTask( FROM_HERE, base::Bind(&MediaResourceTracker::CallInitializeOnMediaThread, base::Unretained(this))); } void MediaResourceTracker::FinalizeMediaLib( const base::Closure& completion_cb) { DCHECK(ui_task_runner_->BelongsToCurrentThread()); DCHECK(!completion_cb.is_null()); media_task_runner_->PostTask( FROM_HERE, base::Bind(&MediaResourceTracker::MaybeCallFinalizeOnMediaThread, base::Unretained(this), completion_cb)); } void MediaResourceTracker::FinalizeAndDestroy() { DCHECK(ui_task_runner_->BelongsToCurrentThread()); delegate_ = nullptr; media_task_runner_->PostTask( FROM_HERE, base::Bind( &MediaResourceTracker::MaybeCallFinalizeOnMediaThreadAndDeleteSelf, base::Unretained(this))); } void MediaResourceTracker::IncrementUsageCount() { DCHECK(media_task_runner_->BelongsToCurrentThread()); DCHECK(media_lib_initialized_); DCHECK(finalize_completion_cb_.is_null()); media_use_count_++; if (media_use_count_ == 1) { ui_task_runner_->PostTask( FROM_HERE, base::Bind(&MediaResourceTracker::CallDelegateStartOnUiThread, base::Unretained(this))); } } void MediaResourceTracker::DecrementUsageCount() { DCHECK(media_task_runner_->BelongsToCurrentThread()); media_use_count_--; if (media_use_count_ == 0) { ui_task_runner_->PostTask( FROM_HERE, base::Bind(&MediaResourceTracker::CallDelegateStopOnUiThread, base::Unretained(this))); if (!finalize_completion_cb_.is_null()) CallFinalizeOnMediaThread(); } } void MediaResourceTracker::CallDelegateStartOnUiThread() { DCHECK(ui_task_runner_->BelongsToCurrentThread()); if (delegate_) delegate_->OnStartUsingMedia(); } void MediaResourceTracker::CallDelegateStopOnUiThread() { DCHECK(ui_task_runner_->BelongsToCurrentThread()); if (delegate_) delegate_->OnStopUsingMedia(); } void MediaResourceTracker::CallInitializeOnMediaThread() { DCHECK(media_task_runner_->BelongsToCurrentThread()); if (media_lib_initialized_) return; base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); media::CastMediaShlib::Initialize(cmd_line->argv()); media_lib_initialized_ = true; } void MediaResourceTracker::MaybeCallFinalizeOnMediaThread( const base::Closure& completion_cb) { DCHECK(media_task_runner_->BelongsToCurrentThread()); DCHECK(finalize_completion_cb_.is_null()); finalize_completion_cb_ = BindToTaskRunner(ui_task_runner_, completion_cb); if (!media_lib_initialized_) { if (!finalize_completion_cb_.is_null()) base::ResetAndReturn(&finalize_completion_cb_).Run(); return; } // If there are things using media, we must wait for them to stop. // CallFinalize will get called later from DecrementUsageCount when // usage count drops to 0. if (media_use_count_ == 0) CallFinalizeOnMediaThread(); } void MediaResourceTracker::MaybeCallFinalizeOnMediaThreadAndDeleteSelf() { DCHECK(media_task_runner_->BelongsToCurrentThread()); if (!media_lib_initialized_) { ui_task_runner_->DeleteSoon(FROM_HERE, this); return; } delete_on_finalize_ = true; // If there are things using media, we must wait for them to stop. // CallFinalize will get called later from DecrementUsageCount when // usage count drops to 0. if (media_use_count_ == 0) CallFinalizeOnMediaThread(); } void MediaResourceTracker::CallFinalizeOnMediaThread() { DCHECK(media_task_runner_->BelongsToCurrentThread()); DCHECK_EQ(media_use_count_, 0ul); DCHECK(media_lib_initialized_); CastMediaShlib::Finalize(); media_lib_initialized_ = false; if (!finalize_completion_cb_.is_null()) base::ResetAndReturn(&finalize_completion_cb_).Run(); if (delete_on_finalize_) ui_task_runner_->DeleteSoon(FROM_HERE, this); } } // namespace media } // namespace chromecast