gecko-dev/dom/media/systemservices/MediaSystemResourceManager.cpp

409 lines
10 KiB
C++
Raw Normal View History

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/TaskQueue.h"
#include "gfxPrefs.h"
#include "MediaSystemResourceManagerChild.h"
#include "mozilla/layers/ImageBridgeChild.h"
#include "MediaSystemResourceManager.h"
namespace mozilla {
using namespace mozilla::ipc;
using namespace mozilla::layers;
/* static */ StaticRefPtr<MediaSystemResourceManager> MediaSystemResourceManager::sSingleton;
/* static */ MediaSystemResourceManager*
MediaSystemResourceManager::Get()
{
if (sSingleton) {
return sSingleton;
}
MediaSystemResourceManager::Init();
return sSingleton;
}
/* static */ void
MediaSystemResourceManager::Shutdown()
{
MOZ_ASSERT(InImageBridgeChildThread());
if (sSingleton) {
sSingleton->CloseIPC();
sSingleton = nullptr;
}
}
class RunnableCallTask : public Task
{
public:
explicit RunnableCallTask(nsIRunnable* aRunnable)
: mRunnable(aRunnable) {}
void Run() override
{
mRunnable->Run();
}
protected:
nsCOMPtr<nsIRunnable> mRunnable;
};
/* static */ void
MediaSystemResourceManager::Init()
{
if (!ImageBridgeChild::IsCreated()) {
NS_WARNING("ImageBridge does not exist");
return;
}
if (InImageBridgeChildThread()) {
if (!sSingleton) {
#ifdef DEBUG
static int timesCreated = 0;
timesCreated++;
MOZ_ASSERT(timesCreated == 1);
#endif
sSingleton = new MediaSystemResourceManager();
}
return;
}
ReentrantMonitor barrier("MediaSystemResourceManager::Init");
ReentrantMonitorAutoEnter autoMon(barrier);
bool done = false;
nsCOMPtr<nsIRunnable> runnable =
NS_NewRunnableFunction([&]() {
if (!sSingleton) {
sSingleton = new MediaSystemResourceManager();
}
ReentrantMonitorAutoEnter autoMon(barrier);
done = true;
barrier.NotifyAll();
});
ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(
FROM_HERE, new RunnableCallTask(runnable));
// should stop the thread until done.
while (!done) {
barrier.Wait();
}
}
MediaSystemResourceManager::MediaSystemResourceManager()
: mReentrantMonitor("MediaSystemResourceManager.mReentrantMonitor")
, mShutDown(false)
, mChild(nullptr)
{
MOZ_ASSERT(InImageBridgeChildThread());
OpenIPC();
}
MediaSystemResourceManager::~MediaSystemResourceManager()
{
MOZ_ASSERT(IsIpcClosed());
}
void
MediaSystemResourceManager::OpenIPC()
{
MOZ_ASSERT(InImageBridgeChildThread());
MOZ_ASSERT(!mChild);
media::PMediaSystemResourceManagerChild* child =
ImageBridgeChild::GetSingleton()->SendPMediaSystemResourceManagerConstructor();
mChild = static_cast<media::MediaSystemResourceManagerChild*>(child);
mChild->SetManager(this);
}
void
MediaSystemResourceManager::CloseIPC()
{
MOZ_ASSERT(InImageBridgeChildThread());
if (!mChild) {
return;
}
mChild->Destroy();
mChild = nullptr;
mShutDown = true;
}
void
MediaSystemResourceManager::OnIpcClosed()
{
mChild = nullptr;
}
bool
MediaSystemResourceManager::IsIpcClosed()
{
return mChild ? true : false;
}
void
MediaSystemResourceManager::Register(MediaSystemResourceClient* aClient)
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
MOZ_ASSERT(aClient);
MOZ_ASSERT(!mResourceClients.Get(aClient->mId));
mResourceClients.Put(aClient->mId, aClient);
}
void
MediaSystemResourceManager::Unregister(MediaSystemResourceClient* aClient)
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
MOZ_ASSERT(aClient);
MOZ_ASSERT(mResourceClients.Get(aClient->mId));
MOZ_ASSERT(mResourceClients.Get(aClient->mId) == aClient);
mResourceClients.Remove(aClient->mId);
}
bool
MediaSystemResourceManager::SetListener(MediaSystemResourceClient* aClient,
MediaSystemResourceReservationListener* aListener)
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
MOZ_ASSERT(aClient);
MediaSystemResourceClient* client = mResourceClients.Get(aClient->mId);
MOZ_ASSERT(client);
if (!client) {
return false;
}
// State Check
if (aClient->mResourceState != MediaSystemResourceClient::RESOURCE_STATE_START) {
return false;
}
aClient->mListener = aListener;
return true;
}
void
MediaSystemResourceManager::Acquire(MediaSystemResourceClient* aClient)
{
MOZ_ASSERT(aClient);
MOZ_ASSERT(!InImageBridgeChildThread());
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
MediaSystemResourceClient* client = mResourceClients.Get(aClient->mId);
MOZ_ASSERT(client);
MOZ_ASSERT(client == aClient);
aClient->mIsSync = false; // async request
if (!client) {
HandleAcquireResult(aClient->mId, false);
return;
}
// State Check
if (aClient->mResourceState != MediaSystemResourceClient::RESOURCE_STATE_START) {
HandleAcquireResult(aClient->mId, false);
return;
}
aClient->mResourceState = MediaSystemResourceClient::RESOURCE_STATE_WAITING;
ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(
FROM_HERE,
NewRunnableMethod(
this,
&MediaSystemResourceManager::DoAcquire,
aClient->mId));
}
bool
MediaSystemResourceManager::AcquireSyncNoWait(MediaSystemResourceClient* aClient)
{
MOZ_ASSERT(aClient);
MOZ_ASSERT(!InImageBridgeChildThread());
ReentrantMonitor barrier("MediaSystemResourceManager::AcquireSyncNoWait");
ReentrantMonitorAutoEnter autoMon(barrier);
bool done = false;
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
MediaSystemResourceClient* client = mResourceClients.Get(aClient->mId);
MOZ_ASSERT(client);
MOZ_ASSERT(client == aClient);
aClient->mIsSync = true; // sync request
if (InImageBridgeChildThread()) {
HandleAcquireResult(aClient->mId, false);
return false;
}
if (!aClient ||
!client ||
client != aClient) {
HandleAcquireResult(aClient->mId, false);
return false;
}
// State Check
if (aClient->mResourceState != MediaSystemResourceClient::RESOURCE_STATE_START) {
HandleAcquireResult(aClient->mId, false);
return false;
}
// Hold barrier Monitor until acquire task end.
aClient->mAcquireSyncWaitMonitor = &barrier;
aClient->mAcquireSyncWaitDone = &done;
aClient->mResourceState = MediaSystemResourceClient::RESOURCE_STATE_WAITING;
}
ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(
FROM_HERE,
NewRunnableMethod(
this,
&MediaSystemResourceManager::DoAcquire,
aClient->mId));
// should stop the thread until done.
while (!done) {
barrier.Wait();
}
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
if (aClient->mResourceState != MediaSystemResourceClient::RESOURCE_STATE_ACQUIRED) {
return false;
}
return true;
}
}
void
MediaSystemResourceManager::DoAcquire(uint32_t aId)
{
MOZ_ASSERT(InImageBridgeChildThread());
if (mShutDown || !mChild) {
HandleAcquireResult(aId, false);
return;
}
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
MediaSystemResourceClient* client = mResourceClients.Get(aId);
MOZ_ASSERT(client);
if (!client ||
client->mResourceState != MediaSystemResourceClient::RESOURCE_STATE_WAITING) {
HandleAcquireResult(aId, false);
return;
}
MOZ_ASSERT(aId == client->mId);
bool willWait = !client->mAcquireSyncWaitMonitor ? true : false;
mChild->SendAcquire(client->mId,
client->mResourceType,
willWait);
}
}
void
MediaSystemResourceManager::ReleaseResource(MediaSystemResourceClient* aClient)
{
MOZ_ASSERT(aClient);
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
MediaSystemResourceClient* client = mResourceClients.Get(aClient->mId);
MOZ_ASSERT(client);
MOZ_ASSERT(client == aClient);
if (!client ||
client != aClient ||
aClient->mResourceState == MediaSystemResourceClient::RESOURCE_STATE_START ||
aClient->mResourceState == MediaSystemResourceClient::RESOURCE_STATE_END) {
aClient->mResourceState = MediaSystemResourceClient::RESOURCE_STATE_END;
return;
}
aClient->mResourceState = MediaSystemResourceClient::RESOURCE_STATE_END;
ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(
FROM_HERE,
NewRunnableMethod(
this,
&MediaSystemResourceManager::DoRelease,
aClient->mId));
}
}
void
MediaSystemResourceManager::DoRelease(uint32_t aId)
{
MOZ_ASSERT(InImageBridgeChildThread());
if (mShutDown || !mChild) {
return;
}
mChild->SendRelease(aId);
}
void
MediaSystemResourceManager::RecvResponse(uint32_t aId, bool aSuccess)
{
HandleAcquireResult(aId, aSuccess);
}
void
MediaSystemResourceManager::HandleAcquireResult(uint32_t aId, bool aSuccess)
{
if (!InImageBridgeChildThread()) {
ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(
FROM_HERE,
NewRunnableMethod(
this,
&MediaSystemResourceManager::HandleAcquireResult,
aId,
aSuccess));
return;
}
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
MediaSystemResourceClient* client = mResourceClients.Get(aId);
if (!client) {
// Client was already unregistered.
return;
}
if (client->mResourceState != MediaSystemResourceClient::RESOURCE_STATE_WAITING) {
return;
}
// Update state
if (aSuccess) {
client->mResourceState = MediaSystemResourceClient::RESOURCE_STATE_ACQUIRED;
} else {
client->mResourceState = MediaSystemResourceClient::RESOURCE_STATE_NOT_ACQUIRED;
}
if (client->mIsSync) {
if (client->mAcquireSyncWaitMonitor) {
// Notify AcquireSync() complete
MOZ_ASSERT(client->mAcquireSyncWaitDone);
ReentrantMonitorAutoEnter autoMon(*client->mAcquireSyncWaitMonitor);
*client->mAcquireSyncWaitDone = true;
client->mAcquireSyncWaitMonitor->NotifyAll();
client->mAcquireSyncWaitMonitor = nullptr;
client->mAcquireSyncWaitDone = nullptr;
}
} else {
// Notify Acquire() result
if (client->mListener) {
if (aSuccess) {
client->mListener->ResourceReserved();
} else {
client->mListener->ResourceReserveFailed();
}
}
}
}
} // namespace mozilla