Skip to content

Conversation

@will3942
Copy link
Contributor

@will3942 will3942 commented Oct 27, 2025

AAudio buffer size minimum should be detected using the PROPERTY_OUTPUT_FRAMES_PER_BUFFER on the AudioManager not using AudioTrack.

Android documentation reference: https://developer.android.com/ndk/guides/audio/audio-latency#buffer-size

This allows for a sensible buffer size minimum to be used in comparison to the 1 second+ buffer sizes reported by AudioTrack.

Tested on a Samsung Galaxy Tab A9: SupportedStreamConfigRange { channels: 1, min_sample_rate: SampleRate(5512), max_sample_rate: SampleRate(5512), buffer_size: Range { min: 256, max: 2147483647 }, sample_format: I16 }

Closes: #890

@will3942 will3942 changed the title fix(aaudio): Correctly detect minimum buffer size. fix(aaudio): Correctly detect minimum buffer size Oct 27, 2025
Copy link
Member

@roderickvd roderickvd left a comment

Choose a reason for hiding this comment

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

Thanks for the contribution!

min_buffer_size
} else {
get_audio_record_min_buffer_size(sample_rate, channel_mask, android_format)
0
Copy link
Member

Choose a reason for hiding this comment

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

I think this could be refactored into something like:

if let Ok(min_buffer_size) = AudioManager::get_frames_per_buffer() {
    SupportedBufferSize::Range {
        min: min_buffer_size as u32,
        max: i32::MAX as u32,
    }
} else {
    SupportedBufferSize::Unknown
}

android_media::ENCODING_PCM_FLOAT
};
for (mask_idx, channel_mask) in CHANNEL_MASKS.iter().enumerate() {
for (mask_idx, _) in CHANNEL_MASKS.iter().enumerate() {
Copy link
Member

Choose a reason for hiding this comment

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

Do we still need CHANNEL_MASKS? Because currently the elements that that array contains aren't used anymore.

};
for (mask_idx, channel_mask) in CHANNEL_MASKS.iter().enumerate() {
for (mask_idx, _) in CHANNEL_MASKS.iter().enumerate() {
let channel_count = mask_idx + 1;
Copy link
Member

Choose a reason for hiding this comment

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

...but maybe they should because while this line works, it's kind of hackish (I know, not your code, nor was it mine 😉). It at some point a 5.1 or whatever mode is introduced, we should use a mapping instead of doing + 1.


impl AudioManager {
/**
* Get the frames per buffer using Android Java API
Copy link
Member

Choose a reason for hiding this comment

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

Style nitpick: please use Rustdoc-standard // comments instead of Javadoc-style /** .. */.

let frames_per_buffer = get_property(
env,
&audio_manager,
AudioManager::PROPERTY_OUTPUT_FRAMES_PER_BUFFER,
Copy link
Member

Choose a reason for hiding this comment

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

Question: is this also valid for input devices? Though I see that AudioManager::PROPERTY_INPUT_FRAMES_PER_BUFFER does not exist.

let mut output = Vec::with_capacity(SAMPLE_RATES.len() * CHANNEL_MASKS.len() * FORMATS.len());
for sample_format in &FORMATS {
let android_format = if *sample_format == SampleFormat::I16 {
android_media::ENCODING_PCM_16BIT
Copy link
Member

Choose a reason for hiding this comment

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

In android_media.rs can these constants now be removed?

@will3942
Copy link
Contributor Author

Thanks for the contribution!

Thanks for the review - will address all feedback in the morning. The Q around input is an interesting one, I couldn't see anything different for input in their docs but also I agree the property is named after output so...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Min buffer size range detected on Android is huge (~1sec)

2 participants