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 |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
102 : ActiveDOMObject(document) | 102 : ActiveDOMObject(document) |
103 , m_isStopScheduled(false) | 103 , m_isStopScheduled(false) |
104 , m_isCleared(false) | 104 , m_isCleared(false) |
105 , m_isInitialized(false) | 105 , m_isInitialized(false) |
106 , m_destinationNode(nullptr) | 106 , m_destinationNode(nullptr) |
107 , m_isResolvingResumePromises(false) | 107 , m_isResolvingResumePromises(false) |
108 , m_automaticPullNodesNeedUpdating(false) | 108 , m_automaticPullNodesNeedUpdating(false) |
109 , m_connectionCount(0) | 109 , m_connectionCount(0) |
110 , m_didInitializeContextGraphMutex(false) | 110 , m_didInitializeContextGraphMutex(false) |
111 , m_audioThread(0) | 111 , m_audioThread(0) |
112 , m_lastZombie(nullptr) | |
113 , m_lastRemovableZombie(nullptr) | |
112 , m_isOfflineContext(false) | 114 , m_isOfflineContext(false) |
113 , m_contextState(Suspended) | 115 , m_contextState(Suspended) |
114 , m_cachedSampleFrame(0) | 116 , m_cachedSampleFrame(0) |
115 { | 117 { |
116 m_didInitializeContextGraphMutex = true; | 118 m_didInitializeContextGraphMutex = true; |
117 m_destinationNode = DefaultAudioDestinationNode::create(this); | 119 m_destinationNode = DefaultAudioDestinationNode::create(this); |
118 | 120 |
119 initialize(); | 121 initialize(); |
120 #if DEBUG_AUDIONODE_REFERENCES | 122 #if DEBUG_AUDIONODE_REFERENCES |
121 fprintf(stderr, "%p: AudioContext::AudioContext() #%u\n", this, AudioContext ::s_hardwareContextCount); | 123 fprintf(stderr, "%p: AudioContext::AudioContext() #%u\n", this, AudioContext ::s_hardwareContextCount); |
122 #endif | 124 #endif |
123 } | 125 } |
124 | 126 |
125 // Constructor for offline (non-realtime) rendering. | 127 // Constructor for offline (non-realtime) rendering. |
126 AudioContext::AudioContext(Document* document, unsigned numberOfChannels, size_t numberOfFrames, float sampleRate) | 128 AudioContext::AudioContext(Document* document, unsigned numberOfChannels, size_t numberOfFrames, float sampleRate) |
127 : ActiveDOMObject(document) | 129 : ActiveDOMObject(document) |
128 , m_isStopScheduled(false) | 130 , m_isStopScheduled(false) |
129 , m_isCleared(false) | 131 , m_isCleared(false) |
130 , m_isInitialized(false) | 132 , m_isInitialized(false) |
131 , m_destinationNode(nullptr) | 133 , m_destinationNode(nullptr) |
132 , m_isResolvingResumePromises(false) | 134 , m_isResolvingResumePromises(false) |
133 , m_automaticPullNodesNeedUpdating(false) | 135 , m_automaticPullNodesNeedUpdating(false) |
134 , m_connectionCount(0) | 136 , m_connectionCount(0) |
135 , m_didInitializeContextGraphMutex(false) | 137 , m_didInitializeContextGraphMutex(false) |
136 , m_audioThread(0) | 138 , m_audioThread(0) |
139 , m_lastZombie(nullptr) | |
140 , m_lastRemovableZombie(nullptr) | |
137 , m_isOfflineContext(true) | 141 , m_isOfflineContext(true) |
138 , m_contextState(Suspended) | 142 , m_contextState(Suspended) |
139 , m_cachedSampleFrame(0) | 143 , m_cachedSampleFrame(0) |
140 { | 144 { |
141 m_didInitializeContextGraphMutex = true; | 145 m_didInitializeContextGraphMutex = true; |
142 // Create a new destination for offline rendering. | 146 // Create a new destination for offline rendering. |
143 m_renderTarget = AudioBuffer::create(numberOfChannels, numberOfFrames, sampl eRate); | 147 m_renderTarget = AudioBuffer::create(numberOfChannels, numberOfFrames, sampl eRate); |
144 if (m_renderTarget.get()) | 148 if (m_renderTarget.get()) |
145 m_destinationNode = OfflineAudioDestinationNode::create(this, m_renderTa rget.get()); | 149 m_destinationNode = OfflineAudioDestinationNode::create(this, m_renderTa rget.get()); |
146 | 150 |
147 initialize(); | 151 initialize(); |
148 } | 152 } |
149 | 153 |
150 AudioContext::~AudioContext() | 154 AudioContext::~AudioContext() |
151 { | 155 { |
152 #if DEBUG_AUDIONODE_REFERENCES | 156 #if DEBUG_AUDIONODE_REFERENCES |
153 fprintf(stderr, "%p: AudioContext::~AudioContext()\n", this); | 157 fprintf(stderr, "%p: AudioContext::~AudioContext()\n", this); |
154 #endif | 158 #endif |
155 // 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. | 159 // 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. |
156 ASSERT(!m_isInitialized); | 160 ASSERT(!m_isInitialized); |
157 ASSERT(!m_referencedNodes.size()); | 161 ASSERT(!m_referencedNodes.size()); |
158 ASSERT(!m_finishedNodes.size()); | 162 ASSERT(!m_finishedNodes.size()); |
159 ASSERT(!m_automaticPullNodes.size()); | 163 ASSERT(!m_automaticPullNodes.size()); |
160 if (m_automaticPullNodesNeedUpdating) | 164 if (m_automaticPullNodesNeedUpdating) |
161 m_renderingAutomaticPullNodes.resize(m_automaticPullNodes.size()); | 165 m_renderingAutomaticPullNodes.resize(m_automaticPullNodes.size()); |
162 ASSERT(!m_renderingAutomaticPullNodes.size()); | 166 ASSERT(!m_renderingAutomaticPullNodes.size()); |
163 ASSERT(!m_suspendResolvers.size()); | 167 ASSERT(!m_suspendResolvers.size()); |
164 ASSERT(!m_resumeResolvers.size()); | 168 ASSERT(!m_resumeResolvers.size()); |
169 ThreadState::current()->removeMarkingTask(this); | |
haraken
2015/02/06 07:57:23
Can we move this to AudioContext::uninitialize()?
tkent
2015/02/09 07:00:50
Yes. It's consistent because we call addMarkingTa
| |
165 } | 170 } |
166 | 171 |
167 void AudioContext::initialize() | 172 void AudioContext::initialize() |
168 { | 173 { |
169 if (isInitialized()) | 174 if (isInitialized()) |
170 return; | 175 return; |
171 | 176 |
177 ThreadState::current()->addMarkingTask(this); | |
172 FFTFrame::initialize(); | 178 FFTFrame::initialize(); |
173 m_listener = AudioListener::create(); | 179 m_listener = AudioListener::create(); |
174 | 180 |
175 if (m_destinationNode.get()) { | 181 if (m_destinationNode.get()) { |
176 m_destinationNode->initialize(); | 182 m_destinationNode->initialize(); |
177 | 183 |
178 if (!isOfflineContext()) { | 184 if (!isOfflineContext()) { |
179 // This starts the audio thread. The destination node's provideInput () method will now be called repeatedly to render audio. | 185 // This starts the audio thread. The destination node's provideInput () method will now be called repeatedly to render audio. |
180 // Each time provideInput() is called, a portion of the audio stream is rendered. Let's call this time period a "render quantum". | 186 // Each time provideInput() is called, a portion of the audio stream is rendered. Let's call this time period a "render quantum". |
181 // NOTE: for now default AudioContext does not need an explicit star tRendering() call from JavaScript. | 187 // NOTE: for now default AudioContext does not need an explicit star tRendering() call from JavaScript. |
(...skipping 628 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
810 if (tryLock()) { | 816 if (tryLock()) { |
811 // Update the channel count mode. | 817 // Update the channel count mode. |
812 updateChangedChannelCountMode(); | 818 updateChangedChannelCountMode(); |
813 | 819 |
814 // Take care of AudioNode tasks where the tryLock() failed previously. | 820 // Take care of AudioNode tasks where the tryLock() failed previously. |
815 handleDeferredAudioNodeTasks(); | 821 handleDeferredAudioNodeTasks(); |
816 | 822 |
817 // Dynamically clean up nodes which are no longer needed. | 823 // Dynamically clean up nodes which are no longer needed. |
818 derefFinishedSourceNodes(); | 824 derefFinishedSourceNodes(); |
819 | 825 |
826 m_lastRemovableZombie = m_lastZombie; | |
827 | |
820 // Fixup the state of any dirty AudioSummingJunctions and AudioNodeOutpu ts. | 828 // Fixup the state of any dirty AudioSummingJunctions and AudioNodeOutpu ts. |
821 handleDirtyAudioSummingJunctions(); | 829 handleDirtyAudioSummingJunctions(); |
822 handleDirtyAudioNodeOutputs(); | 830 handleDirtyAudioNodeOutputs(); |
823 | 831 |
824 updateAutomaticPullNodes(); | 832 updateAutomaticPullNodes(); |
825 resolvePromisesForSuspend(); | 833 resolvePromisesForSuspend(); |
826 | 834 |
827 unlock(); | 835 unlock(); |
828 } | 836 } |
829 } | 837 } |
(...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1103 m_offlineResolver->resolve(renderedBuffer); | 1111 m_offlineResolver->resolve(renderedBuffer); |
1104 } | 1112 } |
1105 } | 1113 } |
1106 | 1114 |
1107 void AudioContext::trace(Visitor* visitor) | 1115 void AudioContext::trace(Visitor* visitor) |
1108 { | 1116 { |
1109 visitor->trace(m_offlineResolver); | 1117 visitor->trace(m_offlineResolver); |
1110 visitor->trace(m_renderTarget); | 1118 visitor->trace(m_renderTarget); |
1111 visitor->trace(m_destinationNode); | 1119 visitor->trace(m_destinationNode); |
1112 visitor->trace(m_listener); | 1120 visitor->trace(m_listener); |
1113 // trace() can be called in AudioContext constructor, and | 1121 visitor->trace(m_referencedNodes); |
1114 // m_contextGraphMutex might be unavailable. | |
1115 if (m_didInitializeContextGraphMutex) { | |
1116 AutoLocker lock(this); | |
1117 visitor->trace(m_referencedNodes); | |
1118 } else { | |
1119 visitor->trace(m_referencedNodes); | |
1120 } | |
1121 visitor->trace(m_resumeResolvers); | 1122 visitor->trace(m_resumeResolvers); |
1122 visitor->trace(m_suspendResolvers); | 1123 visitor->trace(m_suspendResolvers); |
1123 visitor->trace(m_liveNodes); | 1124 visitor->trace(m_liveNodes); |
1124 visitor->trace(m_liveAudioSummingJunctions); | 1125 visitor->trace(m_liveAudioSummingJunctions); |
1125 RefCountedGarbageCollectedEventTargetWithInlineData<AudioContext>::trace(vis itor); | 1126 RefCountedGarbageCollectedEventTargetWithInlineData<AudioContext>::trace(vis itor); |
1126 ActiveDOMObject::trace(visitor); | 1127 ActiveDOMObject::trace(visitor); |
1127 } | 1128 } |
1128 | 1129 |
1129 void AudioContext::addChangedChannelCountMode(AudioNode* node) | 1130 void AudioContext::addChangedChannelCountMode(AudioNode* node) |
1130 { | 1131 { |
(...skipping 17 matching lines...) Expand all Loading... | |
1148 (*k)->updateChannelCountMode(); | 1149 (*k)->updateChannelCountMode(); |
1149 | 1150 |
1150 m_deferredCountModeChange.clear(); | 1151 m_deferredCountModeChange.clear(); |
1151 } | 1152 } |
1152 | 1153 |
1153 SecurityOrigin* AudioContext::securityOrigin() const | 1154 SecurityOrigin* AudioContext::securityOrigin() const |
1154 { | 1155 { |
1155 return executionContext()->securityOrigin(); | 1156 return executionContext()->securityOrigin(); |
1156 } | 1157 } |
1157 | 1158 |
1159 void AudioContext::setLastZombie(void* object) | |
1160 { | |
1161 ASSERT(isGraphOwner()); | |
1162 m_lastZombie = object; | |
1163 } | |
1164 | |
1165 void AudioContext::willStartMarking(ThreadState& threadState) | |
haraken
2015/02/06 07:57:23
willStartMarking is called not only in the ZombieM
tkent
2015/02/09 07:00:50
It's ok.
There are two purposes of this hook:
* S
| |
1166 { | |
1167 lock(); | |
haraken
2015/02/06 07:57:23
What happens if a GC is triggered during AudioCont
tkent
2015/02/09 07:00:50
It won't happen. This task is registered after th
| |
1168 if (!m_lastRemovableZombie) | |
1169 return; | |
1170 if (m_lastZombie != m_lastRemovableZombie) | |
haraken
2015/02/06 07:57:23
I don't quite get what m_lastZombie and m_lastRemo
tkent
2015/02/09 07:00:50
We need to avoid the following scenario:
1. GC ha
| |
1171 return; | |
1172 threadState.purifyZombies(); | |
1173 m_lastZombie = nullptr; | |
1174 m_lastRemovableZombie = nullptr; | |
1175 } | |
1176 | |
1177 void AudioContext::didFinishMarking(ThreadState&) | |
1178 { | |
1179 unlock(); | |
1180 } | |
1181 | |
1158 } // namespace blink | 1182 } // namespace blink |
1159 | 1183 |
1160 #endif // ENABLE(WEB_AUDIO) | 1184 #endif // ENABLE(WEB_AUDIO) |
OLD | NEW |