{"componentChunkName":"component---src-templates-post-template-js","path":"/windows-toggle-audiodevice-en","result":{"data":{"markdownRemark":{"id":"ea74c638-9b1a-5c73-805c-660994b9caab","html":"<blockquote>\n<p>This page has been machine-translated from the <a href=\"/windows-toggle-audiodevice\">original page</a>.</p>\n</blockquote>\n<p>On my PC, I usually keep a random playlist playing through the connected speakers, but switching the sound output to a headset from the Settings app every time just for online English conversation lessons was quite a hassle.</p>\n<p>So I decided to make it possible to switch sound devices with a simple shortcut so that I would not be able to use the inconvenience of switching headsets as an excuse to skip English conversation practice.</p>\n<p>However, on Windows, it seems there is no built-in feature for switching sound devices, so you either need to use some third-party tool or implement your own switching tool.</p>\n<p>As a rule, I do not like installing tools I do not really understand on the main machine I use privately, so this time I decided to implement a switching tool in PowerShell.</p>\n<p>When creating the script, I relied heavily on the following article. (I almost copied it as-is.)</p>\n<p>Reference: <a href=\"https://itib.hatenablog.com/entry/2021121001\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Windowsの音声出力先を変えるショートカット作成 - itiblog</a></p>\n<p>Trying it out taught me more than I expected, such as the need to use a COM interface, so I am summarizing it in this article.</p>\n<!-- omit in toc -->\n<h2 id=\"table-of-contents\" style=\"position:relative;\"><a href=\"#table-of-contents\" aria-label=\"table of contents permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Table of Contents</h2>\n<ul>\n<li><a href=\"#the-script-i-created\">The Script I Created</a></li>\n<li>\n<p><a href=\"#how-to-obtain-audio-device-ids-on-windows\">How to Obtain Audio Device IDs on Windows</a></p>\n<ul>\n<li><a href=\"#check-the-active-audio-device-with-the-immdeviceenumerator-interface\">Check the Active Audio Device with the IMMDeviceEnumerator Interface</a></li>\n</ul>\n</li>\n<li>\n<p><a href=\"#how-to-change-audio-devices-on-windows\">How to Change Audio Devices on Windows</a></p>\n<ul>\n<li><a href=\"#what-is-the-ipolicyconfig-interface\">What Is the IPolicyConfig Interface</a></li>\n<li><a href=\"#implementing-policyconfigclient-using-the-ipolicyconfig-interface\">Implementing PolicyConfigClient Using the IPolicyConfig Interface</a></li>\n</ul>\n</li>\n<li><a href=\"#using-the-c-sharp-code-from-powershell\">Using the C Sharp Code from PowerShell</a></li>\n<li><a href=\"#summary\">Summary</a></li>\n</ul>\n<h2 id=\"the-script-i-created\" style=\"position:relative;\"><a href=\"#the-script-i-created\" aria-label=\"the script i created permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>The Script I Created</h2>\n<p>The final script I created is below.</p>\n<p>You can switch devices by changing the audio device IDs in this script as needed, saving it as a <code class=\"language-text\">ps1</code> file, and running it.</p>\n<div class=\"gatsby-highlight\" data-language=\"powershell\"><pre class=\"language-powershell\"><code class=\"language-powershell\"><span class=\"token variable\">$csharpCode</span> = @<span class=\"token string\">\"\nusing System;\nusing System.Runtime.InteropServices;\n\npublic enum EDataFlow\n{\n    eRender,\n    eCapture,\n    eAll,\n}\n\npublic enum ERole\n{\n    eConsole,\n    eMultimedia,\n    eCommunications,\n}\n\n[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid(\"</span>D666063F-1587-4E43-81F1-B948E807363F<span class=\"token string\">\")]\npublic interface IMMDevice\n{\n    int Activate();\n    int OpenPropertyStore();\n    int GetId([MarshalAs(UnmanagedType.LPWStr)] out string ppstrId);\n    int GetState();\n}\n\n[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid(\"</span>A95664D2-9614-4F35-A746-DE8DB63617E6<span class=\"token string\">\")]\npublic interface IMMDeviceEnumerator\n{\n    int EnumAudioEndpoints();\n    int GetDefaultAudioEndpoint(EDataFlow dataFlow, ERole role, out IMMDevice ppEndpoint);\n}\n\n[ComImport, Guid(\"</span>BCDE0395-E52F-467C-8E3D-C4579291692E<span class=\"token string\">\")]\npublic class MMDeviceEnumerator { }\n\npublic class AudioHelper\n{\n    public static string GetDefaultDeviceId()\n    {\n        IMMDeviceEnumerator enumerator = new MMDeviceEnumerator() as IMMDeviceEnumerator;\n        IMMDevice device;\n        enumerator.GetDefaultAudioEndpoint(EDataFlow.eRender, ERole.eConsole, out device);\n        string id;\n        device.GetId(out id);\n        return id;\n    }\n}\n\n[Guid(\"</span>F8679F50-850A-41CF-9C72-430F290290C8<span class=\"token string\">\"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]\ninternal interface IPolicyConfig\n{\n    [PreserveSig]\n    int GetMixFormat();\n    [PreserveSig]\n    int GetDeviceFormat();\n    [PreserveSig]\n    int ResetDeviceFormat();\n    [PreserveSig]\n    int SetDeviceFormat();\n    [PreserveSig]\n    int GetProcessingPeriod();\n    [PreserveSig]\n    int SetProcessingPeriod();\n    [PreserveSig]\n    int GetShareMode();\n    [PreserveSig]\n    int SetShareMode();\n    [PreserveSig]\n    int GetPropertyValue();\n    [PreserveSig]\n    int SetPropertyValue();\n    [PreserveSig]\n    int SetDefaultEndpoint(\n        [In] [MarshalAs(UnmanagedType.LPWStr)] string deviceId, \n        [In] [MarshalAs(UnmanagedType.U4)] ERole role);\n    [PreserveSig]\n    int SetEndpointVisibility();\n}\n\n[ComImport, Guid(\"</span>870AF99C-171D-4F9E-AF0D-E63DF40C2BC9<span class=\"token string\">\")]\ninternal class _CPolicyConfigClient\n{\n}\npublic class PolicyConfigClient\n{\n    public static int SetDefaultDevice(string deviceID)\n    {\n        IPolicyConfig _policyConfigClient = (new _CPolicyConfigClient() as IPolicyConfig);\n        try {\n            Marshal.ThrowExceptionForHR(_policyConfigClient.SetDefaultEndpoint(deviceID, ERole.eConsole));\n            Marshal.ThrowExceptionForHR(_policyConfigClient.SetDefaultEndpoint(deviceID, ERole.eMultimedia));\n            Marshal.ThrowExceptionForHR(_policyConfigClient.SetDefaultEndpoint(deviceID, ERole.eCommunications));\n            return 0;\n        } catch {\n            return 1;\n        }\n    }\n}\n\"</span>@\n\n<span class=\"token function\">Add-Type</span> <span class=\"token operator\">-</span>TypeDefinition <span class=\"token variable\">$csharpCode</span>\n\n<span class=\"token variable\">$currentDeviceId</span> = <span class=\"token namespace\">[AudioHelper]</span>::GetDefaultDeviceId<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n<span class=\"token variable\">$deviceId</span> = <span class=\"token string\">\"\"</span>\n<span class=\"token variable\">$deviceA</span> = <span class=\"token string\">\"&lt;Device A ID>\"</span>\n<span class=\"token variable\">$deviceB</span> = <span class=\"token string\">\"&lt;Device B ID>\"</span>\n\n<span class=\"token keyword\">if</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$currentDeviceId</span> <span class=\"token operator\">-eq</span> <span class=\"token string\">\"{0.0.0.00000000}.<span class=\"token variable\">$deviceA</span>\"</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n<span class=\"token variable\">$deviceId</span> = <span class=\"token variable\">$deviceB</span>\n<span class=\"token punctuation\">}</span>\n<span class=\"token keyword\">else</span> <span class=\"token punctuation\">{</span>\n<span class=\"token variable\">$deviceId</span> = <span class=\"token variable\">$deviceA</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token comment\"># Change Audio device</span>\n<span class=\"token namespace\">[PolicyConfigClient]</span>::SetDefaultDevice<span class=\"token punctuation\">(</span><span class=\"token string\">\"{0.0.0.00000000}.<span class=\"token variable\">$deviceId</span>\"</span><span class=\"token punctuation\">)</span></code></pre></div>\n<h2 id=\"how-to-obtain-audio-device-ids-on-windows\" style=\"position:relative;\"><a href=\"#how-to-obtain-audio-device-ids-on-windows\" aria-label=\"how to obtain audio device ids on windows permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>How to Obtain Audio Device IDs on Windows</h2>\n<p>First, based on the information in the referenced <a href=\"https://itib.hatenablog.com/entry/2021121001\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">article</a>, I confirmed that by checking the registry information with the following script, I could obtain information that includes the IDs of the audio devices present on the machine.</p>\n<div class=\"gatsby-highlight\" data-language=\"powershell\"><pre class=\"language-powershell\"><code class=\"language-powershell\"><span class=\"token variable\">$regRoot</span> = <span class=\"token string\">\"HKLM:\\Software\\Microsoft\\\"</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">Get-Devices</span>\n<span class=\"token punctuation\">{</span>\n    <span class=\"token variable\">$regKey</span> = <span class=\"token variable\">$regRoot</span> <span class=\"token operator\">+</span> <span class=\"token string\">\"\\Windows\\CurrentVersion\\MMDevices\\Audio\\Render\\\"</span>\n    <span class=\"token function\">Write-Output</span> <span class=\"token string\">\"Active Sound devices:\"</span>\n    <span class=\"token function\">Get-ChildItem</span> <span class=\"token variable\">$regKey</span> <span class=\"token punctuation\">|</span> <span class=\"token function\">Where-Object</span> <span class=\"token punctuation\">{</span> <span class=\"token variable\">$_</span><span class=\"token punctuation\">.</span>GetValue<span class=\"token punctuation\">(</span><span class=\"token string\">\"DeviceState\"</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">-eq</span> 1<span class=\"token punctuation\">}</span> <span class=\"token punctuation\">|</span>\n        <span class=\"token function\">Foreach-Object</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token variable\">$subKey</span> = <span class=\"token variable\">$_</span><span class=\"token punctuation\">.</span>OpenSubKey<span class=\"token punctuation\">(</span><span class=\"token string\">\"Properties\"</span><span class=\"token punctuation\">)</span>\n            <span class=\"token function\">Write-Output</span> <span class=\"token punctuation\">(</span><span class=\"token string\">\"  \"</span> <span class=\"token operator\">+</span> <span class=\"token variable\">$subKey</span><span class=\"token punctuation\">.</span>GetValue<span class=\"token punctuation\">(</span><span class=\"token string\">\"{a45c254e-df1c-4efd-8020-67d146a850e0},2\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n            <span class=\"token function\">Write-Output</span> <span class=\"token punctuation\">(</span><span class=\"token string\">\"    \"</span> <span class=\"token operator\">+</span> <span class=\"token variable\">$_</span><span class=\"token punctuation\">.</span>Name<span class=\"token punctuation\">.</span>Substring<span class=\"token punctuation\">(</span><span class=\"token variable\">$_</span><span class=\"token punctuation\">.</span>Name<span class=\"token punctuation\">.</span>LastIndexOf<span class=\"token punctuation\">(</span><span class=\"token string\">\"\\\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n        <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token function\">Get-Devices</span></code></pre></div>\n<p>However, this time I wanted to identify the ID of the audio device currently in use and implement a toggle switch that automatically changes to another audio device that is not currently in use, so I decided to include code in the script that obtains the ID of the current audio device using the Core Audio API.</p>\n<h3 id=\"check-the-active-audio-device-with-the-immdeviceenumerator-interface\" style=\"position:relative;\"><a href=\"#check-the-active-audio-device-with-the-immdeviceenumerator-interface\" aria-label=\"check the active audio device with the immdeviceenumerator interface permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Check the Active Audio Device with the IMMDeviceEnumerator Interface</h3>\n<p>To identify the ID of the audio device currently in use on the device, I used the <code class=\"language-text\">GetDefaultAudioEndpoint</code> method of the <code class=\"language-text\">IMMDeviceEnumerator</code> interface.</p>\n<p>Unlike <code class=\"language-text\">IPolicyConfig</code>, which is used when changing audio devices, <code class=\"language-text\">IMMDeviceEnumerator</code> appears to be an officially documented interface.</p>\n<p>Reference: <a href=\"https://learn.microsoft.com/ja-jp/windows/win32/api/mmdeviceapi/nn-mmdeviceapi-immdeviceenumerator\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">IMMDeviceEnumerator (mmdeviceapi.h) - Win32 apps | Microsoft Learn</a></p>\n<p>Reference: <a href=\"https://learn.microsoft.com/ja-jp/windows/win32/api/mmdeviceapi/nf-mmdeviceapi-immdeviceenumerator-getdefaultaudioendpoint\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">IMMDeviceEnumerator::GetDefaultAudioEndpoint (mmdeviceapi.h) - Win32 apps | Microsoft Learn</a></p>\n<p>Using this, I wrote the following code to obtain the ID of the currently used audio device through the Core Audio API.</p>\n<div class=\"gatsby-highlight\" data-language=\"c#\"><pre class=\"language-c#\"><code class=\"language-c#\">public enum EDataFlow\n{\n    eRender,\n    eCapture,\n    eAll,\n}\n\npublic enum ERole\n{\n    eConsole,\n    eMultimedia,\n    eCommunications,\n}\n\n\n[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid(&quot;D666063F-1587-4E43-81F1-B948E807363F&quot;)]\npublic interface IMMDevice\n{\n    int Activate();\n    int OpenPropertyStore();\n    int GetId([MarshalAs(UnmanagedType.LPWStr)] out string ppstrId);\n    int GetState();\n}\n\n\n[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid(&quot;A95664D2-9614-4F35-A746-DE8DB63617E6&quot;)]\npublic interface IMMDeviceEnumerator\n{\n    int EnumAudioEndpoints();\n    int GetDefaultAudioEndpoint(EDataFlow dataFlow, ERole role, out IMMDevice ppEndpoint);\n}\n\n\n[ComImport, Guid(&quot;BCDE0395-E52F-467C-8E3D-C4579291692E&quot;)]\npublic class MMDeviceEnumerator { }\n\npublic class AudioHelper\n{\n    public static string GetDefaultDeviceId()\n    {\n        IMMDeviceEnumerator enumerator = new MMDeviceEnumerator() as IMMDeviceEnumerator;\n        IMMDevice device;\n        enumerator.GetDefaultAudioEndpoint(EDataFlow.eRender, ERole.eConsole, out device);\n        string id;\n        device.GetId(out id);\n        return id;\n    }\n}</code></pre></div>\n<p>Once you define the above, you can run <code class=\"language-text\">[AudioHelper]::GetDefaultDeviceId()</code> to obtain the ID of the audio device currently applied on the machine.</p>\n<h2 id=\"how-to-change-audio-devices-on-windows\" style=\"position:relative;\"><a href=\"#how-to-change-audio-devices-on-windows\" aria-label=\"how to change audio devices on windows permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>How to Change Audio Devices on Windows</h2>\n<p>Based on the information in the referenced <a href=\"https://itib.hatenablog.com/entry/2021121001\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">article</a>, I confirmed that the Windows audio output destination can be changed with the following steps.</p>\n<ol>\n<li>Create <code class=\"language-text\">PolicyConfigClient</code> that implements the <code class=\"language-text\">IPolicyConfig</code> interface.</li>\n<li>Implement <code class=\"language-text\">SetDefaultDevice</code> included in <code class=\"language-text\">IPolicyConfig</code> in <code class=\"language-text\">PolicyConfigClient</code>.</li>\n<li>Change the audio playback device by calling <code class=\"language-text\">SetDefaultDevice</code> with the device UUID and <code class=\"language-text\">ERole</code>, which indicates the role assigned by the system to the audio endpoint device.</li>\n</ol>\n<h3 id=\"what-is-the-ipolicyconfig-interface\" style=\"position:relative;\"><a href=\"#what-is-the-ipolicyconfig-interface\" aria-label=\"what is the ipolicyconfig interface permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>What Is the IPolicyConfig Interface</h3>\n<p><code class=\"language-text\">IPolicyConfig</code> is a non-public COM interface that provides methods for managing Windows audio device policy settings, and its COM CLSID is <code class=\"language-text\">F8679F50-850A-41CF-9C72-430F290290C8</code>.</p>\n<p>Regarding this interface, the following issue includes a comment from an MS developer stating that it is an undocumented API.</p>\n<p>Reference: <a href=\"https://github.com/microsoft/CsWin32/issues/1105\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">IPolicyConfig and PolicyConfigClient not created · Issue #1105 · microsoft/CsWin32</a></p>\n<p>However, you can still find implementations such as <code class=\"language-text\">SetDefaultAudioDevice.cpp</code> in the following repository that show how to use the <code class=\"language-text\">IPolicyConfig</code> interface to change Windows audio device settings.</p>\n<p>Reference: <a href=\"https://github.com/amate/SetDefaultAudioDevice/blob/540e9b6c55554f27b5a5436505c8e62d6ed253e6/SetDefaultAudioDevice.cpp#L76\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">SetDefaultAudioDevice/SetDefaultAudioDevice.cpp</a></p>\n<p>Reference: <a href=\"https://github.com/frgnca/AudioDeviceCmdlets/blob/master/SOURCE/IPolicyConfig.cs\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">AudioDeviceCmdlets/SOURCE/IPolicyConfig.cs</a></p>\n<p>Below is the definition of the <code class=\"language-text\">IPolicyConfig</code> interface implemented in <code class=\"language-text\">IPolicyConfig.cs</code>.</p>\n<p>This implementation uses a COM interface from C#.</p>\n<p>It seems that the <code class=\"language-text\">[PreserveSig]</code> attribute before the method names is needed so that .NET does not treat the error codes returned from COM as exceptions.</p>\n<p>Also, the <code class=\"language-text\">IntPtr</code> used in the arguments appears to be used to pass pointers to native structures and similar information used on the COM side.</p>\n<p>Reference: <a href=\"https://makky12.hatenablog.com/entry/2016/08/03/212312\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">C#COMを使ってみた。 - echo(“備忘録”);</a></p>\n<div class=\"gatsby-highlight\" data-language=\"c#\"><pre class=\"language-c#\"><code class=\"language-c#\">using System;\nusing System.Collections.Generic;\nusing System.Text;\nusing System.Runtime.InteropServices;\n\nnamespace CoreAudioApi.Interfaces\n{\n    [Guid(&quot;f8679f50-850a-41cf-9c72-430f290290c8&quot;),\n    InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]\n    internal interface IPolicyConfig\n    {\n        [PreserveSig]\n        int GetMixFormat(string pszDeviceName, IntPtr ppFormat);\n\n        [PreserveSig]\n        int GetDeviceFormat(string pszDeviceName, bool bDefault, IntPtr ppFormat);\n\n        [PreserveSig]\n        int ResetDeviceFormat(string pszDeviceName);\n\n        [PreserveSig]\n        int SetDeviceFormat(string pszDeviceName, IntPtr pEndpointFormat, IntPtr MixFormat);\n\n        [PreserveSig]\n        int GetProcessingPeriod(string pszDeviceName, bool bDefault, IntPtr pmftDefaultPeriod, IntPtr pmftMinimumPeriod);\n\n        [PreserveSig]\n        int SetProcessingPeriod(string pszDeviceName, IntPtr pmftPeriod);\n\n        [PreserveSig]\n        int GetShareMode(string pszDeviceName, IntPtr pMode);\n\n        [PreserveSig]\n        int SetShareMode(string pszDeviceName, IntPtr mode);\n\n        [PreserveSig]\n        int GetPropertyValue(string pszDeviceName, bool bFxStore, IntPtr key, IntPtr pv);\n\n        [PreserveSig]\n        int SetPropertyValue(string pszDeviceName, bool bFxStore, IntPtr key, IntPtr pv);\n\n        [PreserveSig]\n        int SetDefaultEndpoint(string pszDeviceName, ERole role);\n\n        [PreserveSig]\n        int SetEndpointVisibility(string pszDeviceName, bool bVisible);\n    }\n}</code></pre></div>\n<p>This interface includes several methods, but the one mainly needed this time is <code class=\"language-text\">SetDefaultEndpoint</code>, which can set a specific device as the audio playback device.</p>\n<p>Reference: <a href=\"https://stackoverflow.com/questions/57778069/how-can-i-programmatically-set-the-default-input-and-output-audio-device-for-an\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">windows - How can I programmatically set the default input and output audio device for an application? - Stack Overflow</a></p>\n<p>As mentioned above, by calling <code class=\"language-text\">SetDefaultDevice</code> with the device UUID and <code class=\"language-text\">ERole</code> (an enum that specifies audio roles such as <code class=\"language-text\">eConsole</code>, <code class=\"language-text\">eMultimedia</code>, and <code class=\"language-text\">eCommunications</code>, which are assigned by the system to audio endpoint devices), you can change the audio playback device.</p>\n<p><code class=\"language-text\">ERole</code> is defined as follows.</p>\n<div class=\"gatsby-highlight\" data-language=\"c#\"><pre class=\"language-c#\"><code class=\"language-c#\">public enum ERole\n{\n    eConsole,\n    eMultimedia,\n    eCommunications,\n}</code></pre></div>\n<h3 id=\"implementing-policyconfigclient-using-the-ipolicyconfig-interface\" style=\"position:relative;\"><a href=\"#implementing-policyconfigclient-using-the-ipolicyconfig-interface\" aria-label=\"implementing policyconfigclient using the ipolicyconfig interface permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Implementing PolicyConfigClient Using the IPolicyConfig Interface</h3>\n<p>Next, implement <code class=\"language-text\">PolicyConfigClient</code>, which calls the method that changes the audio device using the <code class=\"language-text\">IPolicyConfig</code> interface.</p>\n<p>Here as well, <code class=\"language-text\">PolicyConfigClient.cs</code> in the same repository as above is helpful.</p>\n<p>Reference: <a href=\"https://github.com/frgnca/AudioDeviceCmdlets/blob/master/SOURCE/PolicyConfigClient.cs\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">AudioDeviceCmdlets/SOURCE/PolicyConfigClient.cs</a></p>\n<div class=\"gatsby-highlight\" data-language=\"c#\"><pre class=\"language-c#\"><code class=\"language-c#\">using System;\nusing System.Collections.Generic;\nusing System.Text;\nusing CoreAudioApi.Interfaces;\nusing System.Runtime.InteropServices;\n\nnamespace CoreAudioApi\n{\n    [ComImport, Guid(&quot;870af99c-171d-4f9e-af0d-e63df40c2bc9&quot;)]\n    internal class _PolicyConfigClient\n    {\n    }\n\n    public class PolicyConfigClient\n    {\n        private readonly IPolicyConfig _PolicyConfig;\n        private readonly IPolicyConfigVista _PolicyConfigVista;\n        private readonly IPolicyConfig10 _PolicyConfig10;\n\n        public PolicyConfigClient()\n        {\n            _PolicyConfig = new _PolicyConfigClient() as IPolicyConfig;\n            if (_PolicyConfig != null)\n                return;\n\n            _PolicyConfigVista = new _PolicyConfigClient() as IPolicyConfigVista;\n            if (_PolicyConfigVista != null)\n                return;\n\n            _PolicyConfig10 = new _PolicyConfigClient() as IPolicyConfig10;\n        }\n\n        public void SetDefaultEndpoint(string devID, ERole eRole)\n        {\n            if (_PolicyConfig != null)\n            {\n                Marshal.ThrowExceptionForHR(_PolicyConfig.SetDefaultEndpoint(devID, eRole));\n                return;\n            }\n            if (_PolicyConfigVista != null)\n            {\n                Marshal.ThrowExceptionForHR(_PolicyConfigVista.SetDefaultEndpoint(devID, eRole));\n                return;\n            }\n            if (_PolicyConfig10 != null)\n            {\n                Marshal.ThrowExceptionForHR(_PolicyConfig10.SetDefaultEndpoint(devID, eRole));\n            }\n        }\n    }\n}</code></pre></div>\n<p>In this code, the <code class=\"language-text\">PolicyConfigClient</code> interface is obtained by using the COM CLSID <code class=\"language-text\">870af99c-171d-4f9e-af0d-e63df40c2bc9</code>.</p>\n<p>Then it calls the <code class=\"language-text\">SetDefaultEndpoint</code> method of the <code class=\"language-text\">IPolicyConfig</code> interface to change the default audio device.</p>\n<h2 id=\"using-the-c-sharp-code-from-powershell\" style=\"position:relative;\"><a href=\"#using-the-c-sharp-code-from-powershell\" aria-label=\"using the c sharp code from powershell permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Using the C Sharp Code from PowerShell</h2>\n<p>Finally, I call the C# code created so far from PowerShell and create a toggle script that switches the audio device setting between device A and device B.</p>\n<div class=\"gatsby-highlight\" data-language=\"powershell\"><pre class=\"language-powershell\"><code class=\"language-powershell\"><span class=\"token variable\">$csharpCode</span> = @<span class=\"token string\">\"\n&lt; C# Code >\n\"</span>@\n\n<span class=\"token function\">Add-Type</span> <span class=\"token operator\">-</span>TypeDefinition <span class=\"token variable\">$csharpCode</span>\n\n<span class=\"token variable\">$currentDeviceId</span> = <span class=\"token namespace\">[AudioHelper]</span>::GetDefaultDeviceId<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n<span class=\"token variable\">$deviceId</span> = <span class=\"token string\">\"\"</span>\n<span class=\"token variable\">$deviceA</span> = <span class=\"token string\">\"&lt;Device A ID>\"</span>\n<span class=\"token variable\">$deviceB</span> = <span class=\"token string\">\"&lt;Device B ID>\"</span>\n\n<span class=\"token keyword\">if</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$currentDeviceId</span> <span class=\"token operator\">-eq</span> <span class=\"token string\">\"{0.0.0.00000000}.<span class=\"token variable\">$deviceA</span>\"</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n<span class=\"token variable\">$deviceId</span> = <span class=\"token variable\">$deviceB</span>\n<span class=\"token punctuation\">}</span>\n<span class=\"token keyword\">else</span> <span class=\"token punctuation\">{</span>\n<span class=\"token variable\">$deviceId</span> = <span class=\"token variable\">$deviceA</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token comment\"># Change Audio device</span>\n<span class=\"token namespace\">[PolicyConfigClient]</span>::SetDefaultDevice<span class=\"token punctuation\">(</span><span class=\"token string\">\"{0.0.0.00000000}.<span class=\"token variable\">$deviceId</span>\"</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>The C# code created above is made callable from PowerShell with <code class=\"language-text\">Add-Type -TypeDefinition $csharpCode</code>, as shown in the sample in the following documentation.</p>\n<p>Reference: <a href=\"https://learn.microsoft.com/ja-jp/powershell/module/microsoft.powershell.utility/add-type?view=powershell-7.5#1-net\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Add-Type (Microsoft.PowerShell.Utility) - PowerShell | Microsoft Learn</a></p>\n<p><code class=\"language-text\">Add-Type</code> can also be used when calling assembly objects or native Windows APIs from PowerShell.</p>\n<h2 id=\"summary\" style=\"position:relative;\"><a href=\"#summary\" aria-label=\"summary permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Summary</h2>\n<p>I only wanted an easy way to change audio devices, but it turned out to be more troublesome than expected because I had to use an unofficial COM interface. Still, I learned a lot, so I am glad I worked through it.</p>","fields":{"slug":"/windows-toggle-audiodevice-en","tagSlugs":["/tag/windows/","/tag/power-shell/","/tag/english/"]},"frontmatter":{"date":"2025-04-02","description":"Switch audio device settings using a COM interface from PowerShell.","tags":["Windows","PowerShell","English"],"title":"Switch Audio Device Settings Using a COM Interface from PowerShell","socialImage":{"publicURL":"/static/13580809ee84b0fa888e40708182c94a/windows-toggle-audiodevice.png"}}}},"pageContext":{"slug":"/windows-toggle-audiodevice-en"}},"staticQueryHashes":["251939775","401334301","825871152"]}