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 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
|
// 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/constant_source_handler.h"
#include <tuple>
#include "base/compiler_specific.h"
#include "third_party/blink/renderer/modules/webaudio/audio_node_output.h"
namespace blink {
namespace {
// A ConstantSource is always mono.
constexpr unsigned kNumberOfOutputChannels = 1;
} // namespace
ConstantSourceHandler::ConstantSourceHandler(AudioNode& node,
float sample_rate,
AudioParamHandler& offset)
: AudioScheduledSourceHandler(NodeType::kNodeTypeConstantSource,
node,
sample_rate),
offset_(&offset),
sample_accurate_values_(GetDeferredTaskHandler().RenderQuantumFrames()) {
AddOutput(kNumberOfOutputChannels);
Initialize();
}
scoped_refptr<ConstantSourceHandler> ConstantSourceHandler::Create(
AudioNode& node,
float sample_rate,
AudioParamHandler& offset) {
return base::AdoptRef(new ConstantSourceHandler(node, sample_rate, offset));
}
ConstantSourceHandler::~ConstantSourceHandler() {
Uninitialize();
}
void ConstantSourceHandler::Process(uint32_t frames_to_process) {
AudioBus* output_bus = Output(0).Bus();
DCHECK(output_bus);
if (!IsInitialized() || !output_bus->NumberOfChannels()) {
output_bus->Zero();
return;
}
// The audio thread can't block on this lock, so we call tryLock() instead.
base::AutoTryLock try_locker(process_lock_);
if (!try_locker.is_acquired()) {
// Too bad - the tryLock() failed.
output_bus->Zero();
return;
}
size_t quantum_frame_offset;
size_t non_silent_frames_to_process;
double start_frame_offset;
// Figure out where in the current rendering quantum that the source is
// active and for how many frames.
std::tie(quantum_frame_offset, non_silent_frames_to_process,
start_frame_offset) =
UpdateSchedulingInfo(frames_to_process, output_bus);
if (!non_silent_frames_to_process) {
output_bus->Zero();
return;
}
bool is_sample_accurate = offset_->HasSampleAccurateValues();
if (is_sample_accurate && offset_->IsAudioRate()) {
DCHECK_LE(frames_to_process, sample_accurate_values_.size());
float* offsets = sample_accurate_values_.Data();
offset_->CalculateSampleAccurateValues(
sample_accurate_values_.as_span().first(frames_to_process));
if (non_silent_frames_to_process > 0) {
UNSAFE_TODO(
memcpy(output_bus->Channel(0)->MutableData() + quantum_frame_offset,
offsets + quantum_frame_offset,
non_silent_frames_to_process * sizeof(*offsets)));
output_bus->ClearSilentFlag();
} else {
output_bus->Zero();
}
return;
}
float value = is_sample_accurate ? offset_->FinalValue() : offset_->Value();
if (value == 0) {
output_bus->Zero();
} else {
UNSAFE_TODO({
float* dest = output_bus->Channel(0)->MutableData();
dest += quantum_frame_offset;
for (unsigned k = 0; k < non_silent_frames_to_process; ++k) {
dest[k] = value;
}
output_bus->ClearSilentFlag();
});
}
}
bool ConstantSourceHandler::PropagatesSilence() const {
return !IsPlayingOrScheduled() || HasFinished();
}
void ConstantSourceHandler::HandleStoppableSourceNode() {
double now = Context()->currentTime();
base::AutoTryLock try_locker(process_lock_);
if (!try_locker.is_acquired()) {
// Can't get the lock, so just return. It's ok to handle these at a later
// time; this was just a hint anyway so stopping them a bit later is ok.
return;
}
// If we know the end time, and the source was started and the current time is
// definitely past the end time, we can stop this node. (This handles the
// case where the this source is not connected to the destination and we want
// to stop it.)
if (end_time_ != kUnknownTime && IsPlayingOrScheduled() &&
now >= end_time_ + kExtraStopFrames / Context()->sampleRate()) {
Finish();
}
}
base::WeakPtr<AudioScheduledSourceHandler> ConstantSourceHandler::AsWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
} // namespace blink
|