fix(audio): migrate Android JNI paths
This commit is contained in:
@@ -2448,6 +2448,13 @@ impl std::fmt::Display for AudioModeError {
|
||||
#[cfg(target_os = "android")]
|
||||
impl std::error::Error for AudioModeError {}
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
impl From<jni::errors::Error> for AudioModeError {
|
||||
fn from(value: jni::errors::Error) -> Self {
|
||||
Self::JniAttachFailed(value.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
/// JNI helper shared by `android_get_audio_mode` and
|
||||
/// `android_set_audio_mode`: attach to the current thread and return
|
||||
/// the `AudioManager` jobject. Centralised so SDD-108's two platform
|
||||
@@ -2455,7 +2462,10 @@ impl std::error::Error for AudioModeError {}
|
||||
#[cfg(target_os = "android")]
|
||||
fn android_audio_manager_call<F, R>(op: F) -> Result<R, AudioModeError>
|
||||
where
|
||||
F: FnOnce(&mut jni::JNIEnv, &jni::objects::JObject) -> Result<R, AudioModeError>
|
||||
F: for<'local> FnOnce(
|
||||
&mut jni::Env<'local>,
|
||||
&jni::objects::JObject<'local>,
|
||||
) -> Result<R, AudioModeError>
|
||||
+ std::panic::UnwindSafe,
|
||||
{
|
||||
use jni::objects::{JObject, JString, JValue};
|
||||
@@ -2472,42 +2482,40 @@ where
|
||||
// at a live JavaVM* set by our bridge_init JNI hook. The
|
||||
// unsafe block contains only the cast required by
|
||||
// `JavaVM::from_raw`.
|
||||
let jvm = unsafe { jni::JavaVM::from_raw(vm_ptr as *mut _) }
|
||||
.map_err(|e| AudioModeError::JniAttachFailed(format!("jvm from_raw: {e}")))?;
|
||||
let mut env = jvm
|
||||
.attach_current_thread()
|
||||
.map_err(|e| AudioModeError::JniAttachFailed(format!("attach: {e}")))?;
|
||||
let jvm = unsafe { jni::JavaVM::from_raw(vm_ptr as *mut _) };
|
||||
jvm.attach_current_thread(|env| -> Result<R, AudioModeError> {
|
||||
let context_obj = unsafe { JObject::from_raw(env, ctx.context() as jni::sys::jobject) };
|
||||
|
||||
let context_obj = unsafe { JObject::from_raw(ctx.context() as jni::sys::jobject) };
|
||||
|
||||
let service_name: JString =
|
||||
env.new_string("audio")
|
||||
let service_name: JString =
|
||||
env.new_string("audio")
|
||||
.map_err(|e| AudioModeError::MethodCallFailed {
|
||||
method: "new_string",
|
||||
detail: e.to_string(),
|
||||
})?;
|
||||
let service_name_obj = JObject::from(service_name);
|
||||
let audio_manager = env
|
||||
.call_method(
|
||||
&context_obj,
|
||||
jni::jni_str!("getSystemService"),
|
||||
jni::jni_sig!("(Ljava/lang/String;)Ljava/lang/Object;"),
|
||||
&[JValue::Object(&service_name_obj)],
|
||||
)
|
||||
.map_err(|e| AudioModeError::MethodCallFailed {
|
||||
method: "new_string",
|
||||
method: "getSystemService",
|
||||
detail: e.to_string(),
|
||||
})?
|
||||
.l()
|
||||
.map_err(|e| AudioModeError::MethodCallFailed {
|
||||
method: "getSystemService",
|
||||
detail: format!("obj cast: {e}"),
|
||||
})?;
|
||||
let audio_manager = env
|
||||
.call_method(
|
||||
&context_obj,
|
||||
"getSystemService",
|
||||
"(Ljava/lang/String;)Ljava/lang/Object;",
|
||||
&[JValue::Object(&service_name.into())],
|
||||
)
|
||||
.map_err(|e| AudioModeError::MethodCallFailed {
|
||||
method: "getSystemService",
|
||||
detail: e.to_string(),
|
||||
})?
|
||||
.l()
|
||||
.map_err(|e| AudioModeError::MethodCallFailed {
|
||||
method: "getSystemService",
|
||||
detail: format!("obj cast: {e}"),
|
||||
})?;
|
||||
if audio_manager.is_null() {
|
||||
return Err(AudioModeError::Other(
|
||||
"AudioManager service is null".to_string(),
|
||||
));
|
||||
}
|
||||
op(&mut env, &audio_manager)
|
||||
if audio_manager.is_null() {
|
||||
return Err(AudioModeError::Other(
|
||||
"AudioManager service is null".to_string(),
|
||||
));
|
||||
}
|
||||
op(env, &audio_manager)
|
||||
})
|
||||
});
|
||||
match result {
|
||||
Ok(inner) => inner,
|
||||
@@ -2526,16 +2534,21 @@ where
|
||||
#[cfg(target_os = "android")]
|
||||
pub fn android_get_audio_mode() -> Result<i32, AudioModeError> {
|
||||
android_audio_manager_call(|env, audio_manager| {
|
||||
env.call_method(audio_manager, "getMode", "()I", &[])
|
||||
.map_err(|e| AudioModeError::MethodCallFailed {
|
||||
method: "getMode",
|
||||
detail: e.to_string(),
|
||||
})?
|
||||
.i()
|
||||
.map_err(|e| AudioModeError::MethodCallFailed {
|
||||
method: "getMode",
|
||||
detail: format!("int cast: {e}"),
|
||||
})
|
||||
env.call_method(
|
||||
audio_manager,
|
||||
jni::jni_str!("getMode"),
|
||||
jni::jni_sig!("()I"),
|
||||
&[],
|
||||
)
|
||||
.map_err(|e| AudioModeError::MethodCallFailed {
|
||||
method: "getMode",
|
||||
detail: e.to_string(),
|
||||
})?
|
||||
.i()
|
||||
.map_err(|e| AudioModeError::MethodCallFailed {
|
||||
method: "getMode",
|
||||
detail: format!("int cast: {e}"),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -2549,11 +2562,16 @@ pub fn android_get_audio_mode() -> Result<i32, AudioModeError> {
|
||||
pub fn android_set_audio_mode(mode: i32) -> Result<(), AudioModeError> {
|
||||
use jni::objects::JValue;
|
||||
android_audio_manager_call(move |env, audio_manager| {
|
||||
env.call_method(audio_manager, "setMode", "(I)V", &[JValue::Int(mode)])
|
||||
.map_err(|e| AudioModeError::MethodCallFailed {
|
||||
method: "setMode",
|
||||
detail: e.to_string(),
|
||||
})?;
|
||||
env.call_method(
|
||||
audio_manager,
|
||||
jni::jni_str!("setMode"),
|
||||
jni::jni_sig!("(I)V"),
|
||||
&[JValue::Int(mode)],
|
||||
)
|
||||
.map_err(|e| AudioModeError::MethodCallFailed {
|
||||
method: "setMode",
|
||||
detail: e.to_string(),
|
||||
})?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user