Author SHA1 Message Date
pblivingston 90c09092b6 semicolon in example 2026-08-16 11:59:48 -04:00
pblivingston 0fb26b9e72 add break in example switch 2026-08-08 07:54:19 -04:00
pblivingston c3aa47e7d0 update docs
manual tests pass for
- Get-Remote
- Command.Launch()
- Remote.GetVoicemeeter($kindId)
- Remote.RunVoicemeeter($kindId)
- Remote.RunApplication($appId)
2026-08-07 13:36:20 -04:00
pblivingston 21fce98eef fix Command.Launch() 2026-08-07 13:13:47 -04:00
pblivingston 36e4e16843 GetVoicemeeter 2026-08-07 12:35:03 -04:00
pblivingston 7a6150bf6e Get-Remote 2026-08-06 19:43:15 -04:00
pblivingston d05b46b899 Command.Launch 2026-08-06 19:42:35 -04:00
pblivingston b978f5aa3f RunVoicemeeter, RunApplication 2026-08-06 19:40:54 -04:00
pblivingston 5c5932e7d3 base functions
- Login
- WaitForConnection
- Run
- RunVm
- RunApp
2026-08-06 19:37:46 -04:00
pblivingston 3e5a61eff3 kind 'none' 2026-08-06 19:30:15 -04:00
onyx_online f6c750fe56 add 4.2.0 to CHANGELOG 2026-03-15 02:00:05 +00:00
onyx_online 685854c35a Merge pull request #36 from pblivingston/devices-enumerator
Device enumeration
2026-03-15 01:28:27 +00:00
pblivingston 68cf0cef37 IODevice.Set readability
manual and pester tests pass
2026-03-14 19:52:46 -04:00
pblivingston 91e798caa1 Revert "revert to user folder"
This reverts commit d1dfe2de52.
2026-03-14 18:32:11 -04:00
pblivingston d1dfe2de52 revert to user folder
should be faster this way, and it wasn't actually causing the problems i thought it was causing

pester tests pass for all kinds
2026-03-04 21:15:46 -05:00
pblivingston ed3b7be904 HardwareId
changed capitalization for consistency
2026-03-04 20:43:48 -05:00
pblivingston 33dcc98c8f small docs corrections 2026-03-04 20:39:57 -05:00
pblivingston 55ade960f2 update docs 2026-03-04 20:02:18 -05:00
pblivingston 7d9615d760 Get(), Set($device), Clear()
methods added to IODevice

manual and pester tests pass for all kinds
2026-03-04 04:23:10 -05:00
pblivingston 4ea371af2f more IODevice.driver tweaks
use temp file instead of persistent

manual and pester tests pass
2026-03-04 04:08:08 -05:00
pblivingston 6b2031de99 clean up IODevice.driver
'none' -> ''
early return if name is empty
2026-03-03 19:54:39 -05:00
pblivingston 8d267078ff drivers
switch -> hashtable
2026-03-02 11:31:30 -05:00
pblivingston 1f5b52b439 improve speed of Select-String
device config is at the very top of the xml, so this should be much faster
2026-03-02 06:55:55 -05:00
pblivingston defb2b68c0 driver type capitalization 2026-03-02 05:24:30 -05:00
pblivingston 2f2d4af848 IODevice.driver
initial pester tests pass for all kinds
2026-02-28 20:35:12 -05:00
pblivingston abd792acd5 add device enumeration
bindings, base functions, and Remote methods implemented

initial manual tests for potato pass
2026-02-28 03:13:59 -05:00
11 changed files with 536 additions and 49 deletions
+25
View File
@@ -9,6 +9,31 @@ Before any major/minor/patch is released all unit tests will be run to verify th
## [Unreleased] These changes have not been added to PSGallery yet ## [Unreleased] These changes have not been added to PSGallery yet
### Added
- Get-Remote factory function to log in and return a base Remote instance without launching Voicemeeter
- Command.Launch() method to launch Voicemeeter based on `$this.kind.name`, useful for re-launch after Command.Shutdown()
- Remote.GetVoicemeeter($kindId) to confirm a connection to Voicemeeter and return the requested Remote instance
- Remote.RunVoicemeeter($kindId) to launch Voicemeeter and return an appropriate Remote instance
- Remote.RunApplication($appId) to launch VB-Audio applications
- Remote.GetType(), Remote.GetVersion() to README
## [4.2.0] - 2026-03-15
### Added
- New Remote methods for device enumeration:
- GetInputCount()
- GetOutputCount()
- GetInputDevice($index)
- GetOutputDevice($index)
- New IODevice property `driver` to get the driver type of the current device (e.g. 'wdm', 'mme', etc.)
- New IODevice methods to get, set, or clear the current device for a strip or bus:
- Get(): returns a PSObject with properties Driver, Name, HardwareId, and IsOutput
- Set($device): accepts a PSObject with properties Driver, Name, and IsOutput
- Clear()
## [4.1.0] - 2025-12-23 ## [4.1.0] - 2025-12-23
+102 -1
View File
@@ -78,6 +78,7 @@ Voicemeeter factory function can be:
- Get-RemoteBasic - Get-RemoteBasic
- Get-RemoteBanana - Get-RemoteBanana
- Get-RemotePotato - Get-RemotePotato
- Get-Remote : if only lower-level Remote methods are needed
Added in `v3` you may also use the following entry/exit points: Added in `v3` you may also use the following entry/exit points:
@@ -368,20 +369,32 @@ $vmr.bus[0].FadeBy(-10, 500)
The following Strip.device | Bus.device properties are available: The following Strip.device | Bus.device properties are available:
- name: string - name: string
- driver: string
- sr: int - sr: int
- wdm: string - wdm: string
- ks: string - ks: string
- mme: string - mme: string
- asio: string - asio: string
The following Strip.device | Bus.device methods are available:
- Set($device) : PSObject, where device is a PSObject with properties Driver, Name, and IsOutput
- Get() : PSObject, returns a PSObject with properties Driver, Name, HardwareId, and IsOutput
- Clear() : Clears the currently selected device
for example: for example:
```powershell ```powershell
$vmr.strip[0].device.wdm = "Mic|Line|Instrument 1 (Audient EVO4)" $vmr.strip[0].device.wdm = "Mic|Line|Instrument 1 (Audient EVO4)"
$vmr.bus[0].device.name | Write-Host $vmr.bus[0].device.name | Write-Host
$device = $vmr.strip[3].device.Get()
$vmr.strip[1].device.Set($device) # moves the device selected for strip 4 to strip 2
$vmr.bus[2].device.Clear()
``` ```
name, sr are defined as read only. name, driver, sr are defined as read only.
wdm, ks, mme, asio are defined as write only. wdm, ks, mme, asio are defined as write only.
asio only defined for Bus[0].Device asio only defined for Bus[0].Device
@@ -539,6 +552,7 @@ The following Command methods are available:
- HideVBANChat() - HideVBANChat()
- Restart() - Restart()
- Shutdown() - Shutdown()
- Launch() : launches the current Voicemeeter kind
- Reset() : Reset all config - Reset() : Reset all config
- Save($filepath) : string - Save($filepath) : string
- Load($filepath) : string - Load($filepath) : string
@@ -563,6 +577,21 @@ $vmr.command.StorePreset() # same as StorePreset(''), overwrite
$vmr.command.RecallPreset('example') $vmr.command.RecallPreset('example')
$vmr.command.RecallPreset(63) $vmr.command.RecallPreset(63)
$vmr.command.RecallPreset() # same as RecallPreset(''), recalls last recalled $vmr.command.RecallPreset() # same as RecallPreset(''), recalls last recalled
try {
$vmr = Connect-Voicemeeter -Kind 'potato'
if ($vmr.GetType() -ne 'potato') {
$vmr.command.Shutdown() # shuts down whatever was running
Start-Sleep -Seconds 3
$vmr.command.Launch() # launches Voicemeeter Potato
}
# perform operations with Voicemeeter Potato
}
finally {
Disconnect-Voicemeeter
}
``` ```
StorePreset('') and RecallPreset('') interact with the 'selected' preset. This is highlighted green in the GUI. Recalling a preset selects it. Storing a preset via GUI also selects it. Storing a preset with StorePreset does not select it. StorePreset('') and RecallPreset('') interact with the 'selected' preset. This is highlighted green in the GUI. Recalling a preset selects it. Storing a preset via GUI also selects it. Storing a preset with StorePreset does not select it.
@@ -769,6 +798,63 @@ will load a config file at profiles/banana/config.psd1 for Voicemeeter Banana.
### Remote class ### Remote class
`$vmr.GetType()` : returns current Voicemeeter kind ('basic', 'banana', 'potato')
`$vmr.GetVersion()` : returns current Voicemeeter version string (e.g. '2.1.2.2')
`$vmr.GetVoicemeeter($kindId)` : string, ('basic', 'banana', 'potato'), confirms connection and returns requested Remote instance
`$vmr.RunVoicemeeter($kindId)` : string, ('basic', 'banana', 'potato'), launches Voicemeeter and returns appropriate Remote instance
example:
```powershell
try {
$vmr = Get-Remote
$kind = 'none'
try {
$kind = $vmr.GetType()
$vmr = $vmr.GetVoicemeeter($kind)
}
catch { }
switch ($kind) {
'potato' {
break
}
'basic' {
# perform final operations with Voicemeeter Basic
}
'banana' {
# perform final operations with Voicemeeter Banana
}
{ $_ -in 'basic', 'banana'} {
$vmr.Command.Shutdown()
Start-Sleep -Seconds 3
}
{ $_ -ne 'potato' } {
$vmr = $vmr.RunVoicemeeter('potato')
}
}
# perform operations with Voicemeeter Potato
}
finally {
Disconnect-Voicemeeter
}
```
`$vmr.RunApplication($appId)` : string, launches VB-Audio applications
- 'devicecheck'
- 'macrobuttons'
- 'streamerview'
- 'busmatrix8'
- 'busgeq15'
- 'vban2midi'
- 'cablecontrolpanel'
- 'auxcontrolpanel'
- 'vaio3controlpanel'
- 'vaiocontrolpanel'
Access to lower level Getters and Setters are provided with these functions: Access to lower level Getters and Setters are provided with these functions:
- `$vmr.Getter(param)`: For getting the value of a parameter expected to return a value other than string. - `$vmr.Getter(param)`: For getting the value of a parameter expected to return a value other than string.
@@ -793,6 +879,21 @@ Access to lower level polling functions are provided with these functions:
- `$vmr.PDirty`: Returns true if a parameter has been updated. - `$vmr.PDirty`: Returns true if a parameter has been updated.
- `$vmr.MDirty`: Returns true if a macrobutton has been updated. - `$vmr.MDirty`: Returns true if a macrobutton has been updated.
Access to lower level device enumeration functions are provided with these functions:
- `$vmr.GetInputCount()`: Returns the number of available input devices.
- `$vmr.GetOutputCount()`: Returns the number of available output devices.
- `$vmr.GetInputDevice($index)`: Returns a PSObject with properties Driver, Name, HardwareId, and IsOutput for the input device at the given index.
- `$vmr.GetOutputDevice($index)`: Returns a PSObject with properties Driver, Name, HardwareId, and IsOutput for the output device at the given index.
```powershell
$count = $vmr.GetInputCount()
for ($i = 0; $i -lt $count; $i++) {
$device = $vmr.GetInputDevice($i)
Write-Host "Input Device $i: $($device.Driver) - $($device.Name)"
}
```
### Errors ### Errors
- `VMRemoteError`: Base custom error class. - `VMRemoteError`: Base custom error class.
+55 -1
View File
@@ -40,6 +40,20 @@ class Remote {
Logout Logout
} }
[Remote] GetVoicemeeter([String]$kindId) {
WaitForConnection
return Make_Remote -kindId $kindId
}
[Remote] RunVoicemeeter([String]$kindId) {
RunVm -kindId $kindId
return Make_Remote -kindId $kindId
}
[void] RunApplication([String]$appId) {
RunApp -appId $appId
}
[string] GetType() { [string] GetType() {
return VmType return VmType
} }
@@ -75,6 +89,22 @@ class Remote {
[void] PDirty() { P_Dirty } [void] PDirty() { P_Dirty }
[void] MDirty() { M_Dirty } [void] MDirty() { M_Dirty }
[int] GetOutputCount() {
return Device_Count -IS_OUT $true
}
[int] GetInputCount() {
return Device_Count
}
[PSObject] GetOutputDevice([int]$index) {
return Device_Desc -INDEX $index -IS_OUT $true
}
[PSObject] GetInputDevice([int]$index) {
return Device_Desc -INDEX $index
}
} }
class RemoteBasic : Remote { class RemoteBasic : Remote {
@@ -143,6 +173,30 @@ class RemotePotato : Remote {
} }
} }
function Make_Remote {
param(
[String]$kindId
)
switch ($kindId) {
'basic' {
[RemoteBasic]::new()
}
'banana' {
[RemoteBanana]::new()
}
'potato' {
[RemotePotato]::new()
}
default {
throw [VMRemoteError]::new("Unknown Voicemeeter kind `"$kindId`"")
}
}
}
Function Get-Remote {
[Remote]::new('none').Login()
}
Function Get-RemoteBasic { Function Get-RemoteBasic {
[RemoteBasic]::new().Login() [RemoteBasic]::new().Login()
} }
@@ -177,4 +231,4 @@ Function Disconnect-Voicemeeter {
Logout Logout
} }
Export-ModuleMember -Function Get-RemoteBasic, Get-RemoteBanana, Get-RemotePotato, Connect-Voicemeeter, Disconnect-Voicemeeter Export-ModuleMember -Function Get-Remote, Get-RemoteBasic, Get-RemoteBanana, Get-RemotePotato, Connect-Voicemeeter, Disconnect-Voicemeeter
+99 -8
View File
@@ -11,22 +11,32 @@ function Login {
} }
switch ($retval) { switch ($retval) {
0 {
WaitForConnection
}
1 { 1 {
'Voicemeeter Engine running but GUI not launched. Launching GUI now.' | Write-Verbose if ($kindId -eq 'none') {
RunVoicemeeter -kindId $kindId 'Logged in to Voicemeeter Remote.' | Write-Verbose
}
else {
'Logged in to Voicemeeter Remote but audio engine and GUI not launched. Launching engine now.' | Write-Verbose
RunVm -kindId $kindId
}
} }
-2 { -2 {
throw [LoginError]::new('Login may only be called once per session.') throw [LoginError]::new('Login may only be called once per session.')
} }
} }
}
function WaitForConnection {
$timeout = New-TimeSpan -Seconds 2 $timeout = New-TimeSpan -Seconds 2
$sw = [diagnostics.stopwatch]::StartNew() $sw = [diagnostics.stopwatch]::StartNew()
$exception = $null $exception = $null
do { do {
Start-Sleep -m 100 Start-Sleep -m 100
try { try {
'Successfully logged into Voicemeeter [' + $(VmType).ToUpper() + '] Version ' + $(VmVersion) | Write-Verbose 'Successfully connected to Voicemeeter [' + $(VmType).ToUpper() + '] Version ' + $(VmVersion) | Write-Verbose
$exception = $null $exception = $null
break break
} }
@@ -37,7 +47,7 @@ function Login {
} while ($sw.elapsed -lt $timeout) } while ($sw.elapsed -lt $timeout)
if ($null -ne $exception) { if ($null -ne $exception) {
throw [VMRemoteError]::new('Timeout logging into the API.') throw [VMRemoteError]::new('Timeout waiting to connect to Voicemeeter.')
} }
while (P_Dirty -or M_Dirty) { Start-Sleep -m 1 } while (P_Dirty -or M_Dirty) { Start-Sleep -m 1 }
@@ -52,7 +62,17 @@ function Logout {
if ($retval -eq 0) { 'Sucessfully logged out' | Write-Verbose } if ($retval -eq 0) { 'Sucessfully logged out' | Write-Verbose }
} }
function RunVoicemeeter { function Run {
param(
[int]$id
)
$retval = [int][Voicemeeter.Remote]::VBVMR_RunVoicemeeter([Int64]$id)
if ($retval -notin @(0)) {
throw [CAPIError]::new($retval, 'VBVMR_RunVoicemeeter')
}
}
function RunVm {
param( param(
[string]$kindId [string]$kindId
) )
@@ -61,11 +81,27 @@ function RunVoicemeeter {
'banana' = $(if ([Environment]::Is64BitOperatingSystem) { 5 } else { 2 }) 'banana' = $(if ([Environment]::Is64BitOperatingSystem) { 5 } else { 2 })
'potato' = $(if ([Environment]::Is64BitOperatingSystem) { 6 } else { 3 }) 'potato' = $(if ([Environment]::Is64BitOperatingSystem) { 6 } else { 3 })
} }
Run -id $kinds[$kindId]
WaitForConnection
}
$retval = [int][Voicemeeter.Remote]::VBVMR_RunVoicemeeter([int64]$kinds[$kindId]) function RunApp {
if ($retval -notin @(0)) { param(
throw [CAPIError]::new($retval, 'VBVMR_RunVoicemeeter') [string]$appId
)
$apps = @{
'devicecheck' = 10
'macrobuttons' = 11
'streamerview' = 12
'busmatrix8' = 13
'busgeq15' = 14
'vban2midi' = 15
'cablecontrolpanel' = 20
'auxcontrolpanel' = 21
'vaio3controlpanel' = 22
'vaiocontrolpanel' = 23
} }
Run -id $apps[$appId]
} }
function P_Dirty { function P_Dirty {
@@ -226,3 +262,58 @@ function Get_Level {
} }
[float]$ptr [float]$ptr
} }
function Device_Count {
param(
[bool]$IS_OUT = $false
)
if ($IS_OUT) {
$retval = [int][Voicemeeter.Remote]::VBVMR_Output_GetDeviceNumber()
if ($retval -lt 0) {
throw [CAPIError]::new($retval, 'VBVMR_Output_GetDeviceNumber')
}
}
else {
$retval = [int][Voicemeeter.Remote]::VBVMR_Input_GetDeviceNumber()
if ($retval -lt 0) {
throw [CAPIError]::new($retval, 'VBVMR_Input_GetDeviceNumber')
}
}
$retval
}
function Device_Desc {
param(
[int]$INDEX, [bool]$IS_OUT = $false
)
$driver = 0
$name = [System.Byte[]]::new(512)
$hardwareid = [System.Byte[]]::new(512)
if ($IS_OUT) {
$retval = [int][Voicemeeter.Remote]::VBVMR_Output_GetDeviceDescA($INDEX, [ref]$driver, $name, $hardwareid)
if ($retval -notin @(0)) {
throw [CAPIError]::new($retval, 'VBVMR_Output_GetDeviceDescA')
}
}
else {
$retval = [int][Voicemeeter.Remote]::VBVMR_Input_GetDeviceDescA($INDEX, [ref]$driver, $name, $hardwareid)
if ($retval -notin @(0)) {
throw [CAPIError]::new($retval, 'VBVMR_Input_GetDeviceDescA')
}
}
$drivers = @{
1 = 'mme'
3 = 'wdm'
4 = 'ks'
5 = 'asio'
}
[PSCustomObject]@{
Driver = $drivers[$driver]
Name = [System.Text.Encoding]::ASCII.GetString($name).Trim([char]0)
HardwareId = [System.Text.Encoding]::ASCII.GetString($hardwareid).Trim([char]0)
IsOutput = $IS_OUT
}
}
+9
View File
@@ -43,6 +43,15 @@ function Setup_DLL {
[DllImport(@"$dll")] [DllImport(@"$dll")]
public static extern int VBVMR_GetLevel(Int64 mode, Int64 index, ref float ptr); public static extern int VBVMR_GetLevel(Int64 mode, Int64 index, ref float ptr);
[DllImport(@"$dll")]
public static extern int VBVMR_Output_GetDeviceNumber();
[DllImport(@"$dll")]
public static extern int VBVMR_Input_GetDeviceNumber();
[DllImport(@"$dll")]
public static extern int VBVMR_Output_GetDeviceDescA(Int64 index, ref int type, byte[] name, byte[] hardwareid);
[DllImport(@"$dll")]
public static extern int VBVMR_Input_GetDeviceDescA(Int64 index, ref int type, byte[] name, byte[] hardwareid);
"@ "@
Add-Type -MemberDefinition $Signature -Name Remote -Namespace Voicemeeter -PassThru | Out-Null Add-Type -MemberDefinition $Signature -Name Remote -Namespace Voicemeeter -PassThru | Out-Null
+9 -1
View File
@@ -97,7 +97,7 @@ class VirtualBus : Bus {
} }
class BusDevice : IODevice { class BusDevice : IODevice {
BusDevice ([int]$index, [Object]$remote) : base ($index, $remote) { BusDevice ([int]$index, [Object]$remote) : base ($index, $remote, 'Output') {
if ($this.index -eq 0) { if ($this.index -eq 0) {
AddStringMembers -PARAMS @('asio') -WriteOnly AddStringMembers -PARAMS @('asio') -WriteOnly
} }
@@ -106,6 +106,14 @@ class BusDevice : IODevice {
[string] identifier () { [string] identifier () {
return 'Bus[' + $this.index + '].Device' return 'Bus[' + $this.index + '].Device'
} }
[int] EnumCount () {
return $this.remote.GetOutputCount()
}
[PSObject] EnumDevice ([int]$eIndex) {
return $this.remote.GetOutputDevice($eIndex)
}
} }
function Make_Buses ([Object]$remote) { function Make_Buses ([Object]$remote) {
+5
View File
@@ -7,6 +7,11 @@ class Special : IRemote {
return 'Command' return 'Command'
} }
[void] Launch() {
'Launching Voicemeeter audio engine and GUI' | Write-Verbose
RunVm -kindId $this.remote.kind.name
}
[void] RunMacrobuttons() { [void] RunMacrobuttons() {
'Launching the MacroButtons app' | Write-Verbose 'Launching the MacroButtons app' | Write-Verbose
Start-Process -FilePath $(Join-Path -Path $this.remote.vmpath -ChildPath 'VoicemeeterMacroButtons.exe') Start-Process -FilePath $(Join-Path -Path $this.remote.vmpath -ChildPath 'VoicemeeterMacroButtons.exe')
+115 -1
View File
@@ -100,9 +100,123 @@ class EqCell : IRemote {
} }
class IODevice : IRemote { class IODevice : IRemote {
IODevice ([int]$index, [Object]$remote) : base ($index, $remote) { [string]$kindOfDevice
[Hashtable]$drivers
IODevice ([int]$index, [Object]$remote, [string]$kindOfDevice) : base ($index, $remote) {
$this.kindOfDevice = $kindOfDevice
AddStringMembers -WriteOnly -PARAMS @('wdm', 'ks', 'mme') AddStringMembers -WriteOnly -PARAMS @('wdm', 'ks', 'mme')
AddStringMembers -ReadOnly -PARAMS @('name') AddStringMembers -ReadOnly -PARAMS @('name')
AddIntMembers -ReadOnly -PARAMS @('sr') AddIntMembers -ReadOnly -PARAMS @('sr')
$this.drivers = @{
'1' = 'mme'
'4' = 'wdm'
'8' = 'ks'
'256' = 'asio'
}
} }
[int] EnumCount () {
throw [System.NotImplementedException]::new("$($this.GetType().Name) must override EnumCount()")
}
[PSObject] EnumDevice ([int]$eIndex) {
throw [System.NotImplementedException]::new("$($this.GetType().Name) must override EnumDevice()")
}
[PSObject] Get () {
$device = [PSCustomObject]@{
Driver = $this.driver
Name = $this.name
HardwareId = ''
IsOutput = $this.kindOfDevice -eq 'Output'
}
if (-not [string]::IsNullOrEmpty($device.Name)) {
for ($i = 0; $i -lt $this.EnumCount(); $i++) {
$eDevice = $this.EnumDevice($i)
if ($eDevice.Name -eq $device.Name -and $eDevice.Driver -eq $device.Driver) {
$device = $eDevice
break
}
}
}
return $device
}
[void] Set ([PSObject]$device) {
$required = 'IsOutput', 'Driver', 'Name'
$missing = $required | Where-Object { $null -eq $device.PSObject.Properties[$_] }
if ($missing) {
throw [System.ArgumentException]::new(("Invalid device object. Missing member(s): {0}" -f ($missing -join ', ')), 'device')
}
$expectsOutput = ($this.kindOfDevice -eq 'Output')
if ([bool]$device.IsOutput -ne $expectsOutput) {
throw [System.ArgumentException]::new(("Device direction mismatch. Expected IsOutput={0}." -f $expectsOutput), 'device')
}
$d = $device.Driver
$n = $device.Name
if (-not ($d -is [string])) {
throw [System.ArgumentException]::new('Invalid device object. Driver must be a string.', 'device')
}
if (-not ($n -is [string])) {
throw [System.ArgumentException]::new('Invalid device object. Name must be a string.', 'device')
}
if ($d -eq '' -and $n -eq '') { $this.Clear(); return }
if ($d -notin $this.drivers.Values) {
throw [System.ArgumentOutOfRangeException]::new('device.Driver', $d, 'Invalid device driver provided to Set method.')
}
$this.Setter($d, $n)
}
[void] Clear () {
$this.Setter('mme', '')
}
hidden $_driver = $($this | Add-Member ScriptProperty 'driver' `
{
if ([string]::IsNullOrEmpty($this.name)) { return '' }
$type = $null
try {
$tmp = [System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), "vmrtmp-$(New-Guid).xml")
$this.remote.Setter('Command.Save', $tmp)
$timeout = New-TimeSpan -Seconds 2
$sw = [Diagnostics.Stopwatch]::StartNew()
$line = $null
do {
if (Test-Path $tmp) {
try {
$line = Get-Content $tmp | Select-String -Pattern "<$($this.kindOfDevice)Dev index='$($this.index + 1)'" -List
if ($line) { break }
}
catch {}
}
Start-Sleep -Milliseconds 20
} while ($sw.elapsed -lt $timeout)
if ($line -and $line.ToString() -match "type='(?<type>\d+)'") {
$type = $matches['type']
}
}
finally {
if (Test-Path $tmp) {
Remove-Item $tmp -Force
}
}
if ($type -notin $this.drivers.Keys) { return 'unknown' }
return $this.drivers[$type]
} `
{
Write-Warning ("ERROR: $($this.identifier()).driver is read only")
}
)
} }
+3
View File
@@ -1,4 +1,7 @@
$KindMap = @{ $KindMap = @{
'none' = @{
'name' = 'none'
}
'basic' = @{ 'basic' = @{
'name' = 'basic' 'name' = 'basic'
'p_in' = 2 'p_in' = 2
+9 -1
View File
@@ -155,12 +155,20 @@ class StripEq : IOEq {
} }
class StripDevice : IODevice { class StripDevice : IODevice {
StripDevice ([int]$index, [Object]$remote) : base ($index, $remote) { StripDevice ([int]$index, [Object]$remote) : base ($index, $remote, 'Input') {
} }
[string] identifier () { [string] identifier () {
return 'Strip[' + $this.index + '].Device' return 'Strip[' + $this.index + '].Device'
} }
[int] EnumCount () {
return $this.remote.GetInputCount()
}
[PSObject] EnumDevice ([int]$eIndex) {
return $this.remote.GetInputDevice($eIndex)
}
} }
class VirtualStrip : Strip { class VirtualStrip : Strip {
+96 -27
View File
@@ -850,24 +850,47 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' {
@{ Index = $phys_in } @{ Index = $phys_in }
) { ) {
Context 'Device' -ForEach @( Context 'Device' -ForEach @(
@{ Value = 'testInput' }, @{ Value = '' } @{ Driver = 'mme'; Value = 'testMme'; Expected = 'mme' }
@{ Driver = 'wdm'; Value = 'testWdm'; Expected = 'wdm' }
@{ Driver = 'ks'; Value = 'testKs'; Expected = 'ks' }
@{ Driver = 'mme'; Value = ''; Expected = '' }
) { ) {
It "Should set Strip[$index].Device.wdm" { BeforeEach {
$vmr.strip[$index].device.wdm = $value $vmr.strip[$index].device.Clear()
Start-Sleep -Milliseconds 800 Start-Sleep -Milliseconds 800
$vmr.strip[$index].device.name | Should -Be $value
} }
It "Should set Strip[$index].Device.ks" { It "Should set Strip[$index].Device.$($driver)" {
$vmr.strip[$index].device.ks = $value $vmr.strip[$index].device.name | Should -Be ''
$vmr.strip[$index].device.driver | Should -Be ''
$vmr.strip[$index].device.$($driver) = $value
Start-Sleep -Milliseconds 800 Start-Sleep -Milliseconds 800
$vmr.strip[$index].device.name | Should -Be $value $vmr.strip[$index].device.name | Should -Be $value
$vmr.strip[$index].device.driver | Should -Be $expected
} }
It "Should set Strip[$index].Device.mme" { It "Should set Strip[$index].Device" -ForEach @(
$vmr.strip[$index].device.mme = $value @{
Clear = [PSCustomObject]@{ Driver = ''; Name = ''; HardwareId = ''; IsOutput = $false }
Device = [PSCustomObject]@{ Driver = $expected; Name = $value; HardwareId = ''; IsOutput = $false }
}
) {
$initial = $vmr.strip[$index].device.Get()
$initial.Driver | Should -Be $clear.Driver
$initial.Name | Should -Be $clear.Name
$initial.HardwareId | Should -Be $clear.HardwareId
$initial.IsOutput | Should -Be $clear.IsOutput
$vmr.strip[$index].device.Set($device)
Start-Sleep -Milliseconds 800 Start-Sleep -Milliseconds 800
$vmr.strip[$index].device.name | Should -Be $value $result = $vmr.strip[$index].device.Get()
$result.Driver | Should -Be $device.Driver
$result.Name | Should -Be $device.Name
$result.HardwareId | Should -Be $device.HardwareId
$result.IsOutput | Should -Be $device.IsOutput
} }
} }
@@ -983,24 +1006,47 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' {
@{ Index = $phys_out } @{ Index = $phys_out }
) { ) {
Context 'Device' -ForEach @( Context 'Device' -ForEach @(
@{ Value = 'testOutput' }, @{ Value = '' } @{ Driver = 'mme'; Value = 'testMme'; Expected = 'mme' }
@{ Driver = 'wdm'; Value = 'testWdm'; Expected = 'wdm' }
@{ Driver = 'ks'; Value = 'testKs'; Expected = 'ks' }
@{ Driver = 'mme'; Value = ''; Expected = '' }
) { ) {
It "Should set Bus[$index].Device.wdm" { BeforeEach {
$vmr.bus[$index].device.wdm = $value $vmr.bus[$index].device.Clear()
Start-Sleep -Milliseconds 800 Start-Sleep -Milliseconds 800
$vmr.bus[$index].device.name | Should -Be $value
} }
It "Should set Bus[$index].Device.ks" { It "Should set Bus[$index].Device.$($driver)" {
$vmr.bus[$index].device.ks = $value $vmr.bus[$index].device.name | Should -Be ''
$vmr.bus[$index].device.driver | Should -Be ''
$vmr.bus[$index].device.$($driver) = $value
Start-Sleep -Milliseconds 800 Start-Sleep -Milliseconds 800
$vmr.bus[$index].device.name | Should -Be $value $vmr.bus[$index].device.name | Should -Be $value
$vmr.bus[$index].device.driver | Should -Be $expected
} }
It "Should set Bus[$index].Device.mme" { It "Should set Bus[$index].Device" -ForEach @(
$vmr.bus[$index].device.mme = $value @{
Clear = [PSCustomObject]@{ Driver = ''; Name = ''; HardwareId = ''; IsOutput = $true }
Device = [PSCustomObject]@{ Driver = $expected; Name = $value; HardwareId = ''; IsOutput = $true }
}
) {
$initial = $vmr.bus[$index].device.Get()
$initial.Driver | Should -Be $clear.Driver
$initial.Name | Should -Be $clear.Name
$initial.HardwareId | Should -Be $clear.HardwareId
$initial.IsOutput | Should -Be $clear.IsOutput
$vmr.bus[$index].device.Set($device)
Start-Sleep -Milliseconds 800 Start-Sleep -Milliseconds 800
$vmr.bus[$index].device.name | Should -Be $value $result = $vmr.bus[$index].device.Get()
$result.Driver | Should -Be $device.Driver
$result.Name | Should -Be $device.Name
$result.HardwareId | Should -Be $device.HardwareId
$result.IsOutput | Should -Be $device.IsOutput
} }
} }
} }
@@ -1009,24 +1055,47 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' {
@{ Index = $virt_out } @{ Index = $virt_out }
) { ) {
Context 'Device' -Skip:$ifNotBasic -ForEach @( Context 'Device' -Skip:$ifNotBasic -ForEach @(
@{ Value = 'testOutput' }, @{ Value = '' } @{ Driver = 'mme'; Value = 'testMme'; Expected = 'mme' }
@{ Driver = 'wdm'; Value = 'testWdm'; Expected = 'wdm' }
@{ Driver = 'ks'; Value = 'testKs'; Expected = 'ks' }
@{ Driver = 'mme'; Value = ''; Expected = '' }
) { ) {
It "Should set Bus[$index].Device.wdm" { BeforeEach {
$vmr.bus[$index].device.wdm = $value $vmr.bus[$index].device.Clear()
Start-Sleep -Milliseconds 800 Start-Sleep -Milliseconds 800
$vmr.bus[$index].device.name | Should -Be $value
} }
It "Should set Bus[$index].Device.ks" { It "Should set Bus[$index].Device.$($driver)" {
$vmr.bus[$index].device.ks = $value $vmr.bus[$index].device.name | Should -Be ''
$vmr.bus[$index].device.driver | Should -Be ''
$vmr.bus[$index].device.$($driver) = $value
Start-Sleep -Milliseconds 800 Start-Sleep -Milliseconds 800
$vmr.bus[$index].device.name | Should -Be $value $vmr.bus[$index].device.name | Should -Be $value
$vmr.bus[$index].device.driver | Should -Be $expected
} }
It "Should set Bus[$index].Device.mme" { It "Should set Bus[$index].Device" -ForEach @(
$vmr.bus[$index].device.mme = $value @{
Clear = [PSCustomObject]@{ Driver = ''; Name = ''; HardwareId = ''; IsOutput = $true }
Device = [PSCustomObject]@{ Driver = $expected; Name = $value; HardwareId = ''; IsOutput = $true }
}
) {
$initial = $vmr.bus[$index].device.Get()
$initial.Driver | Should -Be $clear.Driver
$initial.Name | Should -Be $clear.Name
$initial.HardwareId | Should -Be $clear.HardwareId
$initial.IsOutput | Should -Be $clear.IsOutput
$vmr.bus[$index].device.Set($device)
Start-Sleep -Milliseconds 800 Start-Sleep -Milliseconds 800
$vmr.bus[$index].device.name | Should -Be $value $result = $vmr.bus[$index].device.Get()
$result.Driver | Should -Be $device.Driver
$result.Name | Should -Be $device.Name
$result.HardwareId | Should -Be $device.HardwareId
$result.IsOutput | Should -Be $device.IsOutput
} }
} }
} }