Skip to content

Android / Oboe returns duplicate devices #969

Open
@setoelkahfi

Description

@setoelkahfi
Click me

Image

This available_hosts() works correctly in other platforms, but Android returns duplicate entries. I investigated it and it turns out it calls the getDevices in the AudioManager API. The cpal implementation utils.rs line 168:

pub fn get_devices<'j>(
    env: &mut JNIEnv<'j>,
    subject: &JObject<'j>,
    flags: i32,
) -> JResult<JObjectArray<'j>> {
    env.call_method(
        subject,
        "getDevices",
        "(I)[Landroid/media/AudioDeviceInfo;",
        &[flags.into()],
    )?
    .l()
    .map(From::from)
}

Which is called from:

fn try_request_devices_info<'j>(
    env: &mut JNIEnv<'j>,
    context: &JObject<'j>,
    direction: AudioDeviceDirection,
) -> JResult<Vec<AudioDeviceInfo>> {
    let audio_manager = get_system_service(env, context, Context::AUDIO_SERVICE)?;

    let devices = get_devices(env, &audio_manager, direction as i32)?;

    let length = env.get_array_length(&devices)?;

    (0..length)
        .map(|index| {
            let device = env.get_object_array_element(&devices, index)?;
            let id = call_method_no_args_ret_int(env, &device, "getId")?;
            let address = call_method_no_args_ret_string(env, &device, "getAddress")?;
            let address = String::from(env.get_string(&address)?);
            let product_name =
                call_method_no_args_ret_char_sequence(env, &device, "getProductName")?;
            let product_name = String::from(env.get_string(&product_name)?);
            let device_type =
                FromPrimitive::from_i32(call_method_no_args_ret_int(env, &device, "getType")?)
                    .unwrap_or(AudioDeviceType::Unsupported);
            let direction = AudioDeviceDirection::new(
                call_method_no_args_ret_bool(env, &device, "isSource")?,
                call_method_no_args_ret_bool(env, &device, "isSink")?,
            );
            let channel_counts =
                call_method_no_args_ret_int_array(env, &device, "getChannelCounts")?;
            let sample_rates = call_method_no_args_ret_int_array(env, &device, "getSampleRates")?;
            let formats = call_method_no_args_ret_int_array(env, &device, "getEncodings")?
                .into_iter()
                .filter_map(SampleFormat::from_encoding)
                .collect::<Vec<_>>();

            Ok(AudioDeviceInfo {
                id,
                address,
                product_name,
                device_type,
                direction,
                channel_counts,
                sample_rates,
                formats,
            })
        })
        .collect::<Result<Vec<_>, _>>()
}

Is anyone familiar with this part of the codebase?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions