Commands/Send-OBS.ps1
function Send-OBS { <# .SYNOPSIS Sends messages to the OBS websocket. .DESCRIPTION Sends one or more messages to the OBS websocket. .LINK Receive-OBS .LINK Watch-OBS #> param( # The data to send to the obs websocket. [Parameter(ValueFromPipeline,ValueFromPipelineByPropertyName)] [Alias('Payload')] $MessageData, # If provided, will sleep after each step. # If -StepTime is less than 10000 ticks, it will be treated as frames per second. # If -SerialFrame was provied, -StepTime will be the number of frames to wait. [Parameter(ValueFromPipelineByPropertyName)] [timespan] $StepTime, # If set, will process a batch of requests in parallel. [switch] $Parallel, # If set, will process a batch of requests in parallel. [switch] $SerialFrame ) begin { $allMessages = [Collections.Queue]::new() # Keep track of how many requests we have done of a given type # (this makes creating RequestIDs easy) if (-not $script:ObsRequestsCounts) { $script:ObsRequestsCounts = @{} } function SendSingleMessageToOBS { param( [Parameter(ValueFromPipeline)] $payloadObject ) process { if ($null -eq $payloadObject.op) { if ($payloadObject.requestID) { $payloadObject = [Ordered]@{ op = 6 d = $payloadObject } } elseif ($payloadObject.authentication) { $payloadObject = [Ordered]@{ op = 1 d = $payloadObject } } else { Write-Verbose "No payload provided, broadcasting event" $myRequestType = 'BroadcastCustomEvent' # If we don't have a request counter for this request type if (-not $script:ObsRequestsCounts[$myRequestType]) { # initialize it to zero. $script:ObsRequestsCounts[$myRequestType] = 0 } # Increment the counter for requests of this type $script:ObsRequestsCounts[$myRequestType]++ # and make a request ID from that. $myRequestId = "$myRequestType.$($script:ObsRequestsCounts[$myRequestType])" $payloadObject = [Ordered]@{ op = 6 d = [Ordered]@{ requestId = $myRequestId requestType = $myRequestType eventData = $payloadObject } } } } $PayloadJson = $payloadObject | ConvertTo-Json -Depth 100 # And create a byte segment to send it off. $SendSegment = [ArraySegment[Byte]]::new([Text.Encoding]::UTF8.GetBytes($PayloadJson)) # If we have no OBS connections if (-not $script:ObsConnections.Values) { # error out Write-Error "Not connected to OBS. Use Connect-OBS." return } # Otherwise, walk over each connection foreach ($obsConnection in $script:ObsConnections.Values) { $OBSWebSocket = $obsConnection.Websocket if ($VerbosePreference -notin 'silentlyContinue', 'ignore') { Write-Verbose "Sending $payloadJSON" } # and send the payload $null = $OBSWebSocket.SendAsync($SendSegment,'Text', $true, [Threading.CancellationToken]::new($false)) # If a response was expected if ($payloadObject.d.requestID) { $payloadObject | Receive-OBS } } } } } process { $allMessages.Enqueue($MessageData) if ($StepTime.TotalMilliseconds -gt 0) { if ($SerialFrame) { $allMessages.Enqueue([PSCustomObject][Ordered]@{ requestType = 'Sleep' requestData = @{ sleepFrames = [int]$StepTime.Ticks } }) } else { if ($StepTime.Ticks -lt 10000) { $StepTime = [TimeSpan]::FromMilliseconds(1000 / $StepTime.Ticks) } $allMessages.Enqueue([PSCustomObject][Ordered]@{ requestType = 'Sleep' requestData = @{ sleepMillis = [int]$StepTime.TotalMilliseconds } }) } } } end { if ($allMessages.Count -eq 1) { $payloadObject = $allMessages[0] $payloadObject | SendSingleMessageToOBS } elseif ($allMessages.ToArray().RequestType) { if (-not $script:ObsRequestsCounts["Batch"]) { $script:ObsRequestsCounts["Batch"] = 0 } $script:ObsRequestsCounts["Batch"]++ [PSCustomObject]@{ op = 8 d = [Ordered]@{ requestId = "Batch.$([guid]::NewGuid())" executionType = if ($Parallel) { 2 } elseif ($SerialFrame) { 1 } else { 0 } requests = $allMessages.ToArray() } } | SendSingleMessageToOBS } else { $allMessages | SendSingleMessageToOBS } } } |