Non-unified build fixes, late September 2020 edition
[WebKit-https.git] / Source / WebCore / Modules / webaudio / AudioNodeInput.cpp
1 /*
2  * Copyright (C) 2010, Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1.  Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2.  Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16  * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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.
23  */
24
25 #include "config.h"
26
27 #if ENABLE(WEB_AUDIO)
28
29 #include "AudioNodeInput.h"
30
31 #include "AudioContext.h"
32 #include "AudioNode.h"
33 #include "AudioNodeOutput.h"
34 #include "AudioUtilities.h"
35 #include "ChannelCountMode.h"
36 #include <algorithm>
37
38 namespace WebCore {
39
40 AudioNodeInput::AudioNodeInput(AudioNode* node)
41     : AudioSummingJunction(node->context())
42     , m_node(node)
43 {
44     // Set to mono by default.
45     m_internalSummingBus = AudioBus::create(1, AudioUtilities::renderQuantumSize);
46 }
47
48 void AudioNodeInput::connect(AudioNodeOutput* output)
49 {
50     ASSERT(context().isGraphOwner());
51     
52     ASSERT(output && node());
53     if (!output || !node())
54         return;
55
56     auto& outputsMap = output->isEnabled() ? m_outputs : m_disabledOutputs;
57     // Check if we're already connected to this output.
58     if (!outputsMap.add(output).isNewEntry)
59         return;
60
61     output->addInput(this);
62     changedOutputs();
63
64     // Sombody has just connected to us, so count it as a reference.
65     node()->ref(AudioNode::RefTypeConnection);
66 }
67
68 void AudioNodeInput::disconnect(AudioNodeOutput* output)
69 {
70     ASSERT(context().isGraphOwner());
71
72     ASSERT(output && node());
73     if (!output || !node())
74         return;
75
76     // First try to disconnect from "active" connections.
77     if (m_outputs.remove(output)) {
78         changedOutputs();
79         output->removeInput(this);
80         node()->deref(AudioNode::RefTypeConnection); // Note: it's important to return immediately after all deref() calls since the node may be deleted.
81         return;
82     }
83     
84     // Otherwise, try to disconnect from disabled connections.
85     if (m_disabledOutputs.remove(output)) {
86         output->removeInput(this);
87         node()->deref(AudioNode::RefTypeConnection); // Note: it's important to return immediately after all deref() calls since the node may be deleted.
88         return;
89     }
90
91     ASSERT_NOT_REACHED();
92 }
93
94 void AudioNodeInput::disable(AudioNodeOutput* output)
95 {
96     ASSERT(context().isGraphOwner());
97
98     ASSERT(output && node());
99     if (!output || !node())
100         return;
101
102     ASSERT(m_outputs.contains(output));
103     
104     m_disabledOutputs.add(output);
105     m_outputs.remove(output);
106     changedOutputs();
107
108     // Propagate disabled state to outputs.
109     node()->disableOutputsIfNecessary();
110 }
111
112 void AudioNodeInput::enable(AudioNodeOutput* output)
113 {
114     ASSERT(context().isGraphOwner());
115
116     ASSERT(output && node());
117     if (!output || !node())
118         return;
119
120     ASSERT(m_disabledOutputs.contains(output));
121
122     // Move output from disabled list to active list.
123     m_outputs.add(output);
124     m_disabledOutputs.remove(output);
125     changedOutputs();
126
127     // Propagate enabled state to outputs.
128     node()->enableOutputsIfNecessary();
129 }
130
131 void AudioNodeInput::didUpdate()
132 {
133     node()->checkNumberOfChannelsForInput(this);
134 }
135
136 void AudioNodeInput::updateInternalBus()
137 {
138     ASSERT(context().isAudioThread() && context().isGraphOwner());
139
140     unsigned numberOfInputChannels = numberOfChannels();
141
142     if (numberOfInputChannels == m_internalSummingBus->numberOfChannels())
143         return;
144
145     m_internalSummingBus = AudioBus::create(numberOfInputChannels, AudioUtilities::renderQuantumSize);
146 }
147
148 unsigned AudioNodeInput::numberOfChannels() const
149 {
150     auto mode = node()->channelCountMode();
151     if (mode == ChannelCountMode::Explicit)
152         return node()->channelCount();
153
154     // Find the number of channels of the connection with the largest number of channels.
155     unsigned maxChannels = 1; // one channel is the minimum allowed
156
157     for (auto& output : m_outputs) {
158         // Use output()->numberOfChannels() instead of output->bus()->numberOfChannels(),
159         // because the calling of AudioNodeOutput::bus() is not safe here.
160         maxChannels = std::max(maxChannels, output->numberOfChannels());
161     }
162
163     if (mode == ChannelCountMode::ClampedMax)
164         maxChannels = std::min(maxChannels, static_cast<unsigned>(node()->channelCount()));
165
166     return maxChannels;
167 }
168
169 AudioBus* AudioNodeInput::bus()
170 {
171     ASSERT(context().isAudioThread());
172
173     // Handle single connection specially to allow for in-place processing.
174     if (numberOfRenderingConnections() == 1 && node()->channelCountMode() == ChannelCountMode::Max)
175         return renderingOutput(0)->bus();
176
177     // Multiple connections case or complex ChannelCountMode (or no connections).
178     return internalSummingBus();
179 }
180
181 AudioBus* AudioNodeInput::internalSummingBus()
182 {
183     ASSERT(context().isAudioThread());
184
185     return m_internalSummingBus.get();
186 }
187
188 void AudioNodeInput::sumAllConnections(AudioBus* summingBus, size_t framesToProcess)
189 {
190     ASSERT(context().isAudioThread());
191
192     // We shouldn't be calling this method if there's only one connection, since it's less efficient.
193     ASSERT(numberOfRenderingConnections() > 1 || node()->channelCountMode() != ChannelCountMode::Max);
194
195     ASSERT(summingBus);
196     if (!summingBus)
197         return;
198         
199     summingBus->zero();
200
201     auto interpretation = node()->channelInterpretation();
202
203     for (auto& output : m_renderingOutputs) {
204         ASSERT(output);
205
206         // Render audio from this output.
207         AudioBus* connectionBus = output->pull(0, framesToProcess);
208
209         // Sum, with unity-gain.
210         summingBus->sumFrom(*connectionBus, interpretation);
211     }
212 }
213
214 AudioBus* AudioNodeInput::pull(AudioBus* inPlaceBus, size_t framesToProcess)
215 {
216     ASSERT(context().isAudioThread());
217
218     // Handle single connection case.
219     if (numberOfRenderingConnections() == 1 && node()->channelCountMode() == ChannelCountMode::Max) {
220         // The output will optimize processing using inPlaceBus if it's able.
221         AudioNodeOutput* output = this->renderingOutput(0);
222         return output->pull(inPlaceBus, framesToProcess);
223     }
224
225     AudioBus* internalSummingBus = this->internalSummingBus();
226
227     if (!numberOfRenderingConnections()) {
228         // At least, generate silence if we're not connected to anything.
229         // FIXME: if we wanted to get fancy, we could propagate a 'silent hint' here to optimize the downstream graph processing.
230         internalSummingBus->zero();
231         return internalSummingBus;
232     }
233
234     // Handle multiple connections case.
235     sumAllConnections(internalSummingBus, framesToProcess);
236     
237     return internalSummingBus;
238 }
239
240 } // namespace WebCore
241
242 #endif // ENABLE(WEB_AUDIO)