content/media/webaudio/blink/HRTFDatabaseLoader.cpp

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:98342e524614
1 /*
2 * Copyright (C) 2010 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 * its contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "HRTFDatabaseLoader.h"
30 #include "HRTFDatabase.h"
31
32 using namespace mozilla;
33
34 namespace WebCore {
35
36 // Singleton
37 nsTHashtable<HRTFDatabaseLoader::LoaderByRateEntry>*
38 HRTFDatabaseLoader::s_loaderMap = nullptr;
39
40 TemporaryRef<HRTFDatabaseLoader> HRTFDatabaseLoader::createAndLoadAsynchronouslyIfNecessary(float sampleRate)
41 {
42 MOZ_ASSERT(NS_IsMainThread());
43
44 RefPtr<HRTFDatabaseLoader> loader;
45
46 if (!s_loaderMap) {
47 s_loaderMap = new nsTHashtable<LoaderByRateEntry>();
48 }
49
50 LoaderByRateEntry* entry = s_loaderMap->PutEntry(sampleRate);
51 loader = entry->mLoader;
52 if (loader) { // existing entry
53 MOZ_ASSERT(sampleRate == loader->databaseSampleRate());
54 return loader;
55 }
56
57 loader = new HRTFDatabaseLoader(sampleRate);
58 entry->mLoader = loader;
59
60 loader->loadAsynchronously();
61
62 return loader;
63 }
64
65 HRTFDatabaseLoader::HRTFDatabaseLoader(float sampleRate)
66 : m_refCnt(0)
67 , m_threadLock("HRTFDatabaseLoader")
68 , m_databaseLoaderThread(nullptr)
69 , m_databaseSampleRate(sampleRate)
70 {
71 MOZ_ASSERT(NS_IsMainThread());
72 }
73
74 HRTFDatabaseLoader::~HRTFDatabaseLoader()
75 {
76 MOZ_ASSERT(NS_IsMainThread());
77
78 waitForLoaderThreadCompletion();
79 m_hrtfDatabase.reset();
80
81 if (s_loaderMap) {
82 // Remove ourself from the map.
83 s_loaderMap->RemoveEntry(m_databaseSampleRate);
84 if (s_loaderMap->Count() == 0) {
85 delete s_loaderMap;
86 s_loaderMap = nullptr;
87 }
88 }
89 }
90
91 size_t HRTFDatabaseLoader::sizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
92 {
93 size_t amount = aMallocSizeOf(this);
94
95 // NB: Need to make sure we're not competing with the loader thread.
96 const_cast<HRTFDatabaseLoader*>(this)->waitForLoaderThreadCompletion();
97
98 if (m_hrtfDatabase) {
99 amount += m_hrtfDatabase->sizeOfIncludingThis(aMallocSizeOf);
100 }
101
102 return amount;
103 }
104
105 class HRTFDatabaseLoader::ProxyReleaseEvent MOZ_FINAL : public nsRunnable {
106 public:
107 explicit ProxyReleaseEvent(HRTFDatabaseLoader* loader) : mLoader(loader) {}
108 NS_IMETHOD Run() MOZ_OVERRIDE
109 {
110 mLoader->MainThreadRelease();
111 return NS_OK;
112 }
113 private:
114 HRTFDatabaseLoader* mLoader;
115 };
116
117 void HRTFDatabaseLoader::ProxyRelease()
118 {
119 nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
120 if (MOZ_LIKELY(mainThread)) {
121 nsRefPtr<ProxyReleaseEvent> event = new ProxyReleaseEvent(this);
122 DebugOnly<nsresult> rv =
123 mainThread->Dispatch(event, NS_DISPATCH_NORMAL);
124 MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed to dispatch release event");
125 } else {
126 // Should be in XPCOM shutdown.
127 MOZ_ASSERT(NS_IsMainThread(),
128 "Main thread is not available for dispatch.");
129 MainThreadRelease();
130 }
131 }
132
133 void HRTFDatabaseLoader::MainThreadRelease()
134 {
135 MOZ_ASSERT(NS_IsMainThread());
136 int count = --m_refCnt;
137 MOZ_ASSERT(count >= 0, "extra release");
138 NS_LOG_RELEASE(this, count, "HRTFDatabaseLoader");
139 if (count == 0) {
140 // It is safe to delete here as the first reference can only be added
141 // on this (main) thread.
142 delete this;
143 }
144 }
145
146 // Asynchronously load the database in this thread.
147 static void databaseLoaderEntry(void* threadData)
148 {
149 PR_SetCurrentThreadName("HRTFDatabaseLdr");
150
151 HRTFDatabaseLoader* loader = reinterpret_cast<HRTFDatabaseLoader*>(threadData);
152 MOZ_ASSERT(loader);
153 loader->load();
154 }
155
156 void HRTFDatabaseLoader::load()
157 {
158 MOZ_ASSERT(!NS_IsMainThread());
159 MOZ_ASSERT(!m_hrtfDatabase.get(), "Called twice");
160 // Load the default HRTF database.
161 m_hrtfDatabase = HRTFDatabase::create(m_databaseSampleRate);
162 // Notifies the main thread of completion. See loadAsynchronously().
163 Release();
164 }
165
166 void HRTFDatabaseLoader::loadAsynchronously()
167 {
168 MOZ_ASSERT(NS_IsMainThread());
169 MOZ_ASSERT(m_refCnt, "Must not be called before a reference is added");
170
171 // Add a reference so that the destructor won't run and wait for the
172 // loader thread, until load() has completed.
173 AddRef();
174
175 MutexAutoLock locker(m_threadLock);
176
177 MOZ_ASSERT(!m_hrtfDatabase.get() && !m_databaseLoaderThread,
178 "Called twice");
179 // Start the asynchronous database loading process.
180 m_databaseLoaderThread =
181 PR_CreateThread(PR_USER_THREAD, databaseLoaderEntry, this,
182 PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
183 PR_JOINABLE_THREAD, 0);
184 }
185
186 bool HRTFDatabaseLoader::isLoaded() const
187 {
188 return m_hrtfDatabase.get();
189 }
190
191 void HRTFDatabaseLoader::waitForLoaderThreadCompletion()
192 {
193 MutexAutoLock locker(m_threadLock);
194
195 // waitForThreadCompletion() should not be called twice for the same thread.
196 if (m_databaseLoaderThread) {
197 DebugOnly<PRStatus> status = PR_JoinThread(m_databaseLoaderThread);
198 MOZ_ASSERT(status == PR_SUCCESS, "PR_JoinThread failed");
199 }
200 m_databaseLoaderThread = nullptr;
201 }
202
203 PLDHashOperator
204 HRTFDatabaseLoader::shutdownEnumFunc(LoaderByRateEntry *entry, void* unused)
205 {
206 // Ensure the loader thread's reference is removed for leak analysis.
207 entry->mLoader->waitForLoaderThreadCompletion();
208 return PLDHashOperator::PL_DHASH_NEXT;
209 }
210
211 void HRTFDatabaseLoader::shutdown()
212 {
213 MOZ_ASSERT(NS_IsMainThread());
214 if (s_loaderMap) {
215 // Set s_loaderMap to nullptr so that the hashtable is not modified on
216 // reference release during enumeration.
217 nsTHashtable<LoaderByRateEntry>* loaderMap = s_loaderMap;
218 s_loaderMap = nullptr;
219 loaderMap->EnumerateEntries(shutdownEnumFunc, nullptr);
220 delete loaderMap;
221 }
222 }
223 } // namespace WebCore

mercurial