オーディオデバイス関連 もくじ
https://tera1707.com/entry/2022/02/06/144447#COM
やりたいこと
別の記事で、「CsWin32」というライブラリを使って、P/InvokeでWin32APIを呼ぶということをした。
で、そのCsWin32は、COMのinterfaceやインスタンスに対しても使えるらしい。試してみる。
で、以前、PCに接続されているマイク(オーディオデバイス)を取得し、音量設定をする(EnumAudioEndpoints)(C#版)という記事で、C#でそういうことをしたので、それをCsWin32使用して、同じことをやってみる。
前提
Microsoft.Windows.CsWin32 の 0.3.106
※preview版ということで、現在も実装、改善が行われている様子。ぜひ進化してほしい。。。
- .net8
- VS2022 Version 17.11.2
やってみたコード
こちら。
https://github.com/tera1707/AudioDevice
これが、メインのコード。
using Windows.Win32.Foundation; using Windows.Win32.Media.Audio; using Windows.Win32.System.Com.StructuredStorage; using Windows.Win32.UI.Shell.PropertiesSystem; using Windows.Win32.System.Com; using Windows.Win32.Media.Audio.Endpoints; namespace MicJikkenCsWithCsWin32; internal class Program { static void Main(string[] args) { var pEnum = new MMDeviceEnumerator() as IMMDeviceEnumerator; var pNotifClient = new CMMNotificationClient(); pEnum!.RegisterEndpointNotificationCallback(pNotifClient); pEnum!.EnumAudioEndpoints(EDataFlow.eCapture, DEVICE_STATE.DEVICE_STATE_ACTIVE, out var pCollection); pCollection!.GetCount(out var deviceCount); for (uint i = 0; i < deviceCount; i++) { pCollection.Item(i, out var pEndpoint); pEndpoint.OpenPropertyStore(STGM.STGM_READ, out var pProperties); unsafe { var PKEY_Device_FriendlyName = new PROPERTYKEY() { fmtid = new Guid(0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0), pid = 14 }; pProperties.GetValue(&PKEY_Device_FriendlyName, out var vName); Console.WriteLine(vName.Anonymous.Anonymous.Anonymous.pwszVal); Guid IID_IAudioEndpointVolume = typeof(IAudioEndpointVolume).GUID; pEndpoint.Activate(&IID_IAudioEndpointVolume, 0, (PROPVARIANT_unmanaged*)0 ,out var endpointVolume); var masterVol = endpointVolume as IAudioEndpointVolume; var guid = new Guid(); masterVol!.GetMasterVolumeLevelScalar(out var pMasterVolumeLevel); masterVol!.SetMasterVolumeLevelScalar(0.80f, &guid); } } Console.ReadLine(); } public class CMMNotificationClient : IMMNotificationClient { public void OnDeviceStateChanged(PCWSTR pwstrDeviceId, DEVICE_STATE dwNewState) { Console.WriteLine(pwstrDeviceId); } public void OnDeviceAdded(PCWSTR pwstrDeviceId) { Console.WriteLine(pwstrDeviceId); } public void OnDeviceRemoved(PCWSTR pwstrDeviceId) { Console.WriteLine(pwstrDeviceId); } public void OnDefaultDeviceChanged(EDataFlow flow, ERole role, PCWSTR pwstrDefaultDeviceId) { Console.WriteLine(pwstrDefaultDeviceId); } public void OnPropertyValueChanged(PCWSTR pwstrDeviceId, PROPERTYKEY key) { Console.WriteLine(pwstrDeviceId); } } }
コードのよこに、NativeMethods.txt
というファイルを作成し、使いたいCOMのinterfaceなどを並べる。
今回は下記のようにした。
IMMDeviceEnumerator MMDeviceEnumerator IMMNotificationClient IAudioEndpointVolume PROPERTYKEY
※一つ、interfaceを書いたら、そいつが使う別のinterfaceや構造体も、自動で定義してくれる様子。便利。
注意点
- モノによっては、unsafeな定義がされるので、プロジェクトをunsafeありにしないといけない。
- (解決方法としては、CsWin32を使うPJだけ独立させる、というやり方があるらしいが、未検証)
CsWin32の設定
今回はやってないが、「NativeMethods.json」というファイルを作成し、そこにCsWin32の設定を記述できるらしい。
参考
CsWin32 公式
https://github.com/microsoft/CsWin32?tab=readme-ov-file#readme
PCに接続されているマイク(オーディオデバイス)を取得し、音量設定をする(EnumAudioEndpoints)(C#版)
https://tera1707.com/entry/2023/11/21/213253
CsWin32 で Win32 API や COM を使ったアプリケーション開発を効率化する
https://blog.shibayan.jp/entry/20220501/1651339430
unsafeの書き方
https://ufcpp.net/study/csharp/sp_unsafe.html
NativeMethods.jsonに書ける設定項目一覧
https://github.com/microsoft/CsWin32/blob/main/src/Microsoft.Windows.CsWin32/settings.schema.json
NativeMethods.jsonについて
https://qiita.com/radian-jp/items/a4509f9a44101fb2f30e
C# Win32API完全入門 ※pinvoke、ここだけ見ればいいのではというくらい詳しい。