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 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
57 setInternalChannelInterpretation(AudioBus::Speakers); | 57 setInternalChannelInterpretation(AudioBus::Speakers); |
58 } | 58 } |
59 | 59 |
60 PassRefPtr<OfflineAudioDestinationHandler> OfflineAudioDestinationHandler::creat
e(AudioNode& node, AudioBuffer* renderTarget) | 60 PassRefPtr<OfflineAudioDestinationHandler> OfflineAudioDestinationHandler::creat
e(AudioNode& node, AudioBuffer* renderTarget) |
61 { | 61 { |
62 return adoptRef(new OfflineAudioDestinationHandler(node, renderTarget)); | 62 return adoptRef(new OfflineAudioDestinationHandler(node, renderTarget)); |
63 } | 63 } |
64 | 64 |
65 OfflineAudioDestinationHandler::~OfflineAudioDestinationHandler() | 65 OfflineAudioDestinationHandler::~OfflineAudioDestinationHandler() |
66 { | 66 { |
67 ASSERT(!isInitialized()); | 67 DCHECK(!isInitialized()); |
68 } | 68 } |
69 | 69 |
70 void OfflineAudioDestinationHandler::dispose() | 70 void OfflineAudioDestinationHandler::dispose() |
71 { | 71 { |
72 uninitialize(); | 72 uninitialize(); |
73 AudioDestinationHandler::dispose(); | 73 AudioDestinationHandler::dispose(); |
74 } | 74 } |
75 | 75 |
76 void OfflineAudioDestinationHandler::initialize() | 76 void OfflineAudioDestinationHandler::initialize() |
77 { | 77 { |
(...skipping 19 matching lines...) Expand all Loading... |
97 return static_cast<OfflineAudioContext*>(AudioDestinationHandler::context())
; | 97 return static_cast<OfflineAudioContext*>(AudioDestinationHandler::context())
; |
98 } | 98 } |
99 | 99 |
100 unsigned long OfflineAudioDestinationHandler::maxChannelCount() const | 100 unsigned long OfflineAudioDestinationHandler::maxChannelCount() const |
101 { | 101 { |
102 return m_channelCount; | 102 return m_channelCount; |
103 } | 103 } |
104 | 104 |
105 void OfflineAudioDestinationHandler::startRendering() | 105 void OfflineAudioDestinationHandler::startRendering() |
106 { | 106 { |
107 ASSERT(isMainThread()); | 107 DCHECK(isMainThread()); |
108 ASSERT(m_renderThread); | 108 DCHECK(m_renderThread); |
109 ASSERT(m_renderTarget); | 109 DCHECK(m_renderTarget); |
110 | 110 |
111 if (!m_renderTarget) | 111 if (!m_renderTarget) |
112 return; | 112 return; |
113 | 113 |
114 // Rendering was not started. Starting now. | 114 // Rendering was not started. Starting now. |
115 if (!m_isRenderingStarted) { | 115 if (!m_isRenderingStarted) { |
116 m_isRenderingStarted = true; | 116 m_isRenderingStarted = true; |
117 m_renderThread->getWebTaskRunner()->postTask(BLINK_FROM_HERE, | 117 m_renderThread->getWebTaskRunner()->postTask(BLINK_FROM_HERE, |
118 crossThreadBind(&OfflineAudioDestinationHandler::startOfflineRenderi
ng, wrapPassRefPtr(this))); | 118 crossThreadBind(&OfflineAudioDestinationHandler::startOfflineRenderi
ng, wrapPassRefPtr(this))); |
119 return; | 119 return; |
120 } | 120 } |
121 | 121 |
122 // Rendering is already started, which implicitly means we resume the | 122 // Rendering is already started, which implicitly means we resume the |
123 // rendering by calling |doOfflineRendering| on the render thread. | 123 // rendering by calling |doOfflineRendering| on the render thread. |
124 m_renderThread->getWebTaskRunner()->postTask(BLINK_FROM_HERE, | 124 m_renderThread->getWebTaskRunner()->postTask(BLINK_FROM_HERE, |
125 crossThreadBind(&OfflineAudioDestinationHandler::doOfflineRendering, wra
pPassRefPtr(this))); | 125 crossThreadBind(&OfflineAudioDestinationHandler::doOfflineRendering, wra
pPassRefPtr(this))); |
126 } | 126 } |
127 | 127 |
128 void OfflineAudioDestinationHandler::stopRendering() | 128 void OfflineAudioDestinationHandler::stopRendering() |
129 { | 129 { |
130 // offline audio rendering CANNOT BE stopped by JavaScript. | 130 // offline audio rendering CANNOT BE stopped by JavaScript. |
131 ASSERT_NOT_REACHED(); | 131 ASSERT_NOT_REACHED(); |
132 } | 132 } |
133 | 133 |
134 WebThread* OfflineAudioDestinationHandler::offlineRenderThread() | 134 WebThread* OfflineAudioDestinationHandler::offlineRenderThread() |
135 { | 135 { |
136 ASSERT(m_renderThread); | 136 DCHECK(m_renderThread); |
137 | 137 |
138 return m_renderThread.get(); | 138 return m_renderThread.get(); |
139 } | 139 } |
140 | 140 |
141 void OfflineAudioDestinationHandler::startOfflineRendering() | 141 void OfflineAudioDestinationHandler::startOfflineRendering() |
142 { | 142 { |
143 ASSERT(!isMainThread()); | 143 DCHECK(!isMainThread()); |
144 | 144 |
145 ASSERT(m_renderBus); | 145 DCHECK(m_renderBus); |
146 if (!m_renderBus) | 146 if (!m_renderBus) |
147 return; | 147 return; |
148 | 148 |
149 bool isAudioContextInitialized = context()->isDestinationInitialized(); | 149 bool isAudioContextInitialized = context()->isDestinationInitialized(); |
150 ASSERT(isAudioContextInitialized); | 150 DCHECK(isAudioContextInitialized); |
151 if (!isAudioContextInitialized) | 151 if (!isAudioContextInitialized) |
152 return; | 152 return; |
153 | 153 |
154 bool channelsMatch = m_renderBus->numberOfChannels() == m_renderTarget->numb
erOfChannels(); | 154 bool channelsMatch = m_renderBus->numberOfChannels() == m_renderTarget->numb
erOfChannels(); |
155 ASSERT(channelsMatch); | 155 DCHECK(channelsMatch); |
156 if (!channelsMatch) | 156 if (!channelsMatch) |
157 return; | 157 return; |
158 | 158 |
159 bool isRenderBusAllocated = m_renderBus->length() >= renderQuantumSize; | 159 bool isRenderBusAllocated = m_renderBus->length() >= renderQuantumSize; |
160 ASSERT(isRenderBusAllocated); | 160 DCHECK(isRenderBusAllocated); |
161 if (!isRenderBusAllocated) | 161 if (!isRenderBusAllocated) |
162 return; | 162 return; |
163 | 163 |
164 // Start rendering. | 164 // Start rendering. |
165 doOfflineRendering(); | 165 doOfflineRendering(); |
166 } | 166 } |
167 | 167 |
168 void OfflineAudioDestinationHandler::doOfflineRendering() | 168 void OfflineAudioDestinationHandler::doOfflineRendering() |
169 { | 169 { |
170 ASSERT(!isMainThread()); | 170 DCHECK(!isMainThread()); |
171 | 171 |
172 unsigned numberOfChannels = m_renderTarget->numberOfChannels(); | 172 unsigned numberOfChannels = m_renderTarget->numberOfChannels(); |
173 | 173 |
174 // Reset the suspend flag. | 174 // Reset the suspend flag. |
175 m_shouldSuspend = false; | 175 m_shouldSuspend = false; |
176 | 176 |
177 // If there is more to process and there is no suspension at the moment, | 177 // If there is more to process and there is no suspension at the moment, |
178 // do continue to render quanta. Then calling OfflineAudioContext.resume() w
ill pick up | 178 // do continue to render quanta. Then calling OfflineAudioContext.resume() w
ill pick up |
179 // the render loop again from where it was suspended. | 179 // the render loop again from where it was suspended. |
180 while (m_framesToProcess > 0 && !m_shouldSuspend) { | 180 while (m_framesToProcess > 0 && !m_shouldSuspend) { |
181 | 181 |
182 // Suspend the rendering and update m_shouldSuspend if a scheduled | 182 // Suspend the rendering and update m_shouldSuspend if a scheduled |
183 // suspend found at the current sample frame. Otherwise render one | 183 // suspend found at the current sample frame. Otherwise render one |
184 // quantum and return false. | 184 // quantum and return false. |
185 m_shouldSuspend = renderIfNotSuspended(0, m_renderBus.get(), renderQuant
umSize); | 185 m_shouldSuspend = renderIfNotSuspended(0, m_renderBus.get(), renderQuant
umSize); |
186 | 186 |
187 if (m_shouldSuspend) | 187 if (m_shouldSuspend) |
188 return; | 188 return; |
189 | 189 |
190 size_t framesAvailableToCopy = std::min(m_framesToProcess, renderQuantum
Size); | 190 size_t framesAvailableToCopy = std::min(m_framesToProcess, renderQuantum
Size); |
191 | 191 |
192 for (unsigned channelIndex = 0; channelIndex < numberOfChannels; ++chann
elIndex) { | 192 for (unsigned channelIndex = 0; channelIndex < numberOfChannels; ++chann
elIndex) { |
193 const float* source = m_renderBus->channel(channelIndex)->data(); | 193 const float* source = m_renderBus->channel(channelIndex)->data(); |
194 float* destination = m_renderTarget->getChannelData(channelIndex)->d
ata(); | 194 float* destination = m_renderTarget->getChannelData(channelIndex)->d
ata(); |
195 memcpy(destination + m_framesProcessed, source, sizeof(float) * fram
esAvailableToCopy); | 195 memcpy(destination + m_framesProcessed, source, sizeof(float) * fram
esAvailableToCopy); |
196 } | 196 } |
197 | 197 |
198 m_framesProcessed += framesAvailableToCopy; | 198 m_framesProcessed += framesAvailableToCopy; |
199 | 199 |
200 ASSERT(m_framesToProcess >= framesAvailableToCopy); | 200 DCHECK_GE(m_framesToProcess, framesAvailableToCopy); |
201 m_framesToProcess -= framesAvailableToCopy; | 201 m_framesToProcess -= framesAvailableToCopy; |
202 } | 202 } |
203 | 203 |
204 // Finish up the rendering loop if there is no more to process. | 204 // Finish up the rendering loop if there is no more to process. |
205 if (!m_framesToProcess) | 205 if (!m_framesToProcess) |
206 finishOfflineRendering(); | 206 finishOfflineRendering(); |
207 } | 207 } |
208 | 208 |
209 void OfflineAudioDestinationHandler::suspendOfflineRendering() | 209 void OfflineAudioDestinationHandler::suspendOfflineRendering() |
210 { | 210 { |
211 ASSERT(!isMainThread()); | 211 DCHECK(!isMainThread()); |
212 | 212 |
213 // The actual rendering has been suspended. Notify the context. | 213 // The actual rendering has been suspended. Notify the context. |
214 if (context()->getExecutionContext()) { | 214 if (context()->getExecutionContext()) { |
215 context()->getExecutionContext()->postTask( | 215 context()->getExecutionContext()->postTask( |
216 BLINK_FROM_HERE, | 216 BLINK_FROM_HERE, |
217 createCrossThreadTask(&OfflineAudioDestinationHandler::notifySuspend
, PassRefPtr<OfflineAudioDestinationHandler>(this), context()->currentSampleFram
e())); | 217 createCrossThreadTask(&OfflineAudioDestinationHandler::notifySuspend
, PassRefPtr<OfflineAudioDestinationHandler>(this), context()->currentSampleFram
e())); |
218 } | 218 } |
219 } | 219 } |
220 | 220 |
221 void OfflineAudioDestinationHandler::finishOfflineRendering() | 221 void OfflineAudioDestinationHandler::finishOfflineRendering() |
222 { | 222 { |
223 ASSERT(!isMainThread()); | 223 DCHECK(!isMainThread()); |
224 | 224 |
225 // The actual rendering has been completed. Notify the context. | 225 // The actual rendering has been completed. Notify the context. |
226 if (context()->getExecutionContext()) { | 226 if (context()->getExecutionContext()) { |
227 context()->getExecutionContext()->postTask(BLINK_FROM_HERE, | 227 context()->getExecutionContext()->postTask(BLINK_FROM_HERE, |
228 createCrossThreadTask(&OfflineAudioDestinationHandler::notifyComplet
e, PassRefPtr<OfflineAudioDestinationHandler>(this))); | 228 createCrossThreadTask(&OfflineAudioDestinationHandler::notifyComplet
e, PassRefPtr<OfflineAudioDestinationHandler>(this))); |
229 } | 229 } |
230 } | 230 } |
231 | 231 |
232 void OfflineAudioDestinationHandler::notifySuspend(size_t frame) | 232 void OfflineAudioDestinationHandler::notifySuspend(size_t frame) |
233 { | 233 { |
234 ASSERT(isMainThread()); | 234 DCHECK(isMainThread()); |
235 | 235 |
236 if (context()) | 236 if (context()) |
237 context()->resolveSuspendOnMainThread(frame); | 237 context()->resolveSuspendOnMainThread(frame); |
238 } | 238 } |
239 | 239 |
240 void OfflineAudioDestinationHandler::notifyComplete() | 240 void OfflineAudioDestinationHandler::notifyComplete() |
241 { | 241 { |
242 // The OfflineAudioContext might be gone. | 242 // The OfflineAudioContext might be gone. |
243 if (context()) | 243 if (context()) |
244 context()->fireCompletionEvent(); | 244 context()->fireCompletionEvent(); |
245 } | 245 } |
246 | 246 |
247 bool OfflineAudioDestinationHandler::renderIfNotSuspended(AudioBus* sourceBus, A
udioBus* destinationBus, size_t numberOfFrames) | 247 bool OfflineAudioDestinationHandler::renderIfNotSuspended(AudioBus* sourceBus, A
udioBus* destinationBus, size_t numberOfFrames) |
248 { | 248 { |
249 // We don't want denormals slowing down any of the audio processing | 249 // We don't want denormals slowing down any of the audio processing |
250 // since they can very seriously hurt performance. | 250 // since they can very seriously hurt performance. |
251 // This will take care of all AudioNodes because they all process within thi
s scope. | 251 // This will take care of all AudioNodes because they all process within thi
s scope. |
252 DenormalDisabler denormalDisabler; | 252 DenormalDisabler denormalDisabler; |
253 | 253 |
254 // Need to check if the context actually alive. Otherwise the subsequent | 254 // Need to check if the context actually alive. Otherwise the subsequent |
255 // steps will fail. If the context is not alive somehow, return immediately | 255 // steps will fail. If the context is not alive somehow, return immediately |
256 // and do nothing. | 256 // and do nothing. |
257 // | 257 // |
258 // TODO(hongchan): because the context can go away while rendering, so this | 258 // TODO(hongchan): because the context can go away while rendering, so this |
259 // check cannot guarantee the safe execution of the following steps. | 259 // check cannot guarantee the safe execution of the following steps. |
260 ASSERT(context()); | 260 DCHECK(context()); |
261 if (!context()) | 261 if (!context()) |
262 return false; | 262 return false; |
263 | 263 |
264 context()->deferredTaskHandler().setAudioThreadToCurrentThread(); | 264 context()->deferredTaskHandler().setAudioThreadToCurrentThread(); |
265 | 265 |
266 // If the destination node is not initialized, pass the silence to the final | 266 // If the destination node is not initialized, pass the silence to the final |
267 // audio destination (one step before the FIFO). This check is for the case | 267 // audio destination (one step before the FIFO). This check is for the case |
268 // where the destination is in the middle of tearing down process. | 268 // where the destination is in the middle of tearing down process. |
269 if (!isInitialized()) { | 269 if (!isInitialized()) { |
270 destinationBus->zero(); | 270 destinationBus->zero(); |
271 return false; | 271 return false; |
272 } | 272 } |
273 | 273 |
274 // Take care pre-render tasks at the beginning of each render quantum. Then | 274 // Take care pre-render tasks at the beginning of each render quantum. Then |
275 // it will stop the rendering loop if the context needs to be suspended | 275 // it will stop the rendering loop if the context needs to be suspended |
276 // at the beginning of the next render quantum. | 276 // at the beginning of the next render quantum. |
277 if (context()->handlePreOfflineRenderTasks()) { | 277 if (context()->handlePreOfflineRenderTasks()) { |
278 suspendOfflineRendering(); | 278 suspendOfflineRendering(); |
279 return true; | 279 return true; |
280 } | 280 } |
281 | 281 |
282 // Prepare the local audio input provider for this render quantum. | 282 // Prepare the local audio input provider for this render quantum. |
283 if (sourceBus) | 283 if (sourceBus) |
284 m_localAudioInputProvider.set(sourceBus); | 284 m_localAudioInputProvider.set(sourceBus); |
285 | 285 |
286 ASSERT(numberOfInputs() >= 1); | 286 DCHECK_GE(numberOfInputs(), 1u); |
287 if (numberOfInputs() < 1) { | 287 if (numberOfInputs() < 1) { |
288 destinationBus->zero(); | 288 destinationBus->zero(); |
289 return false; | 289 return false; |
290 } | 290 } |
291 // This will cause the node(s) connected to us to process, which in turn wil
l pull on their input(s), | 291 // This will cause the node(s) connected to us to process, which in turn wil
l pull on their input(s), |
292 // all the way backwards through the rendering graph. | 292 // all the way backwards through the rendering graph. |
293 AudioBus* renderedBus = input(0).pull(destinationBus, numberOfFrames); | 293 AudioBus* renderedBus = input(0).pull(destinationBus, numberOfFrames); |
294 | 294 |
295 if (!renderedBus) { | 295 if (!renderedBus) { |
296 destinationBus->zero(); | 296 destinationBus->zero(); |
(...skipping 22 matching lines...) Expand all Loading... |
319 { | 319 { |
320 setHandler(OfflineAudioDestinationHandler::create(*this, renderTarget)); | 320 setHandler(OfflineAudioDestinationHandler::create(*this, renderTarget)); |
321 } | 321 } |
322 | 322 |
323 OfflineAudioDestinationNode* OfflineAudioDestinationNode::create(BaseAudioContex
t* context, AudioBuffer* renderTarget) | 323 OfflineAudioDestinationNode* OfflineAudioDestinationNode::create(BaseAudioContex
t* context, AudioBuffer* renderTarget) |
324 { | 324 { |
325 return new OfflineAudioDestinationNode(*context, renderTarget); | 325 return new OfflineAudioDestinationNode(*context, renderTarget); |
326 } | 326 } |
327 | 327 |
328 } // namespace blink | 328 } // namespace blink |
OLD | NEW |