Skip to content

feat: Keep volume level across audio devices #1328

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Dec 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions SoundSwitch.Audio.Manager/AudioSwitcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,58 @@ public void SwitchForegroundProcessTo(string deviceId, ERole role, EDataFlow flo
SwitchProcessTo(deviceId, role, flow, processId);
}

/// <summary>
/// Set the same master volume level from the default audio device to the next device
/// </summary>
/// <param name="deviceId">Id of the device</param>
/// <param name="role">Which role to switch</param>
/// <param name="flow">Which flow to switch</param>
/// <summary>
/// Get the current default endpoint
/// </summary>
/// <param name="flow"></param>
/// <param name="role"></param>
/// <returns>Null if no default device is defined</returns>
private MMDevice? GetMmDefaultAudioEndpoint(EDataFlow flow, ERole role) => ComThread.Invoke(() => EnumeratorClient.GetDefaultEndpoint(flow, role));

/// <summary>
/// Set the same master volume level from the default audio device to the next device
/// </summary>
/// <param name="device"></param>
public void SetVolumeFromDefaultDevice(DeviceInfo device)
{
var currentDefault = GetMmDefaultAudioEndpoint((EDataFlow)device.Type, ERole.eConsole);
if (currentDefault == null)
return;
var audioInfo = InteractWithMmDevice(currentDefault, mmDevice =>
{
var defaultDeviceAudioEndpointVolume = mmDevice.AudioEndpointVolume;
return defaultDeviceAudioEndpointVolume == null ? default : (Volume: defaultDeviceAudioEndpointVolume.MasterVolumeLevelScalar, IsMuted: defaultDeviceAudioEndpointVolume.Mute);
});

if (audioInfo == default)
return;

var nextDevice = GetDevice(device.Id);

if(nextDevice == null)
return;

InteractWithMmDevice(nextDevice, mmDevice =>
{
if (mmDevice is not { State: DeviceState.Active })
return nextDevice;

if (mmDevice.AudioEndpointVolume == null)
return nextDevice;

mmDevice.AudioEndpointVolume.MasterVolumeLevelScalar = audioInfo.Volume;
mmDevice.AudioEndpointVolume.Mute = audioInfo.IsMuted;
return mmDevice;
});
}


/// <summary>
/// Is the given deviceId the default audio device in the system
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,5 +91,10 @@ public interface ISoundSwitchConfiguration : IConfiguration
/// Is the quick menu showed when using a hotkey
/// </summary>
bool QuickMenuEnabled { get; set; }

/// <summary>
/// Is keep volume enabled
/// </summary>
bool KeepVolumeEnabled { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,11 @@ public SoundSwitchConfiguration()
/// </summary>
public bool QuickMenuEnabled { get; set; } = false;

/// <summary>
/// Is keep volume enabled
/// </summary>
public bool KeepVolumeEnabled { get; set; } = false;

// Needed by Interface
[JsonIgnore]
public string FileLocation { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ private DeviceInfo GetNextDevice(DeviceInfo[] audioDevices, DataFlow type)
/// <param name="device"></param>
public bool SetActiveDevice(DeviceInfo device)
{
if (device.Type != DataFlow.Capture && AppModel.Instance.KeepVolumeEnabled)
{
AudioSwitcher.Instance.SetVolumeFromDefaultDevice(device);
}

Log.Information("Set Default device: {Device}", device);
if (!AppModel.Instance.SetCommunications)
{
Expand Down
18 changes: 18 additions & 0 deletions SoundSwitch/Localization/SettingsStrings.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 8 additions & 2 deletions SoundSwitch/Localization/SettingsStrings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -477,14 +477,20 @@ Restore the state of the system when the application is closed.</value>
<data name="telemetry" xml:space="preserve">
<value>Telemetry</value>
</data>
<data name="telemetry.desc" xml:space="preserve">
<value>Gather anonymously which version of SoundSwitch is in use. Only shared with the developer of SoundSwitch.</value>
</data>
<data name="quickMenu" xml:space="preserve">
<value>Quick Menu on hotkey</value>
</data>
<data name="quickMenu.desc" xml:space="preserve">
<value>Show a quick menu like Windows language when using a hotkey</value>
</data>
<data name="telemetry.desc" xml:space="preserve">
<value>Gather anonymously which version of SoundSwitch is in use. Only shared with the developer of SoundSwitch.</value>
<data name="keepVolume" xml:space="preserve">
<value>Keep volume level across devices</value>
</data>
<data name="keepVolume.desc" xml:space="preserve">
<value>Keep the same volume level when switching playback devices</value>
</data>
<data name="devices.AutoAddNewDevice" xml:space="preserve">
<value>Auto select new devices</value>
Expand Down
9 changes: 9 additions & 0 deletions SoundSwitch/Model/AppModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,15 @@ public bool QuickMenuEnabled
}
}

public bool KeepVolumeEnabled
{
get => AppConfigs.Configuration.KeepVolumeEnabled;
set
{
AppConfigs.Configuration.KeepVolumeEnabled = value;
AppConfigs.Configuration.Save();
}
}

public DeviceCollection<DeviceInfo> SelectedDevices
{
Expand Down
1 change: 1 addition & 0 deletions SoundSwitch/Model/IAppModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ public interface IAppModel : IDisposable

bool Telemetry { get; set; }
bool QuickMenuEnabled { get; set; }
bool KeepVolumeEnabled { get; set; }
bool AutoAddNewDevice { get; set; }

#endregion
Expand Down
Loading