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 15 matching lines...) Expand all Loading... |
26 #if ENABLE(WEB_AUDIO) | 26 #if ENABLE(WEB_AUDIO) |
27 #include "modules/webaudio/AudioNodeInput.h" | 27 #include "modules/webaudio/AudioNodeInput.h" |
28 | 28 |
29 #include "modules/webaudio/AudioContext.h" | 29 #include "modules/webaudio/AudioContext.h" |
30 #include "modules/webaudio/AudioNodeOutput.h" | 30 #include "modules/webaudio/AudioNodeOutput.h" |
31 #include <algorithm> | 31 #include <algorithm> |
32 | 32 |
33 namespace blink { | 33 namespace blink { |
34 | 34 |
35 inline AudioNodeInput::AudioNodeInput(AudioNode& node) | 35 inline AudioNodeInput::AudioNodeInput(AudioNode& node) |
36 : AudioSummingJunction(node.context()) | 36 : AudioSummingJunction(node.context()->handler()) |
37 , m_node(node) | 37 , m_node(node) |
38 { | 38 { |
39 // Set to mono by default. | 39 // Set to mono by default. |
40 m_internalSummingBus = AudioBus::create(1, AudioNode::ProcessingSizeInFrames
); | 40 m_internalSummingBus = AudioBus::create(1, AudioNode::ProcessingSizeInFrames
); |
41 } | 41 } |
42 | 42 |
43 AudioNodeInput* AudioNodeInput::create(AudioNode& node) | 43 AudioNodeInput* AudioNodeInput::create(AudioNode& node) |
44 { | 44 { |
45 return new AudioNodeInput(node); | 45 return new AudioNodeInput(node); |
46 } | 46 } |
47 | 47 |
48 DEFINE_TRACE(AudioNodeInput) | 48 DEFINE_TRACE(AudioNodeInput) |
49 { | 49 { |
| 50 // TODO(tkent): Oilpan: m_renderingOutputs should not be strong references. |
| 51 // This is a short-term workaround to avoid crashes, and causes AudioNode |
| 52 // leaks. |
| 53 AudioContext::AutoLocker locker(deferredTaskHandler()); |
| 54 for (size_t i = 0; i < m_renderingOutputs.size(); ++i) |
| 55 visitor->trace(m_renderingOutputs[i]); |
50 visitor->trace(m_node); | 56 visitor->trace(m_node); |
51 AudioSummingJunction::trace(visitor); | |
52 } | 57 } |
53 | 58 |
54 void AudioNodeInput::connect(AudioNodeOutput& output) | 59 void AudioNodeInput::connect(AudioNodeOutput& output) |
55 { | 60 { |
56 ASSERT(context()->isGraphOwner()); | 61 ASSERT(deferredTaskHandler().isGraphOwner()); |
57 | 62 |
58 // Check if we're already connected to this output. | 63 // Check if we're already connected to this output. |
59 if (m_outputs.contains(&output)) | 64 if (m_outputs.contains(&output)) |
60 return; | 65 return; |
61 | 66 |
62 output.addInput(*this); | 67 output.addInput(*this); |
63 m_outputs.add(&output); | 68 m_outputs.add(&output); |
64 changedOutputs(); | 69 changedOutputs(); |
65 } | 70 } |
66 | 71 |
67 void AudioNodeInput::disconnect(AudioNodeOutput& output) | 72 void AudioNodeInput::disconnect(AudioNodeOutput& output) |
68 { | 73 { |
69 ASSERT(context()->isGraphOwner()); | 74 ASSERT(deferredTaskHandler().isGraphOwner()); |
70 | 75 |
71 // First try to disconnect from "active" connections. | 76 // First try to disconnect from "active" connections. |
72 if (m_outputs.contains(&output)) { | 77 if (m_outputs.contains(&output)) { |
73 m_outputs.remove(&output); | 78 m_outputs.remove(&output); |
74 changedOutputs(); | 79 changedOutputs(); |
75 output.removeInput(*this); | 80 output.removeInput(*this); |
76 // Note: it's important to return immediately after removeInput() calls | 81 // Note: it's important to return immediately after removeInput() calls |
77 // since the node may be deleted. | 82 // since the node may be deleted. |
78 return; | 83 return; |
79 } | 84 } |
80 | 85 |
81 // Otherwise, try to disconnect from disabled connections. | 86 // Otherwise, try to disconnect from disabled connections. |
82 if (m_disabledOutputs.contains(&output)) { | 87 if (m_disabledOutputs.contains(&output)) { |
83 m_disabledOutputs.remove(&output); | 88 m_disabledOutputs.remove(&output); |
84 output.removeInput(*this); | 89 output.removeInput(*this); |
85 // Note: it's important to return immediately after all removeInput() ca
lls | 90 // Note: it's important to return immediately after all removeInput() ca
lls |
86 // since the node may be deleted. | 91 // since the node may be deleted. |
87 return; | 92 return; |
88 } | 93 } |
89 | 94 |
90 ASSERT_NOT_REACHED(); | 95 ASSERT_NOT_REACHED(); |
91 } | 96 } |
92 | 97 |
93 void AudioNodeInput::disable(AudioNodeOutput& output) | 98 void AudioNodeInput::disable(AudioNodeOutput& output) |
94 { | 99 { |
95 ASSERT(context()->isGraphOwner()); | 100 ASSERT(deferredTaskHandler().isGraphOwner()); |
96 ASSERT(m_outputs.contains(&output)); | 101 ASSERT(m_outputs.contains(&output)); |
97 | 102 |
98 m_disabledOutputs.add(&output); | 103 m_disabledOutputs.add(&output); |
99 m_outputs.remove(&output); | 104 m_outputs.remove(&output); |
100 changedOutputs(); | 105 changedOutputs(); |
101 | 106 |
102 // Propagate disabled state to outputs. | 107 // Propagate disabled state to outputs. |
103 node().disableOutputsIfNecessary(); | 108 node().disableOutputsIfNecessary(); |
104 } | 109 } |
105 | 110 |
106 void AudioNodeInput::enable(AudioNodeOutput& output) | 111 void AudioNodeInput::enable(AudioNodeOutput& output) |
107 { | 112 { |
108 ASSERT(context()->isGraphOwner()); | 113 ASSERT(deferredTaskHandler().isGraphOwner()); |
109 ASSERT(m_disabledOutputs.contains(&output)); | 114 ASSERT(m_disabledOutputs.contains(&output)); |
110 | 115 |
111 // Move output from disabled list to active list. | 116 // Move output from disabled list to active list. |
112 m_outputs.add(&output); | 117 m_outputs.add(&output); |
113 m_disabledOutputs.remove(&output); | 118 m_disabledOutputs.remove(&output); |
114 changedOutputs(); | 119 changedOutputs(); |
115 | 120 |
116 // Propagate enabled state to outputs. | 121 // Propagate enabled state to outputs. |
117 node().enableOutputsIfNecessary(); | 122 node().enableOutputsIfNecessary(); |
118 } | 123 } |
119 | 124 |
120 void AudioNodeInput::didUpdate() | 125 void AudioNodeInput::didUpdate() |
121 { | 126 { |
122 node().checkNumberOfChannelsForInput(this); | 127 node().checkNumberOfChannelsForInput(this); |
123 } | 128 } |
124 | 129 |
125 void AudioNodeInput::updateInternalBus() | 130 void AudioNodeInput::updateInternalBus() |
126 { | 131 { |
127 ASSERT(context()->isAudioThread()); | 132 ASSERT(deferredTaskHandler().isAudioThread()); |
128 ASSERT(context()->isGraphOwner()); | 133 ASSERT(deferredTaskHandler().isGraphOwner()); |
129 | 134 |
130 unsigned numberOfInputChannels = numberOfChannels(); | 135 unsigned numberOfInputChannels = numberOfChannels(); |
131 | 136 |
132 if (numberOfInputChannels == m_internalSummingBus->numberOfChannels()) | 137 if (numberOfInputChannels == m_internalSummingBus->numberOfChannels()) |
133 return; | 138 return; |
134 | 139 |
135 m_internalSummingBus = AudioBus::create(numberOfInputChannels, AudioNode::Pr
ocessingSizeInFrames); | 140 m_internalSummingBus = AudioBus::create(numberOfInputChannels, AudioNode::Pr
ocessingSizeInFrames); |
136 } | 141 } |
137 | 142 |
138 unsigned AudioNodeInput::numberOfChannels() const | 143 unsigned AudioNodeInput::numberOfChannels() const |
(...skipping 12 matching lines...) Expand all Loading... |
151 } | 156 } |
152 | 157 |
153 if (mode == AudioNode::ClampedMax) | 158 if (mode == AudioNode::ClampedMax) |
154 maxChannels = std::min(maxChannels, static_cast<unsigned>(node().channel
Count())); | 159 maxChannels = std::min(maxChannels, static_cast<unsigned>(node().channel
Count())); |
155 | 160 |
156 return maxChannels; | 161 return maxChannels; |
157 } | 162 } |
158 | 163 |
159 AudioBus* AudioNodeInput::bus() | 164 AudioBus* AudioNodeInput::bus() |
160 { | 165 { |
161 ASSERT(context()->isAudioThread()); | 166 ASSERT(deferredTaskHandler().isAudioThread()); |
162 | 167 |
163 // Handle single connection specially to allow for in-place processing. | 168 // Handle single connection specially to allow for in-place processing. |
164 if (numberOfRenderingConnections() == 1 && node().internalChannelCountMode()
== AudioNode::Max) | 169 if (numberOfRenderingConnections() == 1 && node().internalChannelCountMode()
== AudioNode::Max) |
165 return renderingOutput(0)->bus(); | 170 return renderingOutput(0)->bus(); |
166 | 171 |
167 // Multiple connections case or complex ChannelCountMode (or no connections)
. | 172 // Multiple connections case or complex ChannelCountMode (or no connections)
. |
168 return internalSummingBus(); | 173 return internalSummingBus(); |
169 } | 174 } |
170 | 175 |
171 AudioBus* AudioNodeInput::internalSummingBus() | 176 AudioBus* AudioNodeInput::internalSummingBus() |
172 { | 177 { |
173 ASSERT(context()->isAudioThread()); | 178 ASSERT(deferredTaskHandler().isAudioThread()); |
174 | 179 |
175 return m_internalSummingBus.get(); | 180 return m_internalSummingBus.get(); |
176 } | 181 } |
177 | 182 |
178 void AudioNodeInput::sumAllConnections(AudioBus* summingBus, size_t framesToProc
ess) | 183 void AudioNodeInput::sumAllConnections(AudioBus* summingBus, size_t framesToProc
ess) |
179 { | 184 { |
180 ASSERT(context()->isAudioThread()); | 185 ASSERT(deferredTaskHandler().isAudioThread()); |
181 | 186 |
182 // We shouldn't be calling this method if there's only one connection, since
it's less efficient. | 187 // We shouldn't be calling this method if there's only one connection, since
it's less efficient. |
183 ASSERT(numberOfRenderingConnections() > 1 || node().internalChannelCountMode
() != AudioNode::Max); | 188 ASSERT(numberOfRenderingConnections() > 1 || node().internalChannelCountMode
() != AudioNode::Max); |
184 | 189 |
185 ASSERT(summingBus); | 190 ASSERT(summingBus); |
186 if (!summingBus) | 191 if (!summingBus) |
187 return; | 192 return; |
188 | 193 |
189 summingBus->zero(); | 194 summingBus->zero(); |
190 | 195 |
191 AudioBus::ChannelInterpretation interpretation = node().internalChannelInter
pretation(); | 196 AudioBus::ChannelInterpretation interpretation = node().internalChannelInter
pretation(); |
192 | 197 |
193 for (unsigned i = 0; i < numberOfRenderingConnections(); ++i) { | 198 for (unsigned i = 0; i < numberOfRenderingConnections(); ++i) { |
194 AudioNodeOutput* output = renderingOutput(i); | 199 AudioNodeOutput* output = renderingOutput(i); |
195 ASSERT(output); | 200 ASSERT(output); |
196 | 201 |
197 // Render audio from this output. | 202 // Render audio from this output. |
198 AudioBus* connectionBus = output->pull(0, framesToProcess); | 203 AudioBus* connectionBus = output->pull(0, framesToProcess); |
199 | 204 |
200 // Sum, with unity-gain. | 205 // Sum, with unity-gain. |
201 summingBus->sumFrom(*connectionBus, interpretation); | 206 summingBus->sumFrom(*connectionBus, interpretation); |
202 } | 207 } |
203 } | 208 } |
204 | 209 |
205 AudioBus* AudioNodeInput::pull(AudioBus* inPlaceBus, size_t framesToProcess) | 210 AudioBus* AudioNodeInput::pull(AudioBus* inPlaceBus, size_t framesToProcess) |
206 { | 211 { |
207 ASSERT(context()->isAudioThread()); | 212 ASSERT(deferredTaskHandler().isAudioThread()); |
208 | 213 |
209 // Handle single connection case. | 214 // Handle single connection case. |
210 if (numberOfRenderingConnections() == 1 && node().internalChannelCountMode()
== AudioNode::Max) { | 215 if (numberOfRenderingConnections() == 1 && node().internalChannelCountMode()
== AudioNode::Max) { |
211 // The output will optimize processing using inPlaceBus if it's able. | 216 // The output will optimize processing using inPlaceBus if it's able. |
212 AudioNodeOutput* output = this->renderingOutput(0); | 217 AudioNodeOutput* output = this->renderingOutput(0); |
213 return output->pull(inPlaceBus, framesToProcess); | 218 return output->pull(inPlaceBus, framesToProcess); |
214 } | 219 } |
215 | 220 |
216 AudioBus* internalSummingBus = this->internalSummingBus(); | 221 AudioBus* internalSummingBus = this->internalSummingBus(); |
217 | 222 |
218 if (!numberOfRenderingConnections()) { | 223 if (!numberOfRenderingConnections()) { |
219 // At least, generate silence if we're not connected to anything. | 224 // At least, generate silence if we're not connected to anything. |
220 // FIXME: if we wanted to get fancy, we could propagate a 'silent hint'
here to optimize the downstream graph processing. | 225 // FIXME: if we wanted to get fancy, we could propagate a 'silent hint'
here to optimize the downstream graph processing. |
221 internalSummingBus->zero(); | 226 internalSummingBus->zero(); |
222 return internalSummingBus; | 227 return internalSummingBus; |
223 } | 228 } |
224 | 229 |
225 // Handle multiple connections case. | 230 // Handle multiple connections case. |
226 sumAllConnections(internalSummingBus, framesToProcess); | 231 sumAllConnections(internalSummingBus, framesToProcess); |
227 | 232 |
228 return internalSummingBus; | 233 return internalSummingBus; |
229 } | 234 } |
230 | 235 |
231 } // namespace blink | 236 } // namespace blink |
232 | 237 |
233 #endif // ENABLE(WEB_AUDIO) | 238 #endif // ENABLE(WEB_AUDIO) |
OLD | NEW |