use crate::types::VoicemeeterApplication;
use super::VoicemeeterRemote;
static HAS_LOGGED_IN: std::sync::OnceLock<VoicemeeterStatus> = std::sync::OnceLock::new();
impl VoicemeeterRemote {
pub fn initial_status() -> VoicemeeterStatus {
HAS_LOGGED_IN.get().unwrap().clone()
}
pub(crate) fn login(&mut self) -> Result<VoicemeeterStatus, LoginError> {
if let Some(res) = HAS_LOGGED_IN.get() {
return Err(LoginError::AlreadyLoggedIn(res.clone()));
}
let res = unsafe { self.raw.VBVMR_Login() };
let res = match res {
0 => Ok(VoicemeeterStatus::Launched),
1 => Ok(VoicemeeterStatus::NotLaunched),
-2 => Err(LoginError::LoginFailed),
s => Err(LoginError::Unexpected(s)),
}?;
tracing::debug!("logged in with status {:?}", res);
Ok(HAS_LOGGED_IN.get_or_init(|| res).clone())
}
pub fn logout(self) -> Result<(), LogoutError> {
drop(self);
if super::LOGOUT_HANDLE
.get()
.unwrap()
.lock()
.unwrap()
.is_some()
{
Err(LogoutError::OtherRemotesExists)
} else {
Ok(())
}
}
pub(crate) fn _logout(&mut self) -> Result<(), LogoutError> {
let _ = self.logout_handle.take();
let Some(mut a) = super::LOGOUT_HANDLE.get().unwrap().lock().unwrap().take() else {
return Ok(());
};
if let Some(logged_out) = std::sync::Arc::get_mut(&mut a) {
if *logged_out {
return Ok(());
}
tracing::debug!("logging out");
let res = unsafe { self.raw.VBVMR_Logout() };
match res {
0 => {
*logged_out = true;
Ok(())
}
s => Err(LogoutError::Unexpected(s)),
}
} else {
super::LOGOUT_HANDLE
.get()
.unwrap()
.lock()
.unwrap()
.replace(a);
Err(LogoutError::OtherRemotesExists)
}
}
pub fn run_voicemeeter(
&self,
r#type: VoicemeeterApplication,
) -> Result<(), RunVoicemeeterError> {
let res = unsafe { self.raw.VBVMR_RunVoicemeeter(r#type as i32) };
match res {
0 => Ok(()),
-1 => Err(RunVoicemeeterError::NotInstalled),
-2 => Err(RunVoicemeeterError::UnknownType),
s => Err(RunVoicemeeterError::Other(s)),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum VoicemeeterStatus {
Launched,
NotLaunched,
}
#[derive(Debug, thiserror::Error, Clone)]
#[non_exhaustive]
pub enum LoginError {
#[error("application has already logged in")]
AlreadyLoggedIn(VoicemeeterStatus),
#[error("unexpected login (logout was expected before)")]
LoginFailed,
#[error("cannot get client (unexpected): {0}")]
Unexpected(i32),
}
#[derive(Debug, thiserror::Error, Clone)]
#[non_exhaustive]
pub enum LogoutError {
#[error("couldn't logout due to other `VoicemeeterRemote`s existing in this program")]
OtherRemotesExists,
#[error("cannot get client (unexpected): {0}")]
Unexpected(i32),
}
#[derive(Debug, thiserror::Error, Clone)]
#[non_exhaustive]
pub enum RunVoicemeeterError {
#[error("voicemeeter is not installed")]
NotInstalled,
#[error("unknown type")]
UnknownType,
#[error("unexpected error occurred: error code {0}")]
Other(i32),
}
impl LoginError {
pub fn is_login_failed(&self) -> bool {
matches!(self, Self::LoginFailed)
}
pub fn is_unexpected(&self) -> bool {
matches!(self, Self::Unexpected(..))
}
}