Skip to content

Commit

Permalink
cras_processor: Support variable block sizes
Browse files Browse the repository at this point in the history
BUG=b:383924467
TEST=bazel test //...

Change-Id: I66b142230a887afa872f48d9d9471c09ca8d30c3
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/adhd/+/6090659
Tested-by: [email protected] <[email protected]>
Reviewed-by: Hung-Hsien Chen <[email protected]>
Commit-Queue: Li-Yu Yu <[email protected]>
  • Loading branch information
afq984 authored and Chromeos LUCI committed Dec 18, 2024
1 parent ea30799 commit a6751ae
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 18 deletions.
4 changes: 3 additions & 1 deletion audio_processor/src/cdcfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ fn resolve(
.inner_block_size
.try_into()
.context("wrap_chunk inner_block_size")?,
disallow_hoisting: false,
},
Resample(resample) => Processor::Resample {
output_frame_rate: resample
Expand Down Expand Up @@ -334,7 +335,8 @@ mod tests {
inner: Box::new(Processor::Resample {
output_frame_rate: 24000
}),
inner_block_size: 10
inner_block_size: 10,
disallow_hoisting: false,
},
Processor::Plugin {
path: PathBuf::from("foo"),
Expand Down
11 changes: 10 additions & 1 deletion audio_processor/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ pub enum Processor {
WrapChunk {
inner: Box<Processor>,
inner_block_size: usize,
/// Prevents merging with the outer pipeline even if they have the same block size.
/// Used when the outer pipeline doesn't actually have a stable block size and the
/// ChunkWrapper is used for regulating it.
disallow_hoisting: bool,
},
Resample {
output_frame_rate: usize,
Expand Down Expand Up @@ -208,8 +212,9 @@ impl PipelineBuilder {
WrapChunk {
inner,
inner_block_size,
disallow_hoisting,
} => {
if self.output_format().block_size == inner_block_size {
if self.output_format().block_size == inner_block_size && !disallow_hoisting {
self.add(*inner).context("inner")?;
} else {
let inner_pipeline = self
Expand Down Expand Up @@ -336,6 +341,7 @@ mod tests {
WrapChunk {
inner: Box::new(Negate),
inner_block_size: 1,
disallow_hoisting: false,
},
WavSink {
path: tempdir.path().join("2.wav"),
Expand All @@ -353,12 +359,14 @@ mod tests {
],
}),
inner_block_size: 2,
disallow_hoisting: false,
},
WrapChunk {
inner_block_size: 5, // Same block size, should pass through.
inner: Box::new(WavSink {
path: tempdir.path().join("5.wav"),
}),
disallow_hoisting: false,
},
Resample {
output_frame_rate: 48000,
Expand Down Expand Up @@ -725,6 +733,7 @@ mod bazel_tests {
],
}),
inner_block_size: 4096,
disallow_hoisting: false,
},
],
})
Expand Down
1 change: 0 additions & 1 deletion cras/server/processor/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ cc_test(
deps = [
":cc",
"@pkg_config//gtest",
"@pkg_config//gtest_main",
],
)

Expand Down
61 changes: 61 additions & 0 deletions cras/server/processor/cras_processor_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <span>
#include <vector>

#include "audio_processor/c/plugin_processor.h"
Expand Down Expand Up @@ -81,6 +82,7 @@ TEST_P(CrasProcessor, Simple) {
.block_size = 480,
.frame_rate = 48000,
.effect = GetParam().effect,
// wrap_mode is implicitly WrapModeNone.
};

auto r = cras_processor_create(&cfg, GetParam().apm);
Expand Down Expand Up @@ -117,3 +119,62 @@ TEST_P(CrasProcessor, Simple) {

processor->ops->destroy(processor);
}

TEST_P(CrasProcessor, Negate) {
CrasProcessorConfig cfg = {
.channels = 2,
.block_size = 2,
.frame_rate = 48000,
.effect = GetParam().effect,
.wrap_mode = WrapModeChunk,
};
const float m = GetParam().expected_output_mult;
auto r = cras_processor_create(&cfg, GetParam().apm);
plugin_processor* processor = r.plugin_processor;
ASSERT_EQ(r.effect, cfg.effect);
ASSERT_THAT(processor, testing::NotNull());

{
std::vector<float> ch0 = {1, 2, 3};
std::vector<float> ch1 = {4, 5, 6};
multi_slice input = {
.channels = 2,
.num_frames = ch0.size(),
.data = {ch0.data(), ch1.data()},
};
multi_slice output = {};
ASSERT_EQ(processor->ops->run(processor, &input, &output), StatusOk);
ASSERT_EQ(output.channels, 2);
ASSERT_EQ(output.num_frames, 3);
EXPECT_THAT(std::span(output.data[0], output.num_frames),
testing::ElementsAre(m * 0, m * 0, m * 1));
EXPECT_THAT(std::span(output.data[1], output.num_frames),
testing::ElementsAre(m * 0, m * 0, m * 4));
}

{
std::vector<float> ch0 = {7, 8, 9, 10};
std::vector<float> ch1 = {11, 12, 13, 14};
multi_slice input = {
.channels = 2,
.num_frames = ch0.size(),
.data = {ch0.data(), ch1.data()},
};
multi_slice output = {};
ASSERT_EQ(processor->ops->run(processor, &input, &output), StatusOk);
ASSERT_EQ(output.channels, 2);
ASSERT_EQ(output.num_frames, 4);
EXPECT_THAT(std::span(output.data[0], output.num_frames),
testing::ElementsAre(m * 2, m * 3, m * 7, m * 8));
EXPECT_THAT(std::span(output.data[1], output.num_frames),
testing::ElementsAre(m * 5, m * 6, m * 11, m * 12));
}

processor->ops->destroy(processor);
}

int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
cras_rust_init_logging();
return RUN_ALL_TESTS();
}
16 changes: 15 additions & 1 deletion cras/server/processor/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,20 @@ extern "C" {
#include "audio_processor/c/plugin_processor.h"
#include "cras/common/rust_common.h"

enum CrasProcessorWrapMode {
WrapModeNone,
/**
* Run the processor pipeline in a separate, dedicated thread.
*/
WrapModeDedicatedThread,
/**
* Run the processor pipeline with a ChunkWrapper.
* In this mode, the caller is allowed to run the pipeline with a block
* size that is different from `CrasProcessorConfig::block_size`
*/
WrapModeChunk,
};

struct CrasProcessorCreateResult {
/**
* The created processor.
Expand All @@ -37,7 +51,7 @@ struct CrasProcessorConfig {
size_t block_size;
size_t frame_rate;
enum CrasProcessorEffect effect;
bool dedicated_thread;
enum CrasProcessorWrapMode wrap_mode;
bool wav_dump;
};

Expand Down
41 changes: 31 additions & 10 deletions cras/server/processor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,18 @@ use cras_s2::global::cras_s2_get_cras_processor_vars;
mod processor_override;
mod proto;

#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub enum CrasProcessorWrapMode {
WrapModeNone,
/// Run the processor pipeline in a separate, dedicated thread.
WrapModeDedicatedThread,
/// Run the processor pipeline with a ChunkWrapper.
/// In this mode, the caller is allowed to run the pipeline with a block
/// size that is different from `CrasProcessorConfig::block_size`
WrapModeChunk,
}

#[repr(C)]
#[derive(Clone, Debug)]
pub struct CrasProcessorConfig {
Expand All @@ -42,8 +54,7 @@ pub struct CrasProcessorConfig {

effect: CrasProcessorEffect,

// Run the processor pipeline in a separate, dedicated thread.
dedicated_thread: bool,
wrap_mode: CrasProcessorWrapMode,

// Enable processing dumps as WAVE files.
wav_dump: bool,
Expand Down Expand Up @@ -226,6 +237,7 @@ impl CrasProcessor {
block_size => Processor::WrapChunk {
inner_block_size: block_size as usize,
inner: Box::new(plugin),
disallow_hoisting: false,
},
});
}
Expand All @@ -249,11 +261,21 @@ impl CrasProcessor {
});
}

let decl_debug = format!("{decl:?}");
let pipeline = if matches!(config.wrap_mode, CrasProcessorWrapMode::WrapModeChunk) {
Processor::WrapChunk {
inner: Box::new(Processor::Pipeline { processors: decl }),
inner_block_size: config.block_size,
disallow_hoisting: true,
}
} else {
Processor::Pipeline { processors: decl }
};

let decl_debug = format!("{pipeline:?}");
let pipeline = PipelineBuilder::new(config.format())
// TODO(b/349784210): Use a hardened worker factory.
.with_worker_factory(AudioWorkerSubprocessFactory::default().with_set_thread_priority())
.build(Processor::Pipeline { processors: decl })
.build(pipeline)
.context("failed to build pipeline")?;

log::info!("CrasProcessor #{id} created with: {config:?}");
Expand Down Expand Up @@ -345,11 +367,7 @@ pub unsafe extern "C" fn cras_processor_create(
CrasProcessor::new(
CrasProcessorConfig {
effect: CrasProcessorEffect::NoEffects,
channels: config.channels,
block_size: config.block_size,
frame_rate: config.frame_rate,
dedicated_thread: config.dedicated_thread,
wav_dump: config.wav_dump,
..config
},
// apm_processor was consumed so create it again.
create_apm_processor(&config, apm_plugin_processor).expect("create_apm_processor should not fail given that we created it successfully once"),
Expand All @@ -359,7 +377,10 @@ pub unsafe extern "C" fn cras_processor_create(
};

let effect = processor.config.effect;
let plugin_processor = if config.dedicated_thread {
let plugin_processor = if matches!(
config.wrap_mode,
CrasProcessorWrapMode::WrapModeDedicatedThread
) {
let threaded_processor = ThreadedProcessor::new(processor, 1);
export_plugin(threaded_processor)
} else {
Expand Down
9 changes: 5 additions & 4 deletions cras/src/server/cras_stream_apm.c
Original file line number Diff line number Diff line change
Expand Up @@ -782,10 +782,11 @@ struct cras_apm* cras_stream_apm_add(struct cras_stream_apm* stream,
.block_size = frame_length,
.frame_rate = apm->fmt.frame_rate,
.effect = cp_effect,
.dedicated_thread =
cp_effect == NoEffects
? false
: cras_feature_enabled(CrOSLateBootCrasProcessorDedicatedThread),
.wrap_mode =
cp_effect != NoEffects &&
cras_feature_enabled(CrOSLateBootCrasProcessorDedicatedThread)
? WrapModeDedicatedThread
: WrapModeNone,
.wav_dump = cras_feature_enabled(CrOSLateBootCrasProcessorWavDump),
};
struct CrasProcessorCreateResult cras_processor_create_result =
Expand Down

0 comments on commit a6751ae

Please sign in to comment.