1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
|
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/modules/webaudio/channel_splitter_handler.h"
#include "third_party/blink/renderer/modules/webaudio/audio_node_input.h"
#include "third_party/blink/renderer/modules/webaudio/audio_node_output.h"
#include "third_party/blink/renderer/modules/webaudio/base_audio_context.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/wtf/text/strcat.h"
namespace blink {
namespace {
constexpr unsigned kNumberOfOutputChannels = 1;
} // namespace
ChannelSplitterHandler::ChannelSplitterHandler(AudioNode& node,
float sample_rate,
unsigned number_of_outputs)
: AudioHandler(NodeType::kNodeTypeChannelSplitter, node, sample_rate) {
// These properties are fixed and cannot be changed by the user.
channel_count_ = number_of_outputs;
SetInternalChannelCountMode(V8ChannelCountMode::Enum::kExplicit);
SetInternalChannelInterpretation(AudioBus::kDiscrete);
AddInput();
// Create a fixed number of outputs (able to handle the maximum number of
// channels fed to an input).
for (unsigned i = 0; i < number_of_outputs; ++i) {
AddOutput(kNumberOfOutputChannels);
}
Initialize();
}
scoped_refptr<ChannelSplitterHandler> ChannelSplitterHandler::Create(
AudioNode& node,
float sample_rate,
unsigned number_of_outputs) {
return base::AdoptRef(
new ChannelSplitterHandler(node, sample_rate, number_of_outputs));
}
void ChannelSplitterHandler::Process(uint32_t frames_to_process) {
scoped_refptr<AudioBus> source = Input(0).Bus();
DCHECK(source);
DCHECK_EQ(frames_to_process, source->length());
unsigned number_of_source_channels = source->NumberOfChannels();
for (unsigned i = 0; i < NumberOfOutputs(); ++i) {
AudioBus* destination = Output(i).Bus();
DCHECK(destination);
if (i < number_of_source_channels) {
// Split the channel out if it exists in the source.
// It would be nice to avoid the copy and simply pass along pointers, but
// this becomes extremely difficult with fanout and fanin.
destination->Channel(0)->CopyFrom(source->Channel(i));
} else if (Output(i).RenderingFanOutCount() > 0) {
// Only bother zeroing out the destination if it's connected to anything
destination->Zero();
}
}
}
void ChannelSplitterHandler::SetChannelCount(unsigned channel_count,
ExceptionState& exception_state) {
DCHECK(IsMainThread());
DeferredTaskHandler::GraphAutoLocker locker(Context());
// channelCount cannot be changed from the number of outputs.
if (channel_count != NumberOfOutputs()) {
exception_state.ThrowDOMException(
DOMExceptionCode::kInvalidStateError,
StrCat({"ChannelSplitter: channelCount cannot be changed from ",
String::Number(NumberOfOutputs())}));
}
}
void ChannelSplitterHandler::SetChannelCountMode(
V8ChannelCountMode::Enum mode,
ExceptionState& exception_state) {
DCHECK(IsMainThread());
DeferredTaskHandler::GraphAutoLocker locker(Context());
// channcelCountMode must be 'explicit'.
if (mode != V8ChannelCountMode::Enum::kExplicit) {
exception_state.ThrowDOMException(
DOMExceptionCode::kInvalidStateError,
"ChannelSplitter: channelCountMode cannot be changed from 'explicit'");
}
}
void ChannelSplitterHandler::SetChannelInterpretation(
V8ChannelInterpretation::Enum mode,
ExceptionState& exception_state) {
DCHECK(IsMainThread());
DeferredTaskHandler::GraphAutoLocker locker(Context());
// channelInterpretation must be "discrete"
if (mode != V8ChannelInterpretation::Enum::kDiscrete) {
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
"ChannelSplitter: channelInterpretation "
"cannot be changed from 'discrete'");
}
}
} // namespace blink
|