Как определить аудиоустройство по умолчанию в Powershell?

Я ищу решение для получения аудиоустройства по умолчанию через Powershell. В лучшем случае он может работать через встроенный код C# для прямого использования IMMDeviceEnumerator::GetDefaultAudioEndpoint (см. Здесь IMMDeviceEnumertor).

Но если это проще получить через RegKeys, то это тоже нормально. Я видел пару фрагментов кода, читающих ключи из HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio\Render или \Capture, но мне все еще трудно определить устройство DEFAULT.

Кажется, когда я изменяю порядок устройств, я могу просто искать активные устройства (DeviceState=1), а затем сортировать по значениям "Уровень:0", "Уровень:1" и "Уровень:2", но значения уровня недоступны в системе, где пользователь не изменил порядок вручную. Каковы критерии сортировки в таком случае?

Это фрагмент кода для решения этой проблемы с помощью RegKeys, но, как уже упоминалось, работает не во всех ситуациях:

$regAudio =  "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio"
$nameId = "{b3f8fa53-0004-438e-9003-51a46e139bfc},6"
$classId = "{a45c254e-df1c-4efd-8020-67d146a850e0},2"
$driverDetails = "{83da6326-97a6-4088-9453-a1923f573b29},3"

function get-DefaultDevice($type) {
    $activeDevices = foreach($key in  Get-ChildItem "$regAudio\$type\") {
        foreach($item in Get-ItemProperty $key.PsPath) { 
            if ($item.DeviceState -eq $activeState) {$item}
        }
    }
    $defaultDevice = $activeDevices | Sort-Object -Property "Level:0","Level:1","Level:2" | select -last 1
    $details = Get-ItemProperty "$($defaultDevice.PSPath)\Properties"
    $name = "$($details.$classId) ($($details.$nameId))"
    return @{
        name   = $name
        driver = $details.$driverDetails
    }
}

$OsRender = get-DefaultDevice "Render"
$OsCapture = get-DefaultDevice "Capture"

Есть ли способ получить эту информацию "по-умному" (конечно, без внешних DLL)?

1 ответ

Решение

Наконец, я понял это и с радостью поделюсь рабочим фрагментом кода:

cls
Add-Type -TypeDefinition @'
using System.Runtime.InteropServices;
[Guid("D666063F-1587-4E43-81F1-B948E807363F"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IMMDevice {
    int a(); int o();
    int GetId([MarshalAs(UnmanagedType.LPWStr)] out string id);
}
[Guid("A95664D2-9614-4F35-A746-DE8DB63617E6"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IMMDeviceEnumerator {
    int f();
    int GetDefaultAudioEndpoint(int dataFlow, int role, out IMMDevice endpoint);
}
[ComImport, Guid("BCDE0395-E52F-467C-8E3D-C4579291692E")] class MMDeviceEnumeratorComObject { }
public class Audio {
    public static string GetDefault (int direction) {
    var enumerator = new MMDeviceEnumeratorComObject() as IMMDeviceEnumerator;
    IMMDevice dev = null;
    Marshal.ThrowExceptionForHR(enumerator.GetDefaultAudioEndpoint(direction, 1, out dev));
    string id = null;
    Marshal.ThrowExceptionForHR(dev.GetId(out id));
    return id;
    }
}
'@

function getFriendlyName($id) {
    $reg = "HKLM:\SYSTEM\CurrentControlSet\Enum\SWD\MMDEVAPI\$id"
    return (get-ItemProperty $reg).FriendlyName
}

$id0 = [audio]::GetDefault(0)
$id1 = [audio]::GetDefault(1)
write-host "Default Speaker: $(getFriendlyName $id0)" 
write-host "Default Micro  : $(getFriendlyName $id1)"
Другие вопросы по тегам