Skip to content

Commit

Permalink
feat(volume): Add an option to keep volume level across audio devices
Browse files Browse the repository at this point in the history
Merge pull request #1328 from XangelMusic/dev
  • Loading branch information
XangelMusic authored Dec 16, 2023
1 parent 1f2e29c commit ca293b5
Show file tree
Hide file tree
Showing 10 changed files with 593 additions and 477 deletions.
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

0 comments on commit ca293b5

Please sign in to comment.