OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (C) 2011, Google Inc. All rights reserved. | 2 * Copyright (C) 2011, 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 10 matching lines...) Expand all Loading... | |
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 "config.h" | 25 #include "config.h" |
26 #if ENABLE(WEB_AUDIO) | 26 #if ENABLE(WEB_AUDIO) |
27 #include "modules/webaudio/OfflineAudioDestinationNode.h" | 27 #include "modules/webaudio/OfflineAudioDestinationNode.h" |
28 | 28 |
29 #include "core/dom/CrossThreadTask.h" | 29 #include "core/dom/CrossThreadTask.h" |
30 #include "modules/webaudio/AudioContext.h" | 30 #include "modules/webaudio/AudioContext.h" |
31 #include "modules/webaudio/OfflineAudioContext.h" | |
31 #include "platform/Task.h" | 32 #include "platform/Task.h" |
32 #include "platform/audio/AudioBus.h" | 33 #include "platform/audio/AudioBus.h" |
33 #include "platform/audio/HRTFDatabaseLoader.h" | 34 #include "platform/audio/HRTFDatabaseLoader.h" |
34 #include "public/platform/Platform.h" | 35 #include "public/platform/Platform.h" |
35 #include <algorithm> | 36 #include <algorithm> |
36 | 37 |
37 namespace blink { | 38 namespace blink { |
38 | 39 |
39 const size_t renderQuantumSize = 128; | 40 const size_t kRenderQuantumSize = 128; |
40 | 41 |
41 OfflineAudioDestinationHandler::OfflineAudioDestinationHandler(AudioNode& node, AudioBuffer* renderTarget) | 42 OfflineAudioDestinationHandler::OfflineAudioDestinationHandler(AudioNode& node, AudioBuffer* renderTarget) |
42 : AudioDestinationHandler(node, renderTarget->sampleRate()) | 43 : AudioDestinationHandler(node, renderTarget->sampleRate()) |
43 , m_renderTarget(renderTarget) | 44 , m_renderTarget(renderTarget) |
44 , m_startedRendering(false) | 45 , m_isRenderingStarted(false) |
46 , m_framesProcessed(0) | |
47 , m_framesToProcess(0) | |
45 { | 48 { |
46 m_renderBus = AudioBus::create(renderTarget->numberOfChannels(), renderQuant umSize); | 49 m_renderBus = AudioBus::create(renderTarget->numberOfChannels(), kRenderQuan tumSize); |
47 } | 50 } |
48 | 51 |
49 PassRefPtr<OfflineAudioDestinationHandler> OfflineAudioDestinationHandler::creat e(AudioNode& node, AudioBuffer* renderTarget) | 52 PassRefPtr<OfflineAudioDestinationHandler> OfflineAudioDestinationHandler::creat e(AudioNode& node, AudioBuffer* renderTarget) |
50 { | 53 { |
51 return adoptRef(new OfflineAudioDestinationHandler(node, renderTarget)); | 54 return adoptRef(new OfflineAudioDestinationHandler(node, renderTarget)); |
52 } | 55 } |
53 | 56 |
54 OfflineAudioDestinationHandler::~OfflineAudioDestinationHandler() | 57 OfflineAudioDestinationHandler::~OfflineAudioDestinationHandler() |
55 { | 58 { |
56 ASSERT(!isInitialized()); | 59 ASSERT(!isInitialized()); |
(...skipping 24 matching lines...) Expand all Loading... | |
81 AudioHandler::uninitialize(); | 84 AudioHandler::uninitialize(); |
82 } | 85 } |
83 | 86 |
84 void OfflineAudioDestinationHandler::startRendering() | 87 void OfflineAudioDestinationHandler::startRendering() |
85 { | 88 { |
86 ASSERT(isMainThread()); | 89 ASSERT(isMainThread()); |
87 ASSERT(m_renderTarget); | 90 ASSERT(m_renderTarget); |
88 if (!m_renderTarget) | 91 if (!m_renderTarget) |
89 return; | 92 return; |
90 | 93 |
91 if (!m_startedRendering) { | 94 // fprintf(stderr, "startRendering() called\n"); |
92 m_startedRendering = true; | 95 |
96 // Rendering was not started. Starting now. | |
97 if (!m_isRenderingStarted) { | |
98 m_isRenderingStarted = true; | |
93 m_renderThread = adoptPtr(Platform::current()->createThread("Offline Aud io Renderer")); | 99 m_renderThread = adoptPtr(Platform::current()->createThread("Offline Aud io Renderer")); |
94 m_renderThread->postTask(FROM_HERE, new Task(threadSafeBind(&OfflineAudi oDestinationHandler::offlineRender, PassRefPtr<OfflineAudioDestinationHandler>(t his)))); | 100 m_renderThread->postTask(FROM_HERE, |
101 new Task(threadSafeBind(&OfflineAudioDestinationHandler::initiateOff lineRendering, this))); | |
102 return; | |
95 } | 103 } |
104 | |
105 // Rendering was already started, which implicitly means we resume the | |
106 // rendering by calling |renderNextQuantum| on m_renderThread. | |
107 // TO FIX: is there any corner case for this? | |
Raymond Toy
2015/05/19 22:04:46
I think blink style is FIXME.
hongchan
2015/05/20 22:09:41
Done.
| |
108 m_renderThread->postTask(FROM_HERE, | |
109 threadSafeBind(&OfflineAudioDestinationHandler::renderNextQuantum, this) ); | |
110 return; | |
96 } | 111 } |
97 | 112 |
98 void OfflineAudioDestinationHandler::stopRendering() | 113 void OfflineAudioDestinationHandler::stopRendering() |
99 { | 114 { |
100 ASSERT_NOT_REACHED(); | 115 ASSERT_NOT_REACHED(); |
101 } | 116 } |
102 | 117 |
103 void OfflineAudioDestinationHandler::offlineRender() | 118 void OfflineAudioDestinationHandler::initiateOfflineRendering() |
104 { | |
105 offlineRenderInternal(); | |
106 context()->handlePostRenderTasks(); | |
107 } | |
108 | |
109 void OfflineAudioDestinationHandler::offlineRenderInternal() | |
110 { | 119 { |
111 ASSERT(!isMainThread()); | 120 ASSERT(!isMainThread()); |
121 | |
112 ASSERT(m_renderBus); | 122 ASSERT(m_renderBus); |
113 if (!m_renderBus) | 123 if (!m_renderBus) |
114 return; | 124 return; |
115 | 125 |
116 bool isAudioContextInitialized = context()->isInitialized(); | 126 bool isAudioContextInitialized = context()->isInitialized(); |
117 ASSERT(isAudioContextInitialized); | 127 ASSERT(isAudioContextInitialized); |
118 if (!isAudioContextInitialized) | 128 if (!isAudioContextInitialized) |
119 return; | 129 return; |
120 | 130 |
121 bool channelsMatch = m_renderBus->numberOfChannels() == m_renderTarget->numb erOfChannels(); | 131 bool channelsMatch = m_renderBus->numberOfChannels() == m_renderTarget->numb erOfChannels(); |
122 ASSERT(channelsMatch); | 132 ASSERT(channelsMatch); |
123 if (!channelsMatch) | 133 if (!channelsMatch) |
124 return; | 134 return; |
125 | 135 |
126 bool isRenderBusAllocated = m_renderBus->length() >= renderQuantumSize; | 136 bool isRenderBusAllocated = m_renderBus->length() >= kRenderQuantumSize; |
127 ASSERT(isRenderBusAllocated); | 137 ASSERT(isRenderBusAllocated); |
128 if (!isRenderBusAllocated) | 138 if (!isRenderBusAllocated) |
129 return; | 139 return; |
130 | 140 |
131 // Break up the render target into smaller "render quantize" sized pieces. | 141 m_framesToProcess = m_renderTarget->length(); |
132 // Render until we're finished. | |
133 size_t framesToProcess = m_renderTarget->length(); | |
134 unsigned numberOfChannels = m_renderTarget->numberOfChannels(); | |
135 | 142 |
136 unsigned n = 0; | 143 // Initiate rendering. |
137 while (framesToProcess > 0) { | 144 renderNextQuantum(); |
138 // Render one render quantum. | 145 } |
139 render(0, m_renderBus.get(), renderQuantumSize); | |
140 | 146 |
141 size_t framesAvailableToCopy = std::min(framesToProcess, renderQuantumSi ze); | 147 void OfflineAudioDestinationHandler::renderNextQuantum() |
148 { | |
149 ASSERT(!isMainThread()); | |
142 | 150 |
143 for (unsigned channelIndex = 0; channelIndex < numberOfChannels; ++chann elIndex) { | 151 if (context()->suspendIfNecessary()) { |
144 const float* source = m_renderBus->channel(channelIndex)->data(); | 152 if (context()->executionContext()) { |
145 float* destination = m_renderTarget->getChannelData(channelIndex)->d ata(); | 153 context()->executionContext()->postTask(FROM_HERE, |
146 memcpy(destination + n, source, sizeof(float) * framesAvailableToCop y); | 154 createCrossThreadTask(&OfflineAudioDestinationHandler::notifySus pend, this)); |
147 } | 155 } |
148 | 156 return; |
149 n += framesAvailableToCopy; | |
150 framesToProcess -= framesAvailableToCopy; | |
151 } | 157 } |
152 | 158 |
159 // Render one render quantum. Note that this includes pre/post render tasks. | |
160 render(0, m_renderBus.get(), kRenderQuantumSize); | |
161 | |
162 unsigned numberOfChannels = m_renderTarget->numberOfChannels(); | |
163 size_t framesAvailableToCopy = std::min(m_framesToProcess, kRenderQuantumSiz e); | |
164 | |
165 for (unsigned channelIndex = 0; channelIndex < numberOfChannels; ++channelIn dex) { | |
166 const float* source = m_renderBus->channel(channelIndex)->data(); | |
167 float* destination = m_renderTarget->getChannelData(channelIndex)->data( ); | |
168 memcpy(destination + m_framesProcessed, source, sizeof(float) * framesAv ailableToCopy); | |
169 } | |
170 | |
171 m_framesProcessed += framesAvailableToCopy; | |
172 m_framesToProcess -= framesAvailableToCopy; | |
173 | |
174 if (m_framesToProcess > 0) | |
175 renderNextQuantum(); | |
176 else | |
177 finishOfflineRendering(); | |
178 } | |
179 | |
180 void OfflineAudioDestinationHandler::finishOfflineRendering() | |
181 { | |
182 ASSERT(!isMainThread()); | |
183 | |
153 // Our work is done. Let the AudioContext know. | 184 // Our work is done. Let the AudioContext know. |
154 if (context()->executionContext()) | 185 if (context()->executionContext()) { |
155 context()->executionContext()->postTask(FROM_HERE, createCrossThreadTask (&OfflineAudioDestinationHandler::notifyComplete, PassRefPtr<OfflineAudioDestina tionHandler>(this))); | 186 context()->executionContext()->postTask(FROM_HERE, |
187 createCrossThreadTask(&OfflineAudioDestinationHandler::notifyComplet e, this)); | |
188 } | |
189 } | |
190 | |
191 void OfflineAudioDestinationHandler::notifySuspend() | |
192 { | |
193 // The AudioContext might be gone. | |
194 if (context()) | |
195 context()->fireSuspendEvent(); | |
156 } | 196 } |
157 | 197 |
158 void OfflineAudioDestinationHandler::notifyComplete() | 198 void OfflineAudioDestinationHandler::notifyComplete() |
159 { | 199 { |
160 // The AudioContext might be gone. | 200 // The AudioContext might be gone. |
161 if (context()) | 201 if (context()) |
162 context()->fireCompletionEvent(); | 202 context()->fireCompletionEvent(); |
163 } | 203 } |
164 | 204 |
165 // ---------------------------------------------------------------- | 205 // ---------------------------------------------------------------- |
166 | 206 |
167 OfflineAudioDestinationNode::OfflineAudioDestinationNode(AudioContext& context, AudioBuffer* renderTarget) | 207 OfflineAudioDestinationNode::OfflineAudioDestinationNode(AudioContext& context, AudioBuffer* renderTarget) |
168 : AudioDestinationNode(context) | 208 : AudioDestinationNode(context) |
169 { | 209 { |
170 setHandler(OfflineAudioDestinationHandler::create(*this, renderTarget)); | 210 setHandler(OfflineAudioDestinationHandler::create(*this, renderTarget)); |
171 } | 211 } |
172 | 212 |
173 OfflineAudioDestinationNode* OfflineAudioDestinationNode::create(AudioContext* c ontext, AudioBuffer* renderTarget) | 213 OfflineAudioDestinationNode* OfflineAudioDestinationNode::create(AudioContext* c ontext, AudioBuffer* renderTarget) |
174 { | 214 { |
175 return new OfflineAudioDestinationNode(*context, renderTarget); | 215 return new OfflineAudioDestinationNode(*context, renderTarget); |
176 } | 216 } |
177 | 217 |
178 } // namespace blink | 218 } // namespace blink |
179 | 219 |
180 #endif // ENABLE(WEB_AUDIO) | 220 #endif // ENABLE(WEB_AUDIO) |
OLD | NEW |