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