Changing the default sound device

  • Context

My son installed a sofware to change his voice.

Unfortunately, I don’t have this software in my profile but the default device is set to use this virtual device as microphone.

  • Solution

I was looking for a way to change the default input and found the following promissing links:

https://github.com/frgnca/AudioDeviceCmdlets
https://github.com/SomeProgrammerGuy/Powershell-Default-Audio-Device-Changer/blob/master/Set-DefaultAudioDevice.ps1

Although it’s designed for Windows 7, I’ve decided to write a script that would set the default device based on the name of the device (using a dynamic paramter) on my Windows 10.

#Requires -RunAsAdministrator
#Requires -PSEdition Desktop
[CmdletBinding(SupportsShouldProcess)]
Param()
DynamicParam {
$Dictionary = New-Object -TypeName System.Management.Automation.RuntimeDefinedParameterDictionary
#region helper function
Function New-ParameterAttributCollection {
[CmdletBinding()]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '')]
Param(
[Switch]$Mandatory,
[Switch]$ValueFromPipeline,
[Switch]$ValueFromPipelineByPropertyName,
[String]$ParameterSetName,
[Parameter()]
[ValidateSet(
'Arguments','Count','Drive','EnumeratedArguments','Length','NotNull',
'NotNullOrEmpty','Pattern','Range','Script','Set','UserDrive'
)][string]$ValidateType,
[Parameter()]
$ValidationContent
)
Begin {
}Process {
$c = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
$a = New-Object System.Management.Automation.ParameterAttribute
if ($Mandatory) {
$a.Mandatory = $true
}
if ($ValueFromPipeline) {
$a.ValueFromPipeline = $true
}
if ($ValueFromPipelineByPropertyName) {
$a.ValueFromPipelineByPropertyName=$true
}
if ($ParameterSetName) {
$a.ParameterSetName = $ParameterSetName
}
$c.Add($a)
if ($ValidateType -and $ValidationContent) {
try {
$c.Add((New-Object "System.Management.Automation.Validate$($ValidateType)Attribute"(
$ValidationContent
)))
} catch {
Throw $_
}
}
$c
}
End {}
}
#endregion
try {
$audioDevices = Get-PnpDevice -ErrorAction Stop |
Where-Object {$_.Class -eq 'AudioEndpoint' } |
Select-Object -Property Caption,Status,DeviceID |
Foreach-Object {
[PSCustomObject]@{
DeviceName = $_.Caption
Status = $_.Status
Id = ($_.DeviceID -split '\.')[4]
}
}
} catch {
Throw 'Failed to enumerate audio devices'
}
#region param DeviceName
$Dictionary.Add(
'DeviceName',
(New-Object System.Management.Automation.RuntimeDefinedParameter(
'DeviceName',
[string],
(New-ParameterAttributCollection -Mandatory -ValidateType Set -ValidationContent (
$audioDevices | ForEach-Object { $_.DeviceName }
))
))
)
$Dictionary
}
Begin {}
Process {}
End {
#Source: https://github.com/SomeProgrammerGuy/Powershell-Default-Audio-Device-Changer/blob/master/Set-DefaultAudioDevice.ps1
$cSharpSourceCode = @"
using System;
using System.Runtime.InteropServices;
// eConsole: Games, system notification sounds, and voice commands. //
// eMultimedia: Music, movies, narration, and live music recording. //
// eCommunications: Voice communications (talking to another person). //
// ERole_enum_count: The number of members in the ERole enumeration //
// (not counting the ERole_enum_count member). //
public enum ERole : uint
{
eConsole = 0,
eMultimedia = 1,
eCommunications = 2,
ERole_enum_count = 3
}
// Undocumented COM-interface IPolicyConfig. //
// Use to set default audio Capture / Render endpoint. //
[Guid("F8679F50-850A-41CF-9C72-430F290290C8"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IPolicyConfig
{
// HRESULT GetMixFormat(PCWSTR, WAVEFORMATEX **);
[PreserveSig]
int GetMixFormat();
// HRESULT STDMETHODCALLTYPE GetDeviceFormat(PCWSTR, INT, WAVEFORMATEX **);
[PreserveSig]
int GetDeviceFormat();
// HRESULT STDMETHODCALLTYPE ResetDeviceFormat(PCWSTR);
[PreserveSig]
int ResetDeviceFormat();
// HRESULT STDMETHODCALLTYPE SetDeviceFormat(PCWSTR, WAVEFORMATEX *, WAVEFORMATEX *);
[PreserveSig]
int SetDeviceFormat();
// HRESULT STDMETHODCALLTYPE GetProcessingPeriod(PCWSTR, INT, PINT64, PINT64);
[PreserveSig]
int GetProcessingPeriod();
// HRESULT STDMETHODCALLTYPE SetProcessingPeriod(PCWSTR, PINT64);
[PreserveSig]
int SetProcessingPeriod();
// HRESULT STDMETHODCALLTYPE GetShareMode(PCWSTR, struct DeviceShareMode *);
[PreserveSig]
int GetShareMode();
// HRESULT STDMETHODCALLTYPE SetShareMode(PCWSTR, struct DeviceShareMode *);
[PreserveSig]
int SetShareMode();
// HRESULT STDMETHODCALLTYPE GetPropertyValue(PCWSTR, const PROPERTYKEY &, PROPVARIANT *);
[PreserveSig]
int GetPropertyValue();
// HRESULT STDMETHODCALLTYPE SetPropertyValue(PCWSTR, const PROPERTYKEY &, PROPVARIANT *);
[PreserveSig]
int SetPropertyValue();
// HRESULT STDMETHODCALLTYPE SetDefaultEndpoint(__in PCWSTR wszDeviceId, __in ERole role);
[PreserveSig]
int SetDefaultEndpoint(
[In] [MarshalAs(UnmanagedType.LPWStr)] string wszDeviceId,
[In] [MarshalAs(UnmanagedType.U4)] ERole role);
// HRESULT STDMETHODCALLTYPE SetEndpointVisibility(PCWSTR, INT);
[PreserveSig]
int SetEndpointVisibility();
}
[ComImport, Guid("870AF99C-171D-4F9E-AF0D-E63DF40C2BC9")]
internal class _CPolicyConfigClient
{
}
public class PolicyConfigClient
{
public static int SetDefaultDevice(string deviceID)
{
IPolicyConfig _policyConfigClient = (new _CPolicyConfigClient() as IPolicyConfig);
try
{
Marshal.ThrowExceptionForHR(_policyConfigClient.SetDefaultEndpoint(deviceID, ERole.eConsole));
Marshal.ThrowExceptionForHR(_policyConfigClient.SetDefaultEndpoint(deviceID, ERole.eMultimedia));
Marshal.ThrowExceptionForHR(_policyConfigClient.SetDefaultEndpoint(deviceID, ERole.eCommunications));
return 0;
}
catch
{
return 1;
}
}
}
"@
try {
Add-Type -TypeDefinition $cSharpSourceCode -ErrorAction Stop
} catch {
Write-Error 'Failed to add cSharp Code'
}
Function Set-DefaultAudioDevice {
[CmdletBinding(SupportsShouldProcess)]
[OutputType([System.Int32])]
Param (
[parameter(Mandatory)]
[string]$deviceId
)
Begin {}
Process {}
End {
try {
if ($pscmdlet.ShouldProcess("$($deviceId)", 'Set default audio device to:')) {
[PolicyConfigClient]::SetDefaultDevice("{0.0.0.00000000}.$($deviceId)")
}
} catch {
Write-Error "Failed to set $($DeviceName) as default because $($_.Exception.Message)"
}
}
}
$d = $audioDevices | Where-Object { $_.DeviceName -eq "$($PSBoundParameters['DeviceName'])" }
try {
if ($pscmdlet.ShouldProcess("$($d.DeviceName)", 'Set default audio device to:')) {
$r = Set-DefaultAudioDevice -deviceId $d.Id
If ($r -eq 0) {
Write-Verbose -Message "Successfully set $($d.DeviceName) as default audio device"
} else {
Write-Warning -Message "Failed to set $($DeviceName) as default audio device, return code was $($r)"
}
}
} catch {
Write-Error -Message "Failed to set $($DeviceName) as default"
}
}

How do I use it?

./Set-DefaultAudioDevice.ps1 -DeviceName 'Headset Earphone (HyperX Virtual Surround Sound)' -Verbose    

The script has a WhatIf parameter and the dynamic parameter supports tab completion to find out present audio device names.

Next step, fire up a scheduled tasks that executes this script at every logon of my account 😀

1 thought on “Changing the default sound device

  1. Pingback: Dew Drop – June 26, 2023 (#3971) – Morning Dew by Alvin Ashcraft

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.