Bug 1048107 - Add GMPTimer implementation and placeholder GMP clock. r=jesup

This commit is contained in:
Chris Pearce 2014-08-05 10:18:31 +12:00
parent 2291089a1f
commit 14210f2acc
15 changed files with 390 additions and 8 deletions

View File

@ -110,7 +110,7 @@ GMPChild::LoadPluginLibrary(const std::string& aPluginPath)
}
auto platformAPI = new GMPPlatformAPI();
InitPlatformAPI(*platformAPI);
InitPlatformAPI(*platformAPI, this);
if (initFunc(platformAPI) != GMPNoErr) {
return false;
@ -301,6 +301,33 @@ GMPChild::RecvPGMPDecryptorConstructor(PGMPDecryptorChild* aActor)
return true;
}
PGMPTimerChild*
GMPChild::AllocPGMPTimerChild()
{
return new GMPTimerChild(this);
}
bool
GMPChild::DeallocPGMPTimerChild(PGMPTimerChild* aActor)
{
MOZ_ASSERT(mTimerChild == static_cast<GMPTimerChild*>(aActor));
mTimerChild = nullptr;
return true;
}
GMPTimerChild*
GMPChild::GetGMPTimers()
{
if (!mTimerChild) {
PGMPTimerChild* sc = SendPGMPTimerConstructor();
if (!sc) {
return nullptr;
}
mTimerChild = static_cast<GMPTimerChild*>(sc);
}
return mTimerChild;
}
bool
GMPChild::RecvCrashPluginNow()
{

View File

@ -8,6 +8,7 @@
#include "mozilla/gmp/PGMPChild.h"
#include "GMPSharedMemManager.h"
#include "GMPTimerChild.h"
#include "gmp-entrypoints.h"
#include "prlink.h"
@ -28,6 +29,9 @@ public:
bool LoadPluginLibrary(const std::string& aPluginPath);
MessageLoop* GMPMessageLoop();
// Main thread only.
GMPTimerChild* GetGMPTimers();
// GMPSharedMem
virtual void CheckThread() MOZ_OVERRIDE;
@ -51,11 +55,16 @@ private:
virtual bool DeallocPGMPAudioDecoderChild(PGMPAudioDecoderChild* aActor) MOZ_OVERRIDE;
virtual bool RecvPGMPAudioDecoderConstructor(PGMPAudioDecoderChild* aActor) MOZ_OVERRIDE;
virtual PGMPTimerChild* AllocPGMPTimerChild() MOZ_OVERRIDE;
virtual bool DeallocPGMPTimerChild(PGMPTimerChild* aActor) MOZ_OVERRIDE;
virtual bool RecvCrashPluginNow() MOZ_OVERRIDE;
virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
virtual void ProcessingError(Result aWhat) MOZ_OVERRIDE;
nsRefPtr<GMPTimerChild> mTimerChild;
PRLibrary* mLib;
GMPGetAPIFunc mGetAPIFunc;
MessageLoop* mGMPMessageLoop;

View File

@ -120,7 +120,7 @@ private:
#ifdef DEBUG
GMPChild* mPlugin;
#endif
#endif
};
} // namespace gmp

View File

@ -16,6 +16,7 @@
#include "mozIGeckoMediaPluginService.h"
#include "mozilla/unused.h"
#include "nsIObserverService.h"
#include "GMPTimerParent.h"
#include "runnable_utils.h"
#include "mozilla/dom/CrashReporterParent.h"
@ -92,7 +93,7 @@ GMPParent::Init(GeckoMediaPluginService *aService, nsIFile* aPluginDir)
if (NS_FAILED(rv)) {
return rv;
}
LOGD(("%s::%s: %p for %s", __CLASS__, __FUNCTION__, this,
LOGD(("%s::%s: %p for %s", __CLASS__, __FUNCTION__, this,
NS_LossyConvertUTF16toASCII(leafname).get()));
MOZ_ASSERT(leafname.Length() > 4);
@ -618,6 +619,28 @@ GMPParent::DeallocPGMPAudioDecoderParent(PGMPAudioDecoderParent* aActor)
return true;
}
bool
GMPParent::RecvPGMPTimerConstructor(PGMPTimerParent* actor)
{
return true;
}
PGMPTimerParent*
GMPParent::AllocPGMPTimerParent()
{
GMPTimerParent* p = new GMPTimerParent(GMPThread());
NS_ADDREF(p); // Released in DeallocPGMPTimerParent.
return p;
}
bool
GMPParent::DeallocPGMPTimerParent(PGMPTimerParent* aActor)
{
GMPTimerParent* p = static_cast<GMPTimerParent*>(aActor);
NS_RELEASE(p);
return true;
}
nsresult
ParseNextRecord(nsILineInputStream* aLineInputStream,
const nsCString& aPrefix,

View File

@ -12,6 +12,7 @@
#include "GMPDecryptorParent.h"
#include "GMPVideoDecoderParent.h"
#include "GMPVideoEncoderParent.h"
#include "GMPTimerParent.h"
#include "mozilla/gmp/PGMPParent.h"
#include "nsCOMPtr.h"
#include "nscore.h"
@ -143,7 +144,7 @@ private:
virtual PGMPVideoDecoderParent* AllocPGMPVideoDecoderParent() MOZ_OVERRIDE;
virtual bool DeallocPGMPVideoDecoderParent(PGMPVideoDecoderParent* aActor) MOZ_OVERRIDE;
virtual PGMPVideoEncoderParent* AllocPGMPVideoEncoderParent() MOZ_OVERRIDE;
virtual bool DeallocPGMPVideoEncoderParent(PGMPVideoEncoderParent* aActor) MOZ_OVERRIDE;
@ -153,6 +154,10 @@ private:
virtual PGMPAudioDecoderParent* AllocPGMPAudioDecoderParent() MOZ_OVERRIDE;
virtual bool DeallocPGMPAudioDecoderParent(PGMPAudioDecoderParent* aActor) MOZ_OVERRIDE;
virtual bool RecvPGMPTimerConstructor(PGMPTimerParent* actor) MOZ_OVERRIDE;
virtual PGMPTimerParent* AllocPGMPTimerParent() MOZ_OVERRIDE;
virtual bool DeallocPGMPTimerParent(PGMPTimerParent* aActor) MOZ_OVERRIDE;
GMPState mState;
nsCOMPtr<nsIFile> mDirectory; // plugin directory on disk
nsString mName; // base name of plugin on disk, UTF-16 because used for paths

View File

@ -4,13 +4,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GMPPlatform.h"
#include "GMPTimerChild.h"
#include "mozilla/Monitor.h"
#include "nsAutoPtr.h"
#include "GMPChild.h"
#include <ctime>
namespace mozilla {
namespace gmp {
static MessageLoop* sMainLoop = nullptr;
static GMPChild* sChild = nullptr;
// We just need a refcounted wrapper for GMPTask objects.
class Runnable MOZ_FINAL
@ -141,12 +145,30 @@ CreateMutex(GMPMutex** aMutex)
return GMPNoErr;
}
GMPErr
SetTimerOnMainThread(GMPTask* aTask, int64_t aTimeoutMS)
{
GMPTimerChild* timers = sChild->GetGMPTimers();
NS_ENSURE_TRUE(timers, GMPGenericErr);
return timers->SetTimer(aTask, aTimeoutMS);
}
GMPErr
GetClock(GMPTimestamp* aOutTime)
{
*aOutTime = time(0) * 1000;
return GMPNoErr;
}
void
InitPlatformAPI(GMPPlatformAPI& aPlatformAPI)
InitPlatformAPI(GMPPlatformAPI& aPlatformAPI, GMPChild* aChild)
{
if (!sMainLoop) {
sMainLoop = MessageLoop::current();
}
if (!sChild) {
sChild = aChild;
}
aPlatformAPI.version = 0;
aPlatformAPI.createthread = &CreateThread;
@ -154,8 +176,8 @@ InitPlatformAPI(GMPPlatformAPI& aPlatformAPI)
aPlatformAPI.syncrunonmainthread = &SyncRunOnMainThread;
aPlatformAPI.createmutex = &CreateMutex;
aPlatformAPI.createrecord = nullptr;
aPlatformAPI.settimer = nullptr;
aPlatformAPI.getcurrenttime = nullptr;
aPlatformAPI.settimer = &SetTimerOnMainThread;
aPlatformAPI.getcurrenttime = &GetClock;
}
GMPThreadImpl::GMPThreadImpl()

View File

@ -15,7 +15,9 @@ namespace gmp {
class GMPChild;
void InitPlatformAPI(GMPPlatformAPI& aPlatformAPI);
void InitPlatformAPI(GMPPlatformAPI& aPlatformAPI, GMPChild* aChild);
GMPErr RunOnMainThread(GMPTask* aTask);
class GMPThreadImpl : public GMPThread
{

View File

@ -0,0 +1,67 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 "GMPTimerChild.h"
#include "GMPPlatform.h"
#include "GMPChild.h"
#define MAX_NUM_TIMERS 1000
namespace mozilla {
namespace gmp {
GMPTimerChild::GMPTimerChild(GMPChild* aPlugin)
: mTimerCount(1)
, mPlugin(aPlugin)
{
MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
}
GMPTimerChild::~GMPTimerChild()
{
MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
}
GMPErr
GMPTimerChild::SetTimer(GMPTask* aTask, int64_t aTimeoutMS)
{
if (!aTask) {
NS_WARNING("Tried to set timer with null task!");
return GMPGenericErr;
}
if (mPlugin->GMPMessageLoop() != MessageLoop::current()) {
NS_WARNING("Tried to set GMP timer on non-main thread.");
return GMPGenericErr;
}
if (mTimers.Count() > MAX_NUM_TIMERS) {
return GMPQuotaExceededErr;
}
uint32_t timerId = mTimerCount;
mTimers.Put(timerId, aTask);
mTimerCount++;
if (!SendSetTimer(timerId, aTimeoutMS)) {
return GMPGenericErr;
}
return GMPNoErr;
}
bool
GMPTimerChild::RecvTimerExpired(const uint32_t& aTimerId)
{
MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
GMPTask* task = mTimers.Get(aTimerId);
mTimers.Remove(aTimerId);
if (task) {
RunOnMainThread(task);
}
return true;
}
} // namespace gmp
} // namespace mozilla

View File

@ -0,0 +1,46 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#ifndef GMPTimerChild_h_
#define GMPTimerChild_h_
#include "mozilla/gmp/PGMPTimerChild.h"
#include "mozilla/Monitor.h"
#include "nsDataHashtable.h"
#include "nsHashKeys.h"
#include "gmp-errors.h"
#include "gmp-platform.h"
namespace mozilla {
namespace gmp {
class GMPChild;
class GMPTimerChild : public PGMPTimerChild
{
public:
NS_INLINE_DECL_REFCOUNTING(GMPTimerChild)
GMPTimerChild(GMPChild* aPlugin);
GMPErr SetTimer(GMPTask* aTask, int64_t aTimeoutMS);
protected:
// GMPTimerChild
virtual bool RecvTimerExpired(const uint32_t& aTimerId) MOZ_OVERRIDE;
private:
~GMPTimerChild();
nsDataHashtable<nsUint32HashKey, GMPTask*> mTimers;
uint32_t mTimerCount;
GMPChild* mPlugin;
};
} // namespace gmp
} // namespace mozilla
#endif // GMPTimerChild_h_

View File

@ -0,0 +1,88 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 "GMPTimerParent.h"
#include "nsComponentManagerUtils.h"
#include "mozilla/unused.h"
namespace mozilla {
namespace gmp {
GMPTimerParent::GMPTimerParent(nsIThread* aGMPThread)
: mGMPThread(aGMPThread)
{
}
bool
GMPTimerParent::RecvSetTimer(const uint32_t& aTimerId,
const uint32_t& aTimeoutMs)
{
MOZ_ASSERT(mGMPThread == NS_GetCurrentThread());
nsresult rv;
nsAutoPtr<Context> ctx(new Context());
ctx->mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
NS_ENSURE_SUCCESS(rv, true);
ctx->mId = aTimerId;
rv = ctx->mTimer->SetTarget(mGMPThread);
NS_ENSURE_SUCCESS(rv, true);
ctx->mParent = this;
rv = ctx->mTimer->InitWithFuncCallback(&GMPTimerParent::GMPTimerExpired,
ctx,
aTimeoutMs,
nsITimer::TYPE_ONE_SHOT);
NS_ENSURE_SUCCESS(rv, true);
mTimers.PutEntry(ctx.forget());
return true;
}
/*static */
PLDHashOperator
GMPTimerParent::CancelTimers(nsPtrHashKey<Context>* aContext, void* aClosure)
{
auto context = aContext->GetKey();
context->mTimer->Cancel();
delete context;
return PL_DHASH_NEXT;
}
void
GMPTimerParent::ActorDestroy(ActorDestroyReason aWhy)
{
MOZ_ASSERT(mGMPThread == NS_GetCurrentThread());
mTimers.EnumerateEntries(GMPTimerParent::CancelTimers, nullptr);
mTimers.Clear();
}
/* static */
void
GMPTimerParent::GMPTimerExpired(nsITimer *aTimer, void *aClosure)
{
MOZ_ASSERT(aClosure);
nsAutoPtr<Context> ctx = static_cast<Context*>(aClosure);
MOZ_ASSERT(ctx->mParent);
if (ctx->mParent) {
ctx->mParent->TimerExpired(ctx);
}
}
void
GMPTimerParent::TimerExpired(Context* aContext)
{
MOZ_ASSERT(mGMPThread == NS_GetCurrentThread());
uint32_t id = aContext->mId;
mTimers.RemoveEntry(aContext);
if (id) {
unused << SendTimerExpired(id);
}
}
} // namespace gmp
} // namespace mozilla

View File

@ -0,0 +1,61 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#ifndef GMPTimerParent_h_
#define GMPTimerParent_h_
#include "mozilla/gmp/PGMPTimerParent.h"
#include "nsITimer.h"
#include "nsCOMPtr.h"
#include "nsClassHashtable.h"
#include "nsHashKeys.h"
#include "nsAutoPtr.h"
#include "mozilla/Monitor.h"
#include "nsIThread.h"
namespace mozilla {
namespace gmp {
class GMPTimerParent : public PGMPTimerParent {
public:
NS_INLINE_DECL_REFCOUNTING(GMPTimerParent)
GMPTimerParent(nsIThread* aGMPThread);
protected:
virtual bool RecvSetTimer(const uint32_t& aTimerId,
const uint32_t& aTimeoutMs) MOZ_OVERRIDE;
virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
private:
~GMPTimerParent() {}
static void GMPTimerExpired(nsITimer *aTimer, void *aClosure);
struct Context {
Context() {
MOZ_COUNT_CTOR(Context);
}
~Context() {
MOZ_COUNT_DTOR(Context);
}
nsCOMPtr<nsITimer> mTimer;
nsRefPtr<GMPTimerParent> mParent; // Note: live timers keep the GMPTimerParent alive.
uint32_t mId;
};
static PLDHashOperator
CancelTimers(nsPtrHashKey<Context>* aContext, void* aClosure);
void TimerExpired(Context* aContext);
nsTHashtable<nsPtrHashKey<Context>> mTimers;
nsCOMPtr<nsIThread> mGMPThread;
};
} // namespace gmp
} // namespace mozilla
#endif // GMPTimerParent_h_

View File

@ -8,6 +8,7 @@ include protocol PGMPVideoEncoder;
include protocol PCrashReporter;
include protocol PGMPDecryptor;
include protocol PGMPAudioDecoder;
include protocol PGMPTimer;
using mozilla::dom::NativeThreadId from "mozilla/dom/TabMessageUtils.h";
@ -21,9 +22,11 @@ intr protocol PGMP
manages PGMPVideoDecoder;
manages PGMPVideoEncoder;
manages PCrashReporter;
manages PGMPTimer;
parent:
async PCrashReporter(NativeThreadId tid);
async PGMPTimer();
child:
async PGMPAudioDecoder();

View File

@ -0,0 +1,22 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 protocol PGMP;
namespace mozilla {
namespace gmp {
async protocol PGMPTimer
{
manager PGMP;
child:
TimerExpired(uint32_t aTimerId);
parent:
SetTimer(uint32_t aTimerId, uint32_t aTimeoutMs);
__delete__();
};
} // namespace gmp
} // namespace mozilla

View File

@ -73,6 +73,8 @@ typedef GMPErr (*GMPCreateRecordPtr)(const char* aRecordName,
uint32_t aRecordNameSize,
GMPRecord** aOutRecord,
GMPRecordClient* aClient);
// Call on main thread only.
typedef GMPErr (*GMPSetTimerOnMainThreadPtr)(GMPTask* aTask, int64_t aTimeoutMS);
typedef GMPErr (*GMPGetCurrentTimePtr)(GMPTimestamp* aOutTime);

View File

@ -46,6 +46,8 @@ EXPORTS += [
'GMPProcessParent.h',
'GMPService.h',
'GMPSharedMemManager.h',
'GMPTimerChild.h',
'GMPTimerParent.h',
'GMPVideoDecoderChild.h',
'GMPVideoDecoderParent.h',
'GMPVideoDecoderProxy.h',
@ -72,6 +74,8 @@ UNIFIED_SOURCES += [
'GMPProcessParent.cpp',
'GMPService.cpp',
'GMPSharedMemManager.cpp',
'GMPTimerChild.cpp',
'GMPTimerParent.cpp',
'GMPVideoDecoderChild.cpp',
'GMPVideoDecoderParent.cpp',
'GMPVideoEncodedFrameImpl.cpp',
@ -87,6 +91,7 @@ IPDL_SOURCES += [
'PGMP.ipdl',
'PGMPAudioDecoder.ipdl',
'PGMPDecryptor.ipdl',
'PGMPTimer.ipdl',
'PGMPVideoDecoder.ipdl',
'PGMPVideoEncoder.ipdl',
]