private void ProcessAdded(ObservableProcess process) { if (process == null) { throw new ArgumentNullException(nameof(process)); } while (applicationDevicePreferences == null) { Task.Delay(250); } SharedModels.ApplicationDevicePreference applicationDevicePreference = applicationDevicePreferences.Applications.FirstOrDefault(x => x.Name == process.ProcessName); if (applicationDevicePreference == null) { applicationDevicePreference = new SharedModels.ApplicationDevicePreference(); } AudioInterface preferredRender = GetApplicationDevicePreference(DataFlow.Render, applicationDevicePreference, process); if (preferredRender != null) { ChangeDefaultApplicationDevice(preferredRender, process); } AudioInterface preferredCapture = GetApplicationDevicePreference(DataFlow.Capture, applicationDevicePreference, process); if (preferredCapture != null) { ChangeDefaultApplicationDevice(preferredCapture, process); } }
private void CheckApplicationDeviceChanges() { foreach (ObservableProcess process in ProcessCollection.Processes) { AudioInterface windowsPreferredRender = GetDefaultApplicationDevice(DataFlow.Render, process); AudioInterface windowsPreferredCapture = GetDefaultApplicationDevice(DataFlow.Capture, process); SharedModels.ApplicationDevicePreference applicationDevicePreference = applicationDevicePreferences.Applications.FirstOrDefault(x => x.Name == process.ProcessName); string preferredRenderId = applicationDevicePreference?.Devices?.RenderDeviceId; string preferredCaptureId = applicationDevicePreference?.Devices?.CaptureDeviceId; bool windowsThinksDefault = windowsPreferredRender == null && windowsPreferredCapture == null; bool noPreferences = preferredRenderId == null && preferredCaptureId == null; // There is agreement that this process uses the default devices. if (noPreferences && windowsThinksDefault) { continue; } // Windows doesn't think this process uses the default device and we don't have any preferences for the process. if (applicationDevicePreference == default && !windowsThinksDefault) { ChangeDefaultApplicationDevice(windowsPreferredRender, process); ChangeDefaultApplicationDevice(windowsPreferredCapture, process); } // Windows doesn't think this process uses the default device. We agree, but we disagree on the preferred audio device. else if (!windowsThinksDefault) { bool changeNeeded = preferredRenderId != windowsPreferredRender?.ID; changeNeeded = changeNeeded || preferredCaptureId != windowsPreferredCapture?.ID; if (changeNeeded) { Trace.WriteLine($"Preference conflict detected between Windows Settings and Stream Controller for process {process.ProcessName}."); } if (process.AudioDeviceTogglingNeeded) { ToggleDefaultApplicationDevice(process); process.AudioDeviceTogglingNeeded = false; } } // Windows thinks the process uses the default device. We disagree and are waiting for the process to make a sound. else if (windowsThinksDefault) { EarTrumpet.DataModel.WindowsAudio.Internal.AudioPolicyConfig audioPolicyConfig; if (preferredRenderId != null) { audioPolicyConfig = new EarTrumpet.DataModel.WindowsAudio.Internal.AudioPolicyConfig(DataFlow.Render); audioPolicyConfig.SetDefaultEndPoint(preferredRenderId, process.Id); } if (preferredCaptureId != null) { audioPolicyConfig = new EarTrumpet.DataModel.WindowsAudio.Internal.AudioPolicyConfig(DataFlow.Capture); audioPolicyConfig.SetDefaultEndPoint(preferredCaptureId, process.Id); } } } }
void IMMNotificationClient.OnDeviceRemoved(string deviceId) { AudioInterface audioInterface = GetAudioInterfaceById(deviceId); mContext.Send( x => Devices.Remove(GetAudioInterfaceById(deviceId)) , null); if (audioInterface.IsActive) { mContext.Send( x => ActiveDevices.Remove(audioInterface), null); } }
void IMMNotificationClient.OnDeviceAdded(string pwstrDeviceId) { AudioInterface device = new AudioInterface { Device = _Enumerator.GetDevice(pwstrDeviceId) }; mContext.Send( x => Devices.Add(device) , null); if (device.IsActive) { mContext.Send( x => ActiveDevices.Add(device), null); } }
public static void ChangeDefaultApplicationDevice(AudioInterface audioInterface, ObservableProcess process) { if (audioInterface == null) { throw new ArgumentNullException(nameof(audioInterface)); } if (process == null) { throw new ArgumentNullException(nameof(process)); } EarTrumpet.DataModel.WindowsAudio.Internal.AudioPolicyConfig audioPolicyConfig = new EarTrumpet.DataModel.WindowsAudio.Internal.AudioPolicyConfig(audioInterface.DataFlow); audioPolicyConfig.SetDefaultEndPoint(audioInterface.ID, process.Id); Instance.RemoveOldApplicationDevicePreference(process, audioInterface); Instance.AddDeviceApplicationPreference(audioInterface, process); Instance.AddApplicationDevicePreference(process, audioInterface); }
private void AddDeviceApplicationPreference(AudioInterface audioInterface, ObservableProcess process) { SharedModels.DeviceApplicationPreference deviceApplicationPreference = deviceApplicationPreferences.Devices.FirstOrDefault(x => x.Id == audioInterface.ID); if (deviceApplicationPreference == default) { deviceApplicationPreference = new SharedModels.DeviceApplicationPreference() { Id = audioInterface.ID, Applications = new List <string>() }; deviceApplicationPreferences.Devices.Add(deviceApplicationPreference); } if (!deviceApplicationPreference.Applications.Contains(process.ProcessName)) { deviceApplicationPreference.Applications.Add(process.ProcessName); } jsonDataDirty = true; }
private void AddApplicationDevicePreference(ObservableProcess process, AudioInterface audioInterface) { SharedModels.ApplicationDevicePreference applicationDevicePreference = applicationDevicePreferences.Applications.FirstOrDefault(x => x.Name == process.ProcessName); if (applicationDevicePreference == default) { applicationDevicePreference = new SharedModels.ApplicationDevicePreference() { Name = process.ProcessName, Devices = new SharedModels.DefaultDevicePreference() }; applicationDevicePreferences.Applications.Add(applicationDevicePreference); } _ = audioInterface.DataFlow switch { DataFlow.Render => applicationDevicePreference.Devices.RenderDeviceId = audioInterface.ID, DataFlow.Capture => applicationDevicePreference.Devices.CaptureDeviceId = audioInterface.ID, _ => null }; jsonDataDirty = true; }
private void DevicesEnumerated(MMDeviceCollection collection) { _Enumerator.RegisterEndpointNotificationCallback(_NotificationClient); foreach (MMDevice device in collection) { AudioInterface audioDevice = new AudioInterface { Device = device }; _Context.Send( x => Devices.Add(audioDevice), null); if (audioDevice.IsActive) { _Context.Send( x => ActiveDevices.Add(audioDevice), null); } } UpdateDefaultDevice(DataFlow.Render, _Enumerator.GetDefaultAudioEndpoint(DataFlow.Render, Role.Console).ID); UpdateDefaultDevice(DataFlow.Capture, _Enumerator.GetDefaultAudioEndpoint(DataFlow.Capture, Role.Console).ID); DevicesAreEnumerated = true; NotifyCollectionEnumerated(); RestoreDeviceApplicationPreferences(); bool processesEnumerated = false; _Context.Send( x => processesEnumerated = ProcessCollection.Instance.ProcessesAreEnumerated, null); if (!processesEnumerated) { ProcessCollection.Instance.CollectionEnumerated += Processes_CollectionEnumerated; } else { Processes_CollectionEnumerated(this, EventArgs.Empty); } ProcessCollection.Instance.CollectionChanged += Processes_CollectionChanged; }
void IMMNotificationClient.OnDeviceStateChanged(string deviceId, DeviceState newState) { AudioInterface audioInterface = GetAudioInterfaceById(deviceId); if (audioInterface != null) { audioInterface.SetProperties(newState); } if (newState != DeviceState.Active) { if (ActiveDevices.Contains(audioInterface)) { mContext.Send( x => ActiveDevices.Remove(audioInterface), null); } return; } mContext.Send( x => ActiveDevices.Add(audioInterface), null); SharedModels.DeviceApplicationPreference deviceApplicationPreference = Instance.deviceApplicationPreferences.Devices.FirstOrDefault(x => x.Id == deviceId); if (deviceApplicationPreference == default) { return; } foreach (string applicationName in deviceApplicationPreference.Applications) { ObservableProcess[] processes = ProcessCollection.Processes.Where(x => x.ProcessName == applicationName).ToArray(); foreach (ObservableProcess process in processes) { ChangeDefaultApplicationDevice(audioInterface, process); } } }
private void RemoveOldApplicationDevicePreference(ObservableProcess process, AudioInterface audioInterface) { SharedModels.ApplicationDevicePreference applicationDevicePreference = applicationDevicePreferences.Applications.FirstOrDefault(x => x.Name == process.ProcessName); if (applicationDevicePreference == default) { return; } string previousPreferredInterface = null; switch (audioInterface.DataFlow) { case DataFlow.Render: previousPreferredInterface = applicationDevicePreference.Devices.RenderDeviceId; applicationDevicePreference.Devices.RenderDeviceId = null; break; case DataFlow.Capture: previousPreferredInterface = applicationDevicePreference.Devices.CaptureDeviceId; applicationDevicePreference.Devices.CaptureDeviceId = null; break; default: return; } if (applicationDevicePreference.Devices.RenderDeviceId == null && applicationDevicePreference.Devices.CaptureDeviceId == null) { applicationDevicePreferences.Applications.Remove(applicationDevicePreference); } SharedModels.DeviceApplicationPreference deviceApplicationPreference = deviceApplicationPreferences.Devices.FirstOrDefault(x => x.Id == previousPreferredInterface); if (deviceApplicationPreference == default) { return; } deviceApplicationPreference.Applications.Remove(process.ProcessName); if (deviceApplicationPreference.Applications.Count == 0) { deviceApplicationPreferences.Devices.Remove(deviceApplicationPreference); } }
public static void ClearApplicationDefaultDevice(DataFlow dataFlow, ObservableProcess process) { if (process == null) { throw new ArgumentNullException(nameof(process)); } AudioInterface dataFlowInterface = dataFlow switch { DataFlow.Render => Instance.DefaultRender, DataFlow.Capture => Instance.DefaultCapture, _ => null }; if (dataFlowInterface == null) { throw new ArgumentException($"{Enum.GetName(typeof(DataFlow),dataFlow)} is not {Enum.GetName(typeof(DataFlow), DataFlow.Render)} or {Enum.GetName(typeof(DataFlow), DataFlow.Capture)}.", nameof(dataFlow)); } EarTrumpet.DataModel.WindowsAudio.Internal.AudioPolicyConfig audioPolicyConfig = new EarTrumpet.DataModel.WindowsAudio.Internal.AudioPolicyConfig(dataFlow); audioPolicyConfig.SetDefaultEndPoint(String.Empty, process.Id); Instance.RemoveOldApplicationDevicePreference(process, dataFlowInterface); }
public static void ToggleDefaultApplicationDevice(ObservableProcess process) { if (process == null) { throw new ArgumentNullException(nameof(process)); } AudioInterface renderDevice = GetDefaultApplicationDevice(DataFlow.Render, process); if (renderDevice != null) { Trace.WriteLine($"Toggling PID {process.Id} render device to default and back to {renderDevice.FriendlyName}."); ChangeDefaultApplicationDevice(Instance.DefaultRender, process); ChangeDefaultApplicationDevice(renderDevice, process); } AudioInterface captureDevice = GetDefaultApplicationDevice(DataFlow.Capture, process); if (captureDevice != null) { Trace.WriteLine($"Toggling PID {process.Id} capture device to default and back to {captureDevice.FriendlyName}."); ChangeDefaultApplicationDevice(Instance.DefaultCapture, process); ChangeDefaultApplicationDevice(captureDevice, process); } }
private AudioInterface GetApplicationDevicePreference(DataFlow dataFlow, SharedModels.ApplicationDevicePreference applicationDevicePreference, ObservableProcess process) { string preferredInterfaceId = dataFlow switch { DataFlow.Render => applicationDevicePreference?.Devices?.RenderDeviceId, DataFlow.Capture => applicationDevicePreference?.Devices?.CaptureDeviceId, _ => null }; if (preferredInterfaceId != null) { return(GetAudioInterfaceById(preferredInterfaceId)); } AudioInterface audioInterface = GetDefaultApplicationDevice(dataFlow, process); if (audioInterface != null) { RemoveOldApplicationDevicePreference(process, audioInterface); AddApplicationDevicePreference(process, audioInterface); AddDeviceApplicationPreference(audioInterface, process); return(audioInterface); } return(null); }