Allow dropping old muters.

This commit is contained in:
Your Name
2023-02-21 23:12:46 -05:00
parent 671814fc81
commit 45f8d9bd26
6 changed files with 115 additions and 37 deletions

View File

@@ -46,3 +46,9 @@ impl IMMNotificationClient_Impl for DeviceNotificationClient {
Ok(())
}
}
impl Drop for DeviceNotificationClient {
fn drop(&mut self) {
println!("DNC Drop");
}
}

View File

@@ -16,7 +16,7 @@ use std::{
};
use sm_session_notifier::SMSessionNotifier;
use window_change::{await_win_change_events};
use window_change::WindowChangeMonitor;
use windows::{
core::Interface,
Win32::{
@@ -31,20 +31,38 @@ struct SessionMuter {
sessions: Vec<IAudioSessionControl2>,
mute_executables: HashSet<String>,
mute_flag: bool,
}
fn load_mute_txt() -> HashSet<String> {
let file = File::open("mute.txt").unwrap();
return HashSet::from_iter(BufReader::new(file).lines().map(|line| line.unwrap()));
win: Option<WindowChangeMonitor>
}
impl SessionMuter {
fn new() -> SessionMuter {
SessionMuter {
fn start(mute_executables: HashSet<String>) -> Arc<Mutex<SessionMuter>> {
let muter = Arc::new(Mutex::new(SessionMuter {
sessions: Vec::new(),
mute_executables: load_mute_txt(),
mute_executables,
mute_flag: true,
win: None
}));
{
let muter = Arc::downgrade(&muter);
let muter_internal = muter.clone();
muter.upgrade().unwrap().lock().as_mut().unwrap().win = Some(WindowChangeMonitor::start(Box::new(move |s| {
muter_internal.upgrade().map(|f| f.lock().unwrap().notify_window_changed(&s));
})));
}
{
let muter = Arc::downgrade(&muter);
let sn = SMSessionNotifier::new(Box::new(move |session| {
muter.upgrade().unwrap().lock().unwrap().add_session(session).unwrap()
}));
sn.lock()
.unwrap()
.as_mut()
.unwrap()
.boot_devices()
.expect("failed to get initial audio devices and sessions");
}
return muter;
}
fn add_session(
@@ -114,24 +132,23 @@ impl SessionMuter {
unsafe impl Send for SessionMuter {}
fn load_mute_txt() -> HashSet<String> {
let file = File::open("mute.txt").unwrap();
return HashSet::from_iter(BufReader::new(file).lines().map(|line| line.unwrap()));
}
fn test_muter() {
SessionMuter::start(load_mute_txt());
}
fn main() {
unsafe {
CoInitializeEx(None, COINIT_MULTITHREADED).unwrap();
}
let muter = Arc::new(Mutex::new(SessionMuter::new()));
let muter2 = muter.clone();
let sn = SMSessionNotifier::new(Box::new(move |session| {
muter2.lock().unwrap().add_session(session).unwrap()
}));
sn.lock()
.unwrap()
.as_mut()
.unwrap()
.boot_devices()
.expect("failed to get initial audio devices and sessions");
await_win_change_events(Box::new(move |s| {
muter.lock().unwrap().notify_window_changed(&s)
}));
loop {
test_muter();
println!("Test_muter done");
}
}

View File

@@ -23,3 +23,9 @@ impl IAudioSessionNotification_Impl for SessionNotification {
Ok(())
}
}
impl Drop for SessionNotification {
fn drop(&mut self) {
println!("SN drop");
}
}

View File

@@ -31,8 +31,8 @@ impl SMSessionNotifier {
) -> Arc<Mutex<Option<SMSessionNotifier>>> {
let session_notifier_arc: Arc<Mutex<Option<SMSessionNotifier>>> =
Arc::new(Mutex::new(None));
let sn2 = session_notifier_arc.clone();
let sn3 = session_notifier_arc.clone();
let sn2 = Arc::downgrade(&session_notifier_arc);
let sn3 = sn2.clone();
let notifier = SMSessionNotifier {
session_managers: Vec::new(),
device_enumerator: unsafe {
@@ -40,7 +40,7 @@ impl SMSessionNotifier {
},
device_notification_client: IMMNotificationClient::from(DeviceNotificationClient {
callback: Box::new(move |id| {
match sn2.lock().unwrap().as_mut().unwrap().add_device_by_id(id) {
match sn2.upgrade().unwrap().lock().unwrap().as_mut().unwrap().add_device_by_id(id) {
Ok(_) => {},
Err(e) => {
println!("Failed to add new device: {:?}", e);
@@ -50,13 +50,13 @@ impl SMSessionNotifier {
}),
session_notification: IAudioSessionNotification::from(SessionNotification {
callback: Box::new(move |session| {
(sn3.lock().unwrap().as_mut().unwrap().notification_function)(session)
(sn3.upgrade().unwrap().lock().unwrap().as_mut().unwrap().notification_function)(session)
}),
}),
notification_function: callback,
};
*session_notifier_arc.lock().unwrap() = Some(notifier);
return session_notifier_arc.clone();
return session_notifier_arc;
}
pub(crate) fn boot_devices(self: &mut SMSessionNotifier) -> Result<(), Box<dyn Error>> {

View File

@@ -1,15 +1,15 @@
use std::sync::Mutex;
use std::{sync::{Mutex, atomic::AtomicU32, Arc}, thread::{self, JoinHandle}};
use windows::Win32::{
Foundation::{HINSTANCE, HWND},
Foundation::{HINSTANCE, HWND, WPARAM, LPARAM},
UI::{
Accessibility::{SetWinEventHook, HWINEVENTHOOK},
WindowsAndMessaging::{
DispatchMessageW, GetForegroundWindow, GetMessageW, GetWindowThreadProcessId,
TranslateMessage, EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_MINIMIZEEND, MSG,
WINEVENT_OUTOFCONTEXT, WINEVENT_SKIPOWNPROCESS,
WINEVENT_OUTOFCONTEXT, WINEVENT_SKIPOWNPROCESS, PostThreadMessageW, WM_QUIT,
},
},
}, System::Threading::GetCurrentThreadId,
};
use crate::pid_to_exe::pid_to_exe_path;
@@ -48,7 +48,9 @@ unsafe extern "system" fn win_event_proc(
}
}
pub fn await_win_change_events(callback: Box<dyn Fn(&str) + Send>) {
type WinCallback = Box<dyn Fn(&str) + Send>;
pub fn await_win_change_events(callback: WinCallback) {
*WIN_CHANGE_CALLBACK.lock().unwrap() = Some(callback);
unsafe {
SetWinEventHook(
@@ -71,9 +73,53 @@ pub fn await_win_change_events(callback: Box<dyn Fn(&str) + Send>) {
);
let mut msg: MSG = MSG::default();
while GetMessageW(&mut msg, HWND::default(), 0, 0).as_bool() {
while GetMessageW(&mut msg, HWND::default(), 0, 0).0 > 0 {
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
}
}
pub struct WindowChangeMonitor {
join_handle: Option<JoinHandle<()>>,
win_thread_id: Arc<AtomicU32>
}
impl Drop for WindowChangeMonitor {
fn drop(&mut self) {
if let Some(join_handle) = self.join_handle.take() {
let tid : u32 = self.win_thread_id.load(std::sync::atomic::Ordering::Relaxed);
if tid != 0 {
unsafe {
PostThreadMessageW(tid, WM_QUIT, WPARAM(0), LPARAM(0)).ok().unwrap();
}
}
join_handle.join().expect("Unable to terminate window change thread");
}
println!("Joined window change thread");
}
}
impl WindowChangeMonitor {
pub(crate) fn start(f : WinCallback) -> WindowChangeMonitor {
let win_thread_id = Arc::new(AtomicU32::new(0));
let join_handle = {
let win_thread_id = win_thread_id.clone();
thread::spawn(move || {
win_thread_id.store(unsafe { GetCurrentThreadId() }.into(), std::sync::atomic::Ordering::Relaxed);
await_win_change_events(f);
})
};
{
let win_thread_id = win_thread_id.clone();
WindowChangeMonitor {
join_handle: Some(join_handle),
win_thread_id
}
}
}
}

View File

@@ -1 +1,4 @@
- create session-focused API - should provide a callback for all existing sessions and any time a new sessions is created
- Add the ability to reload/restart the mute list - must essentially restart/refresh all sessions if this occurs?
- can we simply release everything in this case? Should work given the way the windows-rs COM wrapper works I think.
- Tray icon
- Simple GUI to select from open windows and add to the list