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 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 * its contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "third_party/blink/renderer/modules/webaudio/channel_merger_node.h"
30
31 #include "third_party/blink/renderer/bindings/modules/v8/v8_channel_merger_options.h"
32 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
33 #include "third_party/blink/renderer/modules/webaudio/audio_node_input.h"
34 #include "third_party/blink/renderer/modules/webaudio/audio_node_output.h"
35 #include "third_party/blink/renderer/modules/webaudio/base_audio_context.h"
36 #include "third_party/blink/renderer/platform/bindings/exception_messages.h"
37 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
38
39 namespace blink {
40
ChannelMergerHandler(AudioNode & node,float sample_rate,unsigned number_of_inputs)41 ChannelMergerHandler::ChannelMergerHandler(AudioNode& node,
42 float sample_rate,
43 unsigned number_of_inputs)
44 : AudioHandler(kNodeTypeChannelMerger, node, sample_rate) {
45 // These properties are fixed for the node and cannot be changed by user.
46 channel_count_ = 1;
47 SetInternalChannelCountMode(kExplicit);
48
49 // Create the requested number of inputs.
50 for (unsigned i = 0; i < number_of_inputs; ++i)
51 AddInput();
52
53 // Create the output with the requested number of channels.
54 AddOutput(number_of_inputs);
55
56 Initialize();
57
58 // Until something is connected, we're not actively processing, so disable
59 // outputs so that we produce a single channel of silence. The graph lock is
60 // needed to be able to disable outputs.
61 BaseAudioContext::GraphAutoLocker context_locker(Context());
62
63 DisableOutputs();
64 }
65
Create(AudioNode & node,float sample_rate,unsigned number_of_inputs)66 scoped_refptr<ChannelMergerHandler> ChannelMergerHandler::Create(
67 AudioNode& node,
68 float sample_rate,
69 unsigned number_of_inputs) {
70 return base::AdoptRef(
71 new ChannelMergerHandler(node, sample_rate, number_of_inputs));
72 }
73
Process(uint32_t frames_to_process)74 void ChannelMergerHandler::Process(uint32_t frames_to_process) {
75 AudioNodeOutput& output = this->Output(0);
76 DCHECK_EQ(frames_to_process, output.Bus()->length());
77
78 unsigned number_of_output_channels = output.NumberOfChannels();
79 DCHECK_EQ(NumberOfInputs(), number_of_output_channels);
80
81 // Merge multiple inputs into one output.
82 for (unsigned i = 0; i < number_of_output_channels; ++i) {
83 AudioNodeInput& input = this->Input(i);
84 DCHECK_EQ(input.NumberOfChannels(), 1u);
85 AudioChannel* output_channel = output.Bus()->Channel(i);
86 if (input.IsConnected()) {
87 // The mixing rules will be applied so multiple channels are down-
88 // mixed to mono (when the mixing rule is defined). Note that only
89 // the first channel will be taken for the undefined input channel
90 // layout.
91 //
92 // See:
93 // http://webaudio.github.io/web-audio-api/#channel-up-mixing-and-down-mixing
94 AudioChannel* input_channel = input.Bus()->Channel(0);
95 output_channel->CopyFrom(input_channel);
96
97 } else {
98 // If input is unconnected, fill zeros in the channel.
99 output_channel->Zero();
100 }
101 }
102 }
103
SetChannelCount(unsigned channel_count,ExceptionState & exception_state)104 void ChannelMergerHandler::SetChannelCount(unsigned channel_count,
105 ExceptionState& exception_state) {
106 DCHECK(IsMainThread());
107 BaseAudioContext::GraphAutoLocker locker(Context());
108
109 // channelCount must be 1.
110 if (channel_count != 1) {
111 exception_state.ThrowDOMException(
112 DOMExceptionCode::kInvalidStateError,
113 "ChannelMerger: channelCount cannot be changed from 1");
114 }
115 }
116
SetChannelCountMode(const String & mode,ExceptionState & exception_state)117 void ChannelMergerHandler::SetChannelCountMode(
118 const String& mode,
119 ExceptionState& exception_state) {
120 DCHECK(IsMainThread());
121 BaseAudioContext::GraphAutoLocker locker(Context());
122
123 // channcelCountMode must be 'explicit'.
124 if (mode != "explicit") {
125 exception_state.ThrowDOMException(
126 DOMExceptionCode::kInvalidStateError,
127 "ChannelMerger: channelCountMode cannot be changed from 'explicit'");
128 }
129 }
130
131 // ----------------------------------------------------------------
132
ChannelMergerNode(BaseAudioContext & context,unsigned number_of_inputs)133 ChannelMergerNode::ChannelMergerNode(BaseAudioContext& context,
134 unsigned number_of_inputs)
135 : AudioNode(context) {
136 SetHandler(ChannelMergerHandler::Create(*this, context.sampleRate(),
137 number_of_inputs));
138 }
139
Create(BaseAudioContext & context,ExceptionState & exception_state)140 ChannelMergerNode* ChannelMergerNode::Create(BaseAudioContext& context,
141 ExceptionState& exception_state) {
142 DCHECK(IsMainThread());
143
144 // The default number of inputs for the merger node is 6.
145 return Create(context, 6, exception_state);
146 }
147
Create(BaseAudioContext & context,unsigned number_of_inputs,ExceptionState & exception_state)148 ChannelMergerNode* ChannelMergerNode::Create(BaseAudioContext& context,
149 unsigned number_of_inputs,
150 ExceptionState& exception_state) {
151 DCHECK(IsMainThread());
152
153 if (!number_of_inputs ||
154 number_of_inputs > BaseAudioContext::MaxNumberOfChannels()) {
155 exception_state.ThrowDOMException(
156 DOMExceptionCode::kIndexSizeError,
157 ExceptionMessages::IndexOutsideRange<size_t>(
158 "number of inputs", number_of_inputs, 1,
159 ExceptionMessages::kInclusiveBound,
160 BaseAudioContext::MaxNumberOfChannels(),
161 ExceptionMessages::kInclusiveBound));
162 return nullptr;
163 }
164
165 return MakeGarbageCollected<ChannelMergerNode>(context, number_of_inputs);
166 }
167
Create(BaseAudioContext * context,const ChannelMergerOptions * options,ExceptionState & exception_state)168 ChannelMergerNode* ChannelMergerNode::Create(
169 BaseAudioContext* context,
170 const ChannelMergerOptions* options,
171 ExceptionState& exception_state) {
172 ChannelMergerNode* node =
173 Create(*context, options->numberOfInputs(), exception_state);
174
175 if (!node)
176 return nullptr;
177
178 node->HandleChannelOptions(options, exception_state);
179
180 return node;
181 }
182
ReportDidCreate()183 void ChannelMergerNode::ReportDidCreate() {
184 GraphTracer().DidCreateAudioNode(this);
185 }
186
ReportWillBeDestroyed()187 void ChannelMergerNode::ReportWillBeDestroyed() {
188 GraphTracer().WillDestroyAudioNode(this);
189 }
190
191 } // namespace blink
192