// 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. #ifndef CHROMECAST_MEDIA_BASE_MEDIA_RESOURCE_TRACKER_H_ #define CHROMECAST_MEDIA_BASE_MEDIA_RESOURCE_TRACKER_H_ #include "base/callback.h" #include "base/memory/ref_counted.h" #include "base/sequenced_task_runner_helpers.h" namespace base { class SingleThreadTaskRunner; } namespace chromecast { namespace media { // Keeps track of internal usage of resources that need access to underlying // media playback hardware. Some example users are the CMA pipeline, and the // CDMs. When it's time to release media resources, this class can be used // to be wait and receive notification when all such users have stopped. // // Application should have one MediaResourceTracker instance and perform all // CastMediaShlib::Initialize/Finalize through this interface. // Threading model and lifetime: // * This class interacts on both UI and media threads (task runners required // by ctor to perform thread hopping and checks). See function-level comments // on which thread to use for which operations. // * All interaction with delegate is performed on UI thread. // * The application should instantiate a single MediaResourceTracker instance. // Destruction should be performed by calling FinalizeAndDestroy from the UI // thread. class MediaResourceTracker { public: class Delegate { public: // Called on UI thread when media usage starts (i.e. count steps 0->1). // Does not mean Initialize has happened. virtual void OnStartUsingMedia() = 0; // Called on UI thread when media usage stops (i.e. count steps 1->0). // Does not mean Finalize has happened. virtual void OnStopUsingMedia() = 0; protected: virtual ~Delegate() {} }; MediaResourceTracker( const scoped_refptr& ui_task_runner, const scoped_refptr& media_task_runner); // Sets the delegate to receive start/stop media usage notifications. Must // call on UI thread. Set to nullptr to clear existing delegate. void SetDelegate(Delegate* delegate); // Media resource acquire implementation. Must call on ui thread; runs // CastMediaShlib::Initialize on media thread. Safe to call even if media lib // already initialized. void InitializeMediaLib(); // Media resource release implementation: // (1) Waits for usage count to drop to zero // (2) Calls CastMediaShlib::Finalize on media thread // (3) Calls completion_cb // Must be called on UI thread. Only one Finalize request may be in flight // at a time. |completion_cb| must not be null. void FinalizeMediaLib(const base::Closure& completion_cb); // Shutdown process: // (1) Waits for usage count to drop to zero // (2) Calls CastMediaShlib::Finalize on media thread // (3) Deletes this object // Must be called on UI thread. No further calls should be made on UI thread // after this. Delegate is implicitly cleared. void FinalizeAndDestroy(); // Users of media resource (e.g. CMA pipeline) should call these when they // start and stop using media calls (must be called on media thread). void IncrementUsageCount(); void DecrementUsageCount(); private: friend class base::DeleteHelper; ~MediaResourceTracker(); // Tasks posted to UI thread void CallDelegateStartOnUiThread(); void CallDelegateStopOnUiThread(); // Tasks posted to media thread void CallInitializeOnMediaThread(); void MaybeCallFinalizeOnMediaThread(const base::Closure& completion_cb); void MaybeCallFinalizeOnMediaThreadAndDeleteSelf(); void CallFinalizeOnMediaThread(); // Accessed on UI thread Delegate* delegate_; // Accessed on media thread + ctor size_t media_use_count_; bool media_lib_initialized_; base::Closure finalize_completion_cb_; bool delete_on_finalize_; scoped_refptr ui_task_runner_; scoped_refptr media_task_runner_; DISALLOW_COPY_AND_ASSIGN(MediaResourceTracker); }; } // namespace media } // namespace chromecast #endif // CHROMECAST_MEDIA_BASE_MEDIA_RESOURCE_TRACKER_H_