diff options
Diffstat (limited to '')
-rw-r--r-- | dom/media/webrtc/common/Wrapper.h | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/dom/media/webrtc/common/Wrapper.h b/dom/media/webrtc/common/Wrapper.h new file mode 100644 index 0000000000..69c7406b07 --- /dev/null +++ b/dom/media/webrtc/common/Wrapper.h @@ -0,0 +1,157 @@ +/* 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/. */ + +#pragma once + +/* + * Wrapper - Helper class for wrapper objects. + * + * This helps to construct a shared_ptr object which wraps access to an + * underlying handle. (The handle could be a pointer to some low-level type, a + * conventional C handle, an int ID, a GUID, etc.) + * + * Usage: + * To obtain a FooPtr from a foo_handle_t, call + * FooPtr Foo::wrap(foo_handle_t); + * + * To implement Foo using Wrapper, Foo needs to include this macro in its class + * definition: + * CSF_DECLARE_WRAP(Foo, foo_handle_t); + * It also needs to include this in the cpp file, to provide the wrap() + * implementation and define the static Wrapper. + * CSF_IMPLEMENT_WRAP(Foo, foo_handle_t); + * These are all declared in common/Wrapper.h - Foo.h needs to include this + * too. + * The client needs to declare Foo(foo_handle_t) as private, and provide a + * suitable implementation, as well as implementing wrappers for any other + * functions to be exposed. + * The client needs to implement ~Foo() to perform any cleanup as usual. + * + * wrap() will always return the same FooPtr for a given foo_handle_t, it will + * not construct additional objects if a suitable one already exists. + * changeHandle() is used in rare cases where the underlying handle is changed, + * but the wrapper object is intended to remain. This is the + * case for the "fake" CC_DPCall generated on + * CC_DPLine::CreateCall(), where the correct IDPCall* is + * provided later. + * reset() is a cleanup step to wipe the handle map and allow memory to be + * reclaimed. + * + * Future enhancements: + * - For now, objects remain in the map forever. Better would be to add a + * releaseHandle() function which would allow the map to be emptied as + * underlying handles expired. While we can't force the client to give up + * its shared_ptr<Foo> objects, we can remove our own copy, for instance on a + * call ended event. + */ + +#include <map> +#include "prlock.h" +#include "mozilla/Assertions.h" + +/* + * Wrapper has its own autolock class because the instances are declared + * statically and mozilla::Mutex will not work properly when instantiated + * in a static constructor. + */ + +class LockNSPR { + public: + LockNSPR() : lock_(nullptr) { + lock_ = PR_NewLock(); + MOZ_ASSERT(lock_); + } + ~LockNSPR() { PR_DestroyLock(lock_); } + + void Acquire() { PR_Lock(lock_); } + + void Release() { PR_Unlock(lock_); } + + private: + PRLock* lock_; +}; + +class AutoLockNSPR { + public: + explicit AutoLockNSPR(LockNSPR& lock) : lock_(lock) { lock_.Acquire(); } + ~AutoLockNSPR() { lock_.Release(); } + + private: + LockNSPR& lock_; +}; + +template <class T> +class Wrapper { + private: + typedef std::map<typename T::Handle, typename T::Ptr> HandleMapType; + HandleMapType handleMap; + LockNSPR handleMapMutex; + + public: + Wrapper() {} + + typename T::Ptr wrap(typename T::Handle handle) { + AutoLockNSPR lock(handleMapMutex); + typename HandleMapType::iterator it = handleMap.find(handle); + if (it != handleMap.end()) { + return it->second; + } else { + typename T::Ptr p(new T(handle)); + handleMap[handle] = p; + return p; + } + } + + bool changeHandle(typename T::Handle oldHandle, + typename T::Handle newHandle) { + AutoLockNSPR lock(handleMapMutex); + typename HandleMapType::iterator it = handleMap.find(oldHandle); + if (it != handleMap.end()) { + typename T::Ptr p = it->second; + handleMap.erase(it); + handleMap[newHandle] = p; + return true; + } else { + return false; + } + } + + bool release(typename T::Handle handle) { + AutoLockNSPR lock(handleMapMutex); + typename HandleMapType::iterator it = handleMap.find(handle); + if (it != handleMap.end()) { + handleMap.erase(it); + return true; + } else { + return false; + } + } + + void reset() { + AutoLockNSPR lock(handleMapMutex); + handleMap.clear(); + } +}; + +#define CSF_DECLARE_WRAP(classname, handletype) \ + public: \ + static classname##Ptr wrap(handletype handle); \ + static void reset(); \ + static void release(handletype handle); \ + \ + private: \ + friend class Wrapper<classname>; \ + typedef classname##Ptr Ptr; \ + typedef handletype Handle; \ + static Wrapper<classname>& getWrapper() { \ + static Wrapper<classname> wrapper; \ + return wrapper; \ + } + +#define CSF_IMPLEMENT_WRAP(classname, handletype) \ + classname##Ptr classname::wrap(handletype handle) { \ + return getWrapper().wrap(handle); \ + } \ + void classname::reset() { getWrapper().reset(); } \ + void classname::release(handletype handle) { getWrapper().release(handle); } |