/* -*- Mode: C++; tab-width: 50; 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 "OpenSLESProvider.h" #include "mozilla/Logging.h" #include "nsDebug.h" #include #include #include // MOZ_LOG=OpenSLESProvider:5 #undef LOG #undef LOG_ENABLED mozilla::LazyLogModule gOpenSLESProviderLog("OpenSLESProvider"); #define LOG(args) MOZ_LOG(gOpenSLESProviderLog, mozilla::LogLevel::Debug, args) #define LOG_ENABLED() MOZ_LOG_TEST(gOpenSLESProviderLog, mozilla::LogLevel::Debug) namespace mozilla { OpenSLESProvider::OpenSLESProvider() : mLock("OpenSLESProvider.mLock"), mSLEngine(nullptr), mSLEngineUsers(0), mIsRealized(false), mOpenSLESLib(nullptr) { LOG(("OpenSLESProvider being initialized")); } OpenSLESProvider::~OpenSLESProvider() { if (mOpenSLESLib) { LOG(("OpenSLES Engine was not properly Destroyed")); (void)dlclose(mOpenSLESLib); } } /* static */ OpenSLESProvider& OpenSLESProvider::getInstance() { // This doesn't need a Mutex in C++11 or GCC 4.3+, see N2660 and // https://gcc.gnu.org/projects/cxx0x.html static OpenSLESProvider instance; return instance; } /* static */ SLresult OpenSLESProvider::Get(SLObjectItf * aObjectm, SLuint32 aOptionCount, const SLEngineOption *aOptions) { OpenSLESProvider& provider = OpenSLESProvider::getInstance(); return provider.GetEngine(aObjectm, aOptionCount, aOptions); } SLresult OpenSLESProvider::GetEngine(SLObjectItf * aObjectm, SLuint32 aOptionCount, const SLEngineOption *aOptions) { MutexAutoLock lock(mLock); LOG(("Getting OpenSLES engine")); // Bug 1042051: Validate options are the same if (mSLEngine != nullptr) { *aObjectm = mSLEngine; mSLEngineUsers++; LOG(("Returning existing engine, %d users", mSLEngineUsers)); return SL_RESULT_SUCCESS; } else { int res = ConstructEngine(aObjectm, aOptionCount, aOptions); if (res == SL_RESULT_SUCCESS) { // Bug 1042051: Store engine options mSLEngine = *aObjectm; mSLEngineUsers++; LOG(("Returning new engine")); } else { LOG(("Error getting engine: %d", res)); } return res; } } SLresult OpenSLESProvider::ConstructEngine(SLObjectItf * aObjectm, SLuint32 aOptionCount, const SLEngineOption *aOptions) { mLock.AssertCurrentThreadOwns(); if (!mOpenSLESLib) { mOpenSLESLib = dlopen("libOpenSLES.so", RTLD_LAZY); if (!mOpenSLESLib) { LOG(("Failed to dlopen OpenSLES library")); return SL_RESULT_MEMORY_FAILURE; } } typedef SLresult (*slCreateEngine_t)(SLObjectItf *, SLuint32, const SLEngineOption *, SLuint32, const SLInterfaceID *, const SLboolean *); slCreateEngine_t f_slCreateEngine = (slCreateEngine_t)dlsym(mOpenSLESLib, "slCreateEngine"); int result = f_slCreateEngine(aObjectm, aOptionCount, aOptions, 0, NULL, NULL); return result; } /* static */ void OpenSLESProvider::Destroy(SLObjectItf * aObjectm) { OpenSLESProvider& provider = OpenSLESProvider::getInstance(); provider.DestroyEngine(aObjectm); } void OpenSLESProvider::DestroyEngine(SLObjectItf * aObjectm) { MutexAutoLock lock(mLock); NS_ASSERTION(mOpenSLESLib, "OpenSLES destroy called but library is not open"); mSLEngineUsers--; LOG(("Freeing engine, %d users left", mSLEngineUsers)); if (mSLEngineUsers) { return; } (*(*aObjectm))->Destroy(*aObjectm); // This assumes SLObjectItf is a pointer, but given the previous line, // that's a given. *aObjectm = nullptr; (void)dlclose(mOpenSLESLib); mOpenSLESLib = nullptr; mIsRealized = false; } /* static */ SLresult OpenSLESProvider::Realize(SLObjectItf aObjectm) { OpenSLESProvider& provider = OpenSLESProvider::getInstance(); return provider.RealizeEngine(aObjectm); } SLresult OpenSLESProvider::RealizeEngine(SLObjectItf aObjectm) { MutexAutoLock lock(mLock); NS_ASSERTION(mOpenSLESLib, "OpenSLES realize called but library is not open"); NS_ASSERTION(aObjectm != nullptr, "OpenSLES realize engine with empty ObjectItf"); if (mIsRealized) { LOG(("Not realizing already realized engine")); return SL_RESULT_SUCCESS; } else { SLresult res = (*aObjectm)->Realize(aObjectm, SL_BOOLEAN_FALSE); if (res != SL_RESULT_SUCCESS) { LOG(("Error realizing OpenSLES engine: %d", res)); } else { LOG(("Realized OpenSLES engine")); mIsRealized = true; } return res; } } } // namespace mozilla extern "C" { SLresult mozilla_get_sles_engine(SLObjectItf * aObjectm, SLuint32 aOptionCount, const SLEngineOption *aOptions) { return mozilla::OpenSLESProvider::Get(aObjectm, aOptionCount, aOptions); } void mozilla_destroy_sles_engine(SLObjectItf * aObjectm) { mozilla::OpenSLESProvider::Destroy(aObjectm); } SLresult mozilla_realize_sles_engine(SLObjectItf aObjectm) { return mozilla::OpenSLESProvider::Realize(aObjectm); } }