| 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 #include "bindings/core/v8/Dictionary.h" | 26 #include "bindings/core/v8/Dictionary.h" |
| 27 #include "bindings/core/v8/ExceptionMessages.h" | 27 #include "bindings/core/v8/ExceptionMessages.h" |
| 28 #include "bindings/core/v8/ExceptionState.h" | 28 #include "bindings/core/v8/ExceptionState.h" |
| 29 #include "bindings/core/v8/ScriptPromiseResolver.h" | 29 #include "bindings/core/v8/ScriptPromiseResolver.h" |
| 30 #include "bindings/core/v8/ScriptState.h" | 30 #include "bindings/core/v8/ScriptState.h" |
| 31 #include "core/dom/DOMException.h" | 31 #include "core/dom/DOMException.h" |
| 32 #include "core/dom/Document.h" | 32 #include "core/dom/Document.h" |
| 33 #include "core/dom/ExceptionCode.h" | 33 #include "core/dom/ExceptionCode.h" |
| 34 #include "core/dom/ExecutionContextTask.h" | 34 #include "core/dom/ExecutionContextTask.h" |
| 35 #include "core/frame/Settings.h" | 35 #include "core/frame/Settings.h" |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 79 enum UserGestureRecord { | 79 enum UserGestureRecord { |
| 80 UserGestureRequiredAndAvailable = 0, | 80 UserGestureRequiredAndAvailable = 0, |
| 81 UserGestureRequiredAndNotAvailable, | 81 UserGestureRequiredAndNotAvailable, |
| 82 UserGestureNotRequiredAndAvailable, | 82 UserGestureNotRequiredAndAvailable, |
| 83 UserGestureNotRequiredAndNotAvailable, | 83 UserGestureNotRequiredAndNotAvailable, |
| 84 UserGestureRecordMax | 84 UserGestureRecordMax |
| 85 }; | 85 }; |
| 86 | 86 |
| 87 } // anonymous namespace | 87 } // anonymous namespace |
| 88 | 88 |
| 89 AbstractAudioContext* AbstractAudioContext::create(Document& document, Exception
State& exceptionState) | 89 BaseAudioContext* BaseAudioContext::create(Document& document, ExceptionState& e
xceptionState) |
| 90 { | 90 { |
| 91 return AudioContext::create(document, exceptionState); | 91 return AudioContext::create(document, exceptionState); |
| 92 } | 92 } |
| 93 | 93 |
| 94 // FIXME(dominicc): Devolve these constructors to AudioContext | 94 // FIXME(dominicc): Devolve these constructors to AudioContext |
| 95 // and OfflineAudioContext respectively. | 95 // and OfflineAudioContext respectively. |
| 96 | 96 |
| 97 // Constructor for rendering to the audio hardware. | 97 // Constructor for rendering to the audio hardware. |
| 98 AbstractAudioContext::AbstractAudioContext(Document* document) | 98 BaseAudioContext::BaseAudioContext(Document* document) |
| 99 : ActiveScriptWrappable(this) | 99 : ActiveScriptWrappable(this) |
| 100 , ActiveDOMObject(document) | 100 , ActiveDOMObject(document) |
| 101 , m_destinationNode(nullptr) | 101 , m_destinationNode(nullptr) |
| 102 , m_isCleared(false) | 102 , m_isCleared(false) |
| 103 , m_isResolvingResumePromises(false) | 103 , m_isResolvingResumePromises(false) |
| 104 , m_userGestureRequired(false) | 104 , m_userGestureRequired(false) |
| 105 , m_connectionCount(0) | 105 , m_connectionCount(0) |
| 106 , m_deferredTaskHandler(DeferredTaskHandler::create()) | 106 , m_deferredTaskHandler(DeferredTaskHandler::create()) |
| 107 , m_contextState(Suspended) | 107 , m_contextState(Suspended) |
| 108 , m_closedContextSampleRate(-1) | 108 , m_closedContextSampleRate(-1) |
| 109 , m_periodicWaveSine(nullptr) | 109 , m_periodicWaveSine(nullptr) |
| 110 , m_periodicWaveSquare(nullptr) | 110 , m_periodicWaveSquare(nullptr) |
| 111 , m_periodicWaveSawtooth(nullptr) | 111 , m_periodicWaveSawtooth(nullptr) |
| 112 , m_periodicWaveTriangle(nullptr) | 112 , m_periodicWaveTriangle(nullptr) |
| 113 { | 113 { |
| 114 // TODO(mlamouri): we might want to use other ways of checking for this but | 114 // TODO(mlamouri): we might want to use other ways of checking for this but |
| 115 // in order to record metrics, re-using the HTMLMediaElement setting is | 115 // in order to record metrics, re-using the HTMLMediaElement setting is |
| 116 // probably the simplest solution. | 116 // probably the simplest solution. |
| 117 if (document->settings() && document->settings()->mediaPlaybackRequiresUserG
esture()) | 117 if (document->settings() && document->settings()->mediaPlaybackRequiresUserG
esture()) |
| 118 m_userGestureRequired = true; | 118 m_userGestureRequired = true; |
| 119 | 119 |
| 120 m_destinationNode = DefaultAudioDestinationNode::create(this); | 120 m_destinationNode = DefaultAudioDestinationNode::create(this); |
| 121 | 121 |
| 122 initialize(); | 122 initialize(); |
| 123 } | 123 } |
| 124 | 124 |
| 125 // Constructor for offline (non-realtime) rendering. | 125 // Constructor for offline (non-realtime) rendering. |
| 126 AbstractAudioContext::AbstractAudioContext(Document* document, unsigned numberOf
Channels, size_t numberOfFrames, float sampleRate) | 126 BaseAudioContext::BaseAudioContext(Document* document, unsigned numberOfChannels
, size_t numberOfFrames, float sampleRate) |
| 127 : ActiveScriptWrappable(this) | 127 : ActiveScriptWrappable(this) |
| 128 , ActiveDOMObject(document) | 128 , ActiveDOMObject(document) |
| 129 , m_destinationNode(nullptr) | 129 , m_destinationNode(nullptr) |
| 130 , m_isCleared(false) | 130 , m_isCleared(false) |
| 131 , m_isResolvingResumePromises(false) | 131 , m_isResolvingResumePromises(false) |
| 132 , m_userGestureRequired(false) | 132 , m_userGestureRequired(false) |
| 133 , m_connectionCount(0) | 133 , m_connectionCount(0) |
| 134 , m_deferredTaskHandler(DeferredTaskHandler::create()) | 134 , m_deferredTaskHandler(DeferredTaskHandler::create()) |
| 135 , m_contextState(Suspended) | 135 , m_contextState(Suspended) |
| 136 , m_closedContextSampleRate(-1) | 136 , m_closedContextSampleRate(-1) |
| 137 , m_periodicWaveSine(nullptr) | 137 , m_periodicWaveSine(nullptr) |
| 138 , m_periodicWaveSquare(nullptr) | 138 , m_periodicWaveSquare(nullptr) |
| 139 , m_periodicWaveSawtooth(nullptr) | 139 , m_periodicWaveSawtooth(nullptr) |
| 140 , m_periodicWaveTriangle(nullptr) | 140 , m_periodicWaveTriangle(nullptr) |
| 141 { | 141 { |
| 142 // TODO(mlamouri): we might want to use other ways of checking for this but | 142 // TODO(mlamouri): we might want to use other ways of checking for this but |
| 143 // in order to record metrics, re-using the HTMLMediaElement setting is | 143 // in order to record metrics, re-using the HTMLMediaElement setting is |
| 144 // probably the simplest solution. | 144 // probably the simplest solution. |
| 145 if (document->settings() && document->settings()->mediaPlaybackRequiresUserG
esture()) | 145 if (document->settings() && document->settings()->mediaPlaybackRequiresUserG
esture()) |
| 146 m_userGestureRequired = true; | 146 m_userGestureRequired = true; |
| 147 } | 147 } |
| 148 | 148 |
| 149 AbstractAudioContext::~AbstractAudioContext() | 149 BaseAudioContext::~BaseAudioContext() |
| 150 { | 150 { |
| 151 deferredTaskHandler().contextWillBeDestroyed(); | 151 deferredTaskHandler().contextWillBeDestroyed(); |
| 152 // 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. | 152 // 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. |
| 153 ASSERT(!isDestinationInitialized()); | 153 ASSERT(!isDestinationInitialized()); |
| 154 ASSERT(!m_activeSourceNodes.size()); | 154 ASSERT(!m_activeSourceNodes.size()); |
| 155 ASSERT(!m_finishedSourceHandlers.size()); | 155 ASSERT(!m_finishedSourceHandlers.size()); |
| 156 ASSERT(!m_isResolvingResumePromises); | 156 ASSERT(!m_isResolvingResumePromises); |
| 157 ASSERT(!m_resumeResolvers.size()); | 157 ASSERT(!m_resumeResolvers.size()); |
| 158 } | 158 } |
| 159 | 159 |
| 160 void AbstractAudioContext::initialize() | 160 void BaseAudioContext::initialize() |
| 161 { | 161 { |
| 162 if (isDestinationInitialized()) | 162 if (isDestinationInitialized()) |
| 163 return; | 163 return; |
| 164 | 164 |
| 165 FFTFrame::initialize(); | 165 FFTFrame::initialize(); |
| 166 | 166 |
| 167 if (m_destinationNode) { | 167 if (m_destinationNode) { |
| 168 m_destinationNode->handler().initialize(); | 168 m_destinationNode->handler().initialize(); |
| 169 // The AudioParams in the listener need access to the destination node,
so only create the | 169 // The AudioParams in the listener need access to the destination node,
so only create the |
| 170 // listener if the destination node exists. | 170 // listener if the destination node exists. |
| 171 m_listener = AudioListener::create(*this); | 171 m_listener = AudioListener::create(*this); |
| 172 } | 172 } |
| 173 } | 173 } |
| 174 | 174 |
| 175 void AbstractAudioContext::clear() | 175 void BaseAudioContext::clear() |
| 176 { | 176 { |
| 177 m_destinationNode.clear(); | 177 m_destinationNode.clear(); |
| 178 // The audio rendering thread is dead. Nobody will schedule AudioHandler | 178 // The audio rendering thread is dead. Nobody will schedule AudioHandler |
| 179 // deletion. Let's do it ourselves. | 179 // deletion. Let's do it ourselves. |
| 180 deferredTaskHandler().clearHandlersToBeDeleted(); | 180 deferredTaskHandler().clearHandlersToBeDeleted(); |
| 181 m_isCleared = true; | 181 m_isCleared = true; |
| 182 } | 182 } |
| 183 | 183 |
| 184 void AbstractAudioContext::uninitialize() | 184 void BaseAudioContext::uninitialize() |
| 185 { | 185 { |
| 186 ASSERT(isMainThread()); | 186 ASSERT(isMainThread()); |
| 187 | 187 |
| 188 if (!isDestinationInitialized()) | 188 if (!isDestinationInitialized()) |
| 189 return; | 189 return; |
| 190 | 190 |
| 191 // This stops the audio thread and all audio rendering. | 191 // This stops the audio thread and all audio rendering. |
| 192 if (m_destinationNode) | 192 if (m_destinationNode) |
| 193 m_destinationNode->handler().uninitialize(); | 193 m_destinationNode->handler().uninitialize(); |
| 194 | 194 |
| 195 // Get rid of the sources which may still be playing. | 195 // Get rid of the sources which may still be playing. |
| 196 releaseActiveSourceNodes(); | 196 releaseActiveSourceNodes(); |
| 197 | 197 |
| 198 // Reject any pending resolvers before we go away. | 198 // Reject any pending resolvers before we go away. |
| 199 rejectPendingResolvers(); | 199 rejectPendingResolvers(); |
| 200 didClose(); | 200 didClose(); |
| 201 | 201 |
| 202 ASSERT(m_listener); | 202 ASSERT(m_listener); |
| 203 m_listener->waitForHRTFDatabaseLoaderThreadCompletion(); | 203 m_listener->waitForHRTFDatabaseLoaderThreadCompletion(); |
| 204 | 204 |
| 205 clear(); | 205 clear(); |
| 206 } | 206 } |
| 207 | 207 |
| 208 void AbstractAudioContext::stop() | 208 void BaseAudioContext::stop() |
| 209 { | 209 { |
| 210 uninitialize(); | 210 uninitialize(); |
| 211 } | 211 } |
| 212 | 212 |
| 213 bool AbstractAudioContext::hasPendingActivity() const | 213 bool BaseAudioContext::hasPendingActivity() const |
| 214 { | 214 { |
| 215 // There's no pending activity if the audio context has been cleared. | 215 // There's no pending activity if the audio context has been cleared. |
| 216 return !m_isCleared; | 216 return !m_isCleared; |
| 217 } | 217 } |
| 218 | 218 |
| 219 AudioDestinationNode* AbstractAudioContext::destination() const | 219 AudioDestinationNode* BaseAudioContext::destination() const |
| 220 { | 220 { |
| 221 // Cannot be called from the audio thread because this method touches object
s managed by Oilpan, | 221 // Cannot be called from the audio thread because this method touches object
s managed by Oilpan, |
| 222 // and the audio thread is not managed by Oilpan. | 222 // and the audio thread is not managed by Oilpan. |
| 223 ASSERT(!isAudioThread()); | 223 ASSERT(!isAudioThread()); |
| 224 return m_destinationNode; | 224 return m_destinationNode; |
| 225 } | 225 } |
| 226 | 226 |
| 227 void AbstractAudioContext::throwExceptionForClosedState(ExceptionState& exceptio
nState) | 227 void BaseAudioContext::throwExceptionForClosedState(ExceptionState& exceptionSta
te) |
| 228 { | 228 { |
| 229 exceptionState.throwDOMException(InvalidStateError, "AudioContext has been c
losed."); | 229 exceptionState.throwDOMException(InvalidStateError, "AudioContext has been c
losed."); |
| 230 } | 230 } |
| 231 | 231 |
| 232 AudioBuffer* AbstractAudioContext::createBuffer(unsigned numberOfChannels, size_
t numberOfFrames, float sampleRate, ExceptionState& exceptionState) | 232 AudioBuffer* BaseAudioContext::createBuffer(unsigned numberOfChannels, size_t nu
mberOfFrames, float sampleRate, ExceptionState& exceptionState) |
| 233 { | 233 { |
| 234 // It's ok to call createBuffer, even if the context is closed because the A
udioBuffer doesn't | 234 // It's ok to call createBuffer, even if the context is closed because the A
udioBuffer doesn't |
| 235 // really "belong" to any particular context. | 235 // really "belong" to any particular context. |
| 236 | 236 |
| 237 AudioBuffer* buffer = AudioBuffer::create(numberOfChannels, numberOfFrames,
sampleRate, exceptionState); | 237 AudioBuffer* buffer = AudioBuffer::create(numberOfChannels, numberOfFrames,
sampleRate, exceptionState); |
| 238 | 238 |
| 239 if (buffer) { | 239 if (buffer) { |
| 240 // Only record the data if the creation succeeded. | 240 // Only record the data if the creation succeeded. |
| 241 DEFINE_STATIC_LOCAL(SparseHistogram, audioBufferChannelsHistogram, | 241 DEFINE_STATIC_LOCAL(SparseHistogram, audioBufferChannelsHistogram, |
| 242 ("WebAudio.AudioBuffer.NumberOfChannels")); | 242 ("WebAudio.AudioBuffer.NumberOfChannels")); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 270 DEFINE_STATIC_LOCAL(CustomCountHistogram, audioBufferSampleRateRatio
Histogram, | 270 DEFINE_STATIC_LOCAL(CustomCountHistogram, audioBufferSampleRateRatio
Histogram, |
| 271 ("WebAudio.AudioBuffer.SampleRateRatio", 1, 6400, 50)); | 271 ("WebAudio.AudioBuffer.SampleRateRatio", 1, 6400, 50)); |
| 272 float ratio = 100 * sampleRate / this->sampleRate(); | 272 float ratio = 100 * sampleRate / this->sampleRate(); |
| 273 audioBufferSampleRateRatioHistogram.count(static_cast<int>(0.5 + rat
io)); | 273 audioBufferSampleRateRatioHistogram.count(static_cast<int>(0.5 + rat
io)); |
| 274 } | 274 } |
| 275 } | 275 } |
| 276 | 276 |
| 277 return buffer; | 277 return buffer; |
| 278 } | 278 } |
| 279 | 279 |
| 280 ScriptPromise AbstractAudioContext::decodeAudioData(ScriptState* scriptState, DO
MArrayBuffer* audioData, AudioBufferCallback* successCallback, AudioBufferCallba
ck* errorCallback, ExceptionState& exceptionState) | 280 ScriptPromise BaseAudioContext::decodeAudioData(ScriptState* scriptState, DOMArr
ayBuffer* audioData, AudioBufferCallback* successCallback, AudioBufferCallback*
errorCallback, ExceptionState& exceptionState) |
| 281 { | 281 { |
| 282 ASSERT(isMainThread()); | 282 ASSERT(isMainThread()); |
| 283 ASSERT(audioData); | 283 ASSERT(audioData); |
| 284 | 284 |
| 285 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState)
; | 285 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState)
; |
| 286 ScriptPromise promise = resolver->promise(); | 286 ScriptPromise promise = resolver->promise(); |
| 287 | 287 |
| 288 float rate = isContextClosed() ? closedContextSampleRate() : sampleRate(); | 288 float rate = isContextClosed() ? closedContextSampleRate() : sampleRate(); |
| 289 | 289 |
| 290 ASSERT(rate > 0); | 290 ASSERT(rate > 0); |
| 291 | 291 |
| 292 m_decodeAudioResolvers.add(resolver); | 292 m_decodeAudioResolvers.add(resolver); |
| 293 m_audioDecoder.decodeAsync(audioData, rate, successCallback, errorCallback,
resolver, this); | 293 m_audioDecoder.decodeAsync(audioData, rate, successCallback, errorCallback,
resolver, this); |
| 294 | 294 |
| 295 return promise; | 295 return promise; |
| 296 } | 296 } |
| 297 | 297 |
| 298 void AbstractAudioContext::handleDecodeAudioData(AudioBuffer* audioBuffer, Scrip
tPromiseResolver* resolver, AudioBufferCallback* successCallback, AudioBufferCal
lback* errorCallback) | 298 void BaseAudioContext::handleDecodeAudioData(AudioBuffer* audioBuffer, ScriptPro
miseResolver* resolver, AudioBufferCallback* successCallback, AudioBufferCallbac
k* errorCallback) |
| 299 { | 299 { |
| 300 ASSERT(isMainThread()); | 300 ASSERT(isMainThread()); |
| 301 | 301 |
| 302 if (audioBuffer) { | 302 if (audioBuffer) { |
| 303 // Resolve promise successfully and run the success callback | 303 // Resolve promise successfully and run the success callback |
| 304 resolver->resolve(audioBuffer); | 304 resolver->resolve(audioBuffer); |
| 305 if (successCallback) | 305 if (successCallback) |
| 306 successCallback->handleEvent(audioBuffer); | 306 successCallback->handleEvent(audioBuffer); |
| 307 } else { | 307 } else { |
| 308 // Reject the promise and run the error callback | 308 // Reject the promise and run the error callback |
| 309 DOMException* error = DOMException::create(EncodingError, "Unable to dec
ode audio data"); | 309 DOMException* error = DOMException::create(EncodingError, "Unable to dec
ode audio data"); |
| 310 resolver->reject(error); | 310 resolver->reject(error); |
| 311 if (errorCallback) | 311 if (errorCallback) |
| 312 errorCallback->handleEvent(error); | 312 errorCallback->handleEvent(error); |
| 313 } | 313 } |
| 314 | 314 |
| 315 // We've resolved the promise. Remove it now. | 315 // We've resolved the promise. Remove it now. |
| 316 ASSERT(m_decodeAudioResolvers.contains(resolver)); | 316 ASSERT(m_decodeAudioResolvers.contains(resolver)); |
| 317 m_decodeAudioResolvers.remove(resolver); | 317 m_decodeAudioResolvers.remove(resolver); |
| 318 } | 318 } |
| 319 | 319 |
| 320 AudioBufferSourceNode* AbstractAudioContext::createBufferSource(ExceptionState&
exceptionState) | 320 AudioBufferSourceNode* BaseAudioContext::createBufferSource(ExceptionState& exce
ptionState) |
| 321 { | 321 { |
| 322 ASSERT(isMainThread()); | 322 ASSERT(isMainThread()); |
| 323 | 323 |
| 324 AudioBufferSourceNode* node = AudioBufferSourceNode::create(*this, exception
State); | 324 AudioBufferSourceNode* node = AudioBufferSourceNode::create(*this, exception
State); |
| 325 | 325 |
| 326 // Do not add a reference to this source node now. The reference will be add
ed when start() is | 326 // Do not add a reference to this source node now. The reference will be add
ed when start() is |
| 327 // called. | 327 // called. |
| 328 | 328 |
| 329 return node; | 329 return node; |
| 330 } | 330 } |
| 331 | 331 |
| 332 MediaElementAudioSourceNode* AbstractAudioContext::createMediaElementSource(HTML
MediaElement* mediaElement, ExceptionState& exceptionState) | 332 MediaElementAudioSourceNode* BaseAudioContext::createMediaElementSource(HTMLMedi
aElement* mediaElement, ExceptionState& exceptionState) |
| 333 { | 333 { |
| 334 ASSERT(isMainThread()); | 334 ASSERT(isMainThread()); |
| 335 | 335 |
| 336 return MediaElementAudioSourceNode::create(*this, *mediaElement, exceptionSt
ate); | 336 return MediaElementAudioSourceNode::create(*this, *mediaElement, exceptionSt
ate); |
| 337 } | 337 } |
| 338 | 338 |
| 339 MediaStreamAudioSourceNode* AbstractAudioContext::createMediaStreamSource(MediaS
tream* mediaStream, ExceptionState& exceptionState) | 339 MediaStreamAudioSourceNode* BaseAudioContext::createMediaStreamSource(MediaStrea
m* mediaStream, ExceptionState& exceptionState) |
| 340 { | 340 { |
| 341 ASSERT(isMainThread()); | 341 ASSERT(isMainThread()); |
| 342 | 342 |
| 343 return MediaStreamAudioSourceNode::create(*this, *mediaStream, exceptionStat
e); | 343 return MediaStreamAudioSourceNode::create(*this, *mediaStream, exceptionStat
e); |
| 344 } | 344 } |
| 345 | 345 |
| 346 MediaStreamAudioDestinationNode* AbstractAudioContext::createMediaStreamDestinat
ion(ExceptionState& exceptionState) | 346 MediaStreamAudioDestinationNode* BaseAudioContext::createMediaStreamDestination(
ExceptionState& exceptionState) |
| 347 { | 347 { |
| 348 DCHECK(isMainThread()); | 348 DCHECK(isMainThread()); |
| 349 | 349 |
| 350 // Set number of output channels to stereo by default. | 350 // Set number of output channels to stereo by default. |
| 351 return MediaStreamAudioDestinationNode::create(*this, 2, exceptionState); | 351 return MediaStreamAudioDestinationNode::create(*this, 2, exceptionState); |
| 352 } | 352 } |
| 353 | 353 |
| 354 ScriptProcessorNode* AbstractAudioContext::createScriptProcessor(ExceptionState&
exceptionState) | 354 ScriptProcessorNode* BaseAudioContext::createScriptProcessor(ExceptionState& exc
eptionState) |
| 355 { | 355 { |
| 356 DCHECK(isMainThread()); | 356 DCHECK(isMainThread()); |
| 357 | 357 |
| 358 return ScriptProcessorNode::create(*this, exceptionState); | 358 return ScriptProcessorNode::create(*this, exceptionState); |
| 359 } | 359 } |
| 360 | 360 |
| 361 ScriptProcessorNode* AbstractAudioContext::createScriptProcessor(size_t bufferSi
ze, ExceptionState& exceptionState) | 361 ScriptProcessorNode* BaseAudioContext::createScriptProcessor(size_t bufferSize,
ExceptionState& exceptionState) |
| 362 { | 362 { |
| 363 DCHECK(isMainThread()); | 363 DCHECK(isMainThread()); |
| 364 | 364 |
| 365 return ScriptProcessorNode::create(*this, bufferSize, exceptionState); | 365 return ScriptProcessorNode::create(*this, bufferSize, exceptionState); |
| 366 } | 366 } |
| 367 | 367 |
| 368 ScriptProcessorNode* AbstractAudioContext::createScriptProcessor(size_t bufferSi
ze, size_t numberOfInputChannels, ExceptionState& exceptionState) | 368 ScriptProcessorNode* BaseAudioContext::createScriptProcessor(size_t bufferSize,
size_t numberOfInputChannels, ExceptionState& exceptionState) |
| 369 { | 369 { |
| 370 DCHECK(isMainThread()); | 370 DCHECK(isMainThread()); |
| 371 | 371 |
| 372 return ScriptProcessorNode::create(*this, bufferSize, numberOfInputChannels,
exceptionState); | 372 return ScriptProcessorNode::create(*this, bufferSize, numberOfInputChannels,
exceptionState); |
| 373 } | 373 } |
| 374 | 374 |
| 375 ScriptProcessorNode* AbstractAudioContext::createScriptProcessor(size_t bufferSi
ze, size_t numberOfInputChannels, size_t numberOfOutputChannels, ExceptionState&
exceptionState) | 375 ScriptProcessorNode* BaseAudioContext::createScriptProcessor(size_t bufferSize,
size_t numberOfInputChannels, size_t numberOfOutputChannels, ExceptionState& exc
eptionState) |
| 376 { | 376 { |
| 377 ASSERT(isMainThread()); | 377 ASSERT(isMainThread()); |
| 378 | 378 |
| 379 return ScriptProcessorNode::create( | 379 return ScriptProcessorNode::create( |
| 380 *this, | 380 *this, |
| 381 bufferSize, | 381 bufferSize, |
| 382 numberOfInputChannels, | 382 numberOfInputChannels, |
| 383 numberOfOutputChannels, | 383 numberOfOutputChannels, |
| 384 exceptionState); | 384 exceptionState); |
| 385 } | 385 } |
| 386 | 386 |
| 387 StereoPannerNode* AbstractAudioContext::createStereoPanner(ExceptionState& excep
tionState) | 387 StereoPannerNode* BaseAudioContext::createStereoPanner(ExceptionState& exception
State) |
| 388 { | 388 { |
| 389 ASSERT(isMainThread()); | 389 ASSERT(isMainThread()); |
| 390 | 390 |
| 391 return StereoPannerNode::create(*this, exceptionState); | 391 return StereoPannerNode::create(*this, exceptionState); |
| 392 } | 392 } |
| 393 | 393 |
| 394 BiquadFilterNode* AbstractAudioContext::createBiquadFilter(ExceptionState& excep
tionState) | 394 BiquadFilterNode* BaseAudioContext::createBiquadFilter(ExceptionState& exception
State) |
| 395 { | 395 { |
| 396 ASSERT(isMainThread()); | 396 ASSERT(isMainThread()); |
| 397 | 397 |
| 398 return BiquadFilterNode::create(*this, exceptionState); | 398 return BiquadFilterNode::create(*this, exceptionState); |
| 399 } | 399 } |
| 400 | 400 |
| 401 WaveShaperNode* AbstractAudioContext::createWaveShaper(ExceptionState& exception
State) | 401 WaveShaperNode* BaseAudioContext::createWaveShaper(ExceptionState& exceptionStat
e) |
| 402 { | 402 { |
| 403 ASSERT(isMainThread()); | 403 ASSERT(isMainThread()); |
| 404 | 404 |
| 405 return WaveShaperNode::create(*this, exceptionState); | 405 return WaveShaperNode::create(*this, exceptionState); |
| 406 } | 406 } |
| 407 | 407 |
| 408 PannerNode* AbstractAudioContext::createPanner(ExceptionState& exceptionState) | 408 PannerNode* BaseAudioContext::createPanner(ExceptionState& exceptionState) |
| 409 { | 409 { |
| 410 ASSERT(isMainThread()); | 410 ASSERT(isMainThread()); |
| 411 | 411 |
| 412 return PannerNode::create(*this, exceptionState); | 412 return PannerNode::create(*this, exceptionState); |
| 413 } | 413 } |
| 414 | 414 |
| 415 ConvolverNode* AbstractAudioContext::createConvolver(ExceptionState& exceptionSt
ate) | 415 ConvolverNode* BaseAudioContext::createConvolver(ExceptionState& exceptionState) |
| 416 { | 416 { |
| 417 ASSERT(isMainThread()); | 417 ASSERT(isMainThread()); |
| 418 | 418 |
| 419 return ConvolverNode::create(*this, exceptionState); | 419 return ConvolverNode::create(*this, exceptionState); |
| 420 } | 420 } |
| 421 | 421 |
| 422 DynamicsCompressorNode* AbstractAudioContext::createDynamicsCompressor(Exception
State& exceptionState) | 422 DynamicsCompressorNode* BaseAudioContext::createDynamicsCompressor(ExceptionStat
e& exceptionState) |
| 423 { | 423 { |
| 424 ASSERT(isMainThread()); | 424 ASSERT(isMainThread()); |
| 425 | 425 |
| 426 return DynamicsCompressorNode::create(*this, exceptionState); | 426 return DynamicsCompressorNode::create(*this, exceptionState); |
| 427 } | 427 } |
| 428 | 428 |
| 429 AnalyserNode* AbstractAudioContext::createAnalyser(ExceptionState& exceptionStat
e) | 429 AnalyserNode* BaseAudioContext::createAnalyser(ExceptionState& exceptionState) |
| 430 { | 430 { |
| 431 ASSERT(isMainThread()); | 431 ASSERT(isMainThread()); |
| 432 | 432 |
| 433 return AnalyserNode::create(*this, exceptionState); | 433 return AnalyserNode::create(*this, exceptionState); |
| 434 } | 434 } |
| 435 | 435 |
| 436 GainNode* AbstractAudioContext::createGain(ExceptionState& exceptionState) | 436 GainNode* BaseAudioContext::createGain(ExceptionState& exceptionState) |
| 437 { | 437 { |
| 438 ASSERT(isMainThread()); | 438 ASSERT(isMainThread()); |
| 439 | 439 |
| 440 return GainNode::create(*this, exceptionState); | 440 return GainNode::create(*this, exceptionState); |
| 441 } | 441 } |
| 442 | 442 |
| 443 DelayNode* AbstractAudioContext::createDelay(ExceptionState& exceptionState) | 443 DelayNode* BaseAudioContext::createDelay(ExceptionState& exceptionState) |
| 444 { | 444 { |
| 445 DCHECK(isMainThread()); | 445 DCHECK(isMainThread()); |
| 446 | 446 |
| 447 return DelayNode::create(*this, exceptionState); | 447 return DelayNode::create(*this, exceptionState); |
| 448 } | 448 } |
| 449 | 449 |
| 450 DelayNode* AbstractAudioContext::createDelay(double maxDelayTime, ExceptionState
& exceptionState) | 450 DelayNode* BaseAudioContext::createDelay(double maxDelayTime, ExceptionState& ex
ceptionState) |
| 451 { | 451 { |
| 452 ASSERT(isMainThread()); | 452 ASSERT(isMainThread()); |
| 453 | 453 |
| 454 return DelayNode::create(*this, maxDelayTime, exceptionState); | 454 return DelayNode::create(*this, maxDelayTime, exceptionState); |
| 455 } | 455 } |
| 456 | 456 |
| 457 ChannelSplitterNode* AbstractAudioContext::createChannelSplitter(ExceptionState&
exceptionState) | 457 ChannelSplitterNode* BaseAudioContext::createChannelSplitter(ExceptionState& exc
eptionState) |
| 458 { | 458 { |
| 459 DCHECK(isMainThread()); | 459 DCHECK(isMainThread()); |
| 460 | 460 |
| 461 return ChannelSplitterNode::create(*this, exceptionState); | 461 return ChannelSplitterNode::create(*this, exceptionState); |
| 462 } | 462 } |
| 463 | 463 |
| 464 ChannelSplitterNode* AbstractAudioContext::createChannelSplitter(size_t numberOf
Outputs, ExceptionState& exceptionState) | 464 ChannelSplitterNode* BaseAudioContext::createChannelSplitter(size_t numberOfOutp
uts, ExceptionState& exceptionState) |
| 465 { | 465 { |
| 466 ASSERT(isMainThread()); | 466 ASSERT(isMainThread()); |
| 467 | 467 |
| 468 return ChannelSplitterNode::create(*this, numberOfOutputs, exceptionState); | 468 return ChannelSplitterNode::create(*this, numberOfOutputs, exceptionState); |
| 469 } | 469 } |
| 470 | 470 |
| 471 ChannelMergerNode* AbstractAudioContext::createChannelMerger(ExceptionState& exc
eptionState) | 471 ChannelMergerNode* BaseAudioContext::createChannelMerger(ExceptionState& excepti
onState) |
| 472 { | 472 { |
| 473 DCHECK(isMainThread()); | 473 DCHECK(isMainThread()); |
| 474 | 474 |
| 475 return ChannelMergerNode::create(*this, exceptionState); | 475 return ChannelMergerNode::create(*this, exceptionState); |
| 476 } | 476 } |
| 477 | 477 |
| 478 ChannelMergerNode* AbstractAudioContext::createChannelMerger(size_t numberOfInpu
ts, ExceptionState& exceptionState) | 478 ChannelMergerNode* BaseAudioContext::createChannelMerger(size_t numberOfInputs,
ExceptionState& exceptionState) |
| 479 { | 479 { |
| 480 ASSERT(isMainThread()); | 480 ASSERT(isMainThread()); |
| 481 | 481 |
| 482 return ChannelMergerNode::create(*this, numberOfInputs, exceptionState); | 482 return ChannelMergerNode::create(*this, numberOfInputs, exceptionState); |
| 483 } | 483 } |
| 484 | 484 |
| 485 OscillatorNode* AbstractAudioContext::createOscillator(ExceptionState& exception
State) | 485 OscillatorNode* BaseAudioContext::createOscillator(ExceptionState& exceptionStat
e) |
| 486 { | 486 { |
| 487 ASSERT(isMainThread()); | 487 ASSERT(isMainThread()); |
| 488 | 488 |
| 489 return OscillatorNode::create(*this, exceptionState); | 489 return OscillatorNode::create(*this, exceptionState); |
| 490 } | 490 } |
| 491 | 491 |
| 492 PeriodicWave* AbstractAudioContext::createPeriodicWave(DOMFloat32Array* real, DO
MFloat32Array* imag, ExceptionState& exceptionState) | 492 PeriodicWave* BaseAudioContext::createPeriodicWave(DOMFloat32Array* real, DOMFlo
at32Array* imag, ExceptionState& exceptionState) |
| 493 { | 493 { |
| 494 DCHECK(isMainThread()); | 494 DCHECK(isMainThread()); |
| 495 | 495 |
| 496 return PeriodicWave::create(*this, real, imag, false, exceptionState); | 496 return PeriodicWave::create(*this, real, imag, false, exceptionState); |
| 497 } | 497 } |
| 498 | 498 |
| 499 PeriodicWave* AbstractAudioContext::createPeriodicWave(DOMFloat32Array* real, DO
MFloat32Array* imag, const PeriodicWaveConstraints& options, ExceptionState& exc
eptionState) | 499 PeriodicWave* BaseAudioContext::createPeriodicWave(DOMFloat32Array* real, DOMFlo
at32Array* imag, const PeriodicWaveConstraints& options, ExceptionState& excepti
onState) |
| 500 { | 500 { |
| 501 ASSERT(isMainThread()); | 501 ASSERT(isMainThread()); |
| 502 | 502 |
| 503 bool disable = options.hasDisableNormalization() ? options.disableNormalizat
ion() : false; | 503 bool disable = options.hasDisableNormalization() ? options.disableNormalizat
ion() : false; |
| 504 | 504 |
| 505 return PeriodicWave::create(*this, real, imag, disable, exceptionState); | 505 return PeriodicWave::create(*this, real, imag, disable, exceptionState); |
| 506 } | 506 } |
| 507 | 507 |
| 508 IIRFilterNode* AbstractAudioContext::createIIRFilter(Vector<double> feedforwardC
oef, Vector<double> feedbackCoef, ExceptionState& exceptionState) | 508 IIRFilterNode* BaseAudioContext::createIIRFilter(Vector<double> feedforwardCoef,
Vector<double> feedbackCoef, ExceptionState& exceptionState) |
| 509 { | 509 { |
| 510 ASSERT(isMainThread()); | 510 ASSERT(isMainThread()); |
| 511 | 511 |
| 512 return IIRFilterNode::create(*this, feedforwardCoef, feedbackCoef, exception
State); | 512 return IIRFilterNode::create(*this, feedforwardCoef, feedbackCoef, exception
State); |
| 513 } | 513 } |
| 514 | 514 |
| 515 PeriodicWave* AbstractAudioContext::periodicWave(int type) | 515 PeriodicWave* BaseAudioContext::periodicWave(int type) |
| 516 { | 516 { |
| 517 switch (type) { | 517 switch (type) { |
| 518 case OscillatorHandler::SINE: | 518 case OscillatorHandler::SINE: |
| 519 // Initialize the table if necessary | 519 // Initialize the table if necessary |
| 520 if (!m_periodicWaveSine) | 520 if (!m_periodicWaveSine) |
| 521 m_periodicWaveSine = PeriodicWave::createSine(sampleRate()); | 521 m_periodicWaveSine = PeriodicWave::createSine(sampleRate()); |
| 522 return m_periodicWaveSine; | 522 return m_periodicWaveSine; |
| 523 case OscillatorHandler::SQUARE: | 523 case OscillatorHandler::SQUARE: |
| 524 // Initialize the table if necessary | 524 // Initialize the table if necessary |
| 525 if (!m_periodicWaveSquare) | 525 if (!m_periodicWaveSquare) |
| 526 m_periodicWaveSquare = PeriodicWave::createSquare(sampleRate()); | 526 m_periodicWaveSquare = PeriodicWave::createSquare(sampleRate()); |
| 527 return m_periodicWaveSquare; | 527 return m_periodicWaveSquare; |
| 528 case OscillatorHandler::SAWTOOTH: | 528 case OscillatorHandler::SAWTOOTH: |
| 529 // Initialize the table if necessary | 529 // Initialize the table if necessary |
| 530 if (!m_periodicWaveSawtooth) | 530 if (!m_periodicWaveSawtooth) |
| 531 m_periodicWaveSawtooth = PeriodicWave::createSawtooth(sampleRate()); | 531 m_periodicWaveSawtooth = PeriodicWave::createSawtooth(sampleRate()); |
| 532 return m_periodicWaveSawtooth; | 532 return m_periodicWaveSawtooth; |
| 533 case OscillatorHandler::TRIANGLE: | 533 case OscillatorHandler::TRIANGLE: |
| 534 // Initialize the table if necessary | 534 // Initialize the table if necessary |
| 535 if (!m_periodicWaveTriangle) | 535 if (!m_periodicWaveTriangle) |
| 536 m_periodicWaveTriangle = PeriodicWave::createTriangle(sampleRate()); | 536 m_periodicWaveTriangle = PeriodicWave::createTriangle(sampleRate()); |
| 537 return m_periodicWaveTriangle; | 537 return m_periodicWaveTriangle; |
| 538 default: | 538 default: |
| 539 ASSERT_NOT_REACHED(); | 539 ASSERT_NOT_REACHED(); |
| 540 return nullptr; | 540 return nullptr; |
| 541 } | 541 } |
| 542 } | 542 } |
| 543 | 543 |
| 544 void AbstractAudioContext::recordUserGestureState() | 544 void BaseAudioContext::recordUserGestureState() |
| 545 { | 545 { |
| 546 DEFINE_STATIC_LOCAL(EnumerationHistogram, userGestureHistogram, ("WebAudio.U
serGesture", UserGestureRecordMax)); | 546 DEFINE_STATIC_LOCAL(EnumerationHistogram, userGestureHistogram, ("WebAudio.U
serGesture", UserGestureRecordMax)); |
| 547 | 547 |
| 548 if (!m_userGestureRequired) { | 548 if (!m_userGestureRequired) { |
| 549 if (UserGestureIndicator::processingUserGesture()) | 549 if (UserGestureIndicator::processingUserGesture()) |
| 550 userGestureHistogram.count(UserGestureNotRequiredAndAvailable); | 550 userGestureHistogram.count(UserGestureNotRequiredAndAvailable); |
| 551 else | 551 else |
| 552 userGestureHistogram.count(UserGestureNotRequiredAndNotAvailable); | 552 userGestureHistogram.count(UserGestureNotRequiredAndNotAvailable); |
| 553 return; | 553 return; |
| 554 } | 554 } |
| 555 if (!UserGestureIndicator::processingUserGesture()) { | 555 if (!UserGestureIndicator::processingUserGesture()) { |
| 556 userGestureHistogram.count(UserGestureRequiredAndNotAvailable); | 556 userGestureHistogram.count(UserGestureRequiredAndNotAvailable); |
| 557 return; | 557 return; |
| 558 } | 558 } |
| 559 userGestureHistogram.count(UserGestureRequiredAndAvailable); | 559 userGestureHistogram.count(UserGestureRequiredAndAvailable); |
| 560 m_userGestureRequired = false; | 560 m_userGestureRequired = false; |
| 561 } | 561 } |
| 562 | 562 |
| 563 String AbstractAudioContext::state() const | 563 String BaseAudioContext::state() const |
| 564 { | 564 { |
| 565 // These strings had better match the strings for AudioContextState in Audio
Context.idl. | 565 // These strings had better match the strings for AudioContextState in Audio
Context.idl. |
| 566 switch (m_contextState) { | 566 switch (m_contextState) { |
| 567 case Suspended: | 567 case Suspended: |
| 568 return "suspended"; | 568 return "suspended"; |
| 569 case Running: | 569 case Running: |
| 570 return "running"; | 570 return "running"; |
| 571 case Closed: | 571 case Closed: |
| 572 return "closed"; | 572 return "closed"; |
| 573 } | 573 } |
| 574 ASSERT_NOT_REACHED(); | 574 ASSERT_NOT_REACHED(); |
| 575 return ""; | 575 return ""; |
| 576 } | 576 } |
| 577 | 577 |
| 578 void AbstractAudioContext::setContextState(AudioContextState newState) | 578 void BaseAudioContext::setContextState(AudioContextState newState) |
| 579 { | 579 { |
| 580 ASSERT(isMainThread()); | 580 ASSERT(isMainThread()); |
| 581 | 581 |
| 582 // Validate the transitions. The valid transitions are Suspended->Running,
Running->Suspended, | 582 // Validate the transitions. The valid transitions are Suspended->Running,
Running->Suspended, |
| 583 // and anything->Closed. | 583 // and anything->Closed. |
| 584 switch (newState) { | 584 switch (newState) { |
| 585 case Suspended: | 585 case Suspended: |
| 586 ASSERT(m_contextState == Running); | 586 ASSERT(m_contextState == Running); |
| 587 break; | 587 break; |
| 588 case Running: | 588 case Running: |
| 589 ASSERT(m_contextState == Suspended); | 589 ASSERT(m_contextState == Suspended); |
| 590 break; | 590 break; |
| 591 case Closed: | 591 case Closed: |
| 592 ASSERT(m_contextState != Closed); | 592 ASSERT(m_contextState != Closed); |
| 593 break; | 593 break; |
| 594 } | 594 } |
| 595 | 595 |
| 596 if (newState == m_contextState) { | 596 if (newState == m_contextState) { |
| 597 // ASSERTs above failed; just return. | 597 // ASSERTs above failed; just return. |
| 598 return; | 598 return; |
| 599 } | 599 } |
| 600 | 600 |
| 601 m_contextState = newState; | 601 m_contextState = newState; |
| 602 | 602 |
| 603 // Notify context that state changed | 603 // Notify context that state changed |
| 604 if (getExecutionContext()) | 604 if (getExecutionContext()) |
| 605 getExecutionContext()->postTask(BLINK_FROM_HERE, createSameThreadTask(&A
bstractAudioContext::notifyStateChange, wrapPersistent(this))); | 605 getExecutionContext()->postTask(BLINK_FROM_HERE, createSameThreadTask(&B
aseAudioContext::notifyStateChange, wrapPersistent(this))); |
| 606 } | 606 } |
| 607 | 607 |
| 608 void AbstractAudioContext::notifyStateChange() | 608 void BaseAudioContext::notifyStateChange() |
| 609 { | 609 { |
| 610 dispatchEvent(Event::create(EventTypeNames::statechange)); | 610 dispatchEvent(Event::create(EventTypeNames::statechange)); |
| 611 } | 611 } |
| 612 | 612 |
| 613 void AbstractAudioContext::notifySourceNodeFinishedProcessing(AudioHandler* hand
ler) | 613 void BaseAudioContext::notifySourceNodeFinishedProcessing(AudioHandler* handler) |
| 614 { | 614 { |
| 615 ASSERT(isAudioThread()); | 615 ASSERT(isAudioThread()); |
| 616 m_finishedSourceHandlers.append(handler); | 616 m_finishedSourceHandlers.append(handler); |
| 617 } | 617 } |
| 618 | 618 |
| 619 void AbstractAudioContext::removeFinishedSourceNodes() | 619 void BaseAudioContext::removeFinishedSourceNodes() |
| 620 { | 620 { |
| 621 ASSERT(isMainThread()); | 621 ASSERT(isMainThread()); |
| 622 AutoLocker locker(this); | 622 AutoLocker locker(this); |
| 623 // Quadratic worst case, but sizes of both vectors are considered | 623 // Quadratic worst case, but sizes of both vectors are considered |
| 624 // manageable, especially |m_finishedSourceNodes| is likely to be short. | 624 // manageable, especially |m_finishedSourceNodes| is likely to be short. |
| 625 for (AudioNode* node : m_finishedSourceNodes) { | 625 for (AudioNode* node : m_finishedSourceNodes) { |
| 626 size_t i = m_activeSourceNodes.find(node); | 626 size_t i = m_activeSourceNodes.find(node); |
| 627 if (i != kNotFound) | 627 if (i != kNotFound) |
| 628 m_activeSourceNodes.remove(i); | 628 m_activeSourceNodes.remove(i); |
| 629 } | 629 } |
| 630 m_finishedSourceNodes.clear(); | 630 m_finishedSourceNodes.clear(); |
| 631 } | 631 } |
| 632 | 632 |
| 633 void AbstractAudioContext::releaseFinishedSourceNodes() | 633 void BaseAudioContext::releaseFinishedSourceNodes() |
| 634 { | 634 { |
| 635 ASSERT(isGraphOwner()); | 635 ASSERT(isGraphOwner()); |
| 636 ASSERT(isAudioThread()); | 636 ASSERT(isAudioThread()); |
| 637 bool didRemove = false; | 637 bool didRemove = false; |
| 638 for (AudioHandler* handler : m_finishedSourceHandlers) { | 638 for (AudioHandler* handler : m_finishedSourceHandlers) { |
| 639 for (AudioNode* node : m_activeSourceNodes) { | 639 for (AudioNode* node : m_activeSourceNodes) { |
| 640 if (m_finishedSourceNodes.contains(node)) | 640 if (m_finishedSourceNodes.contains(node)) |
| 641 continue; | 641 continue; |
| 642 if (handler == &node->handler()) { | 642 if (handler == &node->handler()) { |
| 643 handler->breakConnection(); | 643 handler->breakConnection(); |
| 644 m_finishedSourceNodes.add(node); | 644 m_finishedSourceNodes.add(node); |
| 645 didRemove = true; | 645 didRemove = true; |
| 646 break; | 646 break; |
| 647 } | 647 } |
| 648 } | 648 } |
| 649 } | 649 } |
| 650 if (didRemove) | 650 if (didRemove) |
| 651 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FR
OM_HERE, threadSafeBind(&AbstractAudioContext::removeFinishedSourceNodes, wrapCr
ossThreadPersistent(this))); | 651 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FR
OM_HERE, threadSafeBind(&BaseAudioContext::removeFinishedSourceNodes, wrapCrossT
hreadPersistent(this))); |
| 652 | 652 |
| 653 m_finishedSourceHandlers.clear(); | 653 m_finishedSourceHandlers.clear(); |
| 654 } | 654 } |
| 655 | 655 |
| 656 void AbstractAudioContext::notifySourceNodeStartedProcessing(AudioNode* node) | 656 void BaseAudioContext::notifySourceNodeStartedProcessing(AudioNode* node) |
| 657 { | 657 { |
| 658 ASSERT(isMainThread()); | 658 ASSERT(isMainThread()); |
| 659 AutoLocker locker(this); | 659 AutoLocker locker(this); |
| 660 | 660 |
| 661 m_activeSourceNodes.append(node); | 661 m_activeSourceNodes.append(node); |
| 662 node->handler().makeConnection(); | 662 node->handler().makeConnection(); |
| 663 } | 663 } |
| 664 | 664 |
| 665 void AbstractAudioContext::releaseActiveSourceNodes() | 665 void BaseAudioContext::releaseActiveSourceNodes() |
| 666 { | 666 { |
| 667 ASSERT(isMainThread()); | 667 ASSERT(isMainThread()); |
| 668 for (auto& sourceNode : m_activeSourceNodes) | 668 for (auto& sourceNode : m_activeSourceNodes) |
| 669 sourceNode->handler().breakConnection(); | 669 sourceNode->handler().breakConnection(); |
| 670 | 670 |
| 671 m_activeSourceNodes.clear(); | 671 m_activeSourceNodes.clear(); |
| 672 } | 672 } |
| 673 | 673 |
| 674 void AbstractAudioContext::handleStoppableSourceNodes() | 674 void BaseAudioContext::handleStoppableSourceNodes() |
| 675 { | 675 { |
| 676 ASSERT(isGraphOwner()); | 676 ASSERT(isGraphOwner()); |
| 677 | 677 |
| 678 // Find AudioBufferSourceNodes to see if we can stop playing them. | 678 // Find AudioBufferSourceNodes to see if we can stop playing them. |
| 679 for (AudioNode* node : m_activeSourceNodes) { | 679 for (AudioNode* node : m_activeSourceNodes) { |
| 680 // If the AudioNode has been marked as finished and released by | 680 // If the AudioNode has been marked as finished and released by |
| 681 // the audio thread, but not yet removed by the main thread | 681 // the audio thread, but not yet removed by the main thread |
| 682 // (see releaseActiveSourceNodes() above), |node| must not be | 682 // (see releaseActiveSourceNodes() above), |node| must not be |
| 683 // touched as its handler may have been released already. | 683 // touched as its handler may have been released already. |
| 684 if (m_finishedSourceNodes.contains(node)) | 684 if (m_finishedSourceNodes.contains(node)) |
| 685 continue; | 685 continue; |
| 686 if (node->handler().getNodeType() == AudioHandler::NodeTypeAudioBufferSo
urce) { | 686 if (node->handler().getNodeType() == AudioHandler::NodeTypeAudioBufferSo
urce) { |
| 687 AudioBufferSourceNode* sourceNode = static_cast<AudioBufferSourceNod
e*>(node); | 687 AudioBufferSourceNode* sourceNode = static_cast<AudioBufferSourceNod
e*>(node); |
| 688 sourceNode->audioBufferSourceHandler().handleStoppableSourceNode(); | 688 sourceNode->audioBufferSourceHandler().handleStoppableSourceNode(); |
| 689 } | 689 } |
| 690 } | 690 } |
| 691 } | 691 } |
| 692 | 692 |
| 693 void AbstractAudioContext::handlePreRenderTasks() | 693 void BaseAudioContext::handlePreRenderTasks() |
| 694 { | 694 { |
| 695 ASSERT(isAudioThread()); | 695 ASSERT(isAudioThread()); |
| 696 | 696 |
| 697 // At the beginning of every render quantum, try to update the internal rend
ering graph state (from main thread changes). | 697 // At the beginning of every render quantum, try to update the internal rend
ering graph state (from main thread changes). |
| 698 // It's OK if the tryLock() fails, we'll just take slightly longer to pick u
p the changes. | 698 // It's OK if the tryLock() fails, we'll just take slightly longer to pick u
p the changes. |
| 699 if (tryLock()) { | 699 if (tryLock()) { |
| 700 deferredTaskHandler().handleDeferredTasks(); | 700 deferredTaskHandler().handleDeferredTasks(); |
| 701 | 701 |
| 702 resolvePromisesForResume(); | 702 resolvePromisesForResume(); |
| 703 | 703 |
| 704 // Check to see if source nodes can be stopped because the end time has
passed. | 704 // Check to see if source nodes can be stopped because the end time has
passed. |
| 705 handleStoppableSourceNodes(); | 705 handleStoppableSourceNodes(); |
| 706 | 706 |
| 707 // Update the dirty state of the listener. | 707 // Update the dirty state of the listener. |
| 708 listener()->updateState(); | 708 listener()->updateState(); |
| 709 | 709 |
| 710 unlock(); | 710 unlock(); |
| 711 } | 711 } |
| 712 } | 712 } |
| 713 | 713 |
| 714 void AbstractAudioContext::handlePostRenderTasks() | 714 void BaseAudioContext::handlePostRenderTasks() |
| 715 { | 715 { |
| 716 ASSERT(isAudioThread()); | 716 ASSERT(isAudioThread()); |
| 717 | 717 |
| 718 // Must use a tryLock() here too. Don't worry, the lock will very rarely be
contended and this method is called frequently. | 718 // Must use a tryLock() here too. Don't worry, the lock will very rarely be
contended and this method is called frequently. |
| 719 // 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 | 719 // 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 |
| 720 // from the render graph (in which case they'll render silence). | 720 // from the render graph (in which case they'll render silence). |
| 721 if (tryLock()) { | 721 if (tryLock()) { |
| 722 // Take care of AudioNode tasks where the tryLock() failed previously. | 722 // Take care of AudioNode tasks where the tryLock() failed previously. |
| 723 deferredTaskHandler().breakConnections(); | 723 deferredTaskHandler().breakConnections(); |
| 724 | 724 |
| 725 // Dynamically clean up nodes which are no longer needed. | 725 // Dynamically clean up nodes which are no longer needed. |
| 726 releaseFinishedSourceNodes(); | 726 releaseFinishedSourceNodes(); |
| 727 | 727 |
| 728 deferredTaskHandler().handleDeferredTasks(); | 728 deferredTaskHandler().handleDeferredTasks(); |
| 729 deferredTaskHandler().requestToDeleteHandlersOnMainThread(); | 729 deferredTaskHandler().requestToDeleteHandlersOnMainThread(); |
| 730 | 730 |
| 731 unlock(); | 731 unlock(); |
| 732 } | 732 } |
| 733 } | 733 } |
| 734 | 734 |
| 735 void AbstractAudioContext::resolvePromisesForResumeOnMainThread() | 735 void BaseAudioContext::resolvePromisesForResumeOnMainThread() |
| 736 { | 736 { |
| 737 ASSERT(isMainThread()); | 737 ASSERT(isMainThread()); |
| 738 AutoLocker locker(this); | 738 AutoLocker locker(this); |
| 739 | 739 |
| 740 for (auto& resolver : m_resumeResolvers) { | 740 for (auto& resolver : m_resumeResolvers) { |
| 741 if (m_contextState == Closed) { | 741 if (m_contextState == Closed) { |
| 742 resolver->reject( | 742 resolver->reject( |
| 743 DOMException::create(InvalidStateError, "Cannot resume a context
that has been closed")); | 743 DOMException::create(InvalidStateError, "Cannot resume a context
that has been closed")); |
| 744 } else { | 744 } else { |
| 745 resolver->resolve(); | 745 resolver->resolve(); |
| 746 } | 746 } |
| 747 } | 747 } |
| 748 | 748 |
| 749 m_resumeResolvers.clear(); | 749 m_resumeResolvers.clear(); |
| 750 m_isResolvingResumePromises = false; | 750 m_isResolvingResumePromises = false; |
| 751 } | 751 } |
| 752 | 752 |
| 753 void AbstractAudioContext::resolvePromisesForResume() | 753 void BaseAudioContext::resolvePromisesForResume() |
| 754 { | 754 { |
| 755 // This runs inside the AbstractAudioContext's lock when handling pre-render
tasks. | 755 // This runs inside the BaseAudioContext's lock when handling pre-render tas
ks. |
| 756 ASSERT(isAudioThread()); | 756 ASSERT(isAudioThread()); |
| 757 ASSERT(isGraphOwner()); | 757 ASSERT(isGraphOwner()); |
| 758 | 758 |
| 759 // Resolve any pending promises created by resume(). Only do this if we have
n't already started | 759 // Resolve any pending promises created by resume(). Only do this if we have
n't already started |
| 760 // resolving these promises. This gets called very often and it takes some t
ime to resolve the | 760 // resolving these promises. This gets called very often and it takes some t
ime to resolve the |
| 761 // promises in the main thread. | 761 // promises in the main thread. |
| 762 if (!m_isResolvingResumePromises && m_resumeResolvers.size() > 0) { | 762 if (!m_isResolvingResumePromises && m_resumeResolvers.size() > 0) { |
| 763 m_isResolvingResumePromises = true; | 763 m_isResolvingResumePromises = true; |
| 764 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FR
OM_HERE, threadSafeBind(&AbstractAudioContext::resolvePromisesForResumeOnMainThr
ead, wrapCrossThreadPersistent(this))); | 764 Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FR
OM_HERE, threadSafeBind(&BaseAudioContext::resolvePromisesForResumeOnMainThread,
wrapCrossThreadPersistent(this))); |
| 765 } | 765 } |
| 766 } | 766 } |
| 767 | 767 |
| 768 void AbstractAudioContext::rejectPendingDecodeAudioDataResolvers() | 768 void BaseAudioContext::rejectPendingDecodeAudioDataResolvers() |
| 769 { | 769 { |
| 770 // Now reject any pending decodeAudioData resolvers | 770 // Now reject any pending decodeAudioData resolvers |
| 771 for (auto& resolver : m_decodeAudioResolvers) | 771 for (auto& resolver : m_decodeAudioResolvers) |
| 772 resolver->reject(DOMException::create(InvalidStateError, "Audio context
is going away")); | 772 resolver->reject(DOMException::create(InvalidStateError, "Audio context
is going away")); |
| 773 m_decodeAudioResolvers.clear(); | 773 m_decodeAudioResolvers.clear(); |
| 774 } | 774 } |
| 775 | 775 |
| 776 void AbstractAudioContext::rejectPendingResolvers() | 776 void BaseAudioContext::rejectPendingResolvers() |
| 777 { | 777 { |
| 778 ASSERT(isMainThread()); | 778 ASSERT(isMainThread()); |
| 779 | 779 |
| 780 // Audio context is closing down so reject any resume promises that are stil
l pending. | 780 // Audio context is closing down so reject any resume promises that are stil
l pending. |
| 781 | 781 |
| 782 for (auto& resolver : m_resumeResolvers) { | 782 for (auto& resolver : m_resumeResolvers) { |
| 783 resolver->reject(DOMException::create(InvalidStateError, "Audio context
is going away")); | 783 resolver->reject(DOMException::create(InvalidStateError, "Audio context
is going away")); |
| 784 } | 784 } |
| 785 m_resumeResolvers.clear(); | 785 m_resumeResolvers.clear(); |
| 786 m_isResolvingResumePromises = false; | 786 m_isResolvingResumePromises = false; |
| 787 | 787 |
| 788 rejectPendingDecodeAudioDataResolvers(); | 788 rejectPendingDecodeAudioDataResolvers(); |
| 789 } | 789 } |
| 790 | 790 |
| 791 const AtomicString& AbstractAudioContext::interfaceName() const | 791 const AtomicString& BaseAudioContext::interfaceName() const |
| 792 { | 792 { |
| 793 return EventTargetNames::AudioContext; | 793 return EventTargetNames::AudioContext; |
| 794 } | 794 } |
| 795 | 795 |
| 796 ExecutionContext* AbstractAudioContext::getExecutionContext() const | 796 ExecutionContext* BaseAudioContext::getExecutionContext() const |
| 797 { | 797 { |
| 798 return ActiveDOMObject::getExecutionContext(); | 798 return ActiveDOMObject::getExecutionContext(); |
| 799 } | 799 } |
| 800 | 800 |
| 801 void AbstractAudioContext::startRendering() | 801 void BaseAudioContext::startRendering() |
| 802 { | 802 { |
| 803 // This is called for both online and offline contexts. | 803 // This is called for both online and offline contexts. |
| 804 ASSERT(isMainThread()); | 804 ASSERT(isMainThread()); |
| 805 ASSERT(m_destinationNode); | 805 ASSERT(m_destinationNode); |
| 806 | 806 |
| 807 recordUserGestureState(); | 807 recordUserGestureState(); |
| 808 | 808 |
| 809 if (m_contextState == Suspended) { | 809 if (m_contextState == Suspended) { |
| 810 destination()->audioDestinationHandler().startRendering(); | 810 destination()->audioDestinationHandler().startRendering(); |
| 811 setContextState(Running); | 811 setContextState(Running); |
| 812 } | 812 } |
| 813 } | 813 } |
| 814 | 814 |
| 815 DEFINE_TRACE(AbstractAudioContext) | 815 DEFINE_TRACE(BaseAudioContext) |
| 816 { | 816 { |
| 817 visitor->trace(m_destinationNode); | 817 visitor->trace(m_destinationNode); |
| 818 visitor->trace(m_listener); | 818 visitor->trace(m_listener); |
| 819 visitor->trace(m_activeSourceNodes); | 819 visitor->trace(m_activeSourceNodes); |
| 820 visitor->trace(m_resumeResolvers); | 820 visitor->trace(m_resumeResolvers); |
| 821 visitor->trace(m_decodeAudioResolvers); | 821 visitor->trace(m_decodeAudioResolvers); |
| 822 | 822 |
| 823 visitor->trace(m_periodicWaveSine); | 823 visitor->trace(m_periodicWaveSine); |
| 824 visitor->trace(m_periodicWaveSquare); | 824 visitor->trace(m_periodicWaveSquare); |
| 825 visitor->trace(m_periodicWaveSawtooth); | 825 visitor->trace(m_periodicWaveSawtooth); |
| 826 visitor->trace(m_periodicWaveTriangle); | 826 visitor->trace(m_periodicWaveTriangle); |
| 827 EventTargetWithInlineData::trace(visitor); | 827 EventTargetWithInlineData::trace(visitor); |
| 828 ActiveDOMObject::trace(visitor); | 828 ActiveDOMObject::trace(visitor); |
| 829 } | 829 } |
| 830 | 830 |
| 831 SecurityOrigin* AbstractAudioContext::getSecurityOrigin() const | 831 SecurityOrigin* BaseAudioContext::getSecurityOrigin() const |
| 832 { | 832 { |
| 833 if (getExecutionContext()) | 833 if (getExecutionContext()) |
| 834 return getExecutionContext()->getSecurityOrigin(); | 834 return getExecutionContext()->getSecurityOrigin(); |
| 835 | 835 |
| 836 return nullptr; | 836 return nullptr; |
| 837 } | 837 } |
| 838 | 838 |
| 839 } // namespace blink | 839 } // namespace blink |
| OLD | NEW |