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