voicemeeter\interface/
communication_login_logout.rs1use crate::types::VoicemeeterApplication;
9
10use super::VoicemeeterRemote;
11
12static HAS_LOGGED_IN: std::sync::OnceLock<VoicemeeterStatus> = std::sync::OnceLock::new();
13
14impl VoicemeeterRemote {
15 pub fn initial_status() -> VoicemeeterStatus {
17 HAS_LOGGED_IN.get().unwrap().clone()
18 }
19 pub(crate) fn login(&mut self) -> Result<VoicemeeterStatus, LoginError> {
20 if let Some(res) = HAS_LOGGED_IN.get() {
21 return Err(LoginError::AlreadyLoggedIn(res.clone()));
22 }
23 let res = unsafe { self.raw.VBVMR_Login() };
24 let res = match res {
25 0 => Ok(VoicemeeterStatus::Launched),
26 1 => Ok(VoicemeeterStatus::NotLaunched),
27 -2 => Err(LoginError::LoginFailed),
28 s => Err(LoginError::Unexpected(s)),
29 }?;
30 tracing::debug!("logged in with status {:?}", res);
31 Ok(HAS_LOGGED_IN.get_or_init(|| res).clone())
32 }
33 pub fn logout(self) -> Result<(), LogoutError> {
39 drop(self);
40 if super::LOGOUT_HANDLE
41 .get()
42 .unwrap()
43 .lock()
44 .unwrap()
45 .is_some()
46 {
47 Err(LogoutError::OtherRemotesExists)
48 } else {
49 Ok(())
50 }
51 }
52
53 pub(crate) fn _logout(&mut self) -> Result<(), LogoutError> {
54 let _ = self.logout_handle.take();
55 let Some(mut a) = super::LOGOUT_HANDLE.get().unwrap().lock().unwrap().take() else {
57 return Ok(());
58 };
59 if let Some(logged_out) = std::sync::Arc::get_mut(&mut a) {
60 if *logged_out {
61 return Ok(());
62 }
63 tracing::debug!("logging out");
64 let res = unsafe { self.raw.VBVMR_Logout() };
65 match res {
66 0 => {
67 *logged_out = true;
68 Ok(())
69 }
70 s => Err(LogoutError::Unexpected(s)),
71 }
72 } else {
73 super::LOGOUT_HANDLE
74 .get()
75 .unwrap()
76 .lock()
77 .unwrap()
78 .replace(a);
79 Err(LogoutError::OtherRemotesExists)
80 }
81 }
82
83 pub fn run_voicemeeter(
85 &self,
86 r#type: VoicemeeterApplication,
87 ) -> Result<(), RunVoicemeeterError> {
88 let res = unsafe { self.raw.VBVMR_RunVoicemeeter(r#type as i32) };
89 match res {
90 0 => Ok(()),
91 -1 => Err(RunVoicemeeterError::NotInstalled),
92 -2 => Err(RunVoicemeeterError::UnknownType),
93 s => Err(RunVoicemeeterError::Other(s)),
94 }
95 }
96}
97
98#[derive(Debug, Clone, PartialEq, Eq)]
99pub enum VoicemeeterStatus {
101 Launched,
103 NotLaunched,
105}
106
107#[derive(Debug, thiserror::Error, Clone)]
109#[non_exhaustive]
110pub enum LoginError {
111 #[error("application has already logged in")]
113 AlreadyLoggedIn(VoicemeeterStatus),
114 #[error("unexpected login (logout was expected before)")]
116 LoginFailed,
117 #[error("cannot get client (unexpected): {0}")]
119 Unexpected(i32),
120}
121
122#[derive(Debug, thiserror::Error, Clone)]
124#[non_exhaustive]
125pub enum LogoutError {
126 #[error("couldn't logout due to other `VoicemeeterRemote`s existing in this program")]
128 OtherRemotesExists,
129 #[error("cannot get client (unexpected): {0}")]
131 Unexpected(i32),
132}
133#[derive(Debug, thiserror::Error, Clone)]
135#[non_exhaustive]
136pub enum RunVoicemeeterError {
137 #[error("voicemeeter is not installed")]
139 NotInstalled,
140 #[error("unknown type")]
142 UnknownType,
143 #[error("unexpected error occurred: error code {0}")]
145 Other(i32),
146}
147
148impl LoginError {
149 pub fn is_login_failed(&self) -> bool {
153 matches!(self, Self::LoginFailed)
154 }
155
156 pub fn is_unexpected(&self) -> bool {
160 matches!(self, Self::Unexpected(..))
161 }
162}