Skip to content

Set-VmsCameraStream improvements - #123

Merged
joshooaj merged 3 commits into
milestonesys:mainfrom
Silex:stream-improvements
Jan 30, 2026
Merged

Set-VmsCameraStream improvements#123
joshooaj merged 3 commits into
milestonesys:mainfrom
Silex:stream-improvements

Conversation

@Silex

@Silex Silex commented Dec 22, 2025

Copy link
Copy Markdown
Contributor
  • Fix settings lost when stream usage is modified.
  • Fix -WhatIf that displays empty stream names.
  • Adds verbosity when changing settings.
  • Move Write-Verbose to correct place (it was in deprecated -Recorded path).

Parts of it is AI generated so please double check.

@joshooaj

Copy link
Copy Markdown
Contributor

I'm working through this @Silex. As-is, this failed the integration tests and I've made changes to get them to pass, but I'm still observing some annoying behavior that was present before, and your originally reported issue doesn't seem totally resolved.

When using the latest released version, v25.2.21, updating the stream and live mode at the same time does work, but the updated resolution isn't reflected in the local $stream object. And updating more than one stream at a time shows both "sync" issues, as well as a failure to apply all stream-usage changes server side.

I'm not sure what my next step is going to be - I feel like a significant rewrite of the command (while maintaining compatibility) is needed as it was spaghetti code to begin with. In any case, here are some of my observations using the released version of the module for reference.

I'm using a StableFPS camera with three streams, and it starts with only Video Stream 1 enabled:

# Initial resolution and livemode is 555x555 and WhenNeeded
$stream = $camera | Get-VmsCameraStream -LiveDefault

# Changing to 111x111 and Always
$stream | set-vmscamerastream -Settings @{Resolution='111x111'} -LiveMode Always

# Locally, the resolution doesn't seem to change but LiveMode does.
# On the server, both settings were changed as expected.

$stream.Update()

# Now, after manually calling Update() on the local VmsCameraStreamConfig object,
# the resolution shows what I see in Management Client

$stream.Settings.Resolution
111x111

So the command technically worked, but it failed to call Update() on my local VmsCameraStreamConfig object after changing the resolution and still showed the old resolution. Once I called the update method myself, everything was correct locally and on the server.

Next, if I try to enable Video Stream 2, make that the default live stream, set LiveMode to Always, and change the resolution:

$stream = $camera | Get-VmsCameraStream -Name 'Video stream 2'
$stream | Set-VmsCameraStream -Settings @{Resolution='111x111'} -LiveDefault -LiveMode Always

$stream
$stream.Settings.Resolution

<#
Camera   Name           DisplayName    Enabled LiveMode LiveDefault Recorded
------   ----           -----------    ------- -------- ----------- --------
Camera 1 Video stream 2 Video stream 2 True    Always   True        False   

555x555
#>

Once again, all the settings take effect on the server, but the local $stream object shows the old resolution while showing the updated "stream usage" properties.

Multiple streams in the pipeline

If I make changes to multiple streams, I see the same issue with stale resolution values, and I start to see a failure to update all the stream usage properties:

$streams = $camera | Get-VmsCameraStream

<# INITIAL STATE
Camera   Name           DisplayName    Enabled LiveMode   LiveDefault Recorded RecordingTrack    PlaybackDefault UseEdge
------   ----           -----------    ------- --------   ----------- -------- --------------    --------------- -------
Camera 1 Video stream 1 Video stream 1 True    WhenNeeded True        True     Primary recording True            True
Camera 1 Video stream 2                False              False       False    No recording      False           False
Camera 1 Video stream 3                False              False       False    No recording      False           False

555x555
555x555
555x555
#>

$streams | Set-VmsCameraStream -Settings @{ Resolution = '111x111' } -LiveMode Always

<# NEW STATE
Camera   Name           DisplayName    Enabled LiveMode   LiveDefault Recorded RecordingTrack    PlaybackDefault UseEdge
------   ----           -----------    ------- --------   ----------- -------- --------------    --------------- -------
Camera 1 Video stream 1 Video stream 1 True    WhenNeeded True        True     Primary recording True            True
Camera 1 Video stream 2 Video stream 2 True    WhenNeeded False       False    No recording      False           False
Camera 1 Video stream 3 Video stream 3 True    Always     False       False    No recording      False           False

555x555
111x111
111x111
#>

LiveMode

The local state matches what I see in Management Client, so that's good. However, only the third stream was correctly set to Always.

Resolution

The resolutions are all correct in Management Client, but only 2/3 of the local stream objects show the updated value. Running Update() on the three streams gets the local resolution value in sync with the server so they're all showing 111x111, but LiveMode was still only modified on one of the three streams.

@Silex

Silex commented Jan 23, 2026

Copy link
Copy Markdown
Contributor Author

Not sure what to suggest here, you know this much better than I do.

Given most of your pains are with MIPSDK, maybe a "multiple pass" approach could work:

  • 1st pass just enable/disable the streams.
  • 2nd pass reload the streams, then set the flags that modify the stream properties like LiveDefault, RecordingTrack, etc.
  • 3rd pass reload the streams then modify the stream settings.

And I don't think that the lost performance matters much in that case, correctness is more important.


Or maybe a "treat fire with a stick approach" like for at least 5 times do: get the streams, if settings are correct return, if not try to set all properties, repeat.

@joshooaj

Copy link
Copy Markdown
Contributor

I'm experimenting with a C# replacement for the powershell VmsCameraStreamConfig class where it uses getters/setters for the modifications, and uses an internal event to communicate to other stream instances when something has changed that can affect other streamUsage instances from the same camera. Hopefully it will make it easier to maintain accurate local states. As a side effect I think it'll be faster too.

This is one of the few commands in the module where I'm trying to go out of my way to represent something in a different way than the SDK by combining stream settings and "usages" into a custom class, and that choice is biting me squarely in the butt 😅

@Silex

Silex commented Jan 26, 2026

Copy link
Copy Markdown
Contributor Author

This is one of the few commands in the module where I'm trying to go out of my way to represent something in a different way than the SDK by combining stream settings and "usages" into a custom class, and that choice is biting me squarely in the butt 😅

Well the SDK design is quite dated so I think you did the right thing by trying to make it better.

I guess eventually we should stop using the SDK and use the REST API only, when it's mature enough.

@joshooaj
joshooaj force-pushed the stream-improvements branch from 094efb0 to 959d65d Compare January 29, 2026 20:42
@joshooaj

Copy link
Copy Markdown
Contributor

I've rewritten the Set-VmsCameraStream command from scratch, migrating the VmsCameraStreamConfig PowerShell class to a C# class.

Most of the logic for reading & updating stream and streamusage settings has been moved into the new .NET class with proper getters and setters which has simplified the PowerShell function a lot.

A few private static members in the VmsCameraStreamConfig class allow us to share StreamDefinition and DeviceDriverSettings between multiple streams associated with the same camera to avoid things getting out of sync. Similarly, static members are used to track whether any VmsCameraStreamConfig associated with a given camera is "dirty" and requires saving changes.

Performance is improved by lazy loading properties of stream objects returned by Get-VmsCameraStream and reducing unnecessary calls to .Save() on StreamDefinition and DeviceDriverSettings parent objects.

Performance snapshot

Here's a quick look at the performance difference on a test system with 42 streams. Time is in milliseconds.

MilestonePSTools v25.2.21

AverageTimeToGet AverageTimeToSet
---------------- ----------------
      1676.26866       2134.65812

New version

AverageTimeToGet AverageTimeToSet
---------------- ----------------
        303.9607        978.11464

Changes

This adds -PassThru which was weirdly missing from the previous version, and an ExtraParams parameter which can be used to supply stream settings without using a hashtable by just adding the keys/values as if the parameters exist on the command. For example, these three commands have the same effect:

# Using the new shorthand
$stream | Set-VmsCameraStream -Resolution 1920x1080

# Passing a hashtable to the Settings parameter
$settings = @{
  Resolution = '1920x1080'
}
$stream | Set-VmsCameraStream -Settings $settings

# Splat
$splat = @{
  Settings = @{
    Resolution = '1920x1080'
  }
}
$stream | Set-VmsCameraStream @splat

@joshooaj

Copy link
Copy Markdown
Contributor

Good results testing this build against the Next Gen Demo system (NGD). These results are just for Get-VmsCameraStream though since I'm using an account with read-only privileges.

Get-VmsCameraStream

This is faster because the object returned by Get-VmsCameraStream and accepted by Set-VmsCameraStream is now based on a C# class with properties that retrieve values from the underlying streamusage and streamchilditem objects rather than pulling those values out in the constructor.

Measure-Command { $streams = get-vmscamera -EnableFilter All | Get-VmsCameraStream } | Select-Object TotalMilliseconds

# v25.2.21
TotalMilliseconds
-----------------
      101775.5128

# New build
TotalMilliseconds
-----------------
        9269.4193

Get-VmsCameraReport

Since Get-VmsCameraStream is faster now, the Get-VmsCameraReport command will see a performance improvement as well.

Measure-Command { $report = Get-VmsCameraReport } | Select-Object TotalMilliseconds

# v25.2.21
TotalMilliseconds
-----------------
       28050.2215

# New build
TotalMilliseconds
-----------------
       18893.0988

@joshooaj joshooaj self-assigned this Jan 30, 2026
@joshooaj joshooaj added the bug Something isn't working label Jan 30, 2026
@Silex

Silex commented Jan 30, 2026

Copy link
Copy Markdown
Contributor Author

Nice!

When I see $stream | Set-VmsCameraStream -Resolution 1920x1080 I have some warnings going on that at some point some parameter will clash with an existing CmdLet parameter or smth and trigger unexpected behavior, but I also see that for small scripts it's quite elegant.

@joshooaj

Copy link
Copy Markdown
Contributor

Good thinking - the odds of a collision between a stream property and the parameters on the cmdlet are pretty low I think. And the way parameter binding works, the existing parameters will always win. Looking at our NGD demo system with ~50 different camera models there are no collisions 😎

@Tarterman Tarterman left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested various aspects and looked over code. Everything looks good to me.

@joshooaj
joshooaj merged commit 727450c into milestonesys:main Jan 30, 2026
2 checks passed
@Silex
Silex deleted the stream-improvements branch February 1, 2026 12:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants