Skip to content

feat(android): add input_preset to StreamConfig #995

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ rust-version = "1.70"

[features]
asio = ["asio-sys", "num-traits"] # Only available on Windows. See README for setup instructions.
android-input-preset = ["ndk/api-level-28"]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see this requires api-level-28 where the normal feature requires api-level-26. That OK?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see any conflicts between the features in ndk document and didn't find any errors about api levels when I used the branch of this PR in my own project.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, if it works, it works. As it does bump the minimum Android version, it would be a good thing to document. Would you document the feature flag, as well as add an entry to the changelog?


# Deprecated, the `oboe` backend has been removed
oboe-shared-stdcxx = []
Expand Down Expand Up @@ -83,7 +84,7 @@ js-sys = { version = "0.3.35" }
web-sys = { version = "0.3.35", features = [ "AudioContext", "AudioContextOptions", "AudioBuffer", "AudioBufferSourceNode", "AudioNode", "AudioDestinationNode", "Window", "AudioContextState"] }

[target.'cfg(target_os = "android")'.dependencies]
ndk = { version = "0.9", default-features = false, features = ["audio", "api-level-26"]}
ndk = { version = "0.9", default-features = false, features = ["audio", "api-level-26"] }
ndk-context = "0.1"
jni = "0.21"
num-derive = "0.4"
Expand Down
18 changes: 10 additions & 8 deletions src/host/aaudio/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use std::cell::RefCell;
use std::cmp;
use std::convert::TryInto;
use std::time::{Duration, Instant};
Expand All @@ -14,7 +13,7 @@ use crate::{
BackendSpecificError, BufferSize, BuildStreamError, Data, DefaultStreamConfigError,
DeviceNameError, DevicesError, InputCallbackInfo, InputStreamTimestamp, OutputCallbackInfo,
OutputStreamTimestamp, PauseStreamError, PlayStreamError, SampleFormat, SampleRate,
SizedSample, StreamConfig, StreamError, SupportedBufferSize, SupportedStreamConfig,
StreamConfig, StreamError, SupportedBufferSize, SupportedStreamConfig,
SupportedStreamConfigRange, SupportedStreamConfigsError,
};

Expand Down Expand Up @@ -256,7 +255,7 @@ where
);
ndk::audio::AudioCallbackResult::Continue
}))
.error_callback(Box::new(move |stream, error| {
.error_callback(Box::new(move |_, error| {
(error_callback)(StreamError::from(error))
}))
.open_stream()?;
Expand Down Expand Up @@ -298,7 +297,7 @@ where
);
ndk::audio::AudioCallbackResult::Continue
}))
.error_callback(Box::new(move |stream, error| {
.error_callback(Box::new(move |_, error| {
(error_callback)(StreamError::from(error))
}))
.open_stream()?;
Expand Down Expand Up @@ -388,13 +387,13 @@ impl DeviceTrait for Device {
return Err(BackendSpecificError {
description: format!("{} format is not supported on Android.", sample_format),
}
.into())
.into());
}
};
let channel_count = match config.channels {
1 => 1,
2 => 2,
channels => {
_ => {
// TODO: more channels available in native AAudio
return Err(BackendSpecificError {
description: "More than 2 channels are not supported yet.".to_owned(),
Expand All @@ -408,6 +407,9 @@ impl DeviceTrait for Device {
.channel_count(channel_count)
.format(format);

#[cfg(feature = "android-input-preset")]
let builder = builder.input_preset(config.input_preset);

build_input_stream(
self,
config,
Expand Down Expand Up @@ -437,13 +439,13 @@ impl DeviceTrait for Device {
return Err(BackendSpecificError {
description: format!("{} format is not supported on Android.", sample_format),
}
.into())
.into());
}
};
let channel_count = match config.channels {
1 => 1,
2 => 2,
channels => {
_ => {
// TODO: more channels available in native AAudio
return Err(BackendSpecificError {
description: "More than 2 channels are not supported yet.".to_owned(),
Expand Down
4 changes: 4 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,8 @@ pub struct StreamConfig {
pub channels: ChannelCount,
pub sample_rate: SampleRate,
pub buffer_size: BufferSize,
#[cfg(all(target_os = "android", feature = "android-input-preset"))]
pub input_preset: platform::AudioInputPreset,
}

/// Describes the minimum and maximum supported buffer size for the device
Expand Down Expand Up @@ -410,6 +412,8 @@ impl SupportedStreamConfig {
channels: self.channels,
sample_rate: self.sample_rate,
buffer_size: BufferSize::Default,
#[cfg(all(target_os = "android", feature = "android-input-preset"))]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to rename the feature flag to something more specific like "android-voice-recognition" or "android-aec"? Because it seems like there are more input presets that one could choose, if not today then in the future.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it better to keep the name because AEC is not the only function of the flag.

Copy link
Collaborator

@roderickvd roderickvd Aug 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's what I was trying to say. Looking at the AudioInputPreset enum there are six variants today. How can we make the feature flag clearly convey which preset gets enabled?

Edit: what would be a good way going forward to support the other variants as well?

input_preset: platform::AudioInputPreset::VoiceRecognition,
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/platform/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -708,6 +708,8 @@ mod platform_impl {
Stream as AAudioStream, SupportedInputConfigs as AAudioSupportedInputConfigs,
SupportedOutputConfigs as AAudioSupportedOutputConfigs,
};
#[cfg(feature = "android-input-preset")]
pub use ndk::audio::AudioInputPreset;

impl_platform_host!(AAudio aaudio "AAudio");

Expand Down
Loading