summaryrefslogtreecommitdiffstats
path: root/dom/media/gmp/GMPPlatform.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/gmp/GMPPlatform.cpp')
-rw-r--r--dom/media/gmp/GMPPlatform.cpp300
1 files changed, 300 insertions, 0 deletions
diff --git a/dom/media/gmp/GMPPlatform.cpp b/dom/media/gmp/GMPPlatform.cpp
new file mode 100644
index 000000000..71fa03468
--- /dev/null
+++ b/dom/media/gmp/GMPPlatform.cpp
@@ -0,0 +1,300 @@
+/* -*- 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 "GMPPlatform.h"
+#include "GMPStorageChild.h"
+#include "GMPTimerChild.h"
+#include "mozilla/Monitor.h"
+#include "GMPChild.h"
+#include <ctime>
+
+namespace mozilla {
+namespace gmp {
+
+static MessageLoop* sMainLoop = nullptr;
+static GMPChild* sChild = nullptr;
+
+static bool
+IsOnChildMainThread()
+{
+ return sMainLoop && sMainLoop == MessageLoop::current();
+}
+
+// We just need a refcounted wrapper for GMPTask objects.
+class GMPRunnable final
+{
+public:
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GMPRunnable)
+
+ explicit GMPRunnable(GMPTask* aTask)
+ : mTask(aTask)
+ {
+ MOZ_ASSERT(mTask);
+ }
+
+ void Run()
+ {
+ mTask->Run();
+ mTask->Destroy();
+ mTask = nullptr;
+ }
+
+private:
+ ~GMPRunnable()
+ {
+ }
+
+ GMPTask* mTask;
+};
+
+class GMPSyncRunnable final
+{
+public:
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GMPSyncRunnable)
+
+ GMPSyncRunnable(GMPTask* aTask, MessageLoop* aMessageLoop)
+ : mDone(false)
+ , mTask(aTask)
+ , mMessageLoop(aMessageLoop)
+ , mMonitor("GMPSyncRunnable")
+ {
+ MOZ_ASSERT(mTask);
+ MOZ_ASSERT(mMessageLoop);
+ }
+
+ void Post()
+ {
+ // We assert here for two reasons.
+ // 1) Nobody should be blocking the main thread.
+ // 2) This prevents deadlocks when doing sync calls to main which if the
+ // main thread tries to do a sync call back to the calling thread.
+ MOZ_ASSERT(!IsOnChildMainThread());
+
+ mMessageLoop->PostTask(NewRunnableMethod(this, &GMPSyncRunnable::Run));
+ MonitorAutoLock lock(mMonitor);
+ while (!mDone) {
+ lock.Wait();
+ }
+ }
+
+ void Run()
+ {
+ mTask->Run();
+ mTask->Destroy();
+ mTask = nullptr;
+ MonitorAutoLock lock(mMonitor);
+ mDone = true;
+ lock.Notify();
+ }
+
+private:
+ ~GMPSyncRunnable()
+ {
+ }
+
+ bool mDone;
+ GMPTask* mTask;
+ MessageLoop* mMessageLoop;
+ Monitor mMonitor;
+};
+
+GMPErr
+CreateThread(GMPThread** aThread)
+{
+ if (!aThread) {
+ return GMPGenericErr;
+ }
+
+ *aThread = new GMPThreadImpl();
+
+ return GMPNoErr;
+}
+
+GMPErr
+RunOnMainThread(GMPTask* aTask)
+{
+ if (!aTask || !sMainLoop) {
+ return GMPGenericErr;
+ }
+
+ RefPtr<GMPRunnable> r = new GMPRunnable(aTask);
+ sMainLoop->PostTask(NewRunnableMethod(r, &GMPRunnable::Run));
+
+ return GMPNoErr;
+}
+
+GMPErr
+SyncRunOnMainThread(GMPTask* aTask)
+{
+ if (!aTask || !sMainLoop || IsOnChildMainThread()) {
+ return GMPGenericErr;
+ }
+
+ RefPtr<GMPSyncRunnable> r = new GMPSyncRunnable(aTask, sMainLoop);
+
+ r->Post();
+
+ return GMPNoErr;
+}
+
+GMPErr
+CreateMutex(GMPMutex** aMutex)
+{
+ if (!aMutex) {
+ return GMPGenericErr;
+ }
+
+ *aMutex = new GMPMutexImpl();
+
+ return GMPNoErr;
+}
+
+GMPErr
+CreateRecord(const char* aRecordName,
+ uint32_t aRecordNameSize,
+ GMPRecord** aOutRecord,
+ GMPRecordClient* aClient)
+{
+ if (aRecordNameSize > GMP_MAX_RECORD_NAME_SIZE ||
+ aRecordNameSize == 0) {
+ NS_WARNING("GMP tried to CreateRecord with too long or 0 record name");
+ return GMPGenericErr;
+ }
+ GMPStorageChild* storage = sChild->GetGMPStorage();
+ if (!storage) {
+ return GMPGenericErr;
+ }
+ MOZ_ASSERT(storage);
+ return storage->CreateRecord(nsDependentCString(aRecordName, aRecordNameSize),
+ aOutRecord,
+ aClient);
+}
+
+GMPErr
+SetTimerOnMainThread(GMPTask* aTask, int64_t aTimeoutMS)
+{
+ if (!aTask || !sMainLoop || !IsOnChildMainThread()) {
+ return GMPGenericErr;
+ }
+ GMPTimerChild* timers = sChild->GetGMPTimers();
+ NS_ENSURE_TRUE(timers, GMPGenericErr);
+ return timers->SetTimer(aTask, aTimeoutMS);
+}
+
+GMPErr
+GetClock(GMPTimestamp* aOutTime)
+{
+ *aOutTime = time(0) * 1000;
+ return GMPNoErr;
+}
+
+GMPErr
+CreateRecordIterator(RecvGMPRecordIteratorPtr aRecvIteratorFunc,
+ void* aUserArg)
+{
+ if (!aRecvIteratorFunc) {
+ return GMPInvalidArgErr;
+ }
+ GMPStorageChild* storage = sChild->GetGMPStorage();
+ if (!storage) {
+ return GMPGenericErr;
+ }
+ MOZ_ASSERT(storage);
+ return storage->EnumerateRecords(aRecvIteratorFunc, aUserArg);
+}
+
+void
+InitPlatformAPI(GMPPlatformAPI& aPlatformAPI, GMPChild* aChild)
+{
+ if (!sMainLoop) {
+ sMainLoop = MessageLoop::current();
+ }
+ if (!sChild) {
+ sChild = aChild;
+ }
+
+ aPlatformAPI.version = 0;
+ aPlatformAPI.createthread = &CreateThread;
+ aPlatformAPI.runonmainthread = &RunOnMainThread;
+ aPlatformAPI.syncrunonmainthread = &SyncRunOnMainThread;
+ aPlatformAPI.createmutex = &CreateMutex;
+ aPlatformAPI.createrecord = &CreateRecord;
+ aPlatformAPI.settimer = &SetTimerOnMainThread;
+ aPlatformAPI.getcurrenttime = &GetClock;
+ aPlatformAPI.getrecordenumerator = &CreateRecordIterator;
+}
+
+GMPThreadImpl::GMPThreadImpl()
+: mMutex("GMPThreadImpl"),
+ mThread("GMPThread")
+{
+ MOZ_COUNT_CTOR(GMPThread);
+}
+
+GMPThreadImpl::~GMPThreadImpl()
+{
+ MOZ_COUNT_DTOR(GMPThread);
+}
+
+void
+GMPThreadImpl::Post(GMPTask* aTask)
+{
+ MutexAutoLock lock(mMutex);
+
+ if (!mThread.IsRunning()) {
+ bool started = mThread.Start();
+ if (!started) {
+ NS_WARNING("Unable to start GMPThread!");
+ return;
+ }
+ }
+
+ RefPtr<GMPRunnable> r = new GMPRunnable(aTask);
+ mThread.message_loop()->PostTask(NewRunnableMethod(r.get(), &GMPRunnable::Run));
+}
+
+void
+GMPThreadImpl::Join()
+{
+ {
+ MutexAutoLock lock(mMutex);
+ if (mThread.IsRunning()) {
+ mThread.Stop();
+ }
+ }
+ delete this;
+}
+
+GMPMutexImpl::GMPMutexImpl()
+: mMonitor("gmp-mutex")
+{
+ MOZ_COUNT_CTOR(GMPMutexImpl);
+}
+
+GMPMutexImpl::~GMPMutexImpl()
+{
+ MOZ_COUNT_DTOR(GMPMutexImpl);
+}
+
+void
+GMPMutexImpl::Destroy()
+{
+ delete this;
+}
+
+void
+GMPMutexImpl::Acquire()
+{
+ mMonitor.Enter();
+}
+
+void
+GMPMutexImpl::Release()
+{
+ mMonitor.Exit();
+}
+
+} // namespace gmp
+} // namespace mozilla