OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2010, Google Inc. All rights reserved. | 2 * Copyright (C) 2010, Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
11 * documentation and/or other materials provided with the distribution. | 11 * documentation and/or other materials provided with the distribution. |
12 * | 12 * |
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND AN
Y | 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND AN
Y |
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | 15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
16 * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR AN
Y | 16 * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR AN
Y |
17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | 17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
18 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 18 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND O
N | 19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND O
N |
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | 21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
22 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 22 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
23 */ | 23 */ |
24 | 24 |
25 #include "modules/webaudio/AbstractAudioContext.h" | 25 #include "modules/webaudio/BaseAudioContext.h" |
| 26 |
26 #include "bindings/core/v8/Dictionary.h" | 27 #include "bindings/core/v8/Dictionary.h" |
27 #include "bindings/core/v8/ExceptionMessages.h" | 28 #include "bindings/core/v8/ExceptionMessages.h" |
28 #include "bindings/core/v8/ExceptionState.h" | 29 #include "bindings/core/v8/ExceptionState.h" |
29 #include "bindings/core/v8/ScriptPromiseResolver.h" | 30 #include "bindings/core/v8/ScriptPromiseResolver.h" |
30 #include "bindings/core/v8/ScriptState.h" | 31 #include "bindings/core/v8/ScriptState.h" |
31 #include "core/dom/DOMException.h" | 32 #include "core/dom/DOMException.h" |
32 #include "core/dom/Document.h" | 33 #include "core/dom/Document.h" |
33 #include "core/dom/ExceptionCode.h" | 34 #include "core/dom/ExceptionCode.h" |
34 #include "core/dom/ExecutionContextTask.h" | 35 #include "core/dom/ExecutionContextTask.h" |
35 #include "core/html/HTMLMediaElement.h" | 36 #include "core/html/HTMLMediaElement.h" |
(...skipping 27 matching lines...) Expand all Loading... |
63 #include "modules/webaudio/ScriptProcessorNode.h" | 64 #include "modules/webaudio/ScriptProcessorNode.h" |
64 #include "modules/webaudio/StereoPannerNode.h" | 65 #include "modules/webaudio/StereoPannerNode.h" |
65 #include "modules/webaudio/WaveShaperNode.h" | 66 #include "modules/webaudio/WaveShaperNode.h" |
66 #include "platform/ThreadSafeFunctional.h" | 67 #include "platform/ThreadSafeFunctional.h" |
67 #include "platform/audio/IIRFilter.h" | 68 #include "platform/audio/IIRFilter.h" |
68 #include "public/platform/Platform.h" | 69 #include "public/platform/Platform.h" |
69 #include "wtf/text/WTFString.h" | 70 #include "wtf/text/WTFString.h" |
70 | 71 |
71 namespace blink { | 72 namespace blink { |
72 | 73 |
73 AbstractAudioContext* AbstractAudioContext::create(Document& document, Exception
State& exceptionState) | 74 BaseAudioContext* BaseAudioContext::create(Document& document, ExceptionState& e
xceptionState) |
74 { | 75 { |
75 return AudioContext::create(document, exceptionState); | 76 return AudioContext::create(document, exceptionState); |
76 } | 77 } |
77 | 78 |
78 // FIXME(dominicc): Devolve these constructors to AudioContext | 79 // FIXME(dominicc): Devolve these constructors to AudioContext |
79 // and OfflineAudioContext respectively. | 80 // and OfflineAudioContext respectively. |
80 | 81 |
81 // Constructor for rendering to the audio hardware. | 82 // Constructor for rendering to the audio hardware. |
82 AbstractAudioContext::AbstractAudioContext(Document* document) | 83 BaseAudioContext::BaseAudioContext(Document* document) |
83 : ActiveScriptWrappable(this) | 84 : ActiveScriptWrappable(this) |
84 , ActiveDOMObject(document) | 85 , ActiveDOMObject(document) |
85 , m_destinationNode(nullptr) | 86 , m_destinationNode(nullptr) |
86 , m_isCleared(false) | 87 , m_isCleared(false) |
87 , m_isResolvingResumePromises(false) | 88 , m_isResolvingResumePromises(false) |
88 , m_connectionCount(0) | 89 , m_connectionCount(0) |
89 , m_didInitializeContextGraphMutex(false) | 90 , m_didInitializeContextGraphMutex(false) |
90 , m_deferredTaskHandler(DeferredTaskHandler::create()) | 91 , m_deferredTaskHandler(DeferredTaskHandler::create()) |
91 , m_contextState(Suspended) | 92 , m_contextState(Suspended) |
92 , m_closedContextSampleRate(-1) | 93 , m_closedContextSampleRate(-1) |
93 , m_periodicWaveSine(nullptr) | 94 , m_periodicWaveSine(nullptr) |
94 , m_periodicWaveSquare(nullptr) | 95 , m_periodicWaveSquare(nullptr) |
95 , m_periodicWaveSawtooth(nullptr) | 96 , m_periodicWaveSawtooth(nullptr) |
96 , m_periodicWaveTriangle(nullptr) | 97 , m_periodicWaveTriangle(nullptr) |
97 { | 98 { |
98 m_didInitializeContextGraphMutex = true; | 99 m_didInitializeContextGraphMutex = true; |
99 m_destinationNode = DefaultAudioDestinationNode::create(this); | 100 m_destinationNode = DefaultAudioDestinationNode::create(this); |
100 | 101 |
101 initialize(); | 102 initialize(); |
102 } | 103 } |
103 | 104 |
104 // Constructor for offline (non-realtime) rendering. | 105 // Constructor for offline (non-realtime) rendering. |
105 AbstractAudioContext::AbstractAudioContext(Document* document, unsigned numberOf
Channels, size_t numberOfFrames, float sampleRate) | 106 BaseAudioContext::BaseAudioContext(Document* document, unsigned numberOfChannels
, size_t numberOfFrames, float sampleRate) |
106 : ActiveScriptWrappable(this) | 107 : ActiveScriptWrappable(this) |
107 , ActiveDOMObject(document) | 108 , ActiveDOMObject(document) |
108 , m_destinationNode(nullptr) | 109 , m_destinationNode(nullptr) |
109 , m_isCleared(false) | 110 , m_isCleared(false) |
110 , m_isResolvingResumePromises(false) | 111 , m_isResolvingResumePromises(false) |
111 , m_connectionCount(0) | 112 , m_connectionCount(0) |
112 , m_didInitializeContextGraphMutex(false) | 113 , m_didInitializeContextGraphMutex(false) |
113 , m_deferredTaskHandler(DeferredTaskHandler::create()) | 114 , m_deferredTaskHandler(DeferredTaskHandler::create()) |
114 , m_contextState(Suspended) | 115 , m_contextState(Suspended) |
115 , m_closedContextSampleRate(-1) | 116 , m_closedContextSampleRate(-1) |
116 , m_periodicWaveSine(nullptr) | 117 , m_periodicWaveSine(nullptr) |
117 , m_periodicWaveSquare(nullptr) | 118 , m_periodicWaveSquare(nullptr) |
118 , m_periodicWaveSawtooth(nullptr) | 119 , m_periodicWaveSawtooth(nullptr) |
119 , m_periodicWaveTriangle(nullptr) | 120 , m_periodicWaveTriangle(nullptr) |
120 { | 121 { |
121 m_didInitializeContextGraphMutex = true; | 122 m_didInitializeContextGraphMutex = true; |
122 } | 123 } |
123 | 124 |
124 AbstractAudioContext::~AbstractAudioContext() | 125 BaseAudioContext::~BaseAudioContext() |
125 { | 126 { |
126 deferredTaskHandler().contextWillBeDestroyed(); | 127 deferredTaskHandler().contextWillBeDestroyed(); |
127 // AudioNodes keep a reference to their context, so there should be no way t
o be in the destructor if there are still AudioNodes around. | 128 // AudioNodes keep a reference to their context, so there should be no way t
o be in the destructor if there are still AudioNodes around. |
128 ASSERT(!isDestinationInitialized()); | 129 ASSERT(!isDestinationInitialized()); |
129 ASSERT(!m_activeSourceNodes.size()); | 130 ASSERT(!m_activeSourceNodes.size()); |
130 ASSERT(!m_finishedSourceHandlers.size()); | 131 ASSERT(!m_finishedSourceHandlers.size()); |
131 ASSERT(!m_isResolvingResumePromises); | 132 ASSERT(!m_isResolvingResumePromises); |
132 ASSERT(!m_resumeResolvers.size()); | 133 ASSERT(!m_resumeResolvers.size()); |
133 } | 134 } |
134 | 135 |
135 void AbstractAudioContext::initialize() | 136 void BaseAudioContext::initialize() |
136 { | 137 { |
137 if (isDestinationInitialized()) | 138 if (isDestinationInitialized()) |
138 return; | 139 return; |
139 | 140 |
140 FFTFrame::initialize(); | 141 FFTFrame::initialize(); |
141 m_listener = AudioListener::create(); | 142 m_listener = AudioListener::create(); |
142 | 143 |
143 if (m_destinationNode.get()) { | 144 if (m_destinationNode.get()) { |
144 m_destinationNode->handler().initialize(); | 145 m_destinationNode->handler().initialize(); |
145 } | 146 } |
146 } | 147 } |
147 | 148 |
148 void AbstractAudioContext::clear() | 149 void BaseAudioContext::clear() |
149 { | 150 { |
150 m_destinationNode.clear(); | 151 m_destinationNode.clear(); |
151 // The audio rendering thread is dead. Nobody will schedule AudioHandler | 152 // The audio rendering thread is dead. Nobody will schedule AudioHandler |
152 // deletion. Let's do it ourselves. | 153 // deletion. Let's do it ourselves. |
153 deferredTaskHandler().clearHandlersToBeDeleted(); | 154 deferredTaskHandler().clearHandlersToBeDeleted(); |
154 m_isCleared = true; | 155 m_isCleared = true; |
155 } | 156 } |
156 | 157 |
157 void AbstractAudioContext::uninitialize() | 158 void BaseAudioContext::uninitialize() |
158 { | 159 { |
159 ASSERT(isMainThread()); | 160 ASSERT(isMainThread()); |
160 | 161 |
161 if (!isDestinationInitialized()) | 162 if (!isDestinationInitialized()) |
162 return; | 163 return; |
163 | 164 |
164 // This stops the audio thread and all audio rendering. | 165 // This stops the audio thread and all audio rendering. |
165 if (m_destinationNode) | 166 if (m_destinationNode) |
166 m_destinationNode->handler().uninitialize(); | 167 m_destinationNode->handler().uninitialize(); |
167 | 168 |
168 // Get rid of the sources which may still be playing. | 169 // Get rid of the sources which may still be playing. |
169 releaseActiveSourceNodes(); | 170 releaseActiveSourceNodes(); |
170 | 171 |
171 // Reject any pending resolvers before we go away. | 172 // Reject any pending resolvers before we go away. |
172 rejectPendingResolvers(); | 173 rejectPendingResolvers(); |
173 didClose(); | 174 didClose(); |
174 | 175 |
175 ASSERT(m_listener); | 176 ASSERT(m_listener); |
176 m_listener->waitForHRTFDatabaseLoaderThreadCompletion(); | 177 m_listener->waitForHRTFDatabaseLoaderThreadCompletion(); |
177 | 178 |
178 clear(); | 179 clear(); |
179 } | 180 } |
180 | 181 |
181 void AbstractAudioContext::stop() | 182 void BaseAudioContext::stop() |
182 { | 183 { |
183 uninitialize(); | 184 uninitialize(); |
184 } | 185 } |
185 | 186 |
186 bool AbstractAudioContext::hasPendingActivity() const | 187 bool BaseAudioContext::hasPendingActivity() const |
187 { | 188 { |
188 // There's no pending activity if the audio context has been cleared. | 189 // There's no pending activity if the audio context has been cleared. |
189 return !m_isCleared; | 190 return !m_isCleared; |
190 } | 191 } |
191 | 192 |
192 void AbstractAudioContext::throwExceptionForClosedState(ExceptionState& exceptio
nState) | 193 void BaseAudioContext::throwExceptionForClosedState(ExceptionState& exceptionSta
te) |
193 { | 194 { |
194 exceptionState.throwDOMException(InvalidStateError, "AudioContext has been c
losed."); | 195 exceptionState.throwDOMException(InvalidStateError, "AudioContext has been c
losed."); |
195 } | 196 } |
196 | 197 |
197 AudioBuffer* AbstractAudioContext::createBuffer(unsigned numberOfChannels, size_
t numberOfFrames, float sampleRate, ExceptionState& exceptionState) | 198 AudioBuffer* BaseAudioContext::createBuffer(unsigned numberOfChannels, size_t nu
mberOfFrames, float sampleRate, ExceptionState& exceptionState) |
198 { | 199 { |
199 // It's ok to call createBuffer, even if the context is closed because the A
udioBuffer doesn't | 200 // It's ok to call createBuffer, even if the context is closed because the A
udioBuffer doesn't |
200 // really "belong" to any particular context. | 201 // really "belong" to any particular context. |
201 | 202 |
202 return AudioBuffer::create(numberOfChannels, numberOfFrames, sampleRate, exc
eptionState); | 203 return AudioBuffer::create(numberOfChannels, numberOfFrames, sampleRate, exc
eptionState); |
203 } | 204 } |
204 | 205 |
205 ScriptPromise AbstractAudioContext::decodeAudioData(ScriptState* scriptState, DO
MArrayBuffer* audioData, AudioBufferCallback* successCallback, AudioBufferCallba
ck* errorCallback, ExceptionState& exceptionState) | 206 ScriptPromise BaseAudioContext::decodeAudioData(ScriptState* scriptState, DOMArr
ayBuffer* audioData, AudioBufferCallback* successCallback, AudioBufferCallback*
errorCallback, ExceptionState& exceptionState) |
206 { | 207 { |
207 ASSERT(isMainThread()); | 208 ASSERT(isMainThread()); |
208 ASSERT(audioData); | 209 ASSERT(audioData); |
209 | 210 |
210 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState)
; | 211 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState)
; |
211 ScriptPromise promise = resolver->promise(); | 212 ScriptPromise promise = resolver->promise(); |
212 | 213 |
213 float rate = isContextClosed() ? closedContextSampleRate() : sampleRate(); | 214 float rate = isContextClosed() ? closedContextSampleRate() : sampleRate(); |
214 | 215 |
215 ASSERT(rate > 0); | 216 ASSERT(rate > 0); |
216 | 217 |
217 m_decodeAudioResolvers.add(resolver); | 218 m_decodeAudioResolvers.add(resolver); |
218 m_audioDecoder.decodeAsync(audioData, rate, successCallback, errorCallback,
resolver, this); | 219 m_audioDecoder.decodeAsync(audioData, rate, successCallback, errorCallback,
resolver, this); |
219 | 220 |
220 return promise; | 221 return promise; |
221 } | 222 } |
222 | 223 |
223 void AbstractAudioContext::handleDecodeAudioData(AudioBuffer* audioBuffer, Scrip
tPromiseResolver* resolver, AudioBufferCallback* successCallback, AudioBufferCal
lback* errorCallback) | 224 void BaseAudioContext::handleDecodeAudioData(AudioBuffer* audioBuffer, ScriptPro
miseResolver* resolver, AudioBufferCallback* successCallback, AudioBufferCallbac
k* errorCallback) |
224 { | 225 { |
225 ASSERT(isMainThread()); | 226 ASSERT(isMainThread()); |
226 | 227 |
227 if (audioBuffer) { | 228 if (audioBuffer) { |
228 // Resolve promise successfully and run the success callback | 229 // Resolve promise successfully and run the success callback |
229 resolver->resolve(audioBuffer); | 230 resolver->resolve(audioBuffer); |
230 if (successCallback) | 231 if (successCallback) |
231 successCallback->handleEvent(audioBuffer); | 232 successCallback->handleEvent(audioBuffer); |
232 } else { | 233 } else { |
233 // Reject the promise and run the error callback | 234 // Reject the promise and run the error callback |
234 DOMException* error = DOMException::create(EncodingError, "Unable to dec
ode audio data"); | 235 DOMException* error = DOMException::create(EncodingError, "Unable to dec
ode audio data"); |
235 resolver->reject(error); | 236 resolver->reject(error); |
236 if (errorCallback) | 237 if (errorCallback) |
237 errorCallback->handleEvent(error); | 238 errorCallback->handleEvent(error); |
238 } | 239 } |
239 | 240 |
240 // We've resolved the promise. Remove it now. | 241 // We've resolved the promise. Remove it now. |
241 ASSERT(m_decodeAudioResolvers.contains(resolver)); | 242 ASSERT(m_decodeAudioResolvers.contains(resolver)); |
242 m_decodeAudioResolvers.remove(resolver); | 243 m_decodeAudioResolvers.remove(resolver); |
243 } | 244 } |
244 | 245 |
245 AudioBufferSourceNode* AbstractAudioContext::createBufferSource(ExceptionState&
exceptionState) | 246 AudioBufferSourceNode* BaseAudioContext::createBufferSource(ExceptionState& exce
ptionState) |
246 { | 247 { |
247 ASSERT(isMainThread()); | 248 ASSERT(isMainThread()); |
248 | 249 |
249 if (isContextClosed()) { | 250 if (isContextClosed()) { |
250 throwExceptionForClosedState(exceptionState); | 251 throwExceptionForClosedState(exceptionState); |
251 return nullptr; | 252 return nullptr; |
252 } | 253 } |
253 | 254 |
254 AudioBufferSourceNode* node = AudioBufferSourceNode::create(*this, sampleRat
e()); | 255 AudioBufferSourceNode* node = AudioBufferSourceNode::create(*this, sampleRat
e()); |
255 | 256 |
256 // Do not add a reference to this source node now. The reference will be add
ed when start() is | 257 // Do not add a reference to this source node now. The reference will be add
ed when start() is |
257 // called. | 258 // called. |
258 | 259 |
259 return node; | 260 return node; |
260 } | 261 } |
261 | 262 |
262 MediaElementAudioSourceNode* AbstractAudioContext::createMediaElementSource(HTML
MediaElement* mediaElement, ExceptionState& exceptionState) | 263 ScriptProcessorNode* BaseAudioContext::createScriptProcessor(ExceptionState& exc
eptionState) |
263 { | |
264 ASSERT(isMainThread()); | |
265 | |
266 if (isContextClosed()) { | |
267 throwExceptionForClosedState(exceptionState); | |
268 return nullptr; | |
269 } | |
270 | |
271 // First check if this media element already has a source node. | |
272 if (mediaElement->audioSourceNode()) { | |
273 exceptionState.throwDOMException( | |
274 InvalidStateError, | |
275 "HTMLMediaElement already connected previously to a different MediaE
lementSourceNode."); | |
276 return nullptr; | |
277 } | |
278 | |
279 MediaElementAudioSourceNode* node = MediaElementAudioSourceNode::create(*thi
s, *mediaElement); | |
280 | |
281 mediaElement->setAudioSourceNode(node); | |
282 | |
283 notifySourceNodeStartedProcessing(node); // context keeps reference until no
de is disconnected | |
284 return node; | |
285 } | |
286 | |
287 MediaStreamAudioSourceNode* AbstractAudioContext::createMediaStreamSource(MediaS
tream* mediaStream, ExceptionState& exceptionState) | |
288 { | |
289 ASSERT(isMainThread()); | |
290 | |
291 if (isContextClosed()) { | |
292 throwExceptionForClosedState(exceptionState); | |
293 return nullptr; | |
294 } | |
295 | |
296 MediaStreamTrackVector audioTracks = mediaStream->getAudioTracks(); | |
297 if (audioTracks.isEmpty()) { | |
298 exceptionState.throwDOMException( | |
299 InvalidStateError, | |
300 "MediaStream has no audio track"); | |
301 return nullptr; | |
302 } | |
303 | |
304 // Use the first audio track in the media stream. | |
305 MediaStreamTrack* audioTrack = audioTracks[0]; | |
306 OwnPtr<AudioSourceProvider> provider = audioTrack->createWebAudioSource(); | |
307 MediaStreamAudioSourceNode* node = MediaStreamAudioSourceNode::create(*this,
*mediaStream, audioTrack, provider.release()); | |
308 | |
309 // FIXME: Only stereo streams are supported right now. We should be able to
accept multi-channel streams. | |
310 node->setFormat(2, sampleRate()); | |
311 | |
312 notifySourceNodeStartedProcessing(node); // context keeps reference until no
de is disconnected | |
313 return node; | |
314 } | |
315 | |
316 MediaStreamAudioDestinationNode* AbstractAudioContext::createMediaStreamDestinat
ion(ExceptionState& exceptionState) | |
317 { | |
318 if (isContextClosed()) { | |
319 throwExceptionForClosedState(exceptionState); | |
320 return nullptr; | |
321 } | |
322 | |
323 // Set number of output channels to stereo by default. | |
324 return MediaStreamAudioDestinationNode::create(*this, 2); | |
325 } | |
326 | |
327 ScriptProcessorNode* AbstractAudioContext::createScriptProcessor(ExceptionState&
exceptionState) | |
328 { | 264 { |
329 // Set number of input/output channels to stereo by default. | 265 // Set number of input/output channels to stereo by default. |
330 return createScriptProcessor(0, 2, 2, exceptionState); | 266 return createScriptProcessor(0, 2, 2, exceptionState); |
331 } | 267 } |
332 | 268 |
333 ScriptProcessorNode* AbstractAudioContext::createScriptProcessor(size_t bufferSi
ze, ExceptionState& exceptionState) | 269 ScriptProcessorNode* BaseAudioContext::createScriptProcessor(size_t bufferSize,
ExceptionState& exceptionState) |
334 { | 270 { |
335 // Set number of input/output channels to stereo by default. | 271 // Set number of input/output channels to stereo by default. |
336 return createScriptProcessor(bufferSize, 2, 2, exceptionState); | 272 return createScriptProcessor(bufferSize, 2, 2, exceptionState); |
337 } | 273 } |
338 | 274 |
339 ScriptProcessorNode* AbstractAudioContext::createScriptProcessor(size_t bufferSi
ze, size_t numberOfInputChannels, ExceptionState& exceptionState) | 275 ScriptProcessorNode* BaseAudioContext::createScriptProcessor(size_t bufferSize,
size_t numberOfInputChannels, ExceptionState& exceptionState) |
340 { | 276 { |
341 // Set number of output channels to stereo by default. | 277 // Set number of output channels to stereo by default. |
342 return createScriptProcessor(bufferSize, numberOfInputChannels, 2, exception
State); | 278 return createScriptProcessor(bufferSize, numberOfInputChannels, 2, exception
State); |
343 } | 279 } |
344 | 280 |
345 ScriptProcessorNode* AbstractAudioContext::createScriptProcessor(size_t bufferSi
ze, size_t numberOfInputChannels, size_t numberOfOutputChannels, ExceptionState&
exceptionState) | 281 ScriptProcessorNode* BaseAudioContext::createScriptProcessor(size_t bufferSize,
size_t numberOfInputChannels, size_t numberOfOutputChannels, ExceptionState& exc
eptionState) |
346 { | 282 { |
347 ASSERT(isMainThread()); | 283 ASSERT(isMainThread()); |
348 | 284 |
349 if (isContextClosed()) { | 285 if (isContextClosed()) { |
350 throwExceptionForClosedState(exceptionState); | 286 throwExceptionForClosedState(exceptionState); |
351 return nullptr; | 287 return nullptr; |
352 } | 288 } |
353 | 289 |
354 ScriptProcessorNode* node = ScriptProcessorNode::create(*this, sampleRate(),
bufferSize, numberOfInputChannels, numberOfOutputChannels); | 290 ScriptProcessorNode* node = ScriptProcessorNode::create(*this, sampleRate(),
bufferSize, numberOfInputChannels, numberOfOutputChannels); |
355 | 291 |
356 if (!node) { | 292 if (!node) { |
357 if (!numberOfInputChannels && !numberOfOutputChannels) { | 293 if (!numberOfInputChannels && !numberOfOutputChannels) { |
358 exceptionState.throwDOMException( | 294 exceptionState.throwDOMException( |
359 IndexSizeError, | 295 IndexSizeError, |
360 "number of input channels and output channels cannot both be zer
o."); | 296 "number of input channels and output channels cannot both be zer
o."); |
361 } else if (numberOfInputChannels > AbstractAudioContext::maxNumberOfChan
nels()) { | 297 } else if (numberOfInputChannels > BaseAudioContext::maxNumberOfChannels
()) { |
362 exceptionState.throwDOMException( | 298 exceptionState.throwDOMException( |
363 IndexSizeError, | 299 IndexSizeError, |
364 "number of input channels (" + String::number(numberOfInputChann
els) | 300 "number of input channels (" + String::number(numberOfInputChann
els) |
365 + ") exceeds maximum (" | 301 + ") exceeds maximum (" |
366 + String::number(AbstractAudioContext::maxNumberOfChannels()) +
")."); | 302 + String::number(BaseAudioContext::maxNumberOfChannels()) + ")."
); |
367 } else if (numberOfOutputChannels > AbstractAudioContext::maxNumberOfCha
nnels()) { | 303 } else if (numberOfOutputChannels > BaseAudioContext::maxNumberOfChannel
s()) { |
368 exceptionState.throwDOMException( | 304 exceptionState.throwDOMException( |
369 IndexSizeError, | 305 IndexSizeError, |
370 "number of output channels (" + String::number(numberOfInputChan
nels) | 306 "number of output channels (" + String::number(numberOfInputChan
nels) |
371 + ") exceeds maximum (" | 307 + ") exceeds maximum (" |
372 + String::number(AbstractAudioContext::maxNumberOfChannels()) +
")."); | 308 + String::number(BaseAudioContext::maxNumberOfChannels()) + ")."
); |
373 } else { | 309 } else { |
374 exceptionState.throwDOMException( | 310 exceptionState.throwDOMException( |
375 IndexSizeError, | 311 IndexSizeError, |
376 "buffer size (" + String::number(bufferSize) | 312 "buffer size (" + String::number(bufferSize) |
377 + ") must be a power of two between 256 and 16384."); | 313 + ") must be a power of two between 256 and 16384."); |
378 } | 314 } |
379 return nullptr; | 315 return nullptr; |
380 } | 316 } |
381 | 317 |
382 notifySourceNodeStartedProcessing(node); // context keeps reference until we
stop making javascript rendering callbacks | 318 notifySourceNodeStartedProcessing(node); // context keeps reference until we
stop making javascript rendering callbacks |
383 return node; | 319 return node; |
384 } | 320 } |
385 | 321 |
386 StereoPannerNode* AbstractAudioContext::createStereoPanner(ExceptionState& excep
tionState) | 322 StereoPannerNode* BaseAudioContext::createStereoPanner(ExceptionState& exception
State) |
387 { | 323 { |
388 ASSERT(isMainThread()); | 324 ASSERT(isMainThread()); |
389 if (isContextClosed()) { | 325 if (isContextClosed()) { |
390 throwExceptionForClosedState(exceptionState); | 326 throwExceptionForClosedState(exceptionState); |
391 return nullptr; | 327 return nullptr; |
392 } | 328 } |
393 | 329 |
394 return StereoPannerNode::create(*this, sampleRate()); | 330 return StereoPannerNode::create(*this, sampleRate()); |
395 } | 331 } |
396 | 332 |
397 BiquadFilterNode* AbstractAudioContext::createBiquadFilter(ExceptionState& excep
tionState) | 333 BiquadFilterNode* BaseAudioContext::createBiquadFilter(ExceptionState& exception
State) |
398 { | 334 { |
399 ASSERT(isMainThread()); | 335 ASSERT(isMainThread()); |
400 if (isContextClosed()) { | 336 if (isContextClosed()) { |
401 throwExceptionForClosedState(exceptionState); | 337 throwExceptionForClosedState(exceptionState); |
402 return nullptr; | 338 return nullptr; |
403 } | 339 } |
404 | 340 |
405 return BiquadFilterNode::create(*this, sampleRate()); | 341 return BiquadFilterNode::create(*this, sampleRate()); |
406 } | 342 } |
407 | 343 |
408 WaveShaperNode* AbstractAudioContext::createWaveShaper(ExceptionState& exception
State) | 344 WaveShaperNode* BaseAudioContext::createWaveShaper(ExceptionState& exceptionStat
e) |
409 { | 345 { |
410 ASSERT(isMainThread()); | 346 ASSERT(isMainThread()); |
411 if (isContextClosed()) { | 347 if (isContextClosed()) { |
412 throwExceptionForClosedState(exceptionState); | 348 throwExceptionForClosedState(exceptionState); |
413 return nullptr; | 349 return nullptr; |
414 } | 350 } |
415 | 351 |
416 return WaveShaperNode::create(*this); | 352 return WaveShaperNode::create(*this); |
417 } | 353 } |
418 | 354 |
419 PannerNode* AbstractAudioContext::createPanner(ExceptionState& exceptionState) | 355 PannerNode* BaseAudioContext::createPanner(ExceptionState& exceptionState) |
420 { | 356 { |
421 ASSERT(isMainThread()); | 357 ASSERT(isMainThread()); |
422 if (isContextClosed()) { | 358 if (isContextClosed()) { |
423 throwExceptionForClosedState(exceptionState); | 359 throwExceptionForClosedState(exceptionState); |
424 return nullptr; | 360 return nullptr; |
425 } | 361 } |
426 | 362 |
427 return PannerNode::create(*this, sampleRate()); | 363 return PannerNode::create(*this, sampleRate()); |
428 } | 364 } |
429 | 365 |
430 ConvolverNode* AbstractAudioContext::createConvolver(ExceptionState& exceptionSt
ate) | 366 ConvolverNode* BaseAudioContext::createConvolver(ExceptionState& exceptionState) |
431 { | 367 { |
432 ASSERT(isMainThread()); | 368 ASSERT(isMainThread()); |
433 if (isContextClosed()) { | 369 if (isContextClosed()) { |
434 throwExceptionForClosedState(exceptionState); | 370 throwExceptionForClosedState(exceptionState); |
435 return nullptr; | 371 return nullptr; |
436 } | 372 } |
437 | 373 |
438 return ConvolverNode::create(*this, sampleRate()); | 374 return ConvolverNode::create(*this, sampleRate()); |
439 } | 375 } |
440 | 376 |
441 DynamicsCompressorNode* AbstractAudioContext::createDynamicsCompressor(Exception
State& exceptionState) | 377 DynamicsCompressorNode* BaseAudioContext::createDynamicsCompressor(ExceptionStat
e& exceptionState) |
442 { | 378 { |
443 ASSERT(isMainThread()); | 379 ASSERT(isMainThread()); |
444 if (isContextClosed()) { | 380 if (isContextClosed()) { |
445 throwExceptionForClosedState(exceptionState); | 381 throwExceptionForClosedState(exceptionState); |
446 return nullptr; | 382 return nullptr; |
447 } | 383 } |
448 | 384 |
449 return DynamicsCompressorNode::create(*this, sampleRate()); | 385 return DynamicsCompressorNode::create(*this, sampleRate()); |
450 } | 386 } |
451 | 387 |
452 AnalyserNode* AbstractAudioContext::createAnalyser(ExceptionState& exceptionStat
e) | 388 AnalyserNode* BaseAudioContext::createAnalyser(ExceptionState& exceptionState) |
453 { | 389 { |
454 ASSERT(isMainThread()); | 390 ASSERT(isMainThread()); |
455 if (isContextClosed()) { | 391 if (isContextClosed()) { |
456 throwExceptionForClosedState(exceptionState); | 392 throwExceptionForClosedState(exceptionState); |
457 return nullptr; | 393 return nullptr; |
458 } | 394 } |
459 | 395 |
460 return AnalyserNode::create(*this, sampleRate()); | 396 return AnalyserNode::create(*this, sampleRate()); |
461 } | 397 } |
462 | 398 |
463 GainNode* AbstractAudioContext::createGain(ExceptionState& exceptionState) | 399 GainNode* BaseAudioContext::createGain(ExceptionState& exceptionState) |
464 { | 400 { |
465 ASSERT(isMainThread()); | 401 ASSERT(isMainThread()); |
466 if (isContextClosed()) { | 402 if (isContextClosed()) { |
467 throwExceptionForClosedState(exceptionState); | 403 throwExceptionForClosedState(exceptionState); |
468 return nullptr; | 404 return nullptr; |
469 } | 405 } |
470 | 406 |
471 return GainNode::create(*this, sampleRate()); | 407 return GainNode::create(*this, sampleRate()); |
472 } | 408 } |
473 | 409 |
474 DelayNode* AbstractAudioContext::createDelay(ExceptionState& exceptionState) | 410 DelayNode* BaseAudioContext::createDelay(ExceptionState& exceptionState) |
475 { | 411 { |
476 const double defaultMaxDelayTime = 1; | 412 const double defaultMaxDelayTime = 1; |
477 return createDelay(defaultMaxDelayTime, exceptionState); | 413 return createDelay(defaultMaxDelayTime, exceptionState); |
478 } | 414 } |
479 | 415 |
480 DelayNode* AbstractAudioContext::createDelay(double maxDelayTime, ExceptionState
& exceptionState) | 416 DelayNode* BaseAudioContext::createDelay(double maxDelayTime, ExceptionState& ex
ceptionState) |
481 { | 417 { |
482 ASSERT(isMainThread()); | 418 ASSERT(isMainThread()); |
483 if (isContextClosed()) { | 419 if (isContextClosed()) { |
484 throwExceptionForClosedState(exceptionState); | 420 throwExceptionForClosedState(exceptionState); |
485 return nullptr; | 421 return nullptr; |
486 } | 422 } |
487 | 423 |
488 return DelayNode::create(*this, sampleRate(), maxDelayTime, exceptionState); | 424 return DelayNode::create(*this, sampleRate(), maxDelayTime, exceptionState); |
489 } | 425 } |
490 | 426 |
491 ChannelSplitterNode* AbstractAudioContext::createChannelSplitter(ExceptionState&
exceptionState) | 427 ChannelSplitterNode* BaseAudioContext::createChannelSplitter(ExceptionState& exc
eptionState) |
492 { | 428 { |
493 const unsigned ChannelSplitterDefaultNumberOfOutputs = 6; | 429 const unsigned ChannelSplitterDefaultNumberOfOutputs = 6; |
494 return createChannelSplitter(ChannelSplitterDefaultNumberOfOutputs, exceptio
nState); | 430 return createChannelSplitter(ChannelSplitterDefaultNumberOfOutputs, exceptio
nState); |
495 } | 431 } |
496 | 432 |
497 ChannelSplitterNode* AbstractAudioContext::createChannelSplitter(size_t numberOf
Outputs, ExceptionState& exceptionState) | 433 ChannelSplitterNode* BaseAudioContext::createChannelSplitter(size_t numberOfOutp
uts, ExceptionState& exceptionState) |
498 { | 434 { |
499 ASSERT(isMainThread()); | 435 ASSERT(isMainThread()); |
500 | 436 |
501 if (isContextClosed()) { | 437 if (isContextClosed()) { |
502 throwExceptionForClosedState(exceptionState); | 438 throwExceptionForClosedState(exceptionState); |
503 return nullptr; | 439 return nullptr; |
504 } | 440 } |
505 | 441 |
506 ChannelSplitterNode* node = ChannelSplitterNode::create(*this, sampleRate(),
numberOfOutputs); | 442 ChannelSplitterNode* node = ChannelSplitterNode::create(*this, sampleRate(),
numberOfOutputs); |
507 | 443 |
508 if (!node) { | 444 if (!node) { |
509 exceptionState.throwDOMException( | 445 exceptionState.throwDOMException( |
510 IndexSizeError, | 446 IndexSizeError, |
511 "number of outputs (" + String::number(numberOfOutputs) | 447 "number of outputs (" + String::number(numberOfOutputs) |
512 + ") must be between 1 and " | 448 + ") must be between 1 and " |
513 + String::number(AbstractAudioContext::maxNumberOfChannels()) + ".")
; | 449 + String::number(BaseAudioContext::maxNumberOfChannels()) + "."); |
514 return nullptr; | 450 return nullptr; |
515 } | 451 } |
516 | 452 |
517 return node; | 453 return node; |
518 } | 454 } |
519 | 455 |
520 ChannelMergerNode* AbstractAudioContext::createChannelMerger(ExceptionState& exc
eptionState) | 456 ChannelMergerNode* BaseAudioContext::createChannelMerger(ExceptionState& excepti
onState) |
521 { | 457 { |
522 const unsigned ChannelMergerDefaultNumberOfInputs = 6; | 458 const unsigned ChannelMergerDefaultNumberOfInputs = 6; |
523 return createChannelMerger(ChannelMergerDefaultNumberOfInputs, exceptionStat
e); | 459 return createChannelMerger(ChannelMergerDefaultNumberOfInputs, exceptionStat
e); |
524 } | 460 } |
525 | 461 |
526 ChannelMergerNode* AbstractAudioContext::createChannelMerger(size_t numberOfInpu
ts, ExceptionState& exceptionState) | 462 ChannelMergerNode* BaseAudioContext::createChannelMerger(size_t numberOfInputs,
ExceptionState& exceptionState) |
527 { | 463 { |
528 ASSERT(isMainThread()); | 464 ASSERT(isMainThread()); |
529 if (isContextClosed()) { | 465 if (isContextClosed()) { |
530 throwExceptionForClosedState(exceptionState); | 466 throwExceptionForClosedState(exceptionState); |
531 return nullptr; | 467 return nullptr; |
532 } | 468 } |
533 | 469 |
534 ChannelMergerNode* node = ChannelMergerNode::create(*this, sampleRate(), num
berOfInputs); | 470 ChannelMergerNode* node = ChannelMergerNode::create(*this, sampleRate(), num
berOfInputs); |
535 | 471 |
536 if (!node) { | 472 if (!node) { |
537 exceptionState.throwDOMException( | 473 exceptionState.throwDOMException( |
538 IndexSizeError, | 474 IndexSizeError, |
539 ExceptionMessages::indexOutsideRange<size_t>( | 475 ExceptionMessages::indexOutsideRange<size_t>( |
540 "number of inputs", | 476 "number of inputs", |
541 numberOfInputs, | 477 numberOfInputs, |
542 1, | 478 1, |
543 ExceptionMessages::InclusiveBound, | 479 ExceptionMessages::InclusiveBound, |
544 AbstractAudioContext::maxNumberOfChannels(), | 480 BaseAudioContext::maxNumberOfChannels(), |
545 ExceptionMessages::InclusiveBound)); | 481 ExceptionMessages::InclusiveBound)); |
546 return nullptr; | 482 return nullptr; |
547 } | 483 } |
548 | 484 |
549 return node; | 485 return node; |
550 } | 486 } |
551 | 487 |
552 OscillatorNode* AbstractAudioContext::createOscillator(ExceptionState& exception
State) | 488 OscillatorNode* BaseAudioContext::createOscillator(ExceptionState& exceptionStat
e) |
553 { | 489 { |
554 ASSERT(isMainThread()); | 490 ASSERT(isMainThread()); |
555 if (isContextClosed()) { | 491 if (isContextClosed()) { |
556 throwExceptionForClosedState(exceptionState); | 492 throwExceptionForClosedState(exceptionState); |
557 return nullptr; | 493 return nullptr; |
558 } | 494 } |
559 | 495 |
560 OscillatorNode* node = OscillatorNode::create(*this, sampleRate()); | 496 OscillatorNode* node = OscillatorNode::create(*this, sampleRate()); |
561 | 497 |
562 // Do not add a reference to this source node now. The reference will be add
ed when start() is | 498 // Do not add a reference to this source node now. The reference will be add
ed when start() is |
563 // called. | 499 // called. |
564 | 500 |
565 return node; | 501 return node; |
566 } | 502 } |
567 | 503 |
568 PeriodicWave* AbstractAudioContext::createPeriodicWave(DOMFloat32Array* real, DO
MFloat32Array* imag, ExceptionState& exceptionState) | 504 PeriodicWave* BaseAudioContext::createPeriodicWave(DOMFloat32Array* real, DOMFlo
at32Array* imag, ExceptionState& exceptionState) |
569 { | 505 { |
570 return PeriodicWave::create(sampleRate(), real, imag, false); | 506 return PeriodicWave::create(sampleRate(), real, imag, false); |
571 } | 507 } |
572 | 508 |
573 PeriodicWave* AbstractAudioContext::createPeriodicWave(DOMFloat32Array* real, DO
MFloat32Array* imag, const Dictionary& options, ExceptionState& exceptionState) | 509 PeriodicWave* BaseAudioContext::createPeriodicWave(DOMFloat32Array* real, DOMFlo
at32Array* imag, const Dictionary& options, ExceptionState& exceptionState) |
574 { | 510 { |
575 ASSERT(isMainThread()); | 511 ASSERT(isMainThread()); |
576 | 512 |
577 if (isContextClosed()) { | 513 if (isContextClosed()) { |
578 throwExceptionForClosedState(exceptionState); | 514 throwExceptionForClosedState(exceptionState); |
579 return nullptr; | 515 return nullptr; |
580 } | 516 } |
581 | 517 |
582 if (real->length() != imag->length()) { | 518 if (real->length() != imag->length()) { |
583 exceptionState.throwDOMException( | 519 exceptionState.throwDOMException( |
584 IndexSizeError, | 520 IndexSizeError, |
585 "length of real array (" + String::number(real->length()) | 521 "length of real array (" + String::number(real->length()) |
586 + ") and length of imaginary array (" + String::number(imag->length
()) | 522 + ") and length of imaginary array (" + String::number(imag->length
()) |
587 + ") must match."); | 523 + ") must match."); |
588 return nullptr; | 524 return nullptr; |
589 } | 525 } |
590 | 526 |
591 bool isNormalizationDisabled = false; | 527 bool isNormalizationDisabled = false; |
592 DictionaryHelper::getWithUndefinedOrNullCheck(options, "disableNormalization
", isNormalizationDisabled); | 528 DictionaryHelper::getWithUndefinedOrNullCheck(options, "disableNormalization
", isNormalizationDisabled); |
593 | 529 |
594 return PeriodicWave::create(sampleRate(), real, imag, isNormalizationDisable
d); | 530 return PeriodicWave::create(sampleRate(), real, imag, isNormalizationDisable
d); |
595 } | 531 } |
596 | 532 |
597 IIRFilterNode* AbstractAudioContext::createIIRFilter(Vector<double> feedforwardC
oef, Vector<double> feedbackCoef, ExceptionState& exceptionState) | 533 IIRFilterNode* BaseAudioContext::createIIRFilter(Vector<double> feedforwardCoef,
Vector<double> feedbackCoef, ExceptionState& exceptionState) |
598 { | 534 { |
599 ASSERT(isMainThread()); | 535 ASSERT(isMainThread()); |
600 | 536 |
601 if (isContextClosed()) { | 537 if (isContextClosed()) { |
602 throwExceptionForClosedState(exceptionState); | 538 throwExceptionForClosedState(exceptionState); |
603 return nullptr; | 539 return nullptr; |
604 } | 540 } |
605 | 541 |
606 if (feedbackCoef.size() == 0 || (feedbackCoef.size() > IIRFilter::kMaxOrder
+ 1)) { | 542 if (feedbackCoef.size() == 0 || (feedbackCoef.size() > IIRFilter::kMaxOrder
+ 1)) { |
607 exceptionState.throwDOMException( | 543 exceptionState.throwDOMException( |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
671 exceptionState.throwDOMException( | 607 exceptionState.throwDOMException( |
672 InvalidStateError, | 608 InvalidStateError, |
673 ExceptionMessages::notAFiniteNumber(c, name.ascii().data())); | 609 ExceptionMessages::notAFiniteNumber(c, name.ascii().data())); |
674 return nullptr; | 610 return nullptr; |
675 } | 611 } |
676 } | 612 } |
677 | 613 |
678 return IIRFilterNode::create(*this, sampleRate(), feedforwardCoef, feedbackC
oef); | 614 return IIRFilterNode::create(*this, sampleRate(), feedforwardCoef, feedbackC
oef); |
679 } | 615 } |
680 | 616 |
681 PeriodicWave* AbstractAudioContext::periodicWave(int type) | 617 PeriodicWave* BaseAudioContext::periodicWave(int type) |
682 { | 618 { |
683 switch (type) { | 619 switch (type) { |
684 case OscillatorHandler::SINE: | 620 case OscillatorHandler::SINE: |
685 // Initialize the table if necessary | 621 // Initialize the table if necessary |
686 if (!m_periodicWaveSine) | 622 if (!m_periodicWaveSine) |
687 m_periodicWaveSine = PeriodicWave::createSine(sampleRate()); | 623 m_periodicWaveSine = PeriodicWave::createSine(sampleRate()); |
688 return m_periodicWaveSine; | 624 return m_periodicWaveSine; |
689 case OscillatorHandler::SQUARE: | 625 case OscillatorHandler::SQUARE: |
690 // Initialize the table if necessary | 626 // Initialize the table if necessary |
691 if (!m_periodicWaveSquare) | 627 if (!m_periodicWaveSquare) |
692 m_periodicWaveSquare = PeriodicWave::createSquare(sampleRate()); | 628 m_periodicWaveSquare = PeriodicWave::createSquare(sampleRate()); |
693 return m_periodicWaveSquare; | 629 return m_periodicWaveSquare; |
694 case OscillatorHandler::SAWTOOTH: | 630 case OscillatorHandler::SAWTOOTH: |
695 // Initialize the table if necessary | 631 // Initialize the table if necessary |
696 if (!m_periodicWaveSawtooth) | 632 if (!m_periodicWaveSawtooth) |
697 m_periodicWaveSawtooth = PeriodicWave::createSawtooth(sampleRate()); | 633 m_periodicWaveSawtooth = PeriodicWave::createSawtooth(sampleRate()); |
698 return m_periodicWaveSawtooth; | 634 return m_periodicWaveSawtooth; |
699 case OscillatorHandler::TRIANGLE: | 635 case OscillatorHandler::TRIANGLE: |
700 // Initialize the table if necessary | 636 // Initialize the table if necessary |
701 if (!m_periodicWaveTriangle) | 637 if (!m_periodicWaveTriangle) |
702 m_periodicWaveTriangle = PeriodicWave::createTriangle(sampleRate()); | 638 m_periodicWaveTriangle = PeriodicWave::createTriangle(sampleRate()); |
703 return m_periodicWaveTriangle; | 639 return m_periodicWaveTriangle; |
704 default: | 640 default: |
705 ASSERT_NOT_REACHED(); | 641 ASSERT_NOT_REACHED(); |
706 return nullptr; | 642 return nullptr; |
707 } | 643 } |
708 } | 644 } |
709 | 645 |
710 String AbstractAudioContext::state() const | 646 String BaseAudioContext::state() const |
711 { | 647 { |
712 // These strings had better match the strings for AudioContextState in Audio
Context.idl. | 648 // These strings had better match the strings for AudioContextState in Audio
Context.idl. |
713 switch (m_contextState) { | 649 switch (m_contextState) { |
714 case Suspended: | 650 case Suspended: |
715 return "suspended"; | 651 return "suspended"; |
716 case Running: | 652 case Running: |
717 return "running"; | 653 return "running"; |
718 case Closed: | 654 case Closed: |
719 return "closed"; | 655 return "closed"; |
720 } | 656 } |
721 ASSERT_NOT_REACHED(); | 657 ASSERT_NOT_REACHED(); |
722 return ""; | 658 return ""; |
723 } | 659 } |
724 | 660 |
725 void AbstractAudioContext::setContextState(AudioContextState newState) | 661 void BaseAudioContext::setContextState(AudioContextState newState) |
726 { | 662 { |
727 ASSERT(isMainThread()); | 663 ASSERT(isMainThread()); |
728 | 664 |
729 // Validate the transitions. The valid transitions are Suspended->Running,
Running->Suspended, | 665 // Validate the transitions. The valid transitions are Suspended->Running,
Running->Suspended, |
730 // and anything->Closed. | 666 // and anything->Closed. |
731 switch (newState) { | 667 switch (newState) { |
732 case Suspended: | 668 case Suspended: |
733 ASSERT(m_contextState == Running); | 669 ASSERT(m_contextState == Running); |
734 break; | 670 break; |
735 case Running: | 671 case Running: |
736 ASSERT(m_contextState == Suspended); | 672 ASSERT(m_contextState == Suspended); |
737 break; | 673 break; |
738 case Closed: | 674 case Closed: |
739 ASSERT(m_contextState != Closed); | 675 ASSERT(m_contextState != Closed); |
740 break; | 676 break; |
741 } | 677 } |
742 | 678 |
743 if (newState == m_contextState) { | 679 if (newState == m_contextState) { |
744 // ASSERTs above failed; just return. | 680 // ASSERTs above failed; just return. |
745 return; | 681 return; |
746 } | 682 } |
747 | 683 |
748 m_contextState = newState; | 684 m_contextState = newState; |
749 | 685 |
750 // Notify context that state changed | 686 // Notify context that state changed |
751 if (getExecutionContext()) | 687 if (getExecutionContext()) |
752 getExecutionContext()->postTask(BLINK_FROM_HERE, createSameThreadTask(&A
bstractAudioContext::notifyStateChange, this)); | 688 getExecutionContext()->postTask(BLINK_FROM_HERE, createSameThreadTask(&B
aseAudioContext::notifyStateChange, this)); |
753 } | 689 } |
754 | 690 |
755 void AbstractAudioContext::notifyStateChange() | 691 void BaseAudioContext::notifyStateChange() |
756 { | 692 { |
757 dispatchEvent(Event::create(EventTypeNames::statechange)); | 693 dispatchEvent(Event::create(EventTypeNames::statechange)); |
758 } | 694 } |
759 | 695 |
760 void AbstractAudioContext::notifySourceNodeFinishedProcessing(AudioHandler* hand
ler) | 696 void BaseAudioContext::notifySourceNodeFinishedProcessing(AudioHandler* handler) |
761 { | 697 { |
762 ASSERT(isAudioThread()); | 698 ASSERT(isAudioThread()); |
763 m_finishedSourceHandlers.append(handler); | 699 m_finishedSourceHandlers.append(handler); |
764 } | 700 } |
765 | 701 |
766 void AbstractAudioContext::releaseFinishedSourceNodes() | 702 void BaseAudioContext::releaseFinishedSourceNodes() |
767 { | 703 { |
768 ASSERT(isGraphOwner()); | 704 ASSERT(isGraphOwner()); |
769 ASSERT(isAudioThread()); | 705 ASSERT(isAudioThread()); |
770 for (AudioHandler* handler : m_finishedSourceHandlers) { | 706 for (AudioHandler* handler : m_finishedSourceHandlers) { |
771 for (unsigned i = 0; i < m_activeSourceNodes.size(); ++i) { | 707 for (unsigned i = 0; i < m_activeSourceNodes.size(); ++i) { |
772 if (handler == &m_activeSourceNodes[i]->handler()) { | 708 if (handler == &m_activeSourceNodes[i]->handler()) { |
773 handler->breakConnection(); | 709 handler->breakConnection(); |
774 m_activeSourceNodes.remove(i); | 710 m_activeSourceNodes.remove(i); |
775 break; | 711 break; |
776 } | 712 } |
777 } | 713 } |
778 } | 714 } |
779 | 715 |
780 m_finishedSourceHandlers.clear(); | 716 m_finishedSourceHandlers.clear(); |
781 } | 717 } |
782 | 718 |
783 void AbstractAudioContext::notifySourceNodeStartedProcessing(AudioNode* node) | 719 void BaseAudioContext::notifySourceNodeStartedProcessing(AudioNode* node) |
784 { | 720 { |
785 ASSERT(isMainThread()); | 721 ASSERT(isMainThread()); |
786 AutoLocker locker(this); | 722 AutoLocker locker(this); |
787 | 723 |
788 m_activeSourceNodes.append(node); | 724 m_activeSourceNodes.append(node); |
789 node->handler().makeConnection(); | 725 node->handler().makeConnection(); |
790 } | 726 } |
791 | 727 |
792 void AbstractAudioContext::releaseActiveSourceNodes() | 728 void BaseAudioContext::releaseActiveSourceNodes() |
793 { | 729 { |
794 ASSERT(isMainThread()); | 730 ASSERT(isMainThread()); |
795 for (auto& sourceNode : m_activeSourceNodes) | 731 for (auto& sourceNode : m_activeSourceNodes) |
796 sourceNode->handler().breakConnection(); | 732 sourceNode->handler().breakConnection(); |
797 | 733 |
798 m_activeSourceNodes.clear(); | 734 m_activeSourceNodes.clear(); |
799 } | 735 } |
800 | 736 |
801 void AbstractAudioContext::handleStoppableSourceNodes() | 737 void BaseAudioContext::handleStoppableSourceNodes() |
802 { | 738 { |
803 ASSERT(isGraphOwner()); | 739 ASSERT(isGraphOwner()); |
804 | 740 |
805 // Find AudioBufferSourceNodes to see if we can stop playing them. | 741 // Find AudioBufferSourceNodes to see if we can stop playing them. |
806 for (AudioNode* node : m_activeSourceNodes) { | 742 for (AudioNode* node : m_activeSourceNodes) { |
807 if (node->handler().getNodeType() == AudioHandler::NodeTypeAudioBufferSo
urce) { | 743 if (node->handler().getNodeType() == AudioHandler::NodeTypeAudioBufferSo
urce) { |
808 AudioBufferSourceNode* sourceNode = static_cast<AudioBufferSourceNod
e*>(node); | 744 AudioBufferSourceNode* sourceNode = static_cast<AudioBufferSourceNod
e*>(node); |
809 sourceNode->audioBufferSourceHandler().handleStoppableSourceNode(); | 745 sourceNode->audioBufferSourceHandler().handleStoppableSourceNode(); |
810 } | 746 } |
811 } | 747 } |
812 } | 748 } |
813 | 749 |
814 void AbstractAudioContext::handlePreRenderTasks() | 750 void BaseAudioContext::handlePreRenderTasks() |
815 { | 751 { |
816 ASSERT(isAudioThread()); | 752 ASSERT(isAudioThread()); |
817 | 753 |
818 // At the beginning of every render quantum, try to update the internal rend
ering graph state (from main thread changes). | 754 // At the beginning of every render quantum, try to update the internal rend
ering graph state (from main thread changes). |
819 // It's OK if the tryLock() fails, we'll just take slightly longer to pick u
p the changes. | 755 // It's OK if the tryLock() fails, we'll just take slightly longer to pick u
p the changes. |
820 if (tryLock()) { | 756 if (tryLock()) { |
821 deferredTaskHandler().handleDeferredTasks(); | 757 deferredTaskHandler().handleDeferredTasks(); |
822 | 758 |
823 resolvePromisesForResume(); | 759 resolvePromisesForResume(); |
824 | 760 |
825 // Check to see if source nodes can be stopped because the end time has
passed. | 761 // Check to see if source nodes can be stopped because the end time has
passed. |
826 handleStoppableSourceNodes(); | 762 handleStoppableSourceNodes(); |
827 | 763 |
828 unlock(); | 764 unlock(); |
829 } | 765 } |
830 } | 766 } |
831 | 767 |
832 void AbstractAudioContext::handlePostRenderTasks() | 768 void BaseAudioContext::handlePostRenderTasks() |
833 { | 769 { |
834 ASSERT(isAudioThread()); | 770 ASSERT(isAudioThread()); |
835 | 771 |
836 // Must use a tryLock() here too. Don't worry, the lock will very rarely be
contended and this method is called frequently. | 772 // Must use a tryLock() here too. Don't worry, the lock will very rarely be
contended and this method is called frequently. |
837 // The worst that can happen is that there will be some nodes which will tak
e slightly longer than usual to be deleted or removed | 773 // The worst that can happen is that there will be some nodes which will tak
e slightly longer than usual to be deleted or removed |
838 // from the render graph (in which case they'll render silence). | 774 // from the render graph (in which case they'll render silence). |
839 if (tryLock()) { | 775 if (tryLock()) { |
840 // Take care of AudioNode tasks where the tryLock() failed previously. | 776 // Take care of AudioNode tasks where the tryLock() failed previously. |
841 deferredTaskHandler().breakConnections(); | 777 deferredTaskHandler().breakConnections(); |
842 | 778 |
843 // Dynamically clean up nodes which are no longer needed. | 779 // Dynamically clean up nodes which are no longer needed. |
844 releaseFinishedSourceNodes(); | 780 releaseFinishedSourceNodes(); |
845 | 781 |
846 deferredTaskHandler().handleDeferredTasks(); | 782 deferredTaskHandler().handleDeferredTasks(); |
847 deferredTaskHandler().requestToDeleteHandlersOnMainThread(); | 783 deferredTaskHandler().requestToDeleteHandlersOnMainThread(); |
848 | 784 |
849 unlock(); | 785 unlock(); |
850 } | 786 } |
851 } | 787 } |
852 | 788 |
853 void AbstractAudioContext::resolvePromisesForResumeOnMainThread() | 789 void BaseAudioContext::resolvePromisesForResumeOnMainThread() |
854 { | 790 { |
855 ASSERT(isMainThread()); | 791 ASSERT(isMainThread()); |
856 AutoLocker locker(this); | 792 AutoLocker locker(this); |
857 | 793 |
858 for (auto& resolver : m_resumeResolvers) { | 794 for (auto& resolver : m_resumeResolvers) { |
859 if (m_contextState == Closed) { | 795 if (m_contextState == Closed) { |
860 resolver->reject( | 796 resolver->reject( |
861 DOMException::create(InvalidStateError, "Cannot resume a context
that has been closed")); | 797 DOMException::create(InvalidStateError, "Cannot resume a context
that has been closed")); |
862 } else { | 798 } else { |
863 resolver->resolve(); | 799 resolver->resolve(); |
864 } | 800 } |
865 } | 801 } |
866 | 802 |
867 m_resumeResolvers.clear(); | 803 m_resumeResolvers.clear(); |
868 m_isResolvingResumePromises = false; | 804 m_isResolvingResumePromises = false; |
869 } | 805 } |
870 | 806 |
871 void AbstractAudioContext::resolvePromisesForResume() | 807 void BaseAudioContext::resolvePromisesForResume() |
872 { | 808 { |
873 // This runs inside the AbstractAudioContext's lock when handling pre-render
tasks. | 809 // This runs inside the BaseAudioContext's lock when handling pre-render tas
ks. |
874 ASSERT(isAudioThread()); | 810 ASSERT(isAudioThread()); |
875 ASSERT(isGraphOwner()); | 811 ASSERT(isGraphOwner()); |
876 | 812 |
877 // Resolve any pending promises created by resume(). Only do this if we have
n't already started | 813 // Resolve any pending promises created by resume(). Only do this if we have
n't already started |
878 // resolving these promises. This gets called very often and it takes some t
ime to resolve the | 814 // resolving these promises. This gets called very often and it takes some t
ime to resolve the |
879 // promises in the main thread. | 815 // promises in the main thread. |
880 if (!m_isResolvingResumePromises && m_resumeResolvers.size() > 0) { | 816 if (!m_isResolvingResumePromises && m_resumeResolvers.size() > 0) { |
881 m_isResolvingResumePromises = true; | 817 m_isResolvingResumePromises = true; |
882 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FR
OM_HERE, threadSafeBind(&AbstractAudioContext::resolvePromisesForResumeOnMainThr
ead, this)); | 818 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FR
OM_HERE, threadSafeBind(&BaseAudioContext::resolvePromisesForResumeOnMainThread,
this)); |
883 } | 819 } |
884 } | 820 } |
885 | 821 |
886 void AbstractAudioContext::rejectPendingResolvers() | 822 void BaseAudioContext::rejectPendingResolvers() |
887 { | 823 { |
888 ASSERT(isMainThread()); | 824 ASSERT(isMainThread()); |
889 | 825 |
890 // Audio context is closing down so reject any resume promises that are stil
l pending. | 826 // Audio context is closing down so reject any resume promises that are stil
l pending. |
891 | 827 |
892 for (auto& resolver : m_resumeResolvers) { | 828 for (auto& resolver : m_resumeResolvers) { |
893 resolver->reject(DOMException::create(InvalidStateError, "Audio context
is going away")); | 829 resolver->reject(DOMException::create(InvalidStateError, "Audio context
is going away")); |
894 } | 830 } |
895 m_resumeResolvers.clear(); | 831 m_resumeResolvers.clear(); |
896 m_isResolvingResumePromises = false; | 832 m_isResolvingResumePromises = false; |
897 | 833 |
898 // Now reject any pending decodeAudioData resolvers | 834 // Now reject any pending decodeAudioData resolvers |
899 for (auto& resolver : m_decodeAudioResolvers) | 835 for (auto& resolver : m_decodeAudioResolvers) |
900 resolver->reject(DOMException::create(InvalidStateError, "Audio context
is going away")); | 836 resolver->reject(DOMException::create(InvalidStateError, "Audio context
is going away")); |
901 m_decodeAudioResolvers.clear(); | 837 m_decodeAudioResolvers.clear(); |
902 } | 838 } |
903 | 839 |
904 const AtomicString& AbstractAudioContext::interfaceName() const | 840 const AtomicString& BaseAudioContext::interfaceName() const |
905 { | 841 { |
906 return EventTargetNames::AudioContext; | 842 return EventTargetNames::AudioContext; |
907 } | 843 } |
908 | 844 |
909 ExecutionContext* AbstractAudioContext::getExecutionContext() const | 845 ExecutionContext* BaseAudioContext::getExecutionContext() const |
910 { | 846 { |
911 return ActiveDOMObject::getExecutionContext(); | 847 return ActiveDOMObject::getExecutionContext(); |
912 } | 848 } |
913 | 849 |
914 void AbstractAudioContext::startRendering() | 850 void BaseAudioContext::startRendering() |
915 { | 851 { |
916 // This is called for both online and offline contexts. | 852 // This is called for both online and offline contexts. |
917 ASSERT(isMainThread()); | 853 ASSERT(isMainThread()); |
918 ASSERT(m_destinationNode); | 854 ASSERT(m_destinationNode); |
919 | 855 |
920 if (m_contextState == Suspended) { | 856 if (m_contextState == Suspended) { |
921 destination()->audioDestinationHandler().startRendering(); | 857 destination()->audioDestinationHandler().startRendering(); |
922 setContextState(Running); | 858 setContextState(Running); |
923 } | 859 } |
924 } | 860 } |
925 | 861 |
926 DEFINE_TRACE(AbstractAudioContext) | 862 DEFINE_TRACE(BaseAudioContext) |
927 { | 863 { |
928 visitor->trace(m_destinationNode); | 864 visitor->trace(m_destinationNode); |
929 visitor->trace(m_listener); | 865 visitor->trace(m_listener); |
930 // trace() can be called in AbstractAudioContext constructor, and | 866 // trace() can be called in BaseAudioContext constructor, and |
931 // m_contextGraphMutex might be unavailable. | 867 // m_contextGraphMutex might be unavailable. |
932 if (m_didInitializeContextGraphMutex) { | 868 if (m_didInitializeContextGraphMutex) { |
933 AutoLocker lock(this); | 869 AutoLocker lock(this); |
934 visitor->trace(m_activeSourceNodes); | 870 visitor->trace(m_activeSourceNodes); |
935 } else { | 871 } else { |
936 visitor->trace(m_activeSourceNodes); | 872 visitor->trace(m_activeSourceNodes); |
937 } | 873 } |
938 visitor->trace(m_resumeResolvers); | 874 visitor->trace(m_resumeResolvers); |
939 visitor->trace(m_decodeAudioResolvers); | 875 visitor->trace(m_decodeAudioResolvers); |
940 | 876 |
941 visitor->trace(m_periodicWaveSine); | 877 visitor->trace(m_periodicWaveSine); |
942 visitor->trace(m_periodicWaveSquare); | 878 visitor->trace(m_periodicWaveSquare); |
943 visitor->trace(m_periodicWaveSawtooth); | 879 visitor->trace(m_periodicWaveSawtooth); |
944 visitor->trace(m_periodicWaveTriangle); | 880 visitor->trace(m_periodicWaveTriangle); |
945 RefCountedGarbageCollectedEventTargetWithInlineData<AbstractAudioContext>::t
race(visitor); | 881 RefCountedGarbageCollectedEventTargetWithInlineData<BaseAudioContext>::trace
(visitor); |
946 ActiveDOMObject::trace(visitor); | 882 ActiveDOMObject::trace(visitor); |
947 } | 883 } |
948 | 884 |
949 SecurityOrigin* AbstractAudioContext::getSecurityOrigin() const | 885 SecurityOrigin* BaseAudioContext::getSecurityOrigin() const |
950 { | 886 { |
951 if (getExecutionContext()) | 887 if (getExecutionContext()) |
952 return getExecutionContext()->getSecurityOrigin(); | 888 return getExecutionContext()->getSecurityOrigin(); |
953 | 889 |
954 return nullptr; | 890 return nullptr; |
955 } | 891 } |
956 | 892 |
957 } // namespace blink | 893 } // namespace blink |
958 | 894 |
OLD | NEW |