More docs-related commits will follow, but this needs to be merged in order to continue with other development.
* Docs: Overhaul docs generator (beginning)
* docs: Rename comments file
* docs: Move comments gitignore
* docs: Initial request documentation
* docs: Improvements to comment processing
* docs: More improvements
* docs: Add enum functionality for protocol.json
* WebSocketServer: Document enums
* RequestHandler: Document RequestStatus enum
* Base: Move ObsWebSocketRequestBatchExecutionType to its own file
Moves it to its own file, renaming it to `RequestBatchExecutionType`.
Changes the RPC to use integer values for selecting execution type
instead of strings.
* docs: Update introduction header
Removes the enum section, and documents RequestBatchExecutionType.
* WebSocketCloseCode: Shuffle a bit
* Base: Use `field` instead of `key` or `parameter` in most places
* RequestStatus: Mild shuffle
It was really bothering me that OutputPaused and OutputNotPaused
had to be separated, so we're breaking it while we're breaking
other stuff.
* docs: Delete old files
They may be added back in some form, but for now I'm getting them
out of the way.
* docs: Add enum identifier value
Forgot to add this before, oops
* docs: Document more enums
* docs: Add basic protocol.md generator
* docs: More work on MD generator
* docs: MD generator should be finished now
* docs: More fixes
* docs: More fixes
* docs: More tweaks + add readme
* docs: Update readme and add inputs docs
* docs: More documentation
This is probably one of the most requested features for obs-websocket.
This currently works by firing an event to all explicit subscribers
with an array of all active audio sources every **60 milliseconds.**
The `inputLevelsMul` field follows this data format:
Base: [Channel, Channel]
Channel: [magnitude (mul), peak (mul), input_peak (mul)]
*Not Muted* *Muted*
Example: [[0.3, 0.5, 0.9], [0.0, 0.0, 0.0]]
(input_peak is the actual peak value, before volume adjustment.)
You may notice that the values are only in mul. This is because we are
trying to cut down on bandwidth. dB values can be calculated using this
formula:
`dB = 20.0 * log10(mul)`
obs-studio's LOG_DEBUG setting only works in very specific
circumstances, which is why we implement our own debug logging. This
will help a lot of code cleanup.
- Implements a WIP ObsWebSocketApi, for obs-websocket-api.h. Events are
finished, but requests are not.
- Some logging improvements
- A bit of code cleanup around the plugin
- Adds variables to execution types SERIAL_REALTIME and SERIAL_FRAME
- Pass by reference where copy is unnecessary
- Start WebSocket server after OBS finishes loading instead of on
plugin load
Crashes can occur if there is no current program scene. Currently
caused by connecting to obs-websocket and calling `GetSceneList`
before OBS has actually finished loading.
A new `executionType` field has been added to the `RequestBatch` Op
Types added:
- `OBS_WEBSOCKET_REQUEST_BATCH_EXECUTION_TYPE_SERIAL_REALTIME`(default)
- `OBS_WEBSOCKET_REQUEST_BATCH_EXECUTION_TYPE_SERIAL_FRAME`
- `OBS_WEBSOCKET_REQUEST_BATCH_EXECUTION_TYPE_PARALLEL`
`OBS_WEBSOCKET_REQUEST_BATCH_EXECUTION_TYPE_SERIAL_REALTIME`:
- Same as how request batches have always worked.
- Requests are processed in-order
- Requests are processed as soon as possible by one worker thread
- The `Sleep` request blocks execution for a specified amount of real
world time
`OBS_WEBSOCKET_REQUEST_BATCH_EXECUTION_TYPE_SERIAL_FRAME`:
- New!
- Requests are processed in-order
- Requests are processed on the graphics thread. BE VERY CAREFUL NOT
TO OVERLOAD THE GRAPHICS THREAD WITH LARGE REQUESTS. A general rule
of thumb is for your request batches to take a maximum of 2ms per
frame of processing.
- Requests processing starts right before the next frame is composited.
This functionality is perfect for things like `SetSceneItemTransform`
- The `Sleep` request will halt processing of the request batch for
a specified number of frames (ticks)
- To be clear: If you do not have any sleep requests, all requests in
the batch will be processed in the span of a single frame
- For developers: The execution of requests gets profiled by the OBS
profiler under the `obs-websocket-request-batch-frame-tick` name.
This value (shown in the OBS log after OBS shutdown) represents the
amount of time that the graphics thread spent actively processing
requests per frame. This tool can be used to determine the amount of
load that your request batches are placing on the graphics thread.
`OBS_WEBSOCKET_REQUEST_BATCH_EXECUTION_TYPE_PARALLEL`:
- New!
- Requests are processed asynchronously at the soonest possible time.
- Requests are processed by the core obs-websocket thread pool, where
the number of workers == the number of threads on your machine.
- If you have 12 threads on your machine, obs-websocket will be able
to process 12 requests at any given moment.
- The `results` array is populated by order of request completion.
Consider the order to be random.
- The `Sleep` request will return an error if attempted to be used in
this mode.
- Note: This feature is experimental and can increase the chances of
causing race conditions (crashes). While the implementation is fully
thread-safe, OBS itself is not. Usage of this is only recommended if
you are processing very large batches and need the performance benefit.
- Example use case: Performing `SaveSourceScreenshot` on 8 sources
at once.
I realized that it was not entirely fair to expect users to fetch a
scene's item list, then search the list on the client in order to find
an item ID, so this is a compromise. This will also help developers
move from the 4.x scene item functionality to 5.x's
Operating on scene items by relying on source name can be dangerous
and in some cases exhibit what would be considered undefinied behavior.
Operating on scene items using IDs is best practice.
QCloseEvent is the wrong event to use here. If the `Ok` button is
pressed for example, QCloseEvent is not emitted. QHideEvent is
always called when the dialog is hidden.
Fixes these things:
- Websocket password is not generated if FirstLoad and overridden
- Save generated password immediately if FirstLoad
- Do not generate new password if FirstLoad and password already exists
- More logging
- Merge WebSocketProtocol into WebSocketServer
- Having them separated was not doing anything productive
- Request: Move SessionPtr to RequestHandler
- Less copying to do for batch requests
- Fully modularize EventHandler
- Make BroadcastEvent a stored callback that WebSocketServer sets
- Return early on high volume events to avoid unnecessary compute
- These events will only generate a json object when it is actually
needed
As discussed in the #development channel in discord
- Switch from using message types to integer op codes
- Consolidate op-specific keys into `d` sub-object
- Shorten low-level payload keys from `messageType` to `op`, add `d`
Other changes:
- The WebSocketCloseCode enum has been refactored. It's best to just
treat it like it's new
- Some performance benefits came along the way. Nothing gamechanging,
but notable
- Various bug fixes discovered while refactoring
obs_queue_task is set to wait, so there is no need to create our
bool on the stack, as it should never go out of scope when the task
is run. Additionally, the old way didn't actually work anyway.
Final "UI" part of the plugin to be completed. I'm annoyed at how
many includes are required in order to implement this feature. It
breaks quite a bit of the modularity of the plugin because suddenly
everything has to include obs libraries (for translations)
Events can be tricky when it comes to the size of payloads. Many
embedded devices can have troubles receiving large payloads, so
we should be mindful of that. It is much harder to avoid large
payload sizes as a client for events than it is for requests.
Clients that need the data not included here should either cache
it from other sources or grab it fresh.
Pointers in calldata are theoretically already incremented,
so incrementing their refcount then decrementing them is
unnecessary in the context of the event system.
It was pointed out that the existing functionality was not effective
at filtering out invalid interfaces, so we add a priority system
to try harder at finding a valid address.
The functionality of not reloading the server when debug mode is
changed I determined was too confusing to use considering the
benefit that it provides by not reloading the websocket server.
It is technically possible to set debug mode to the server while
it is running, however the implementation would somewhat dirty the
UI code, so I do not feel comfortable doing it at this point.
A request from the OBS developers. Debug mode tends to be enabled,
then not remembered to be disabled, leading to logs that are both
long and difficult to read. In some cases, the OBS logviewer may
noticeably lock up the UI just trying to parse the long log file.
Show a confirmation dialog when the Show Connect Info button is
clicked and video is active, to prevent users from
unintentionally showing sensitive information while live.
Among lots of stuff:
- Generate a random password on first load
- Add `ConnectInfo` dialog including QR code display
- Add `Generate Password` button to generate a new random
password
- Delete `Copy Password to Clipboard` button
- Delete `GetConnectString` or whatever from WebSocketServer
(reimplemented the functionality directly into ConnectInfo)
- Added `GeneratePassword()` to Utils
Todo: Show warning when users specify their own passwords
Debug mode requires a restart of the websocket server by design.
However, to avoid interrupting connections, the websocket server is
not automatically restarted when the setting is changed
Took a night of sleep but I realized how I could solve the
concurrency issues in a good way. Uses shared_ptr, where the map
always accounts for one reference to a session.
Working towards fixing concurrency issues. Todo:
- Wait for refcount to be 0 before deleting object
- Use .at() instead of operator[] to prevent recreating deleted
sessions
- There was a third thing. Dont remember what it was