| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (C) 2010, Google Inc. All rights reserved. | |
| 3 * | |
| 4 * Redistribution and use in source and binary forms, with or without | |
| 5 * modification, are permitted provided that the following conditions | |
| 6 * are met: | |
| 7 * 1. Redistributions of source code must retain the above copyright | |
| 8 * notice, this list of conditions and the following disclaimer. | |
| 9 * 2. Redistributions in binary form must reproduce the above copyright | |
| 10 * notice, this list of conditions and the following disclaimer in the | |
| 11 * documentation and/or other materials provided with the distribution. | |
| 12 * | |
| 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 | |
| 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 | |
| 17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
| 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 | |
| 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 | |
| 22 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 23 */ | |
| 24 | |
| 25 #ifndef AbstractAudioContext_h | |
| 26 #define AbstractAudioContext_h | |
| 27 | |
| 28 #include "bindings/core/v8/ActiveScriptWrappable.h" | |
| 29 #include "bindings/core/v8/ScriptPromise.h" | |
| 30 #include "bindings/core/v8/ScriptPromiseResolver.h" | |
| 31 #include "core/dom/ActiveDOMObject.h" | |
| 32 #include "core/dom/DOMTypedArray.h" | |
| 33 #include "core/events/EventListener.h" | |
| 34 #include "modules/EventTargetModules.h" | |
| 35 #include "modules/ModulesExport.h" | |
| 36 #include "modules/webaudio/AsyncAudioDecoder.h" | |
| 37 #include "modules/webaudio/AudioDestinationNode.h" | |
| 38 #include "modules/webaudio/DeferredTaskHandler.h" | |
| 39 #include "modules/webaudio/IIRFilterNode.h" | |
| 40 #include "platform/audio/AudioBus.h" | |
| 41 #include "platform/heap/Handle.h" | |
| 42 #include "wtf/HashSet.h" | |
| 43 #include "wtf/RefPtr.h" | |
| 44 #include "wtf/Threading.h" | |
| 45 #include "wtf/Vector.h" | |
| 46 #include "wtf/build_config.h" | |
| 47 | |
| 48 namespace blink { | |
| 49 | |
| 50 class AnalyserNode; | |
| 51 class AudioBuffer; | |
| 52 class AudioBufferCallback; | |
| 53 class AudioBufferSourceNode; | |
| 54 class AudioListener; | |
| 55 class AudioSummingJunction; | |
| 56 class BiquadFilterNode; | |
| 57 class ChannelMergerNode; | |
| 58 class ChannelSplitterNode; | |
| 59 class ConvolverNode; | |
| 60 class DelayNode; | |
| 61 class Dictionary; | |
| 62 class Document; | |
| 63 class DynamicsCompressorNode; | |
| 64 class ExceptionState; | |
| 65 class GainNode; | |
| 66 class HTMLMediaElement; | |
| 67 class IIRFilterNode; | |
| 68 class MediaElementAudioSourceNode; | |
| 69 class MediaStreamAudioDestinationNode; | |
| 70 class MediaStreamAudioSourceNode; | |
| 71 class OscillatorNode; | |
| 72 class PannerNode; | |
| 73 class PeriodicWave; | |
| 74 class PeriodicWaveConstraints; | |
| 75 class ScriptProcessorNode; | |
| 76 class ScriptPromiseResolver; | |
| 77 class ScriptState; | |
| 78 class SecurityOrigin; | |
| 79 class StereoPannerNode; | |
| 80 class WaveShaperNode; | |
| 81 | |
| 82 // AbstractAudioContext is the cornerstone of the web audio API and all AudioNod
es are created from it. | |
| 83 // For thread safety between the audio thread and the main thread, it has a rend
ering graph locking mechanism. | |
| 84 | |
| 85 class MODULES_EXPORT AbstractAudioContext : public EventTargetWithInlineData, pu
blic ActiveScriptWrappable, public ActiveDOMObject { | |
| 86 USING_GARBAGE_COLLECTED_MIXIN(AbstractAudioContext); | |
| 87 DEFINE_WRAPPERTYPEINFO(); | |
| 88 public: | |
| 89 // The state of an audio context. On creation, the state is Suspended. The
state is Running if | |
| 90 // audio is being processed (audio graph is being pulled for data). The stat
e is Closed if the | |
| 91 // audio context has been closed. The valid transitions are from Suspended
to either Running or | |
| 92 // Closed; Running to Suspended or Closed. Once Closed, there are no valid t
ransitions. | |
| 93 enum AudioContextState { | |
| 94 Suspended, | |
| 95 Running, | |
| 96 Closed | |
| 97 }; | |
| 98 | |
| 99 // Create an AudioContext for rendering to the audio hardware. | |
| 100 static AbstractAudioContext* create(Document&, ExceptionState&); | |
| 101 | |
| 102 ~AbstractAudioContext() override; | |
| 103 | |
| 104 DECLARE_VIRTUAL_TRACE(); | |
| 105 | |
| 106 // Is the destination node initialized and ready to handle audio? | |
| 107 bool isDestinationInitialized() const | |
| 108 { | |
| 109 AudioDestinationNode* dest = destination(); | |
| 110 return dest ? dest->audioDestinationHandler().isInitialized() : false; | |
| 111 } | |
| 112 | |
| 113 // Document notification | |
| 114 void stop() final; | |
| 115 bool hasPendingActivity() const final; | |
| 116 | |
| 117 // Cannnot be called from the audio thread. | |
| 118 AudioDestinationNode* destination() const; | |
| 119 | |
| 120 size_t currentSampleFrame() const | |
| 121 { | |
| 122 // TODO: What is the correct value for the current frame if the destinat
ion node has gone | |
| 123 // away? 0 is a valid frame. | |
| 124 return m_destinationNode ? m_destinationNode->audioDestinationHandler().
currentSampleFrame() : 0; | |
| 125 } | |
| 126 | |
| 127 double currentTime() const | |
| 128 { | |
| 129 // TODO: What is the correct value for the current time if the destinati
on node has gone | |
| 130 // away? 0 is a valid time. | |
| 131 return m_destinationNode ? m_destinationNode->audioDestinationHandler().
currentTime() : 0; | |
| 132 } | |
| 133 | |
| 134 float sampleRate() const { return m_destinationNode ? m_destinationNode->han
dler().sampleRate() : 0; } | |
| 135 | |
| 136 String state() const; | |
| 137 AudioContextState contextState() const { return m_contextState; } | |
| 138 void throwExceptionForClosedState(ExceptionState&); | |
| 139 | |
| 140 AudioBuffer* createBuffer(unsigned numberOfChannels, size_t numberOfFrames,
float sampleRate, ExceptionState&); | |
| 141 | |
| 142 // Asynchronous audio file data decoding. | |
| 143 ScriptPromise decodeAudioData(ScriptState*, DOMArrayBuffer* audioData, Audio
BufferCallback* successCallback, AudioBufferCallback* errorCallback, ExceptionSt
ate&); | |
| 144 | |
| 145 // Handles the promise and callbacks when |decodeAudioData| is finished deco
ding. | |
| 146 void handleDecodeAudioData(AudioBuffer*, ScriptPromiseResolver*, AudioBuffer
Callback* successCallback, AudioBufferCallback* errorCallback); | |
| 147 | |
| 148 AudioListener* listener() { return m_listener; } | |
| 149 | |
| 150 virtual bool hasRealtimeConstraint() = 0; | |
| 151 | |
| 152 // The AudioNode create methods are called on the main thread (from JavaScri
pt). | |
| 153 AudioBufferSourceNode* createBufferSource(ExceptionState&); | |
| 154 MediaElementAudioSourceNode* createMediaElementSource(HTMLMediaElement*, Exc
eptionState&); | |
| 155 MediaStreamAudioSourceNode* createMediaStreamSource(MediaStream*, ExceptionS
tate&); | |
| 156 MediaStreamAudioDestinationNode* createMediaStreamDestination(ExceptionState
&); | |
| 157 GainNode* createGain(ExceptionState&); | |
| 158 BiquadFilterNode* createBiquadFilter(ExceptionState&); | |
| 159 WaveShaperNode* createWaveShaper(ExceptionState&); | |
| 160 DelayNode* createDelay(ExceptionState&); | |
| 161 DelayNode* createDelay(double maxDelayTime, ExceptionState&); | |
| 162 PannerNode* createPanner(ExceptionState&); | |
| 163 ConvolverNode* createConvolver(ExceptionState&); | |
| 164 DynamicsCompressorNode* createDynamicsCompressor(ExceptionState&); | |
| 165 AnalyserNode* createAnalyser(ExceptionState&); | |
| 166 ScriptProcessorNode* createScriptProcessor(ExceptionState&); | |
| 167 ScriptProcessorNode* createScriptProcessor(size_t bufferSize, ExceptionState
&); | |
| 168 ScriptProcessorNode* createScriptProcessor(size_t bufferSize, size_t numberO
fInputChannels, ExceptionState&); | |
| 169 ScriptProcessorNode* createScriptProcessor(size_t bufferSize, size_t numberO
fInputChannels, size_t numberOfOutputChannels, ExceptionState&); | |
| 170 StereoPannerNode* createStereoPanner(ExceptionState&); | |
| 171 ChannelSplitterNode* createChannelSplitter(ExceptionState&); | |
| 172 ChannelSplitterNode* createChannelSplitter(size_t numberOfOutputs, Exception
State&); | |
| 173 ChannelMergerNode* createChannelMerger(ExceptionState&); | |
| 174 ChannelMergerNode* createChannelMerger(size_t numberOfInputs, ExceptionState
&); | |
| 175 OscillatorNode* createOscillator(ExceptionState&); | |
| 176 PeriodicWave* createPeriodicWave(DOMFloat32Array* real, DOMFloat32Array* ima
g, ExceptionState&); | |
| 177 PeriodicWave* createPeriodicWave(DOMFloat32Array* real, DOMFloat32Array* ima
g, const PeriodicWaveConstraints&, ExceptionState&); | |
| 178 | |
| 179 // Close | |
| 180 virtual ScriptPromise closeContext(ScriptState*) = 0; | |
| 181 | |
| 182 // Suspend | |
| 183 virtual ScriptPromise suspendContext(ScriptState*) = 0; | |
| 184 | |
| 185 // Resume | |
| 186 virtual ScriptPromise resumeContext(ScriptState*) = 0; | |
| 187 | |
| 188 // IIRFilter | |
| 189 IIRFilterNode* createIIRFilter(Vector<double> feedforwardCoef, Vector<double
> feedbackCoef, | |
| 190 ExceptionState&); | |
| 191 | |
| 192 // When a source node has started processing and needs to be protected, | |
| 193 // this method tells the context to protect the node. | |
| 194 // | |
| 195 // The context itself keeps a reference to all source nodes. The source | |
| 196 // nodes, then reference all nodes they're connected to. In turn, these | |
| 197 // nodes reference all nodes they're connected to. All nodes are ultimately | |
| 198 // connected to the AudioDestinationNode. When the context release a source | |
| 199 // node, it will be deactivated from the rendering graph along with all | |
| 200 // other nodes it is uniquely connected to. | |
| 201 void notifySourceNodeStartedProcessing(AudioNode*); | |
| 202 // When a source node has no more processing to do (has finished playing), | |
| 203 // this method tells the context to release the corresponding node. | |
| 204 void notifySourceNodeFinishedProcessing(AudioHandler*); | |
| 205 | |
| 206 // Called at the start of each render quantum. | |
| 207 void handlePreRenderTasks(); | |
| 208 | |
| 209 // Called at the end of each render quantum. | |
| 210 void handlePostRenderTasks(); | |
| 211 | |
| 212 // Called periodically at the end of each render quantum to release finished | |
| 213 // source nodes. | |
| 214 void releaseFinishedSourceNodes(); | |
| 215 | |
| 216 // Keeps track of the number of connections made. | |
| 217 void incrementConnectionCount() | |
| 218 { | |
| 219 ASSERT(isMainThread()); | |
| 220 m_connectionCount++; | |
| 221 } | |
| 222 | |
| 223 unsigned connectionCount() const { return m_connectionCount; } | |
| 224 | |
| 225 DeferredTaskHandler& deferredTaskHandler() const { return *m_deferredTaskHan
dler; } | |
| 226 // | |
| 227 // Thread Safety and Graph Locking: | |
| 228 // | |
| 229 // The following functions call corresponding functions of | |
| 230 // DeferredTaskHandler. | |
| 231 bool isAudioThread() const { return deferredTaskHandler().isAudioThread(); } | |
| 232 void lock() { deferredTaskHandler().lock(); } | |
| 233 bool tryLock() { return deferredTaskHandler().tryLock(); } | |
| 234 void unlock() { deferredTaskHandler().unlock(); } | |
| 235 #if ENABLE(ASSERT) | |
| 236 // Returns true if this thread owns the context's lock. | |
| 237 bool isGraphOwner() { return deferredTaskHandler().isGraphOwner(); } | |
| 238 #endif | |
| 239 using AutoLocker = DeferredTaskHandler::AutoLocker; | |
| 240 | |
| 241 // Returns the maximum numuber of channels we can support. | |
| 242 static unsigned maxNumberOfChannels() { return MaxNumberOfChannels;} | |
| 243 | |
| 244 // EventTarget | |
| 245 const AtomicString& interfaceName() const final; | |
| 246 ExecutionContext* getExecutionContext() const final; | |
| 247 | |
| 248 DEFINE_ATTRIBUTE_EVENT_LISTENER(statechange); | |
| 249 | |
| 250 void startRendering(); | |
| 251 void notifyStateChange(); | |
| 252 | |
| 253 // A context is considered closed if: | |
| 254 // - closeContext() has been called. | |
| 255 // - it has been stopped by its execution context. | |
| 256 virtual bool isContextClosed() const { return m_isCleared; } | |
| 257 | |
| 258 // Get the security origin for this audio context. | |
| 259 SecurityOrigin* getSecurityOrigin() const; | |
| 260 | |
| 261 // Get the PeriodicWave for the specified oscillator type. The table is ini
tialized internally | |
| 262 // if necessary. | |
| 263 PeriodicWave* periodicWave(int type); | |
| 264 | |
| 265 // Check whether the AudioContext requires a user gesture and whether the | |
| 266 // current stack is processing user gesture and record these information in | |
| 267 // a histogram. | |
| 268 void recordUserGestureState(); | |
| 269 | |
| 270 protected: | |
| 271 explicit AbstractAudioContext(Document*); | |
| 272 AbstractAudioContext(Document*, unsigned numberOfChannels, size_t numberOfFr
ames, float sampleRate); | |
| 273 | |
| 274 void initialize(); | |
| 275 void uninitialize(); | |
| 276 | |
| 277 void setContextState(AudioContextState); | |
| 278 | |
| 279 virtual void didClose() {} | |
| 280 | |
| 281 // Tries to handle AudioBufferSourceNodes that were started but became disco
nnected or was never | |
| 282 // connected. Because these never get pulled anymore, they will stay around
forever. So if we | |
| 283 // can, try to stop them so they can be collected. | |
| 284 void handleStoppableSourceNodes(); | |
| 285 | |
| 286 Member<AudioDestinationNode> m_destinationNode; | |
| 287 | |
| 288 // FIXME(dominicc): Move m_resumeResolvers to AudioContext, because only | |
| 289 // it creates these Promises. | |
| 290 // Vector of promises created by resume(). It takes time to handle them, so
we collect all of | |
| 291 // the promises here until they can be resolved or rejected. | |
| 292 HeapVector<Member<ScriptPromiseResolver>> m_resumeResolvers; | |
| 293 | |
| 294 void setClosedContextSampleRate(float newSampleRate) { m_closedContextSample
Rate = newSampleRate; } | |
| 295 float closedContextSampleRate() const { return m_closedContextSampleRate; } | |
| 296 | |
| 297 void rejectPendingDecodeAudioDataResolvers(); | |
| 298 | |
| 299 private: | |
| 300 bool m_isCleared; | |
| 301 void clear(); | |
| 302 | |
| 303 // When the context goes away, there might still be some sources which | |
| 304 // haven't finished playing. Make sure to release them here. | |
| 305 void releaseActiveSourceNodes(); | |
| 306 | |
| 307 void removeFinishedSourceNodes(); | |
| 308 | |
| 309 // Listener for the PannerNodes | |
| 310 Member<AudioListener> m_listener; | |
| 311 | |
| 312 // Only accessed in the audio thread. | |
| 313 // These raw pointers are safe because AudioSourceNodes in | |
| 314 // m_activeSourceNodes own them. | |
| 315 Vector<AudioHandler*> m_finishedSourceHandlers; | |
| 316 | |
| 317 // List of source nodes. This is either accessed when the graph lock is | |
| 318 // held, or on the main thread when the audio thread has finished. | |
| 319 // Oilpan: This Vector holds connection references. We must call | |
| 320 // AudioHandler::makeConnection when we add an AudioNode to this, and must | |
| 321 // call AudioHandler::breakConnection() when we remove an AudioNode from | |
| 322 // this. | |
| 323 HeapVector<Member<AudioNode>> m_activeSourceNodes; | |
| 324 | |
| 325 // The main thread controls m_activeSourceNodes, all updates and additions | |
| 326 // are performed by it. When the audio thread marks a source node as finishe
d, | |
| 327 // the nodes are added to |m_finishedSourceNodes| and scheduled for removal | |
| 328 // from |m_activeSourceNodes| by the main thread. | |
| 329 HashSet<UntracedMember<AudioNode>> m_finishedSourceNodes; | |
| 330 | |
| 331 // FIXME(dominicc): Move these to AudioContext because only | |
| 332 // it creates these Promises. | |
| 333 // Handle Promises for resume() and suspend() | |
| 334 void resolvePromisesForResume(); | |
| 335 void resolvePromisesForResumeOnMainThread(); | |
| 336 | |
| 337 // When the context is going away, reject any pending script promise resolve
rs. | |
| 338 virtual void rejectPendingResolvers(); | |
| 339 | |
| 340 // True if we're in the process of resolving promises for resume(). Resolvi
ng can take some | |
| 341 // time and the audio context process loop is very fast, so we don't want to
call resolve an | |
| 342 // excessive number of times. | |
| 343 bool m_isResolvingResumePromises; | |
| 344 | |
| 345 // Whether a user gesture is required to start this AudioContext. | |
| 346 bool m_userGestureRequired; | |
| 347 | |
| 348 unsigned m_connectionCount; | |
| 349 | |
| 350 // Graph locking. | |
| 351 RefPtr<DeferredTaskHandler> m_deferredTaskHandler; | |
| 352 | |
| 353 // The state of the AbstractAudioContext. | |
| 354 AudioContextState m_contextState; | |
| 355 | |
| 356 AsyncAudioDecoder m_audioDecoder; | |
| 357 | |
| 358 // When a context is closed, the sample rate is cleared. But decodeAudioDat
a can be called | |
| 359 // after the context has been closed and it needs the sample rate. When the
context is closed, | |
| 360 // the sample rate is saved here. | |
| 361 float m_closedContextSampleRate; | |
| 362 | |
| 363 // Vector of promises created by decodeAudioData. This keeps the resolvers
alive until | |
| 364 // decodeAudioData finishes decoding and can tell the main thread to resolve
them. | |
| 365 HeapHashSet<Member<ScriptPromiseResolver>> m_decodeAudioResolvers; | |
| 366 | |
| 367 // PeriodicWave's for the builtin oscillator types. These only depend on th
e sample rate. so | |
| 368 // they can be shared with all OscillatorNodes in the context. To conserve
memory, these are | |
| 369 // lazily initiialized on first use. | |
| 370 Member<PeriodicWave> m_periodicWaveSine; | |
| 371 Member<PeriodicWave> m_periodicWaveSquare; | |
| 372 Member<PeriodicWave> m_periodicWaveSawtooth; | |
| 373 Member<PeriodicWave> m_periodicWaveTriangle; | |
| 374 | |
| 375 // This is considering 32 is large enough for multiple channels audio. | |
| 376 // It is somewhat arbitrary and could be increased if necessary. | |
| 377 enum { MaxNumberOfChannels = 32 }; | |
| 378 }; | |
| 379 | |
| 380 } // namespace blink | |
| 381 | |
| 382 #endif // AbstractAudioContext_h | |
| OLD | NEW |