Skip to content

Commit

Permalink
Populated.
Browse files Browse the repository at this point in the history
  • Loading branch information
snnz committed Dec 14, 2024
1 parent a499181 commit 6236d9b
Show file tree
Hide file tree
Showing 15 changed files with 383 additions and 398 deletions.
400 changes: 3 additions & 397 deletions .gitignore

Large diffs are not rendered by default.

35 changes: 35 additions & 0 deletions Enums.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System;

namespace SwitchSound
{
[Flags]
enum EDeviceState : uint
{
Active = 1,
Disabled = 2,
NotPresent = 4,
Unplugged = 8,
All = Active | Disabled | NotPresent | Unplugged
}

enum EDataFlow
{
Render,
Capture,
All
}

enum ERole
{
Console,
Multimedia,
Communications
}

enum StorageAccessMode : uint
{
Read,
Write,
ReadWrite
}
}
20 changes: 20 additions & 0 deletions MultimediaDevice.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;
using System.Runtime.InteropServices;

namespace SwitchSound
{
[Guid("D666063F-1587-4E43-81F1-B948E807363F")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IMultimediaDevice
{
void Activate();
IPropertyStore OpenPropertyStore(StorageAccessMode accessMode);
string Id { [return : MarshalAs(UnmanagedType.LPWStr)] get; }
}

static class MultimediaDevice
{
static PropertyKey PKEY_DEVICE_FRIENDLY_NAME = new PropertyKey(new Guid("A45C254E-DF1C-4EFD-8020-67D146A850E0"), 14);
public static string Name(this IMultimediaDevice device) => device.OpenPropertyStore(StorageAccessMode.Read).GetValue(ref PKEY_DEVICE_FRIENDLY_NAME).AsString;
}
}
22 changes: 22 additions & 0 deletions MultimediaDeviceCollection.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System.Collections.Generic;
using System.Runtime.InteropServices;

namespace SwitchSound
{
[Guid("0BD7A1BE-7A1A-44DB-8397-CC5392387B5E")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IMultimediaDeviceCollection
{
uint Count { get; }
IMultimediaDevice this[uint index] { get; }
}

static class MultimediaDeviceCollection
{
public static IEnumerable<IMultimediaDevice> ToEnumerable(this IMultimediaDeviceCollection collection)
{
for (uint i = 0, n = collection.Count; i < n; ++i)
yield return collection[i];
}
}
}
17 changes: 17 additions & 0 deletions MultimediaDeviceEnumerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System.Runtime.InteropServices;

namespace SwitchSound
{
[Guid("A95664D2-9614-4F35-A746-DE8DB63617E6")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IMultimediaDeviceEnumerator
{
IMultimediaDeviceCollection EnumAudioEndpoints(EDataFlow dataFlow, EDeviceState stateMask);
IMultimediaDevice GetDefaultAudioEndpoint(EDataFlow dataFlow, ERole role);
}

[ComImport, Guid("BCDE0395-E52F-467C-8E3D-C4579291692E")]
class MultimediaDeviceEnumerator
{
}
}
27 changes: 27 additions & 0 deletions PolicyConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System;
using System.Runtime.InteropServices;

namespace SwitchSound
{
[Guid("F8679F50-850A-41CF-9C72-430F290290C8")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IPolicyConfig
{
void GetMixFormat();
void GetDeviceFormat();
void ResetDeviceFormat();
void SetDeviceFormat();
void GetProcessingPeriod();
void SetProcessingPeriod();
void GetShareMode();
void SetShareMode();
void GetPropertyValue();
void SetPropertyValue();
void SetDefaultEndpoint([MarshalAs(UnmanagedType.LPWStr)] string pszDeviceName, ERole role);
}

[ComImport, Guid("870AF99C-171D-4F9E-AF0D-E63DF40C2BC9")]
class PolicyConfig
{
}
}
37 changes: 37 additions & 0 deletions Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System;

namespace SwitchSound
{
class Program
{
static void Main(string[] args)
{
try
{
var devices = (IMultimediaDeviceEnumerator)new MultimediaDeviceEnumerator();
var default_id = devices.GetDefaultAudioEndpoint(EDataFlow.Render, ERole.Multimedia).Id;

if (args.Length < 1)
foreach (var device in devices.EnumAudioEndpoints(EDataFlow.Render, EDeviceState.Active).ToEnumerable())
{
var id = device.Id;
Console.WriteLine("{0}{1}\n {2}\n", id == default_id ? "*" : " ", device.Name(), id);
}
else
{
var new_default_id = args[0];
if (new_default_id == default_id)
{
if (args.Length < 2) return;
new_default_id = args[1];
}
((IPolicyConfig)new PolicyConfig()).SetDefaultEndpoint(new_default_id, ERole.Multimedia);
}
}
catch (Exception e)
{
Console.Error.WriteLine(e.Message);
}
}
}
}
17 changes: 17 additions & 0 deletions PropVariant.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System;
using System.Runtime.InteropServices;

namespace SwitchSound
{
[StructLayout(LayoutKind.Sequential)]
struct PropVariant
{
short vt;
short wReserved1;
short wReserved2;
short wReserved3;
IntPtr LPWSTR;

public string AsString => (VarEnum)vt == VarEnum.VT_LPWSTR ? Marshal.PtrToStringUni(LPWSTR) : null;
}
}
35 changes: 35 additions & 0 deletions Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System.Reflection;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("SwitchSound")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("SwitchSound")]
[assembly: AssemblyCopyright("Copyright © 2017 Sergey Nozhenko")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("71716191-d69b-4409-bfca-d3a9579e03ca")]

// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
18 changes: 18 additions & 0 deletions PropertyKey.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System;
using System.Runtime.InteropServices;

namespace SwitchSound
{
[StructLayout(LayoutKind.Sequential)]
struct PropertyKey
{
public Guid FormatId;
public uint PropertyId;

public PropertyKey(Guid formatId, uint propertyId)
{
FormatId = formatId;
PropertyId = propertyId;
}
}
}
13 changes: 13 additions & 0 deletions PropertyStore.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System.Runtime.InteropServices;

namespace SwitchSound
{
[Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IPropertyStore
{
void GetCount();
void GetAt();
PropVariant GetValue(ref PropertyKey propertyKey);
}
}
54 changes: 53 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,53 @@
# SwitchSound
# SwitchSound

A tiny console tool for switching between audio output devices.

#### Run:

- Without agruments - list devices with their interface identifiers.
Currently active is marked with '*'.

- With a list of interface identifiers as arguments - switch between devices in a circle: active -> next, last -> first.

#### For example:

```
> SwitchSound.exe
*S22E390 (HD Audio Driver for Display Audio)
{0.0.0.00000000}.{24a8b3c5-8ece-48eb-9980-cf104f3ff711}
Digital Audio (S/PDIF) (High Definition Audio Device)
{0.0.0.00000000}.{42b8a793-61c3-430d-a214-d43c9b086421}
Speakers (High Definition Audio Device)
{0.0.0.00000000}.{a4a19331-61d9-46d4-8118-33c5003c1c20}
> SwitchSound.exe {0.0.0.00000000}.{24a8b3c5-8ece-48eb-9980-cf104f3ff711} {0.0.0.00000000}.{a4a19331-61d9-46d4-8118-33c5003c1c20}
> SwitchSound.exe
S22E390 (HD Audio Driver for Display Audio)
{0.0.0.00000000}.{24a8b3c5-8ece-48eb-9980-cf104f3ff711}
Digital Audio (S/PDIF) (High Definition Audio Device)
{0.0.0.00000000}.{42b8a793-61c3-430d-a214-d43c9b086421}
*Speakers (High Definition Audio Device)
{0.0.0.00000000}.{a4a19331-61d9-46d4-8118-33c5003c1c20}
> SwitchSound.exe {0.0.0.00000000}.{24a8b3c5-8ece-48eb-9980-cf104f3ff711} {0.0.0.00000000}.{a4a19331-61d9-46d4-8118-33c5003c1c20}
> SwitchSound.exe
*S22E390 (HD Audio Driver for Display Audio)
{0.0.0.00000000}.{24a8b3c5-8ece-48eb-9980-cf104f3ff711}
Digital Audio (S/PDIF) (High Definition Audio Device)
{0.0.0.00000000}.{42b8a793-61c3-430d-a214-d43c9b086421}
Speakers (High Definition Audio Device)
{0.0.0.00000000}.{a4a19331-61d9-46d4-8118-33c5003c1c20}
```

A typical usage is to create a shortcut with arguments to switch between selected devices and assign it to a hotkey.
64 changes: 64 additions & 0 deletions SwitchSound.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{71716191-D69B-4409-BFCA-D3A9579E03CA}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>SwitchSound</RootNamespace>
<AssemblyName>SwitchSound</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>none</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>SwitchSound.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
</ItemGroup>
<ItemGroup>
<Compile Include="Enums.cs" />
<Compile Include="MultimediaDevice.cs" />
<Compile Include="MultimediaDeviceCollection.cs" />
<Compile Include="MultimediaDeviceEnumerator.cs" />
<Compile Include="PolicyConfig.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="PropertyKey.cs" />
<Compile Include="PropertyStore.cs" />
<Compile Include="PropVariant.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="SwitchSound.ico" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
Binary file added SwitchSound.ico
Binary file not shown.
Loading

0 comments on commit 6236d9b

Please sign in to comment.