b=815643 Add Blink's HRTFDatabase and HRTFDatabaseLoader to the build r=ehsan

--HG--
extra : rebase_source : e7aa0ce1ca436bbb429cb1f6051b3b8210bf767a
This commit is contained in:
Karl Tomlinson 2013-08-09 09:56:28 +12:00
parent 76ae42715c
commit 296268450d
5 changed files with 101 additions and 102 deletions

View File

@ -26,15 +26,9 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "HRTFDatabase.h"
#if ENABLE(WEB_AUDIO)
#include "core/platform/audio/HRTFDatabase.h"
#include "core/platform/PlatformMemoryInstrumentation.h"
#include "core/platform/audio/HRTFElevation.h"
#include <wtf/MemoryInstrumentationVector.h>
#include "HRTFElevation.h"
using namespace std;
@ -47,24 +41,24 @@ const unsigned HRTFDatabase::NumberOfRawElevations = 10; // -45 -> +90 (each 15
const unsigned HRTFDatabase::InterpolationFactor = 1;
const unsigned HRTFDatabase::NumberOfTotalElevations = NumberOfRawElevations * InterpolationFactor;
PassOwnPtr<HRTFDatabase> HRTFDatabase::create(float sampleRate)
nsReturnRef<HRTFDatabase> HRTFDatabase::create(float sampleRate)
{
OwnPtr<HRTFDatabase> hrtfDatabase = adoptPtr(new HRTFDatabase(sampleRate));
return hrtfDatabase.release();
return nsReturnRef<HRTFDatabase>(new HRTFDatabase(sampleRate));
}
HRTFDatabase::HRTFDatabase(float sampleRate)
: m_elevations(NumberOfTotalElevations)
, m_sampleRate(sampleRate)
: m_sampleRate(sampleRate)
{
m_elevations.SetLength(NumberOfTotalElevations);
unsigned elevationIndex = 0;
for (int elevation = MinElevation; elevation <= MaxElevation; elevation += RawElevationAngleSpacing) {
OwnPtr<HRTFElevation> hrtfElevation = HRTFElevation::createForSubject("Composite", elevation, sampleRate);
ASSERT(hrtfElevation.get());
nsAutoRef<HRTFElevation> hrtfElevation(HRTFElevation::createBuiltin(elevation, sampleRate));
MOZ_ASSERT(hrtfElevation.get());
if (!hrtfElevation.get())
return;
m_elevations[elevationIndex] = hrtfElevation.release();
m_elevations[elevationIndex] = hrtfElevation.out();
elevationIndex += InterpolationFactor;
}
@ -79,7 +73,7 @@ HRTFDatabase::HRTFDatabase(float sampleRate)
for (unsigned jj = 1; jj < InterpolationFactor; ++jj) {
float x = static_cast<float>(jj) / static_cast<float>(InterpolationFactor);
m_elevations[i + jj] = HRTFElevation::createByInterpolatingSlices(m_elevations[i].get(), m_elevations[j].get(), x, sampleRate);
ASSERT(m_elevations[i + jj].get());
MOZ_ASSERT(m_elevations[i + jj].get());
}
}
}
@ -89,19 +83,19 @@ void HRTFDatabase::getKernelsFromAzimuthElevation(double azimuthBlend, unsigned
double& frameDelayL, double& frameDelayR)
{
unsigned elevationIndex = indexFromElevationAngle(elevationAngle);
ASSERT_WITH_SECURITY_IMPLICATION(elevationIndex < m_elevations.size() && m_elevations.size() > 0);
MOZ_ASSERT(elevationIndex < m_elevations.Length() && m_elevations.Length() > 0);
if (!m_elevations.size()) {
if (!m_elevations.Length()) {
kernelL = 0;
kernelR = 0;
return;
}
if (elevationIndex > m_elevations.size() - 1)
elevationIndex = m_elevations.size() - 1;
if (elevationIndex > m_elevations.Length() - 1)
elevationIndex = m_elevations.Length() - 1;
HRTFElevation* hrtfElevation = m_elevations[elevationIndex].get();
ASSERT(hrtfElevation);
MOZ_ASSERT(hrtfElevation);
if (!hrtfElevation) {
kernelL = 0;
kernelR = 0;
@ -114,19 +108,12 @@ void HRTFDatabase::getKernelsFromAzimuthElevation(double azimuthBlend, unsigned
unsigned HRTFDatabase::indexFromElevationAngle(double elevationAngle)
{
// Clamp to allowed range.
elevationAngle = max(static_cast<double>(MinElevation), elevationAngle);
elevationAngle = min(static_cast<double>(MaxElevation), elevationAngle);
elevationAngle = mozilla::clamped(elevationAngle,
static_cast<double>(MinElevation),
static_cast<double>(MaxElevation));
unsigned elevationIndex = static_cast<int>(InterpolationFactor * (elevationAngle - MinElevation) / RawElevationAngleSpacing);
return elevationIndex;
}
void HRTFDatabase::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
{
MemoryClassInfo info(memoryObjectInfo, this, PlatformMemoryTypes::AudioSharedData);
info.addMember(m_elevations, "elevations");
}
} // namespace WebCore
#endif // ENABLE(WEB_AUDIO)

View File

@ -29,21 +29,17 @@
#ifndef HRTFDatabase_h
#define HRTFDatabase_h
#include "core/platform/audio/HRTFElevation.h"
#include <wtf/Forward.h>
#include <wtf/Noncopyable.h>
#include <wtf/OwnPtr.h>
#include <wtf/PassRefPtr.h>
#include <wtf/Vector.h>
#include "HRTFElevation.h"
#include "nsAutoRef.h"
#include "nsTArray.h"
namespace WebCore {
class HRTFKernel;
class HRTFDatabase {
WTF_MAKE_NONCOPYABLE(HRTFDatabase);
public:
static PassOwnPtr<HRTFDatabase> create(float sampleRate);
static nsReturnRef<HRTFDatabase> create(float sampleRate);
// getKernelsFromAzimuthElevation() returns a left and right ear kernel, and an interpolated left and right frame delay for the given azimuth and elevation.
// azimuthBlend must be in the range 0 -> 1.
@ -59,9 +55,10 @@ public:
// Number of elevations loaded from resource.
static const unsigned NumberOfRawElevations;
void reportMemoryUsage(MemoryObjectInfo*) const;
private:
HRTFDatabase(const HRTFDatabase& other) MOZ_DELETE;
void operator=(const HRTFDatabase& other) MOZ_DELETE;
explicit HRTFDatabase(float sampleRate);
// Minimum and maximum elevation angles (inclusive) for a HRTFDatabase.
@ -78,10 +75,17 @@ private:
// Returns the index for the correct HRTFElevation given the elevation angle.
static unsigned indexFromElevationAngle(double);
Vector<OwnPtr<HRTFElevation> > m_elevations;
nsTArray<nsAutoRef<HRTFElevation> > m_elevations;
float m_sampleRate;
};
} // namespace WebCore
template <>
class nsAutoRefTraits<WebCore::HRTFDatabase> :
public nsPointerRefTraits<WebCore::HRTFDatabase> {
public:
static void Release(WebCore::HRTFDatabase* ptr) { delete(ptr); }
};
#endif // HRTFDatabase_h

View File

@ -26,39 +26,38 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "HRTFDatabaseLoader.h"
#if ENABLE(WEB_AUDIO)
#include "HRTFDatabase.h"
#include "core/platform/audio/HRTFDatabaseLoader.h"
#include "core/platform/PlatformMemoryInstrumentation.h"
#include "core/platform/audio/HRTFDatabase.h"
#include "wtf/MainThread.h"
#include "wtf/MemoryInstrumentationHashMap.h"
using namespace mozilla;
namespace WebCore {
// Singleton
HRTFDatabaseLoader::LoaderMap* HRTFDatabaseLoader::s_loaderMap = 0;
nsTHashtable<HRTFDatabaseLoader::LoaderByRateEntry>*
HRTFDatabaseLoader::s_loaderMap = nullptr;
PassRefPtr<HRTFDatabaseLoader> HRTFDatabaseLoader::createAndLoadAsynchronouslyIfNecessary(float sampleRate)
TemporaryRef<HRTFDatabaseLoader> HRTFDatabaseLoader::createAndLoadAsynchronouslyIfNecessary(float sampleRate)
{
ASSERT(isMainThread());
MOZ_ASSERT(NS_IsMainThread());
RefPtr<HRTFDatabaseLoader> loader;
if (!s_loaderMap)
s_loaderMap = adoptPtr(new LoaderMap()).leakPtr();
if (!s_loaderMap) {
s_loaderMap = new nsTHashtable<LoaderByRateEntry>();
s_loaderMap->Init();
}
loader = s_loaderMap->get(sampleRate);
if (loader) {
ASSERT(sampleRate == loader->databaseSampleRate());
LoaderByRateEntry* entry = s_loaderMap->PutEntry(sampleRate);
loader = entry->mLoader;
if (loader) { // existing entry
MOZ_ASSERT(sampleRate == loader->databaseSampleRate());
return loader;
}
loader = adoptRef(new HRTFDatabaseLoader(sampleRate));
s_loaderMap->add(sampleRate, loader.get());
loader = new HRTFDatabaseLoader(sampleRate);
entry->mLoader = loader;
loader->loadAsynchronously();
@ -66,35 +65,41 @@ PassRefPtr<HRTFDatabaseLoader> HRTFDatabaseLoader::createAndLoadAsynchronouslyIf
}
HRTFDatabaseLoader::HRTFDatabaseLoader(float sampleRate)
: m_databaseLoaderThread(0)
: m_threadLock("HRTFDatabaseLoader")
, m_databaseLoaderThread(nullptr)
, m_databaseSampleRate(sampleRate)
{
ASSERT(isMainThread());
MOZ_ASSERT(NS_IsMainThread());
}
HRTFDatabaseLoader::~HRTFDatabaseLoader()
{
ASSERT(isMainThread());
MOZ_ASSERT(NS_IsMainThread());
waitForLoaderThreadCompletion();
m_hrtfDatabase.clear();
m_hrtfDatabase.reset();
// Remove ourself from the map.
if (s_loaderMap)
s_loaderMap->remove(m_databaseSampleRate);
s_loaderMap->RemoveEntry(m_databaseSampleRate);
if (s_loaderMap->Count() == 0) {
delete s_loaderMap;
s_loaderMap = nullptr;
}
}
// Asynchronously load the database in this thread.
static void databaseLoaderEntry(void* threadData)
{
PR_SetCurrentThreadName("HRTFDatabaseLdr");
HRTFDatabaseLoader* loader = reinterpret_cast<HRTFDatabaseLoader*>(threadData);
ASSERT(loader);
MOZ_ASSERT(loader);
loader->load();
}
void HRTFDatabaseLoader::load()
{
ASSERT(!isMainThread());
MOZ_ASSERT(!NS_IsMainThread());
if (!m_hrtfDatabase.get()) {
// Load the default HRTF database.
m_hrtfDatabase = HRTFDatabase::create(m_databaseSampleRate);
@ -103,13 +108,16 @@ void HRTFDatabaseLoader::load()
void HRTFDatabaseLoader::loadAsynchronously()
{
ASSERT(isMainThread());
MOZ_ASSERT(NS_IsMainThread());
MutexLocker locker(m_threadLock);
MutexAutoLock locker(m_threadLock);
if (!m_hrtfDatabase.get() && !m_databaseLoaderThread) {
// Start the asynchronous database loading process.
m_databaseLoaderThread = createThread(databaseLoaderEntry, this, "HRTF database loader");
m_databaseLoaderThread =
PR_CreateThread(PR_USER_THREAD, databaseLoaderEntry, this,
PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
PR_JOINABLE_THREAD, 0);
}
}
@ -120,21 +128,14 @@ bool HRTFDatabaseLoader::isLoaded() const
void HRTFDatabaseLoader::waitForLoaderThreadCompletion()
{
MutexLocker locker(m_threadLock);
MutexAutoLock locker(m_threadLock);
// waitForThreadCompletion() should not be called twice for the same thread.
if (m_databaseLoaderThread)
waitForThreadCompletion(m_databaseLoaderThread);
m_databaseLoaderThread = 0;
}
void HRTFDatabaseLoader::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
{
MemoryClassInfo info(memoryObjectInfo, this, PlatformMemoryTypes::AudioSharedData);
info.addMember(m_hrtfDatabase, "hrtfDatabase");
info.addMember(s_loaderMap, "loaderMap", WTF::RetainingPointer);
if (m_databaseLoaderThread) {
DebugOnly<PRStatus> status = PR_JoinThread(m_databaseLoaderThread);
MOZ_ASSERT(status == PR_SUCCESS, "PR_JoinThread failed");
}
m_databaseLoaderThread = nullptr;
}
} // namespace WebCore
#endif // ENABLE(WEB_AUDIO)

View File

@ -29,24 +29,23 @@
#ifndef HRTFDatabaseLoader_h
#define HRTFDatabaseLoader_h
#include "core/platform/audio/HRTFDatabase.h"
#include "wtf/HashMap.h"
#include "wtf/PassRefPtr.h"
#include "wtf/RefCounted.h"
#include "wtf/RefPtr.h"
#include "wtf/Threading.h"
#include "HRTFDatabase.h"
#include "nsTHashtable.h"
#include "mozilla/RefPtr.h"
#include "nsIThread.h"
#include "mozilla/Mutex.h"
namespace WebCore {
// HRTFDatabaseLoader will asynchronously load the default HRTFDatabase in a new thread.
class HRTFDatabaseLoader : public RefCounted<HRTFDatabaseLoader> {
class HRTFDatabaseLoader : public mozilla::RefCounted<HRTFDatabaseLoader> {
public:
// Lazily creates a HRTFDatabaseLoader (if not already created) for the given sample-rate
// and starts loading asynchronously (when created the first time).
// Returns the HRTFDatabaseLoader.
// Must be called from the main thread.
static PassRefPtr<HRTFDatabaseLoader> createAndLoadAsynchronouslyIfNecessary(float sampleRate);
static mozilla::TemporaryRef<HRTFDatabaseLoader> createAndLoadAsynchronouslyIfNecessary(float sampleRate);
// Both constructor and destructor must be called from the main thread.
~HRTFDatabaseLoader();
@ -54,7 +53,8 @@ public:
// Returns true once the default database has been completely loaded.
bool isLoaded() const;
// waitForLoaderThreadCompletion() may be called more than once and is thread-safe.
// waitForLoaderThreadCompletion() may be called more than once,
// on any thread except m_databaseLoaderThread.
void waitForLoaderThreadCompletion();
HRTFDatabase* database() { return m_hrtfDatabase.get(); }
@ -64,8 +64,6 @@ public:
// Called in asynchronous loading thread.
void load();
void reportMemoryUsage(MemoryObjectInfo*) const;
private:
// Both constructor and destructor must be called from the main thread.
explicit HRTFDatabaseLoader(float sampleRate);
@ -75,16 +73,23 @@ private:
void loadAsynchronously();
// Map from sample-rate to loader.
typedef HashMap<double, HRTFDatabaseLoader*> LoaderMap;
class LoaderByRateEntry : public nsFloatHashKey {
public:
LoaderByRateEntry(KeyTypePointer aKey)
: nsFloatHashKey(aKey)
, mLoader() // so PutEntry() will zero-initialize
{
}
HRTFDatabaseLoader* mLoader;
};
// Keeps track of loaders on a per-sample-rate basis.
static LoaderMap* s_loaderMap; // singleton
static nsTHashtable<LoaderByRateEntry> *s_loaderMap; // singleton
OwnPtr<HRTFDatabase> m_hrtfDatabase;
nsAutoRef<HRTFDatabase> m_hrtfDatabase;
// Holding a m_threadLock is required when accessing m_databaseLoaderThread.
Mutex m_threadLock;
ThreadIdentifier m_databaseLoaderThread;
mozilla::Mutex m_threadLock;
PRThread* m_databaseLoaderThread;
float m_databaseSampleRate;
};

View File

@ -12,6 +12,8 @@ CPP_SOURCES += [
'DynamicsCompressor.cpp',
'DynamicsCompressorKernel.cpp',
'FFTConvolver.cpp',
'HRTFDatabase.cpp',
'HRTFDatabaseLoader.cpp',
'HRTFElevation.cpp',
'HRTFKernel.cpp',
'Reverb.cpp',