From 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c Mon Sep 17 00:00:00 2001 From: Lorry Tar Creator Date: Tue, 27 Jun 2017 06:07:23 +0000 Subject: webkitgtk-2.16.5 --- Source/WebCore/Modules/webaudio/AudioContext.h | 251 ++++++++++++++----------- 1 file changed, 146 insertions(+), 105 deletions(-) (limited to 'Source/WebCore/Modules/webaudio/AudioContext.h') diff --git a/Source/WebCore/Modules/webaudio/AudioContext.h b/Source/WebCore/Modules/webaudio/AudioContext.h index 1e965d9ad..c631f1f19 100644 --- a/Source/WebCore/Modules/webaudio/AudioContext.h +++ b/Source/WebCore/Modules/webaudio/AudioContext.h @@ -1,5 +1,6 @@ /* - * Copyright (C) 2010, Google Inc. All rights reserved. + * Copyright (C) 2010 Google Inc. All rights reserved. + * Copyright (C) 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -22,8 +23,7 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef AudioContext_h -#define AudioContext_h +#pragma once #include "ActiveDOMObject.h" #include "AsyncAudioDecoder.h" @@ -31,12 +31,13 @@ #include "AudioDestinationNode.h" #include "EventListener.h" #include "EventTarget.h" +#include "JSDOMPromise.h" #include "MediaCanStartListener.h" +#include "MediaProducer.h" +#include "PlatformMediaSession.h" #include #include #include -#include -#include #include #include #include @@ -45,41 +46,39 @@ namespace WebCore { +class AnalyserNode; class AudioBuffer; class AudioBufferCallback; class AudioBufferSourceNode; -class MediaElementAudioSourceNode; -class MediaStreamAudioDestinationNode; -class MediaStreamAudioSourceNode; -class HRTFDatabaseLoader; -class HTMLMediaElement; -class ChannelMergerNode; -class ChannelSplitterNode; -class GainNode; -class PannerNode; class AudioListener; class AudioSummingJunction; class BiquadFilterNode; +class ChannelMergerNode; +class ChannelSplitterNode; +class ConvolverNode; class DelayNode; class Document; -class ConvolverNode; class DynamicsCompressorNode; -class AnalyserNode; -class WaveShaperNode; -class ScriptProcessorNode; +class GainNode; +class GenericEventQueue; +class HTMLMediaElement; +class MediaElementAudioSourceNode; +class MediaStream; +class MediaStreamAudioDestinationNode; +class MediaStreamAudioSourceNode; class OscillatorNode; +class PannerNode; class PeriodicWave; +class ScriptProcessorNode; +class WaveShaperNode; // AudioContext is the cornerstone of the web audio API and all AudioNodes are created from it. // For thread safety between the audio thread and the main thread, it has a rendering graph locking mechanism. -class AudioContext : public ActiveDOMObject, public ThreadSafeRefCounted, public EventTargetWithInlineData, public MediaCanStartListener { +class AudioContext : public ActiveDOMObject, public ThreadSafeRefCounted, public EventTargetWithInlineData, public MediaCanStartListener, public MediaProducer, private PlatformMediaSessionClient { public: // Create an AudioContext for rendering to the audio hardware. - static PassRefPtr create(Document&, ExceptionCode&); - - // Create an AudioContext for offline (non-realtime) rendering. - static PassRefPtr createOfflineContext(Document*, unsigned numberOfChannels, size_t numberOfFrames, float sampleRate, ExceptionCode&); + static RefPtr create(Document&); virtual ~AudioContext(); @@ -87,16 +86,10 @@ public: bool isOfflineContext() { return m_isOfflineContext; } - // Returns true when initialize() was called AND all asynchronous initialization has completed. - bool isRunnable() const; - - HRTFDatabaseLoader* hrtfDatabaseLoader() const { return m_hrtfDatabaseLoader.get(); } - - // Document notification - virtual void stop() override; - Document* document() const; // ASSERTs if document no longer exists. + const Document* hostingDocument() const override; + AudioDestinationNode* destination() { return m_destinationNode.get(); } size_t currentSampleFrame() const { return m_destinationNode->currentSampleFrame(); } double currentTime() const { return m_destinationNode->currentTime(); } @@ -106,41 +99,46 @@ public: void incrementActiveSourceCount(); void decrementActiveSourceCount(); - PassRefPtr createBuffer(unsigned numberOfChannels, size_t numberOfFrames, float sampleRate, ExceptionCode&); - PassRefPtr createBuffer(ArrayBuffer*, bool mixToMono, ExceptionCode&); + ExceptionOr> createBuffer(unsigned numberOfChannels, size_t numberOfFrames, float sampleRate); + ExceptionOr> createBuffer(ArrayBuffer&, bool mixToMono); // Asynchronous audio file data decoding. - void decodeAudioData(ArrayBuffer*, PassRefPtr, PassRefPtr, ExceptionCode& ec); + void decodeAudioData(Ref&&, RefPtr&&, RefPtr&&); AudioListener* listener() { return m_listener.get(); } + using ActiveDOMObject::suspend; + using ActiveDOMObject::resume; + + void suspend(DOMPromise&&); + void resume(DOMPromise&&); + void close(DOMPromise&&); + + enum class State { Suspended, Running, Interrupted, Closed }; + State state() const; + // The AudioNode create methods are called on the main thread (from JavaScript). - PassRefPtr createBufferSource(); + Ref createBufferSource(); #if ENABLE(VIDEO) - PassRefPtr createMediaElementSource(HTMLMediaElement*, ExceptionCode&); + ExceptionOr> createMediaElementSource(HTMLMediaElement&); #endif #if ENABLE(MEDIA_STREAM) - PassRefPtr createMediaStreamSource(MediaStream*, ExceptionCode&); - PassRefPtr createMediaStreamDestination(); + ExceptionOr> createMediaStreamSource(MediaStream&); + Ref createMediaStreamDestination(); #endif - PassRefPtr createGain(); - PassRefPtr createBiquadFilter(); - PassRefPtr createWaveShaper(); - PassRefPtr createDelay(ExceptionCode&); - PassRefPtr createDelay(double maxDelayTime, ExceptionCode&); - PassRefPtr createPanner(); - PassRefPtr createConvolver(); - PassRefPtr createDynamicsCompressor(); - PassRefPtr createAnalyser(); - PassRefPtr createScriptProcessor(size_t bufferSize, ExceptionCode&); - PassRefPtr createScriptProcessor(size_t bufferSize, size_t numberOfInputChannels, ExceptionCode&); - PassRefPtr createScriptProcessor(size_t bufferSize, size_t numberOfInputChannels, size_t numberOfOutputChannels, ExceptionCode&); - PassRefPtr createChannelSplitter(ExceptionCode&); - PassRefPtr createChannelSplitter(size_t numberOfOutputs, ExceptionCode&); - PassRefPtr createChannelMerger(ExceptionCode&); - PassRefPtr createChannelMerger(size_t numberOfInputs, ExceptionCode&); - PassRefPtr createOscillator(); - PassRefPtr createPeriodicWave(Float32Array* real, Float32Array* imag, ExceptionCode&); + Ref createGain(); + Ref createBiquadFilter(); + Ref createWaveShaper(); + ExceptionOr> createDelay(double maxDelayTime); + Ref createPanner(); + Ref createConvolver(); + Ref createDynamicsCompressor(); + Ref createAnalyser(); + ExceptionOr> createScriptProcessor(size_t bufferSize, size_t numberOfInputChannels, size_t numberOfOutputChannels); + ExceptionOr> createChannelSplitter(size_t numberOfOutputs); + ExceptionOr> createChannelMerger(size_t numberOfInputs); + Ref createOscillator(); + ExceptionOr> createPeriodicWave(Float32Array& real, Float32Array& imaginary); // When a source node has no more processing to do (has finished playing), then it tells the context to dereference it. void notifyNodeFinishedProcessing(AudioNode*); @@ -198,8 +196,8 @@ public: // Returns true if this thread owns the context's lock. bool isGraphOwner() const; - // Returns the maximum numuber of channels we can support. - static unsigned maxNumberOfChannels() { return MaxNumberOfChannels;} + // Returns the maximum number of channels we can support. + static unsigned maxNumberOfChannels() { return MaxNumberOfChannels; } class AutoLocker { public: @@ -234,14 +232,12 @@ public: void removeMarkedSummingJunction(AudioSummingJunction*); // EventTarget - virtual EventTargetInterface eventTargetInterface() const override final { return AudioContextEventTargetInterfaceType; } - virtual ScriptExecutionContext* scriptExecutionContext() const override final; - - DEFINE_ATTRIBUTE_EVENT_LISTENER(complete); + EventTargetInterface eventTargetInterface() const final { return AudioContextEventTargetInterfaceType; } + ScriptExecutionContext* scriptExecutionContext() const final; // Reconcile ref/deref which are defined both in ThreadSafeRefCounted and EventTarget. - using ThreadSafeRefCounted::ref; - using ThreadSafeRefCounted::deref; + using ThreadSafeRefCounted::ref; + using ThreadSafeRefCounted::deref; void startRendering(); void fireCompletionEvent(); @@ -256,12 +252,14 @@ public: }; typedef unsigned BehaviorRestrictions; - bool userGestureRequiredForAudioStart() const { return m_restrictions & RequireUserGestureForAudioStartRestriction; } - bool pageConsentRequiredForAudioStart() const { return m_restrictions & RequirePageConsentForAudioStartRestriction; } - + BehaviorRestrictions behaviorRestrictions() const { return m_restrictions; } void addBehaviorRestriction(BehaviorRestrictions restriction) { m_restrictions |= restriction; } void removeBehaviorRestriction(BehaviorRestrictions restriction) { m_restrictions &= ~restriction; } + void isPlayingAudioDidChange(); + + void nodeWillBeginPlayback(); + protected: explicit AudioContext(Document&); AudioContext(Document&, unsigned numberOfChannels, size_t numberOfFrames, float sampleRate); @@ -274,33 +272,62 @@ private: void lazyInitialize(); void uninitialize(); - // ScriptExecutionContext calls stop twice. - // We'd like to schedule only one stop action for them. - bool m_isStopScheduled; - static void stopDispatch(void* userData); + bool willBeginPlayback(); + bool willPausePlayback(); + + bool userGestureRequiredForAudioStart() const { return m_restrictions & RequireUserGestureForAudioStartRestriction; } + bool pageConsentRequiredForAudioStart() const { return m_restrictions & RequirePageConsentForAudioStartRestriction; } + + void setState(State); + void clear(); void scheduleNodeDeletion(); - static void deleteMarkedNodesDispatch(void* userData); - virtual void mediaCanStart() override; + void mediaCanStart(Document&) override; - bool m_isInitialized; - bool m_isAudioThreadFinished; + // MediaProducer + MediaProducer::MediaStateFlags mediaState() const override; + void pageMutedStateDidChange() override; // The context itself keeps a reference to all source nodes. The source nodes, then reference all nodes they're connected to. // In turn, these nodes reference all nodes they're connected to. All nodes are ultimately connected to the AudioDestinationNode. // When the context dereferences a source node, it will be deactivated from the rendering graph along with all other nodes it is // uniquely connected to. See the AudioNode::ref() and AudioNode::deref() methods for more details. - void refNode(AudioNode*); - void derefNode(AudioNode*); + void refNode(AudioNode&); + void derefNode(AudioNode&); + + // ActiveDOMObject API. + void stop() override; + bool canSuspendForDocumentSuspension() const override; + const char* activeDOMObjectName() const override; // When the context goes away, there might still be some sources which haven't finished playing. // Make sure to dereference them here. void derefUnfinishedSourceNodes(); - RefPtr m_destinationNode; - RefPtr m_listener; + // PlatformMediaSessionClient + PlatformMediaSession::MediaType mediaType() const override { return PlatformMediaSession::WebAudio; } + PlatformMediaSession::MediaType presentationType() const override { return PlatformMediaSession::WebAudio; } + PlatformMediaSession::CharacteristicsFlags characteristics() const override { return m_state == State::Running ? PlatformMediaSession::HasAudio : PlatformMediaSession::HasNothing; } + void mayResumePlayback(bool shouldResume) override; + void suspendPlayback() override; + bool canReceiveRemoteControlCommands() const override { return false; } + void didReceiveRemoteControlCommand(PlatformMediaSession::RemoteControlCommandType, const PlatformMediaSession::RemoteCommandArgument*) override { } + bool supportsSeeking() const override { return false; } + bool shouldOverrideBackgroundPlaybackRestriction(PlatformMediaSession::InterruptionType) const override { return false; } + String sourceApplicationIdentifier() const override; + bool canProduceAudio() const final { return true; } + + // EventTarget + void refEventTarget() override { ref(); } + void derefEventTarget() override { deref(); } + + void handleDirtyAudioSummingJunctions(); + void handleDirtyAudioNodeOutputs(); + + void addReaction(State, DOMPromise&&); + void updateAutomaticPullNodes(); // Only accessed in the audio thread. Vector m_finishedNodes; @@ -318,42 +345,39 @@ private: // They will be scheduled for deletion (on the main thread) at the end of a render cycle (in realtime thread). Vector m_nodesToDelete; - bool m_isDeletionScheduled; + + bool m_isDeletionScheduled { false }; + bool m_isStopScheduled { false }; + bool m_isInitialized { false }; + bool m_isAudioThreadFinished { false }; + bool m_automaticPullNodesNeedUpdating { false }; + bool m_isOfflineContext { false }; // Only accessed when the graph lock is held. HashSet m_dirtySummingJunctions; HashSet m_dirtyAudioNodeOutputs; - void handleDirtyAudioSummingJunctions(); - void handleDirtyAudioNodeOutputs(); // For the sake of thread safety, we maintain a seperate Vector of automatic pull nodes for rendering in m_renderingAutomaticPullNodes. // It will be copied from m_automaticPullNodes by updateAutomaticPullNodes() at the very start or end of the rendering quantum. HashSet m_automaticPullNodes; Vector m_renderingAutomaticPullNodes; - // m_automaticPullNodesNeedUpdating keeps track if m_automaticPullNodes is modified. - bool m_automaticPullNodesNeedUpdating; - void updateAutomaticPullNodes(); - - unsigned m_connectionCount; - - // Graph locking. - Mutex m_contextGraphMutex; - volatile ThreadIdentifier m_audioThread; - volatile ThreadIdentifier m_graphOwnerThread; // if the lock is held then this is the thread which owns it, otherwise == UndefinedThreadIdentifier - // Only accessed in the audio thread. Vector m_deferredFinishDerefList; - - // HRTF Database loader - RefPtr m_hrtfDatabaseLoader; + Vector>> m_stateReactions; - // EventTarget - virtual void refEventTarget() override { ref(); } - virtual void derefEventTarget() override { deref(); } + std::unique_ptr m_mediaSession; + std::unique_ptr m_eventQueue; RefPtr m_renderTarget; - - bool m_isOfflineContext; + RefPtr m_destinationNode; + RefPtr m_listener; + + unsigned m_connectionCount { 0 }; + + // Graph locking. + Lock m_contextGraphMutex; + volatile ThreadIdentifier m_audioThread { 0 }; + volatile ThreadIdentifier m_graphOwnerThread; // if the lock is held then this is the thread which owns it, otherwise == UndefinedThreadIdentifier AsyncAudioDecoder m_audioDecoder; @@ -362,11 +386,28 @@ private: enum { MaxNumberOfChannels = 32 }; // Number of AudioBufferSourceNodes that are active (playing). - std::atomic m_activeSourceCount; + std::atomic m_activeSourceCount { 0 }; - BehaviorRestrictions m_restrictions; + BehaviorRestrictions m_restrictions { NoRestrictions }; + + State m_state { State::Suspended }; }; -} // WebCore +// FIXME: Find out why these ==/!= functions are needed and remove them if possible. -#endif // AudioContext_h +inline bool operator==(const AudioContext& lhs, const AudioContext& rhs) +{ + return &lhs == &rhs; +} + +inline bool operator!=(const AudioContext& lhs, const AudioContext& rhs) +{ + return &lhs != &rhs; +} + +inline AudioContext::State AudioContext::state() const +{ + return m_state; +} + +} // WebCore -- cgit v1.2.1