1use crate::{types::VoicemeeterApplication, LoadError};
5
6use self::{
7 communication_login_logout::LoginError, general_information::GetVoicemeeterInformationError,
8};
9
10pub mod callback;
11pub mod communication_login_logout;
12pub mod device;
13pub mod general_information;
14pub mod get_levels;
15pub mod macro_buttons;
16pub mod parameters;
17
18#[derive(Clone)]
20#[cfg(feature = "interface")] pub struct VoicemeeterRemote {
22 raw: &'static crate::bindings::VoicemeeterRemoteRaw,
23 logout_handle: Option<std::sync::Arc<bool>>,
24 pub program: VoicemeeterApplication,
26}
27
28pub(crate) static LOGOUT_HANDLE: std::sync::OnceLock<
29 std::sync::Mutex<Option<std::sync::Arc<bool>>>,
30> = std::sync::OnceLock::new();
31
32impl std::fmt::Debug for VoicemeeterRemote {
33 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34 match self.program {
35 VoicemeeterApplication::None => write!(f, "[no voicemeeter program running]"),
36 p => write!(f, "[{p}]"),
37 }
38 }
39}
40
41impl VoicemeeterRemote {
42 #[tracing::instrument]
52 pub fn new() -> Result<Self, InitializationError> {
53 let raw = crate::get_voicemeeter_raw()?;
54 let mut s = VoicemeeterRemote::from_raw(raw);
55 if s.logout_handle.is_none() {
56 return Err(InitializationError::AlreadyLoggedOut);
57 }
58 match s.login() {
59 Ok(_) => {}
60 Err(LoginError::AlreadyLoggedIn(_)) => {}
61 e => {
62 e?;
63 }
64 };
65 s.update_program()?;
66 Ok(s)
67 }
68
69 fn from_raw(raw: &'static crate::VoicemeeterRemoteRaw) -> VoicemeeterRemote {
70 Self {
71 raw,
72 program: VoicemeeterApplication::Other,
73 logout_handle: LOGOUT_HANDLE
74 .get_or_init(|| std::sync::Mutex::new(Some(std::sync::Arc::new(false))))
75 .lock()
76 .unwrap()
77 .clone(),
78 }
79 }
80
81 pub fn update_program(&mut self) -> Result<(), GetVoicemeeterInformationError> {
83 match self.get_voicemeeter_type() {
84 Ok(t) => self.program = t,
85 Err(GetVoicemeeterInformationError::NoServer) => {
86 self.program = VoicemeeterApplication::None
87 }
88 Err(e) => return Err(e),
89 }
90 Ok(())
91 }
92}
93
94impl Drop for VoicemeeterRemote {
95 fn drop(&mut self) {
96 let _ = self._logout();
98 }
99}
100
101#[derive(Debug, thiserror::Error)]
103#[non_exhaustive]
104pub enum InitializationError {
105 #[error("could not load the client")]
107 LoadError(#[from] LoadError),
108 #[error("could not login")]
110 LoginError(#[from] LoginError),
111 #[error("application has already logged out, so cannot login again")]
113 AlreadyLoggedOut,
114 #[error("could not get voicemeeter type")]
116 InformationError(#[from] GetVoicemeeterInformationError),
117}