- Revision
- 266518
- Author
- cdu...@apple.com
- Date
- 2020-09-03 08:33:04 -0700 (Thu, 03 Sep 2020)
Log Message
Make our implementation of ChannelMergerNode standards compliant
https://bugs.webkit.org/show_bug.cgi?id=216113
Reviewed by Darin Adler.
LayoutTests/imported/w3c:
Rebaseline WPT tests now that they are passing.
* web-platform-tests/webaudio/the-audio-api/the-channelmergernode-interface/audiochannelmerger-disconnect-expected.txt:
* web-platform-tests/webaudio/the-audio-api/the-channelmergernode-interface/audiochannelmerger-input-expected.txt:
* web-platform-tests/webaudio/the-audio-api/the-channelmergernode-interface/audiochannelmerger-input-non-default-expected.txt:
Source/WebCore:
This aligns our implementation of ChannelMergerNode with Chromium's, allowing us
to pass more web platform tests.
No new tests, rebaselined existing tests.
* Modules/webaudio/AudioNode.cpp:
(WebCore::AudioNode::disableOutputsIfNecessary):
(WebCore::AudioNode::disableOutputs):
* Modules/webaudio/AudioNode.h:
Split disableOutputs() out of disableOutputsIfNecessary() so that it can be called
directly.
* Modules/webaudio/AudioNodeInput.cpp:
(WebCore::AudioNodeInput::connect):
* Modules/webaudio/AudioNodeOutput.h:
(WebCore::AudioNodeOutput::isEnabled const):
When connected to an output, AudioNodeInput keeps the output either in m_outputs when
the output is enabled, m_disabledOutputs when it is disabled. AudioNodeInput's enable()
& disable() take care of moving the output from one map to another. However, connect()
would assume that the output we're connecting to is enabled and add it to m_outputs
unconditionally. This was causing an assertion to get hit in enable() later on because
the output we're trying to enable was not in m_disabledOutputs (because it was already
in m_outputs). This change is needed because the ChannelMergerNode now disables its
output right away, before it is connected.
* Modules/webaudio/ChannelMergerNode.cpp:
(WebCore::ChannelMergerNode::ChannelMergerNode):
Make sure that the output has a number of channels equal to the number of inputs.
Initially disable outputs so that we output a single silent channel until something
is connected.
(WebCore::ChannelMergerNode::process):
* Modules/webaudio/ChannelMergerNode.h:
Simplify code now that the number of inputs is equal to output's number of channels.
Modified Paths
Diff
Modified: trunk/LayoutTests/imported/w3c/ChangeLog (266517 => 266518)
--- trunk/LayoutTests/imported/w3c/ChangeLog 2020-09-03 15:29:57 UTC (rev 266517)
+++ trunk/LayoutTests/imported/w3c/ChangeLog 2020-09-03 15:33:04 UTC (rev 266518)
@@ -1,3 +1,16 @@
+2020-09-03 Chris Dumez <cdu...@apple.com>
+
+ Make our implementation of ChannelMergerNode standards compliant
+ https://bugs.webkit.org/show_bug.cgi?id=216113
+
+ Reviewed by Darin Adler.
+
+ Rebaseline WPT tests now that they are passing.
+
+ * web-platform-tests/webaudio/the-audio-api/the-channelmergernode-interface/audiochannelmerger-disconnect-expected.txt:
+ * web-platform-tests/webaudio/the-audio-api/the-channelmergernode-interface/audiochannelmerger-input-expected.txt:
+ * web-platform-tests/webaudio/the-audio-api/the-channelmergernode-interface/audiochannelmerger-input-non-default-expected.txt:
+
2020-09-03 Youenn Fablet <you...@apple.com>
Expose RTCPeerConnection.restartIce
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/webaudio/the-audio-api/the-channelmergernode-interface/audiochannelmerger-disconnect-expected.txt (266517 => 266518)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/webaudio/the-audio-api/the-channelmergernode-interface/audiochannelmerger-disconnect-expected.txt 2020-09-03 15:29:57 UTC (rev 266517)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/webaudio/the-audio-api/the-channelmergernode-interface/audiochannelmerger-disconnect-expected.txt 2020-09-03 15:33:04 UTC (rev 266518)
@@ -4,8 +4,8 @@
PASS Audit report
PASS > [silent-disconnect]
PASS Channel #0 contains only the constant 1.
-FAIL X Channel #1 expected to have the value sequence of [1,0] but got 1 values, [1], instead of 2. assert_true: expected true got false
-FAIL X The index of first zero in the channel #1 is not equal to 11136. Got -1. assert_true: expected true got false
-FAIL < [silent-disconnect] 2 out of 3 assertions were failed. assert_true: expected true got false
-FAIL # AUDIT TASK RUNNER FINISHED: 1 out of 1 tasks were failed. assert_true: expected true got false
+PASS Channel #1 contains all the expected values in the correct order: [1,0].
+PASS The index of first zero in the channel #1 is equal to 11136.
+PASS < [silent-disconnect] All assertions passed. (total 3 assertions)
+PASS # AUDIT TASK RUNNER FINISHED: 1 tasks ran successfully.
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/webaudio/the-audio-api/the-channelmergernode-interface/audiochannelmerger-input-expected.txt (266517 => 266518)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/webaudio/the-audio-api/the-channelmergernode-interface/audiochannelmerger-input-expected.txt 2020-09-03 15:29:57 UTC (rev 266517)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/webaudio/the-audio-api/the-channelmergernode-interface/audiochannelmerger-input-expected.txt 2020-09-03 15:33:04 UTC (rev 266518)
@@ -8,66 +8,30 @@
PASS > [silent-channel]
PASS 1-channel source: Channel #0 contains only the constant 0.
PASS 1-channel source: Channel #1 contains only the constant 0.
-FAIL X 1-channel source: Channel #2: Expected 0 for all values but found 128 unexpected values:
- Index Actual
- [0] 1
- [1] 1
- [2] 1
- [3] 1
- ...and 124 more errors. assert_true: expected true got false
-FAIL X 1-channel source: Channel #3: Expected 1 for all values but found 128 unexpected values:
- Index Actual
- [0] 0
- [1] 0
- [2] 0
- [3] 0
- ...and 124 more errors. assert_true: expected true got false
+PASS 1-channel source: Channel #2 contains only the constant 0.
+PASS 1-channel source: Channel #3 contains only the constant 1.
PASS 1-channel source: Channel #4 contains only the constant 0.
PASS 1-channel source: Channel #5 contains only the constant 0.
-FAIL < [silent-channel] 2 out of 6 assertions were failed. assert_true: expected true got false
+PASS < [silent-channel] All assertions passed. (total 6 assertions)
PASS > [stereo-down-mixing]
-FAIL X 2-channel source: Channel #0: Expected 1.5 for all values but found 128 unexpected values:
- Index Actual
- [0] 0
- [1] 0
- [2] 0
- [3] 0
- ...and 124 more errors. assert_true: expected true got false
+PASS 2-channel source: Channel #0 contains only the constant 1.5.
PASS 2-channel source: Channel #1 contains only the constant 0.
-FAIL X 2-channel source: Channel #2: Expected 0 for all values but found 128 unexpected values:
- Index Actual
- [0] 1.5
- [1] 1.5
- [2] 1.5
- [3] 1.5
- ...and 124 more errors. assert_true: expected true got false
+PASS 2-channel source: Channel #2 contains only the constant 0.
PASS 2-channel source: Channel #3 contains only the constant 0.
PASS 2-channel source: Channel #4 contains only the constant 0.
PASS 2-channel source: Channel #5 contains only the constant 0.
-FAIL < [stereo-down-mixing] 2 out of 6 assertions were failed. assert_true: expected true got false
+PASS < [stereo-down-mixing] All assertions passed. (total 6 assertions)
PASS > [undefined-channel-layout]
-FAIL X 3-channel source: Channel #0: Expected 1 for all values but found 128 unexpected values:
- Index Actual
- [0] 0
- [1] 0
- [2] 0
- [3] 0
- ...and 124 more errors. assert_true: expected true got false
+PASS 3-channel source: Channel #0 contains only the constant 1.
PASS 3-channel source: Channel #1 contains only the constant 0.
-FAIL X 3-channel source: Channel #2: Expected 0 for all values but found 128 unexpected values:
- Index Actual
- [0] 1
- [1] 1
- [2] 1
- [3] 1
- ...and 124 more errors. assert_true: expected true got false
+PASS 3-channel source: Channel #2 contains only the constant 0.
PASS 3-channel source: Channel #3 contains only the constant 0.
PASS 3-channel source: Channel #4 contains only the constant 0.
PASS 3-channel source: Channel #5 contains only the constant 0.
-FAIL < [undefined-channel-layout] 2 out of 6 assertions were failed. assert_true: expected true got false
+PASS < [undefined-channel-layout] All assertions passed. (total 6 assertions)
PASS > [merging-to-stereo]
PASS Channel #0 contains only the constant 1.
PASS Channel #1 contains only the constant -1.
PASS < [merging-to-stereo] All assertions passed. (total 2 assertions)
-FAIL # AUDIT TASK RUNNER FINISHED: 3 out of 4 tasks were failed. assert_true: expected true got false
+PASS # AUDIT TASK RUNNER FINISHED: 4 tasks ran successfully.
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/webaudio/the-audio-api/the-channelmergernode-interface/audiochannelmerger-input-non-default-expected.txt (266517 => 266518)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/webaudio/the-audio-api/the-channelmergernode-interface/audiochannelmerger-input-non-default-expected.txt 2020-09-03 15:29:57 UTC (rev 266517)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/webaudio/the-audio-api/the-channelmergernode-interface/audiochannelmerger-input-non-default-expected.txt 2020-09-03 15:33:04 UTC (rev 266518)
@@ -5,67 +5,31 @@
PASS Executing "undefined-channel-layout"
PASS Audit report
PASS > [silent-channel]
-FAIL X 1-channel source: Channel #0: Expected 0 for all values but found 128 unexpected values:
- Index Actual
- [0] 1
- [1] 1
- [2] 1
- [3] 1
- ...and 124 more errors. assert_true: expected true got false
+PASS 1-channel source: Channel #0 contains only the constant 0.
PASS 1-channel source: Channel #1 contains only the constant 0.
PASS 1-channel source: Channel #2 contains only the constant 0.
PASS 1-channel source: Channel #3 contains only the constant 0.
PASS 1-channel source: Channel #4 contains only the constant 0.
PASS 1-channel source: Channel #5 contains only the constant 0.
-FAIL X 1-channel source: Channel #6: Expected 1 for all values but found 128 unexpected values:
- Index Actual
- [0] 0
- [1] 0
- [2] 0
- [3] 0
- ...and 124 more errors. assert_true: expected true got false
-FAIL < [silent-channel] 2 out of 7 assertions were failed. assert_true: expected true got false
+PASS 1-channel source: Channel #6 contains only the constant 1.
+PASS < [silent-channel] All assertions passed. (total 7 assertions)
PASS > [stereo-down-mixing]
-FAIL X 2-channel source: Channel #0: Expected 0 for all values but found 128 unexpected values:
- Index Actual
- [0] 1.5
- [1] 1.5
- [2] 1.5
- [3] 1.5
- ...and 124 more errors. assert_true: expected true got false
+PASS 2-channel source: Channel #0 contains only the constant 0.
PASS 2-channel source: Channel #1 contains only the constant 0.
PASS 2-channel source: Channel #2 contains only the constant 0.
PASS 2-channel source: Channel #3 contains only the constant 0.
PASS 2-channel source: Channel #4 contains only the constant 0.
PASS 2-channel source: Channel #5 contains only the constant 0.
-FAIL X 2-channel source: Channel #6: Expected 1.5 for all values but found 128 unexpected values:
- Index Actual
- [0] 0
- [1] 0
- [2] 0
- [3] 0
- ...and 124 more errors. assert_true: expected true got false
-FAIL < [stereo-down-mixing] 2 out of 7 assertions were failed. assert_true: expected true got false
+PASS 2-channel source: Channel #6 contains only the constant 1.5.
+PASS < [stereo-down-mixing] All assertions passed. (total 7 assertions)
PASS > [undefined-channel-layout]
-FAIL X 3-channel source: Channel #0: Expected 0 for all values but found 128 unexpected values:
- Index Actual
- [0] 1
- [1] 1
- [2] 1
- [3] 1
- ...and 124 more errors. assert_true: expected true got false
+PASS 3-channel source: Channel #0 contains only the constant 0.
PASS 3-channel source: Channel #1 contains only the constant 0.
PASS 3-channel source: Channel #2 contains only the constant 0.
PASS 3-channel source: Channel #3 contains only the constant 0.
PASS 3-channel source: Channel #4 contains only the constant 0.
PASS 3-channel source: Channel #5 contains only the constant 0.
-FAIL X 3-channel source: Channel #6: Expected 1 for all values but found 128 unexpected values:
- Index Actual
- [0] 0
- [1] 0
- [2] 0
- [3] 0
- ...and 124 more errors. assert_true: expected true got false
-FAIL < [undefined-channel-layout] 2 out of 7 assertions were failed. assert_true: expected true got false
-FAIL # AUDIT TASK RUNNER FINISHED: 3 out of 3 tasks were failed. assert_true: expected true got false
+PASS 3-channel source: Channel #6 contains only the constant 1.
+PASS < [undefined-channel-layout] All assertions passed. (total 7 assertions)
+PASS # AUDIT TASK RUNNER FINISHED: 3 tasks ran successfully.
Modified: trunk/Source/WebCore/ChangeLog (266517 => 266518)
--- trunk/Source/WebCore/ChangeLog 2020-09-03 15:29:57 UTC (rev 266517)
+++ trunk/Source/WebCore/ChangeLog 2020-09-03 15:33:04 UTC (rev 266518)
@@ -1,3 +1,45 @@
+2020-09-03 Chris Dumez <cdu...@apple.com>
+
+ Make our implementation of ChannelMergerNode standards compliant
+ https://bugs.webkit.org/show_bug.cgi?id=216113
+
+ Reviewed by Darin Adler.
+
+ This aligns our implementation of ChannelMergerNode with Chromium's, allowing us
+ to pass more web platform tests.
+
+ No new tests, rebaselined existing tests.
+
+ * Modules/webaudio/AudioNode.cpp:
+ (WebCore::AudioNode::disableOutputsIfNecessary):
+ (WebCore::AudioNode::disableOutputs):
+ * Modules/webaudio/AudioNode.h:
+ Split disableOutputs() out of disableOutputsIfNecessary() so that it can be called
+ directly.
+
+ * Modules/webaudio/AudioNodeInput.cpp:
+ (WebCore::AudioNodeInput::connect):
+ * Modules/webaudio/AudioNodeOutput.h:
+ (WebCore::AudioNodeOutput::isEnabled const):
+ When connected to an output, AudioNodeInput keeps the output either in m_outputs when
+ the output is enabled, m_disabledOutputs when it is disabled. AudioNodeInput's enable()
+ & disable() take care of moving the output from one map to another. However, connect()
+ would assume that the output we're connecting to is enabled and add it to m_outputs
+ unconditionally. This was causing an assertion to get hit in enable() later on because
+ the output we're trying to enable was not in m_disabledOutputs (because it was already
+ in m_outputs). This change is needed because the ChannelMergerNode now disables its
+ output right away, before it is connected.
+
+ * Modules/webaudio/ChannelMergerNode.cpp:
+ (WebCore::ChannelMergerNode::ChannelMergerNode):
+ Make sure that the output has a number of channels equal to the number of inputs.
+ Initially disable outputs so that we output a single silent channel until something
+ is connected.
+
+ (WebCore::ChannelMergerNode::process):
+ * Modules/webaudio/ChannelMergerNode.h:
+ Simplify code now that the number of inputs is equal to output's number of channels.
+
2020-09-03 Alex Christensen <achristen...@webkit.org>
Use unicode macros instead of manual range checks in TextCodecUTF16
Modified: trunk/Source/WebCore/Modules/webaudio/AudioNode.cpp (266517 => 266518)
--- trunk/Source/WebCore/Modules/webaudio/AudioNode.cpp 2020-09-03 15:29:57 UTC (rev 266517)
+++ trunk/Source/WebCore/Modules/webaudio/AudioNode.cpp 2020-09-03 15:33:04 UTC (rev 266518)
@@ -551,14 +551,18 @@
// If a node requires tail processing, we defer the disabling of
// the outputs so that the tail for the node can be output.
// Otherwise, we can disable the outputs right away.
- if (!requiresTailProcessing()) {
- m_isDisabled = true;
- for (auto& output : m_outputs)
- output->disable();
- }
+ if (!requiresTailProcessing())
+ disableOutputs();
}
}
+void AudioNode::disableOutputs()
+{
+ m_isDisabled = true;
+ for (auto& output : m_outputs)
+ output->disable();
+}
+
void AudioNode::ref(RefType refType)
{
switch (refType) {
Modified: trunk/Source/WebCore/Modules/webaudio/AudioNode.h (266517 => 266518)
--- trunk/Source/WebCore/Modules/webaudio/AudioNode.h 2020-09-03 15:29:57 UTC (rev 266517)
+++ trunk/Source/WebCore/Modules/webaudio/AudioNode.h 2020-09-03 15:33:04 UTC (rev 266518)
@@ -187,6 +187,7 @@
void enableOutputsIfNecessary();
void disableOutputsIfNecessary();
+ void disableOutputs();
unsigned channelCount() const { return m_channelCount; }
virtual ExceptionOr<void> setChannelCount(unsigned);
Modified: trunk/Source/WebCore/Modules/webaudio/AudioNodeInput.cpp (266517 => 266518)
--- trunk/Source/WebCore/Modules/webaudio/AudioNodeInput.cpp 2020-09-03 15:29:57 UTC (rev 266517)
+++ trunk/Source/WebCore/Modules/webaudio/AudioNodeInput.cpp 2020-09-03 15:33:04 UTC (rev 266518)
@@ -52,10 +52,11 @@
if (!output || !node())
return;
+ auto& outputsMap = output->isEnabled() ? m_outputs : m_disabledOutputs;
// Check if we're already connected to this output.
- if (!m_outputs.add(output).isNewEntry)
+ if (!outputsMap.add(output).isNewEntry)
return;
-
+
output->addInput(this);
changedOutputs();
Modified: trunk/Source/WebCore/Modules/webaudio/AudioNodeOutput.h (266517 => 266518)
--- trunk/Source/WebCore/Modules/webaudio/AudioNodeOutput.h 2020-09-03 15:29:57 UTC (rev 266517)
+++ trunk/Source/WebCore/Modules/webaudio/AudioNodeOutput.h 2020-09-03 15:33:04 UTC (rev 266518)
@@ -84,6 +84,8 @@
void disable();
void enable();
+ bool isEnabled() const { return m_isEnabled; }
+
// updateRenderingState() is called in the audio thread at the start or end of the render quantum to handle any recent changes to the graph state.
// It must be called with the context's graph lock.
void updateRenderingState();
Modified: trunk/Source/WebCore/Modules/webaudio/ChannelMergerNode.cpp (266517 => 266518)
--- trunk/Source/WebCore/Modules/webaudio/ChannelMergerNode.cpp 2020-09-03 15:29:57 UTC (rev 266517)
+++ trunk/Source/WebCore/Modules/webaudio/ChannelMergerNode.cpp 2020-09-03 15:33:04 UTC (rev 266518)
@@ -37,8 +37,6 @@
#include "AudioNodeOutput.h"
#include <wtf/IsoMallocInlines.h>
-const unsigned DefaultNumberOfOutputChannels = 1;
-
namespace WebCore {
WTF_MAKE_ISO_ALLOCATED_IMPL(ChannelMergerNode);
@@ -64,7 +62,6 @@
ChannelMergerNode::ChannelMergerNode(BaseAudioContext& context, unsigned numberOfInputs)
: AudioNode(context)
- , m_desiredNumberOfOutputChannels(DefaultNumberOfOutputChannels)
{
setNodeType(NodeTypeChannelMerger);
@@ -72,9 +69,12 @@
for (unsigned i = 0; i < numberOfInputs; ++i)
addInput(makeUnique<AudioNodeInput>(this));
- addOutput(makeUnique<AudioNodeOutput>(this, 1));
+ addOutput(makeUnique<AudioNodeOutput>(this, numberOfInputs));
initialize();
+
+ BaseAudioContext::AutoLocker contextLocker(context);
+ disableOutputs();
}
void ChannelMergerNode::process(size_t framesToProcess)
@@ -82,32 +82,28 @@
AudioNodeOutput* output = this->output(0);
ASSERT(output);
ASSERT_UNUSED(framesToProcess, framesToProcess == output->bus()->length());
-
- // Output bus not updated yet, so just output silence.
- if (m_desiredNumberOfOutputChannels != output->numberOfChannels()) {
- output->bus()->zero();
- return;
- }
+ ASSERT(numberOfInputs() == output->numberOfChannels());
// Merge all the channels from all the inputs into one output.
- unsigned outputChannelIndex = 0;
for (unsigned i = 0; i < numberOfInputs(); ++i) {
AudioNodeInput* input = this->input(i);
+ ASSERT(input->numberOfChannels() == 1u);
+ auto* outputChannel = output->bus()->channel(i);
if (input->isConnected()) {
- unsigned numberOfInputChannels = input->bus()->numberOfChannels();
-
- // Merge channels from this particular input.
- for (unsigned j = 0; j < numberOfInputChannels; ++j) {
- AudioChannel* inputChannel = input->bus()->channel(j);
- AudioChannel* outputChannel = output->bus()->channel(outputChannelIndex);
- outputChannel->copyFrom(inputChannel);
-
- ++outputChannelIndex;
- }
+ // The mixing rules will be applied so multiple channels are down-
+ // mixed to mono (when the mixing rule is defined). Note that only
+ // the first channel will be taken for the undefined input channel
+ // layout.
+ //
+ // See:
+ // http://webaudio.github.io/web-audio-api/#channel-up-mixing-and-down-mixing
+ auto* inputChannel = input->bus()->channel(0);
+ outputChannel->copyFrom(inputChannel);
+ } else {
+ // If input is unconnected, fill zeros in the channel.
+ outputChannel->zero();
}
}
-
- ASSERT(outputChannelIndex == output->numberOfChannels());
}
void ChannelMergerNode::reset()
@@ -114,32 +110,6 @@
{
}
-// Any time a connection or disconnection happens on any of our inputs, we potentially need to change the
-// number of channels of our output.
-void ChannelMergerNode::checkNumberOfChannelsForInput(AudioNodeInput* input)
-{
- ASSERT(context().isAudioThread() && context().isGraphOwner());
-
- // Count how many channels we have all together from all of the inputs.
- unsigned numberOfOutputChannels = 0;
- for (unsigned i = 0; i < numberOfInputs(); ++i) {
- AudioNodeInput* input = this->input(i);
- if (input->isConnected())
- numberOfOutputChannels += input->numberOfChannels();
- }
-
- // Set the correct number of channels on the output
- AudioNodeOutput* output = this->output(0);
- ASSERT(output);
- output->setNumberOfChannels(numberOfOutputChannels);
- // There can in rare cases be a slight delay before the output bus is updated to the new number of
- // channels because of tryLocks() in the context's updating system. So record the new number of
- // output channels here.
- m_desiredNumberOfOutputChannels = numberOfOutputChannels;
-
- AudioNode::checkNumberOfChannelsForInput(input);
-}
-
ExceptionOr<void> ChannelMergerNode::setChannelCount(unsigned channelCount)
{
if (channelCount != 1)
Modified: trunk/Source/WebCore/Modules/webaudio/ChannelMergerNode.h (266517 => 266518)
--- trunk/Source/WebCore/Modules/webaudio/ChannelMergerNode.h 2020-09-03 15:29:57 UTC (rev 266517)
+++ trunk/Source/WebCore/Modules/webaudio/ChannelMergerNode.h 2020-09-03 15:33:04 UTC (rev 266518)
@@ -43,16 +43,11 @@
// AudioNode
void process(size_t framesToProcess) override;
void reset() override;
-
- // Called in the audio thread (pre-rendering task) when the number of channels for an input may have changed.
- void checkNumberOfChannelsForInput(AudioNodeInput*) override;
ExceptionOr<void> setChannelCount(unsigned) final;
ExceptionOr<void> setChannelCountMode(ChannelCountMode) final;
private:
- unsigned m_desiredNumberOfOutputChannels;
-
double tailTime() const override { return 0; }
double latencyTime() const override { return 0; }
bool requiresTailProcessing() const final { return false; }