| Lift freeq's AV media plane out of sleek 90f8b89 nandi 20d ago | 1 | use num_traits::FromPrimitive; |
| 2 | |
| 3 | use crate::{DeviceDirection, SampleFormat}; |
| 4 | |
| 5 | use super::{ |
| 6 | android_device_flags, |
| 7 | utils::{ |
| 8 | call_method_no_args_ret_bool, call_method_no_args_ret_char_sequence, |
| 9 | call_method_no_args_ret_int, call_method_no_args_ret_int_array, |
| 10 | call_method_no_args_ret_string, get_context, get_devices, get_system_service, |
| 11 | with_attached, JNIEnv, JObject, JResult, |
| 12 | }, |
| 13 | AudioDeviceInfo, AudioDeviceType, Context, |
| 14 | }; |
| 15 | |
| 16 | impl AudioDeviceInfo { |
| 17 | /** |
| 18 | * Request audio devices using Android Java API |
| 19 | */ |
| 20 | pub fn request(direction: DeviceDirection) -> Result<Vec<AudioDeviceInfo>, String> { |
| 21 | let context = get_context(); |
| 22 | |
| 23 | with_attached(context, |env, context| { |
| 24 | let sdk_version = env |
| 25 | .get_static_field("android/os/Build$VERSION", "SDK_INT", "I")? |
| 26 | .i()?; |
| 27 | |
| 28 | if sdk_version >= 23 { |
| 29 | try_request_devices_info(env, &context, direction) |
| 30 | } else { |
| 31 | Err(jni::errors::Error::MethodNotFound { |
| 32 | name: "".into(), |
| 33 | sig: "".into(), |
| 34 | }) |
| 35 | } |
| 36 | }) |
| 37 | .map_err(|error| error.to_string()) |
| 38 | } |
| 39 | } |
| 40 | |
| 41 | fn try_request_devices_info<'j>( |
| 42 | env: &mut JNIEnv<'j>, |
| 43 | context: &JObject<'j>, |
| 44 | direction: DeviceDirection, |
| 45 | ) -> JResult<Vec<AudioDeviceInfo>> { |
| 46 | let audio_manager = get_system_service(env, context, Context::AUDIO_SERVICE)?; |
| 47 | |
| 48 | let devices = get_devices(env, &audio_manager, android_device_flags(direction))?; |
| 49 | |
| 50 | let length = env.get_array_length(&devices)?; |
| 51 | |
| 52 | (0..length) |
| 53 | .map(|index| { |
| 54 | let device = env.get_object_array_element(&devices, index)?; |
| 55 | let id = call_method_no_args_ret_int(env, &device, "getId")?; |
| 56 | let address = call_method_no_args_ret_string(env, &device, "getAddress")?; |
| 57 | let address = String::from(env.get_string(&address)?); |
| 58 | let product_name = |
| 59 | call_method_no_args_ret_char_sequence(env, &device, "getProductName")?; |
| 60 | let product_name = String::from(env.get_string(&product_name)?); |
| 61 | let device_type = |
| 62 | FromPrimitive::from_i32(call_method_no_args_ret_int(env, &device, "getType")?) |
| 63 | .unwrap_or(AudioDeviceType::Unsupported); |
| 64 | |
| 65 | let is_source = call_method_no_args_ret_bool(env, &device, "isSource")?; |
| 66 | let is_sink = call_method_no_args_ret_bool(env, &device, "isSink")?; |
| 67 | let direction = crate::device_description::direction_from_caps(is_source, is_sink); |
| 68 | let channel_counts = |
| 69 | call_method_no_args_ret_int_array(env, &device, "getChannelCounts")?; |
| 70 | let sample_rates = call_method_no_args_ret_int_array(env, &device, "getSampleRates")?; |
| 71 | let formats = call_method_no_args_ret_int_array(env, &device, "getEncodings")? |
| 72 | .into_iter() |
| 73 | .filter_map(SampleFormat::from_encoding) |
| 74 | .collect::<Vec<_>>(); |
| 75 | |
| 76 | Ok(AudioDeviceInfo { |
| 77 | id, |
| 78 | address, |
| 79 | product_name, |
| 80 | device_type, |
| 81 | direction, |
| 82 | channel_counts, |
| 83 | sample_rates, |
| 84 | formats, |
| 85 | }) |
| 86 | }) |
| 87 | .collect::<Result<Vec<_>, _>>() |
| 88 | } |