From f4dac4ddc561c905d11caf8e31666209b2fdbc93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Fr=C3=B8yland?= Date: Wed, 15 Nov 2023 13:32:49 +0100 Subject: [PATCH 1/5] add control of default input device --- src/lib.rs | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index c6df593..dc5e4e8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,7 +3,7 @@ use windows::{ core::Interface, Win32::{ Media::Audio::{ - eMultimedia, eRender, Endpoints::IAudioEndpointVolume, IAudioSessionControl, + eMultimedia, eRender, eCapture, Endpoints::IAudioEndpointVolume, IAudioSessionControl, IAudioSessionControl2, IAudioSessionEnumerator, IAudioSessionManager2, IMMDevice, IMMDeviceEnumerator, ISimpleAudioVolume, MMDeviceEnumerator, }, @@ -20,6 +20,7 @@ mod session; pub struct AudioController { default_device: Option, + default_input_device: Option, imm_device_enumerator: Option, sessions: Vec>, } @@ -45,6 +46,7 @@ impl AudioController { Self { default_device: None, + default_input_device: None, imm_device_enumerator: None, sessions: vec![], } @@ -76,6 +78,18 @@ impl AudioController { exit(1); }), ); + + self.default_input_device = Some( + self.imm_device_enumerator + .clone() + .unwrap() + .GetDefaultAudioEndpoint(eCapture, eMultimedia) + .unwrap_or_else(|err| { + eprintln!("ERROR: Couldn't get Default audio input endpoint {err}"); + exit(1); + }), + ); + let simple_audio_volume: IAudioEndpointVolume = self .default_device .clone() @@ -86,9 +100,26 @@ impl AudioController { exit(1); }); + self.sessions.push(Box::new(EndPointSession::new( simple_audio_volume, "master".to_string(), + ))); + + let simple_mic_volume: IAudioEndpointVolume = self + .default_input_device + .clone() + .unwrap() + .Activate(CLSCTX_ALL, None) + .unwrap_or_else(|err| { + eprintln!("ERROR: Couldn't get Endpoint volume control: {err}"); + exit(1); + }); + + + self.sessions.push(Box::new(EndPointSession::new( + simple_mic_volume, + "mic".to_string(), ))); } @@ -179,4 +210,5 @@ impl AudioController { pub unsafe fn get_session_by_name(&self, name: String) -> Option<&Box> { self.sessions.iter().find(|i| i.getName() == name) } + } From 4c5c4feb12c94423d0f9f7c7677b8b7ace60991d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Fr=C3=B8yland?= Date: Sat, 2 Dec 2023 12:38:18 +0100 Subject: [PATCH 2/5] add a number after app name to indicate duplicates --- src/lib.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index dc5e4e8..33d4f57 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -198,7 +198,16 @@ impl AudioController { continue; } }; - let application_session = ApplicationSession::new(audio_control, str_filename); + //loop through all sessions and check if the session name already exists, if it does, change name to name + 1 + let mut name = str_filename; + let mut counter = 2; + while self.sessions.iter().any(|i| i.getName() == name) { + name = format!("{}{}", name, counter); + counter += 1; + } + + let application_session = ApplicationSession::new(audio_control, name); + self.sessions.push(Box::new(application_session)); } } From 307f00771fad53cf4d7ee1375e59240cb1418a23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Fr=C3=B8yland?= Date: Sat, 2 Dec 2023 13:07:23 +0100 Subject: [PATCH 3/5] add () around number --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 33d4f57..b315167 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -202,7 +202,7 @@ impl AudioController { let mut name = str_filename; let mut counter = 2; while self.sessions.iter().any(|i| i.getName() == name) { - name = format!("{}{}", name, counter); + name = format!("{}({})", name, counter); counter += 1; } From 032ff192bdf5edc35a396b7f855a1cf4f020183e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Fr=C3=B8yland?= Date: Wed, 6 Dec 2023 19:23:22 +0100 Subject: [PATCH 4/5] do not crash on input device not found --- Cargo.lock | 7 +++++++ Cargo.toml | 1 + src/lib.rs | 37 ++++++++++++++++++++++++++++--------- 3 files changed, 36 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1941873..d8f2c4f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + [[package]] name = "proc-macro2" version = "1.0.56" @@ -89,6 +95,7 @@ dependencies = [ name = "windows-volume-control" version = "0.1.1" dependencies = [ + "log", "windows", ] diff --git a/Cargo.toml b/Cargo.toml index c8b6525..8746697 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ license = "MIT" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +log = "0.4.20" windows = { version = "0.44.0", features = [ "implement", "Win32_Media_Audio", diff --git a/src/lib.rs b/src/lib.rs index b315167..55482f3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,6 +15,7 @@ use windows::{ }, }; use std::process::exit; +use log::error; mod session; @@ -41,6 +42,7 @@ impl AudioController { } CoInitializeEx(None, coinit).unwrap_or_else(|err| { eprintln!("ERROR: Couldn't initialize windows connection: {err}"); + error!("ERROR: Couldn't initialize windows connection: {}", err); exit(1); }); @@ -56,6 +58,7 @@ impl AudioController { CoCreateInstance(&MMDeviceEnumerator, None, CLSCTX_INPROC_SERVER).unwrap_or_else( |err| { eprintln!("ERROR: Couldn't get Media device enumerator: {err}"); + error!("ERROR: Couldn't get Media device enumerator: {}", err); exit(1); }, ), @@ -65,29 +68,36 @@ impl AudioController { pub unsafe fn GetDefaultAudioEnpointVolumeControl(&mut self) { if self.imm_device_enumerator.is_none() { eprintln!("ERROR: Function called before creating enumerator"); + error!("ERROR: Function called before creating enumerator"); return; } self.default_device = Some( - self.imm_device_enumerator + match self.imm_device_enumerator .clone() .unwrap() .GetDefaultAudioEndpoint(eRender, eMultimedia) - .unwrap_or_else(|err| { - eprintln!("ERROR: Couldn't get Default audio endpoint {err}"); - exit(1); - }), + { + Ok(device) => device, + Err(err) => { + eprintln!("ERROR: Couldn't get Default audio output endpoint {err}"); + return; + } + } ); self.default_input_device = Some( - self.imm_device_enumerator + match self.imm_device_enumerator .clone() .unwrap() .GetDefaultAudioEndpoint(eCapture, eMultimedia) - .unwrap_or_else(|err| { + { + Ok(device) => device, + Err(err) => { eprintln!("ERROR: Couldn't get Default audio input endpoint {err}"); - exit(1); - }), + return; + } + } ); let simple_audio_volume: IAudioEndpointVolume = self @@ -131,6 +141,7 @@ impl AudioController { let session_manager2: IAudioSessionManager2 = self.default_device.as_ref().unwrap().Activate(CLSCTX_INPROC_SERVER, None).unwrap_or_else(|err| { eprintln!("ERROR: Couldnt get AudioSessionManager for enumerating over processes... {err}"); + error!("ERROR: Couldnt get AudioSessionManager for enumerating over processes... {}", err); exit(1); }); @@ -138,6 +149,7 @@ impl AudioController { .GetSessionEnumerator() .unwrap_or_else(|err| { eprintln!("ERROR: Couldnt get session enumerator... {err}"); + error!("ERROR: Couldnt get session enumerator... {}", err); exit(1); }); @@ -146,6 +158,7 @@ impl AudioController { session_enumerator.GetSession(i).ok(); if normal_session_control.is_none() { eprintln!("ERROR: Couldn't get session control of audio session..."); + error!("ERROR: Couldn't get session control of audio session..."); continue; } @@ -155,6 +168,7 @@ impl AudioController { eprintln!( "ERROR: Couldn't convert from normal session control to session control 2" ); + error!("ERROR: Couldn't convert from normal session control to session control 2"); continue; } @@ -165,6 +179,7 @@ impl AudioController { let process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, pid).ok(); if process.is_none() { eprintln!("ERROR: Couldn't get process information of process id {pid}"); + error!("ERROR: Couldn't get process information of process id {}", pid); continue; } let mut filename: [u8; 128] = [0; 128]; @@ -180,6 +195,7 @@ impl AudioController { Ok(data) => data, Err(err) => { eprintln!("ERROR: Filename couldn't be converted to string, {err}"); + error!("ERROR: Filename couldn't be converted to string, {}", err); continue; } }; @@ -195,6 +211,9 @@ impl AudioController { eprintln!( "ERROR: Couldn't get the simpleaudiovolume from session controller: {err}" ); + error!( + "ERROR: Couldn't get the simpleaudiovolume from session controller: {}", + err); continue; } }; From 4452937af4562a1f1ccb5a41f1d881866194eec5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Fr=C3=B8yland?= Date: Wed, 6 Dec 2023 22:01:35 +0100 Subject: [PATCH 5/5] check if value is not none, to still add main if mic is missing --- src/lib.rs | 73 +++++++++++++++++++++++++++--------------------------- 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 55482f3..3bcf14f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -72,51 +72,50 @@ impl AudioController { return; } - self.default_device = Some( - match self.imm_device_enumerator - .clone() - .unwrap() - .GetDefaultAudioEndpoint(eRender, eMultimedia) + self.default_device = match self.imm_device_enumerator + .clone() + .unwrap() + .GetDefaultAudioEndpoint(eRender, eMultimedia) { - Ok(device) => device, + Ok(device) => Some(device), Err(err) => { eprintln!("ERROR: Couldn't get Default audio output endpoint {err}"); - return; + None } - } - ); + }; - self.default_input_device = Some( - match self.imm_device_enumerator - .clone() - .unwrap() - .GetDefaultAudioEndpoint(eCapture, eMultimedia) + self.default_input_device = match self.imm_device_enumerator + .clone() + .unwrap() + .GetDefaultAudioEndpoint(eCapture, eMultimedia) { - Ok(device) => device, + Ok(device) => Some(device), Err(err) => { eprintln!("ERROR: Couldn't get Default audio input endpoint {err}"); - return; + None } - } - ); + }; - let simple_audio_volume: IAudioEndpointVolume = self - .default_device - .clone() - .unwrap() - .Activate(CLSCTX_ALL, None) - .unwrap_or_else(|err| { - eprintln!("ERROR: Couldn't get Endpoint volume control: {err}"); - exit(1); - }); + if !self.default_device.is_none() { + let simple_audio_volume: IAudioEndpointVolume = self + .default_device + .clone() + .unwrap() + .Activate(CLSCTX_ALL, None) + .unwrap_or_else(|err| { + eprintln!("ERROR: Couldn't get Endpoint volume control: {err}"); + exit(1); + }); - self.sessions.push(Box::new(EndPointSession::new( - simple_audio_volume, - "master".to_string(), - ))); + self.sessions.push(Box::new(EndPointSession::new( + simple_audio_volume, + "master".to_string(), + ))); + } - let simple_mic_volume: IAudioEndpointVolume = self + if !self.default_input_device.is_none() { + let simple_mic_volume: IAudioEndpointVolume = self .default_input_device .clone() .unwrap() @@ -126,11 +125,13 @@ impl AudioController { exit(1); }); + self.sessions.push(Box::new(EndPointSession::new( + simple_mic_volume, + "mic".to_string(), + ))); + } + - self.sessions.push(Box::new(EndPointSession::new( - simple_mic_volume, - "mic".to_string(), - ))); } pub unsafe fn GetAllProcessSessions(&mut self) {