Compare commits

...

37 Commits
5.0.2 ... 5.1.0

Author SHA1 Message Date
31f9845b61 base: Update version to 5.1.0
- Renamed the tools menu button title to `WebSocket Server Settings`
- WebSocket session disconnects are now logged with the close code and
reason
- Fixed a few UI formatting issues
- Fixed the `ObsOutputState` enum not being shown in protocol.md
- Implemented new reconnect output states to the stream output
  - `OBS_WEBSOCKET_OUTPUT_RECONNECTING`
  - `OBS_WEBSOCKET_OUTPUT_RECONNECTED`
- Added the `ScreenshotSaved` event for the screenshot hotkey
- Fixed a bug where `GetLastReplayBufferFileName` could return an empty
string
- Documented `CustomEvent`
- Various other documentation fixes
- Added the following new software and libraries to the README:
  - Macro Deck
  - Bitfocus Companion
  - Kruiz Control
  - Aitum
  - OBS Blade
  - Deckboard
  - Streamer.bot
  - OBS-web
  - obws (Rust)
  - goobs
  - obsws-python
2022-11-18 02:29:10 -08:00
cb6f0b8986 docs(ci): Update generated docs - 9959acb [skip ci] 2022-11-18 10:10:12 +00:00
9959acb0e8 forms: Various UI improvements 2022-11-18 02:09:48 -08:00
8b1ef17c25 docs: Fix initial version for reconnect enum fields 2022-11-18 02:09:48 -08:00
a254172c12 eventhandler: Add reconnecting and reconnected stream output states
Closes #1050
2022-11-18 02:09:48 -08:00
57a9e23f16 docs: Document ObsOutputState enum 2022-11-18 02:09:48 -08:00
4c3660c08d docs: Enable ObsMediaInputAction enum documentation
It should now show up in protocol.md
2022-11-18 02:09:48 -08:00
323b5d0b5d eventhandler, utils: Implement missing output states 2022-11-18 02:09:48 -08:00
23f883d906 eventhandler: Split some handling code into multi handlers
Code cleanup
2022-11-18 02:09:48 -08:00
60dbcc1b66 docs(ci): Update generated docs - 8cabe24 [skip ci] 2022-11-18 06:20:26 +00:00
8cabe24b77 eventhandler: Add ScreenshotSaved event
No, this does not trigger with `Get/SaveScreenshot`. I've tried to make
that super clear in the docs. Hopefully people don't get too confused.
2022-11-17 22:19:12 -08:00
9cfca3c7d1 utils: Use new method to get last replay
Uses the newer obs-frontend-api function instead of our original
method. It was cool, but is no longer necessary.
2022-11-17 22:18:18 -08:00
cfa0b4363e utils: Add function to get last screenshot file name 2022-11-17 22:16:59 -08:00
815d47e2ff README: Add Macro Deck software link 2022-11-17 18:40:27 -08:00
9bdf560bf8 utils: Fix use-after-free in GetLastReplayBufferFileName 2022-11-17 18:36:25 -08:00
47f9beb095 docs(ci): Update generated docs - 32d0834 [skip ci] 2022-11-13 00:00:45 +00:00
32d0834c3f docs: Fix description of "mul" volume notation 2022-11-12 16:00:28 -08:00
9722ed3df4 Add CustomEvent docs entry
Resolves #1031
2022-11-12 15:56:03 -08:00
9f72852588 doc: Update README to add Java library 2022-11-12 15:51:05 -08:00
6e0220ac7b Update translations from Crowdin 2022-10-25 22:32:12 +00:00
6d4b7c786e docs(ci): Update generated docs - 290e042 [skip ci] 2022-10-22 22:22:39 +00:00
290e042612 fix: Sleep request fields are exclusive so both optional fixes #1042 2022-10-22 15:22:20 -07:00
7e4c9529eb docs(ci): Update generated docs - bc18401 [skip ci] 2022-10-18 20:11:17 +00:00
bc18401fb0 docs: Fix ouputPaused typo 2022-10-18 13:10:58 -07:00
265899f76f docs(ci): Update generated docs - 9e1a41f [skip ci] 2022-09-19 01:02:32 +00:00
9e1a41f219 docs: Clarify that nested scenes are recommended instead of groups
Seems like it would be obvious, but apparently not
2022-09-18 18:02:13 -07:00
7893ae5caa docs: Add top-level headings to main TOC
It may be worth having the entire TOC up here, but this way, at least
it's possible to jump to the other TOCs.
2022-09-16 04:54:42 -07:00
a715639302 docs(ci): Update generated docs - 6038fe9 [skip ci] 2022-09-07 19:43:58 +00:00
6038fe9a0a docs: Start list of known propertyName values for common buttons 2022-09-07 12:43:29 -07:00
6fba48929a README: Add second contributor to obsws-python 2022-09-05 15:33:30 -07:00
7eb4eb101c README: Add Bitfocus Companion to client software 2022-09-05 15:32:51 -07:00
f2e595e1ab README: Add Kruiz Control and obsws-python to list 2022-09-04 17:11:30 -07:00
c1ffbf0111 README: Add Aitum 2022-09-03 15:16:30 -07:00
f08d3225ad README: Add OBS Blade to supported client software 2022-09-03 07:06:10 -07:00
84542e1ed5 README: Add deckboard to supported client software list 2022-09-03 06:53:41 -07:00
bb9371b0dc locale: Rename plugin settings title to match other plugins
Closes obsproject/obs-studio#7231
2022-09-02 00:11:59 -07:00
ab918faea8 README: Add streamer.bot to list of supported client software 2022-09-01 03:12:56 -07:00
27 changed files with 816 additions and 155 deletions

View File

@ -28,10 +28,8 @@ body:
- macOS 10.14
- macOS 10.13
- Ubuntu 22.04 LTS
- Ubuntu 21.04
- Ubuntu 20.10
- Ubuntu 20.04 LTS
- Ubuntu 18.04 LTS
- Other
validations:
required: true
@ -49,16 +47,10 @@ body:
label: OBS Studio Version
description: What version of OBS Studio are you using?
options:
- 28.0.0
- 29.0.x
- 28.1.x
- 28.0.x
- 27.2.4
- 27.2.3
- 27.2.2
- 27.2.1
- 27.2.0
- 27.1.3
- 27.1.1
- 27.1.0
- 27.0.1
- Git
- Other
validations:
@ -76,9 +68,9 @@ body:
label: obs-websocket Version
description: What version of obs-websocket are you using?
options:
- 5.1.0
- 5.0.1
- 5.0.0
- 5.0.0-beta1
- Git
validations:
required: true

View File

@ -1,4 +1,4 @@
project(obs-websocket VERSION 5.0.1)
project(obs-websocket VERSION 5.1.0)
set(OBS_WEBSOCKET_RPC_VERSION 1)
option(ENABLE_WEBSOCKET "Enable building OBS with websocket plugin" ON)

View File

@ -31,21 +31,30 @@ It is **highly recommended** to keep obs-websocket protected with a password aga
### Client software
- [Macro Deck](https://www.macrodeck.org/)
- [Touch Portal](https://www.touch-portal.com/)
- [Twitchat](https://twitchat.fr/)
- [OBS-web](https://github.com/Niek/obs-web) - hosted client at [obs-web.niek.tv/](http://obs-web.niek.tv/)
- [Streamer.bot](https://streamer.bot/)
- [Deckboard](https://deckboard.app/)
- [OBS Blade](https://github.com/Kounex/obs_blade)
- [Aitum](https://aitum.tv/)
- [Kruiz Control](https://github.com/Kruiser8/Kruiz-Control)
- [Bitfocus Companion Module](https://bitfocus.io/companion/)
### Client libraries (for developers)
Here's a list of available language APIs for obs-websocket:
- Python 3.7+ (Asyncio): [simpleobsws](https://github.com/IRLToolkit/simpleobsws/tree/master) by IRLToolkit
- Python 3.10+ (Non-Asyncio): [obsws-python](https://pypi.org/project/obsws-python) by aatikturk and onyx-and-iris
- Rust: [obws](https://github.com/dnaka91/obws) by dnaka91
- Godot 3.4.x: [obs-websocket-gd](https://github.com/you-win/obs-websocket-gd) by you-win
- Javascript (Node and web): [obs-websocket-js](https://github.com/obs-websocket-community-projects/obs-websocket-js) by OBS Websocket Community
- C (uses obs-websocket-js): [v8-libwebsocket-obs-websocket](https://github.com/dgatwood/v8-libwebsocket-obs-websocket)
- Go: [goobs](https://github.com/andreykaipov/goobs) by andreykaipov
- Dart/Flutter (can target all supported platforms): [obs_websocket](https://github.com/faithoflifedev/obs_websocket) by faithoflifedev
- Java: [obs-websocket-java](https://github.com/obs-websocket-community-projects/obs-websocket-java) by OBS Websocket Community
The 5.x server is a typical WebSocket server running by default on port 4455 (the port number can be changed in the Settings dialog under `Tools`).
The protocol we use is documented in [PROTOCOL.md](docs/generated/protocol.md).

View File

@ -1,6 +1,6 @@
OBSWebSocket.Plugin.Description="Remote-control of OBS Studio through WebSocket"
OBSWebSocket.Settings.DialogTitle="obs-websocket Settings"
OBSWebSocket.Settings.DialogTitle="WebSocket Server Settings"
OBSWebSocket.Settings.PluginSettingsTitle="Plugin Settings"
OBSWebSocket.Settings.ServerEnable="Enable WebSocket server"

View File

@ -1,3 +1,43 @@
OBSWebSocket.Plugin.Description="کنترل از راه دور OBS Studio از طریق WebSocket"
OBSWebSocket.Settings.DialogTitle="تنظیمات obs-سوکت وب"
OBSWebSocket.Settings.PluginSettingsTitle="تنظیمات پلاگین"
OBSWebSocket.Settings.ServerEnable="سرور سوکت وب را فعال کنید"
OBSWebSocket.Settings.AlertsEnable="هشدارهای سینی سیستم را فعال کنید"
OBSWebSocket.Settings.DebugEnable="فعال کردن گزارش اشکال زدایی"
OBSWebSocket.Settings.DebugEnableHoverText="ثبت اشکال زدایی را برای نمونه فعلی OBS فعال می کند. در بارگذاری ادامه نمی‌یابد.\n برای فعال کردن در بارگذاری از --websocket_debug استفاده کنید."
OBSWebSocket.Settings.ServerSettingsTitle="تنظیمات سرور"
OBSWebSocket.Settings.AuthRequired="فعال کردن احراز هویت"
OBSWebSocket.Settings.Password="رمز سرور"
OBSWebSocket.Settings.GeneratePassword="ایجاد رمز عبور"
OBSWebSocket.Settings.ServerPort="پورت سرور"
OBSWebSocket.Settings.ShowConnectInfo="نمایش اطلاعات اتصال"
OBSWebSocket.Settings.ShowConnectInfoWarningTitle="هشدار: در حال حاضر زنده است"
OBSWebSocket.Settings.ShowConnectInfoWarningMessage="به نظر می رسد که یک خروجی (جریان، ضبط و غیره) در حال حاضر فعال است."
OBSWebSocket.Settings.ShowConnectInfoWarningInfoText="آیا مطمئن هستید که می خواهید اطلاعات اتصال خود را نشان دهید؟"
OBSWebSocket.Settings.Save.UserPasswordWarningTitle="هشدار: مشکل امنیتی احتمالی"
OBSWebSocket.Settings.Save.UserPasswordWarningMessage="obs-websocket رمز عبور سرور را به صورت متن ساده ذخیره می کند. استفاده از رمز عبور تولید شده توسط obs-websocket بسیار توصیه می شود."
OBSWebSocket.Settings.Save.UserPasswordWarningInfoText="آیا مطمئن هستید که می خواهید از رمز عبور خود استفاده کنید؟"
OBSWebSocket.Settings.Save.PasswordInvalidErrorTitle="خطا: پیکربندی نامعتبر است"
OBSWebSocket.Settings.Save.PasswordInvalidErrorMessage="باید از رمز عبور 6 کاراکتر یا بیشتر استفاده کنید."
OBSWebSocket.SessionTable.Title="جلسات سوکت وب متصل"
OBSWebSocket.SessionTable.RemoteAddressColumnTitle="آدرس از راه دور"
OBSWebSocket.SessionTable.SessionDurationColumnTitle="مدت زمان جلسه"
OBSWebSocket.SessionTable.MessagesInOutColumnTitle="پیام های ورودی/خارجی"
OBSWebSocket.SessionTable.IdentifiedTitle="تایید هویت شده"
OBSWebSocket.SessionTable.KickButtonColumnTitle="لگد زدن؟"
OBSWebSocket.SessionTable.KickButtonText="اخراج"
OBSWebSocket.ConnectInfo.DialogTitle="اطلاعات اتصال سوکت وب"
OBSWebSocket.ConnectInfo.CopyText="رونوشت‌"
OBSWebSocket.ConnectInfo.ServerIp="IP سرور (بهترین حدس)"
OBSWebSocket.ConnectInfo.ServerPort="پورت سرور"
OBSWebSocket.ConnectInfo.ServerPassword="رمز سرور"
OBSWebSocket.ConnectInfo.ServerPasswordPlaceholderText="[احراز غیر فعال]"
OBSWebSocket.ConnectInfo.QrTitle="QR را وصل کنید"
OBSWebSocket.TrayNotification.Identified.Title="اتصال سوکت وب جدید"
OBSWebSocket.TrayNotification.Identified.Body="سرویس گیرنده %1 شناسایی شد."
OBSWebSocket.TrayNotification.AuthenticationFailed.Title="خرابی تأیید اعتبار سوکت وب"
OBSWebSocket.TrayNotification.AuthenticationFailed.Body="سرویس گیرنده %1 احراز هویت نشد."
OBSWebSocket.TrayNotification.Disconnected.Title="سرویس گیرنده سوکت وب قطع شد"
OBSWebSocket.TrayNotification.Disconnected.Body="سرویس گیرنده %1 قطع شد."
OBSWebSocket.Server.StartFailed.Title="خرابی سرور سوکت وب"
OBSWebSocket.Server.StartFailed.Message="سرور WebSocket راه‌اندازی نشد. درگاه TCP % 1 ممکن است قبلاً در جای دیگری در این سیستم توسط برنامه دیگری استفاده شده باشد. یک پورت TCP دیگر را در تنظیمات سرور WebSocket تنظیم کنید، یا هر برنامه‌ای را که می‌تواند از این پورت استفاده کند متوقف کنید.\n پیام خطا: %2"

View File

@ -22,7 +22,7 @@ OBSWebSocket.Settings.Save.PasswordInvalidErrorMessage="Você deve usar uma senh
OBSWebSocket.SessionTable.Title="Sessões WebSocket Conectadas"
OBSWebSocket.SessionTable.RemoteAddressColumnTitle="Endereço Remoto"
OBSWebSocket.SessionTable.SessionDurationColumnTitle="Duração de Sessão"
OBSWebSocket.SessionTable.MessagesInOutColumnTitle="Mengsagens de Entrada/Saída"
OBSWebSocket.SessionTable.MessagesInOutColumnTitle="Mensagens"
OBSWebSocket.SessionTable.IdentifiedTitle="Identificada"
OBSWebSocket.SessionTable.KickButtonColumnTitle="Expulsar?"
OBSWebSocket.SessionTable.KickButtonText="Expulsar"

View File

@ -12,11 +12,11 @@ OBSWebSocket.Settings.GeneratePassword="Generează parola"
OBSWebSocket.Settings.ServerPort="Portul serverului"
OBSWebSocket.Settings.ShowConnectInfo="Afișează informațiile de conectare"
OBSWebSocket.Settings.ShowConnectInfoWarningTitle="Avertisment: În prezent în direct"
OBSWebSocket.Settings.ShowConnectInfoWarningMessage="Se pare că o ieșire (flux, înregistrare etc.) este activă în prezent."
OBSWebSocket.Settings.ShowConnectInfoWarningInfoText="Ești sigur vrei să-ți arăți informațiile de conectare?"
OBSWebSocket.Settings.ShowConnectInfoWarningMessage="Se pare că un output (transmisiune, înregistrare etc.) este activ în prezent."
OBSWebSocket.Settings.ShowConnectInfoWarningInfoText="Sigur vrei să afișezi informațiile de conectare?"
OBSWebSocket.Settings.Save.UserPasswordWarningTitle="Avertisment: Potențială problemă de securitate"
OBSWebSocket.Settings.Save.UserPasswordWarningMessage="obs-websocket stochează parola serverului ca text simplu. Este foarte recomandat să folosiți o parolă generată de obs-websocket."
OBSWebSocket.Settings.Save.UserPasswordWarningInfoText="Ești sigur vrei să-ți folosești propria parolă?"
OBSWebSocket.Settings.Save.UserPasswordWarningInfoText="Sigur vrei să-ți folosești propria parolă?"
OBSWebSocket.Settings.Save.PasswordInvalidErrorTitle="Eroare: Configurație invalidă"
OBSWebSocket.Settings.Save.PasswordInvalidErrorMessage="Trebuie să folosești o parolă care să aibă 6 sau mai multe caractere."
OBSWebSocket.SessionTable.Title="Sesiuni WebSocket conectate"

7
data/locale/vi-VN.ini Normal file
View File

@ -0,0 +1,7 @@
OBSWebSocket.Settings.PluginSettingsTitle="Thiết đặt trình cắm"
OBSWebSocket.Settings.ServerEnable="Bật máy chủ WebSocket"
OBSWebSocket.Settings.ServerSettingsTitle="Thiết đặt máy chủ"
OBSWebSocket.Settings.Password="Mật khẩu máy chủ"
OBSWebSocket.Settings.GeneratePassword="Tạo mật khẩu"
OBSWebSocket.Settings.ServerPort="Cổng máy chủ"
OBSWebSocket.Settings.ShowConnectInfo="Hiện thông tin kết nối"

View File

@ -9,7 +9,9 @@ enumTypeOrder = [
'WebSocketCloseCode',
'RequestBatchExecutionType',
'RequestStatus',
'EventSubscription'
'EventSubscription',
'ObsMediaInputAction',
'ObsOutputState'
]
categoryOrder = [

View File

@ -1,5 +1,5 @@
# obs-websocket 5.0.1 Protocol
# obs-websocket 5.1.0 Protocol
## Main Table of Contents
@ -19,6 +19,9 @@
- [RequestResponse (OpCode 7)](#requestresponse-opcode-7)
- [RequestBatch (OpCode 8)](#requestbatch-opcode-8)
- [RequestBatchResponse (OpCode 9)](#requestbatchresponse-opcode-9)
- [Enumerations](#enums)
- [Events](#events)
- [Requests](#requests)
## General Intro
@ -143,7 +146,7 @@ Authentication is required
{
"op": 0,
"d": {
"obsWebSocketVersion": "5.0.1",
"obsWebSocketVersion": "5.1.0",
"rpcVersion": 1,
"authentication": {
"challenge": "+IxH4CnCiqpX1rM9scsNynZzbOe4KhDeYcTNS3PDaeY=",
@ -159,7 +162,7 @@ Authentication is not required
{
"op": 0,
"d": {
"obsWebSocketVersion": "5.0.1",
"obsWebSocketVersion": "5.1.0",
"rpcVersion": 1
}
}

View File

@ -447,6 +447,83 @@
}
]
},
{
"enumType": "ObsOutputState",
"enumIdentifiers": [
{
"description": "Unknown state.",
"enumIdentifier": "OBS_WEBSOCKET_OUTPUT_UNKNOWN",
"rpcVersion": 1,
"deprecated": true,
"initialVersion": "5.0.0",
"enumValue": "OBS_WEBSOCKET_OUTPUT_UNKNOWN"
},
{
"description": "The output is starting.",
"enumIdentifier": "OBS_WEBSOCKET_OUTPUT_STARTING",
"rpcVersion": 1,
"deprecated": true,
"initialVersion": "5.0.0",
"enumValue": "OBS_WEBSOCKET_OUTPUT_STARTING"
},
{
"description": "The input has started.",
"enumIdentifier": "OBS_WEBSOCKET_OUTPUT_STARTED",
"rpcVersion": 1,
"deprecated": true,
"initialVersion": "5.0.0",
"enumValue": "OBS_WEBSOCKET_OUTPUT_STARTED"
},
{
"description": "The output is stopping.",
"enumIdentifier": "OBS_WEBSOCKET_OUTPUT_STOPPING",
"rpcVersion": 1,
"deprecated": true,
"initialVersion": "5.0.0",
"enumValue": "OBS_WEBSOCKET_OUTPUT_STOPPING"
},
{
"description": "The output has stopped.",
"enumIdentifier": "OBS_WEBSOCKET_OUTPUT_STOPPED",
"rpcVersion": 1,
"deprecated": true,
"initialVersion": "5.0.0",
"enumValue": "OBS_WEBSOCKET_OUTPUT_STOPPED"
},
{
"description": "The output has disconnected and is reconnecting.",
"enumIdentifier": "OBS_WEBSOCKET_OUTPUT_RECONNECTING",
"rpcVersion": 1,
"deprecated": true,
"initialVersion": "5.0.0",
"enumValue": "OBS_WEBSOCKET_OUTPUT_RECONNECTING"
},
{
"description": "The output has reconnected successfully.",
"enumIdentifier": "OBS_WEBSOCKET_OUTPUT_RECONNECTED",
"rpcVersion": 1,
"deprecated": true,
"initialVersion": "5.1.0",
"enumValue": "OBS_WEBSOCKET_OUTPUT_RECONNECTED"
},
{
"description": "The output is now paused.",
"enumIdentifier": "OBS_WEBSOCKET_OUTPUT_PAUSED",
"rpcVersion": 1,
"deprecated": true,
"initialVersion": "5.1.0",
"enumValue": "OBS_WEBSOCKET_OUTPUT_PAUSED"
},
{
"description": "The output has been resumed (unpaused).",
"enumIdentifier": "OBS_WEBSOCKET_OUTPUT_RESUMED",
"rpcVersion": 1,
"deprecated": true,
"initialVersion": "5.0.0",
"enumValue": "OBS_WEBSOCKET_OUTPUT_RESUMED"
}
]
},
{
"enumType": "ObsMediaInputAction",
"enumIdentifiers": [
@ -1776,16 +1853,16 @@
"valueType": "Number",
"valueDescription": "Number of milliseconds to sleep for (if `SERIAL_REALTIME` mode)",
"valueRestrictions": ">= 0, <= 50000",
"valueOptional": false,
"valueOptionalBehavior": null
"valueOptional": true,
"valueOptionalBehavior": "Unknown"
},
{
"valueName": "sleepFrames",
"valueType": "Number",
"valueDescription": "Number of frames to sleep for (if `SERIAL_FRAME` mode)",
"valueRestrictions": ">= 0, <= 10000",
"valueOptional": false,
"valueOptionalBehavior": null
"valueOptional": true,
"valueOptionalBehavior": "Unknown"
}
],
"responseFields": []
@ -2481,7 +2558,7 @@
]
},
{
"description": "Presses a button in the properties of an input.\n\nNote: Use this in cases where there is a button in the properties of an input that cannot be accessed in any other way. For example, browser sources, where there is a refresh button.",
"description": "Presses a button in the properties of an input.\n\nSome known `propertyName` values are:\n\n- `refreshnocache` - Browser source reload button\n\nNote: Use this in cases where there is a button in the properties of an input that cannot be accessed in any other way. For example, browser sources, where there is a refresh button.",
"requestType": "PressInputPropertiesButton",
"complexity": 4,
"rpcVersion": "1",
@ -2777,7 +2854,13 @@
"initialVersion": "5.0.0",
"category": "outputs",
"requestFields": [],
"responseFields": []
"responseFields": [
{
"valueName": "outputs",
"valueType": "Array<Object>",
"valueDescription": "Array of outputs"
}
]
},
{
"description": "Gets the status of an output.",
@ -2976,7 +3059,7 @@
"valueDescription": "Whether the output is active"
},
{
"valueName": "ouputPaused",
"valueName": "outputPaused",
"valueType": "Boolean",
"valueDescription": "Whether the output is paused"
},
@ -3096,7 +3179,7 @@
]
},
{
"description": "Basically GetSceneItemList, but for groups.\n\nUsing groups at all in OBS is discouraged, as they are very broken under the hood.\n\nGroups only",
"description": "Basically GetSceneItemList, but for groups.\n\nUsing groups at all in OBS is discouraged, as they are very broken under the hood. Please use nested scenes instead.\n\nGroups only",
"requestType": "GetGroupSceneItemList",
"complexity": 3,
"rpcVersion": "1",
@ -4955,7 +5038,7 @@
{
"valueName": "inputVolumeMul",
"valueType": "Number",
"valueDescription": "New volume level in multimap"
"valueDescription": "New volume level multiplier"
},
{
"valueName": "inputVolumeDb",
@ -5638,6 +5721,23 @@
}
]
},
{
"description": "A screenshot has been saved.\n\nNote: Triggered for the screenshot feature available in `Settings -> Hotkeys -> Screenshot Output` ONLY.\nApplications using `Get/SaveSourceScreenshot` should implement a `CustomEvent` if this kind of inter-client\ncommunication is desired.",
"eventType": "ScreenshotSaved",
"eventSubscription": "Ui",
"complexity": 2,
"rpcVersion": "1",
"deprecated": false,
"initialVersion": "5.1.0",
"category": "ui",
"dataFields": [
{
"valueName": "savedScreenshotPath",
"valueType": "String",
"valueDescription": "Path of the saved image file"
}
]
},
{
"description": "An event has been emitted from a vendor.\n\nA vendor is a unique name registered by a third-party plugin or script, which allows for custom requests and events to be added to obs-websocket.\nIf a plugin or script implements vendor requests or events, documentation is expected to be provided with them.",
"eventType": "VendorEvent",
@ -5664,6 +5764,23 @@
"valueDescription": "Vendor-provided event data. {} if event does not provide any data"
}
]
},
{
"description": "Custom event emitted by `BroadcastCustomEvent`.",
"eventType": "CustomEvent",
"eventSubscription": "General",
"complexity": 1,
"rpcVersion": "1",
"deprecated": false,
"initialVersion": "5.0.0",
"category": "general",
"dataFields": [
{
"valueName": "eventData",
"valueType": "Object",
"valueDescription": "Custom event data"
}
]
}
]
}

View File

@ -21,6 +21,9 @@
- [RequestResponse (OpCode 7)](#requestresponse-opcode-7)
- [RequestBatch (OpCode 8)](#requestbatch-opcode-8)
- [RequestBatchResponse (OpCode 9)](#requestbatchresponse-opcode-9)
- [Enumerations](#enums)
- [Events](#events)
- [Requests](#requests)
## General Intro
@ -512,6 +515,24 @@ These are enumeration declarations, which are referenced throughout obs-websocke
- [EventSubscription::InputActiveStateChanged](#eventsubscriptioninputactivestatechanged)
- [EventSubscription::InputShowStateChanged](#eventsubscriptioninputshowstatechanged)
- [EventSubscription::SceneItemTransformChanged](#eventsubscriptionsceneitemtransformchanged)
- [ObsMediaInputAction](#obsmediainputaction)
- [ObsMediaInputAction::OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NONE](#obsmediainputactionobs_websocket_media_input_action_none)
- [ObsMediaInputAction::OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PLAY](#obsmediainputactionobs_websocket_media_input_action_play)
- [ObsMediaInputAction::OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PAUSE](#obsmediainputactionobs_websocket_media_input_action_pause)
- [ObsMediaInputAction::OBS_WEBSOCKET_MEDIA_INPUT_ACTION_STOP](#obsmediainputactionobs_websocket_media_input_action_stop)
- [ObsMediaInputAction::OBS_WEBSOCKET_MEDIA_INPUT_ACTION_RESTART](#obsmediainputactionobs_websocket_media_input_action_restart)
- [ObsMediaInputAction::OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NEXT](#obsmediainputactionobs_websocket_media_input_action_next)
- [ObsMediaInputAction::OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PREVIOUS](#obsmediainputactionobs_websocket_media_input_action_previous)
- [ObsOutputState](#obsoutputstate)
- [ObsOutputState::OBS_WEBSOCKET_OUTPUT_UNKNOWN](#obsoutputstateobs_websocket_output_unknown)
- [ObsOutputState::OBS_WEBSOCKET_OUTPUT_STARTING](#obsoutputstateobs_websocket_output_starting)
- [ObsOutputState::OBS_WEBSOCKET_OUTPUT_STARTED](#obsoutputstateobs_websocket_output_started)
- [ObsOutputState::OBS_WEBSOCKET_OUTPUT_STOPPING](#obsoutputstateobs_websocket_output_stopping)
- [ObsOutputState::OBS_WEBSOCKET_OUTPUT_STOPPED](#obsoutputstateobs_websocket_output_stopped)
- [ObsOutputState::OBS_WEBSOCKET_OUTPUT_RECONNECTING](#obsoutputstateobs_websocket_output_reconnecting)
- [ObsOutputState::OBS_WEBSOCKET_OUTPUT_RECONNECTED](#obsoutputstateobs_websocket_output_reconnected)
- [ObsOutputState::OBS_WEBSOCKET_OUTPUT_PAUSED](#obsoutputstateobs_websocket_output_paused)
- [ObsOutputState::OBS_WEBSOCKET_OUTPUT_RESUMED](#obsoutputstateobs_websocket_output_resumed)
## WebSocketOpCode
@ -1294,6 +1315,182 @@ Subscription value to receive the `SceneItemTransformChanged` high-volume event.
- Latest Supported RPC Version: `1`
- Added in v5.0.0
## ObsMediaInputAction
### ObsMediaInputAction::OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NONE
No action.
- Identifier Value: `OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NONE`
- Latest Supported RPC Version: `1`
- **⚠️ Deprecated. ⚠️**
- Added in v5.0.0
---
### ObsMediaInputAction::OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PLAY
Play the media input.
- Identifier Value: `OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PLAY`
- Latest Supported RPC Version: `1`
- **⚠️ Deprecated. ⚠️**
- Added in v5.0.0
---
### ObsMediaInputAction::OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PAUSE
Pause the media input.
- Identifier Value: `OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PAUSE`
- Latest Supported RPC Version: `1`
- **⚠️ Deprecated. ⚠️**
- Added in v5.0.0
---
### ObsMediaInputAction::OBS_WEBSOCKET_MEDIA_INPUT_ACTION_STOP
Stop the media input.
- Identifier Value: `OBS_WEBSOCKET_MEDIA_INPUT_ACTION_STOP`
- Latest Supported RPC Version: `1`
- **⚠️ Deprecated. ⚠️**
- Added in v5.0.0
---
### ObsMediaInputAction::OBS_WEBSOCKET_MEDIA_INPUT_ACTION_RESTART
Restart the media input.
- Identifier Value: `OBS_WEBSOCKET_MEDIA_INPUT_ACTION_RESTART`
- Latest Supported RPC Version: `1`
- **⚠️ Deprecated. ⚠️**
- Added in v5.0.0
---
### ObsMediaInputAction::OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NEXT
Go to the next playlist item.
- Identifier Value: `OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NEXT`
- Latest Supported RPC Version: `1`
- **⚠️ Deprecated. ⚠️**
- Added in v5.0.0
---
### ObsMediaInputAction::OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PREVIOUS
Go to the previous playlist item.
- Identifier Value: `OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PREVIOUS`
- Latest Supported RPC Version: `1`
- **⚠️ Deprecated. ⚠️**
- Added in v5.0.0
## ObsOutputState
### ObsOutputState::OBS_WEBSOCKET_OUTPUT_UNKNOWN
Unknown state.
- Identifier Value: `OBS_WEBSOCKET_OUTPUT_UNKNOWN`
- Latest Supported RPC Version: `1`
- **⚠️ Deprecated. ⚠️**
- Added in v5.0.0
---
### ObsOutputState::OBS_WEBSOCKET_OUTPUT_STARTING
The output is starting.
- Identifier Value: `OBS_WEBSOCKET_OUTPUT_STARTING`
- Latest Supported RPC Version: `1`
- **⚠️ Deprecated. ⚠️**
- Added in v5.0.0
---
### ObsOutputState::OBS_WEBSOCKET_OUTPUT_STARTED
The input has started.
- Identifier Value: `OBS_WEBSOCKET_OUTPUT_STARTED`
- Latest Supported RPC Version: `1`
- **⚠️ Deprecated. ⚠️**
- Added in v5.0.0
---
### ObsOutputState::OBS_WEBSOCKET_OUTPUT_STOPPING
The output is stopping.
- Identifier Value: `OBS_WEBSOCKET_OUTPUT_STOPPING`
- Latest Supported RPC Version: `1`
- **⚠️ Deprecated. ⚠️**
- Added in v5.0.0
---
### ObsOutputState::OBS_WEBSOCKET_OUTPUT_STOPPED
The output has stopped.
- Identifier Value: `OBS_WEBSOCKET_OUTPUT_STOPPED`
- Latest Supported RPC Version: `1`
- **⚠️ Deprecated. ⚠️**
- Added in v5.0.0
---
### ObsOutputState::OBS_WEBSOCKET_OUTPUT_RECONNECTING
The output has disconnected and is reconnecting.
- Identifier Value: `OBS_WEBSOCKET_OUTPUT_RECONNECTING`
- Latest Supported RPC Version: `1`
- **⚠️ Deprecated. ⚠️**
- Added in v5.0.0
---
### ObsOutputState::OBS_WEBSOCKET_OUTPUT_RECONNECTED
The output has reconnected successfully.
- Identifier Value: `OBS_WEBSOCKET_OUTPUT_RECONNECTED`
- Latest Supported RPC Version: `1`
- **⚠️ Deprecated. ⚠️**
- Added in v5.1.0
---
### ObsOutputState::OBS_WEBSOCKET_OUTPUT_PAUSED
The output is now paused.
- Identifier Value: `OBS_WEBSOCKET_OUTPUT_PAUSED`
- Latest Supported RPC Version: `1`
- **⚠️ Deprecated. ⚠️**
- Added in v5.1.0
---
### ObsOutputState::OBS_WEBSOCKET_OUTPUT_RESUMED
The output has been resumed (unpaused).
- Identifier Value: `OBS_WEBSOCKET_OUTPUT_RESUMED`
- Latest Supported RPC Version: `1`
- **⚠️ Deprecated. ⚠️**
- Added in v5.0.0
# Events
## Events Table of Contents
@ -1301,6 +1498,7 @@ Subscription value to receive the `SceneItemTransformChanged` high-volume event.
- [General Events](#general-events)
- [ExitStarted](#exitstarted)
- [VendorEvent](#vendorevent)
- [CustomEvent](#customevent)
- [Config Events](#config-events)
- [CurrentSceneCollectionChanging](#currentscenecollectionchanging)
- [CurrentSceneCollectionChanged](#currentscenecollectionchanged)
@ -1360,6 +1558,7 @@ Subscription value to receive the `SceneItemTransformChanged` high-volume event.
- [MediaInputActionTriggered](#mediainputactiontriggered)
- [Ui Events](#ui-events)
- [StudioModeStateChanged](#studiomodestatechanged)
- [ScreenshotSaved](#screenshotsaved)
## General Events
@ -1392,6 +1591,22 @@ If a plugin or script implements vendor requests or events, documentation is exp
| eventType | String | Vendor-provided event typedef |
| eventData | Object | Vendor-provided event data. {} if event does not provide any data |
---
### CustomEvent
Custom event emitted by `BroadcastCustomEvent`.
- Complexity Rating: `1/5`
- Latest Supported RPC Version: `1`
- Added in v5.0.0
**Data Fields:**
| Name | Type | Description |
| ---- | :---: | ----------- |
| eventData | Object | Custom event data |
## Config Events
### CurrentSceneCollectionChanging
@ -1717,7 +1932,7 @@ An input's volume level has changed.
| Name | Type | Description |
| ---- | :---: | ----------- |
| inputName | String | Name of the input |
| inputVolumeMul | Number | New volume level in multimap |
| inputVolumeMul | Number | New volume level multiplier |
| inputVolumeDb | Number | New volume level in dB |
---
@ -2265,6 +2480,26 @@ Studio mode has been enabled or disabled.
| ---- | :---: | ----------- |
| studioModeEnabled | Boolean | True == Enabled, False == Disabled |
---
### ScreenshotSaved
A screenshot has been saved.
Note: Triggered for the screenshot feature available in `Settings -> Hotkeys -> Screenshot Output` ONLY.
Applications using `Get/SaveSourceScreenshot` should implement a `CustomEvent` if this kind of inter-client
communication is desired.
- Complexity Rating: `2/5`
- Latest Supported RPC Version: `1`
- Added in v5.1.0
**Data Fields:**
| Name | Type | Description |
| ---- | :---: | ----------- |
| savedScreenshotPath | String | Path of the saved image file |
# Requests
## Requests Table of Contents
@ -2580,8 +2815,8 @@ Sleeps for a time duration or number of frames. Only available in request batche
| Name | Type | Description | Value Restrictions | ?Default Behavior |
| ---- | :---: | ----------- | :----------------: | ----------------- |
| sleepMillis | Number | Number of milliseconds to sleep for (if `SERIAL_REALTIME` mode) | >= 0, <= 50000 | N/A |
| sleepFrames | Number | Number of frames to sleep for (if `SERIAL_FRAME` mode) | >= 0, <= 10000 | N/A |
| ?sleepMillis | Number | Number of milliseconds to sleep for (if `SERIAL_REALTIME` mode) | >= 0, <= 50000 | Unknown |
| ?sleepFrames | Number | Number of frames to sleep for (if `SERIAL_FRAME` mode) | >= 0, <= 10000 | Unknown |
## Config Requests
@ -3652,6 +3887,10 @@ Note: Use this in cases where an input provides a dynamic, selectable list of it
Presses a button in the properties of an input.
Some known `propertyName` values are:
- `refreshnocache` - Browser source reload button
Note: Use this in cases where there is a button in the properties of an input that cannot be accessed in any other way. For example, browser sources, where there is a refresh button.
- Complexity Rating: `4/5`
@ -4029,7 +4268,7 @@ Scenes only
Basically GetSceneItemList, but for groups.
Using groups at all in OBS is discouraged, as they are very broken under the hood.
Using groups at all in OBS is discouraged, as they are very broken under the hood. Please use nested scenes instead.
Groups only
@ -4521,6 +4760,12 @@ Gets the list of available outputs.
- Latest Supported RPC Version: `1`
- Added in v5.0.0
**Response Fields:**
| Name | Type | Description |
| ---- | :---: | ----------- |
| outputs | Array&lt;Object&gt; | Array of outputs |
---
### GetOutputStatus
@ -4733,7 +4978,7 @@ Gets the status of the record output.
| Name | Type | Description |
| ---- | :---: | ----------- |
| outputActive | Boolean | Whether the output is active |
| ouputPaused | Boolean | Whether the output is paused |
| outputPaused | Boolean | Whether the output is paused |
| outputTimecode | String | Current formatted timecode string for the output |
| outputDuration | Number | Current duration in milliseconds for the output |
| outputBytes | Number | Number of bytes sent by the output |

View File

@ -267,97 +267,10 @@ void EventHandler::OnFrontendEvent(enum obs_frontend_event event, void *private_
switch (event) {
// General
case OBS_FRONTEND_EVENT_FINISHED_LOADING:
blog_debug(
"[EventHandler::OnFrontendEvent] OBS has finished loading. Connecting final handlers and enabling events...");
// Connect source signals and enable events only after OBS has fully loaded (to reduce extra logging).
eventHandler->_obsLoaded.store(true);
// In the case that plugins become hotloadable, this will have to go back into `EventHandler::EventHandler()`
// Enumerate inputs and connect each one
{
auto enumInputs = [](void *param, obs_source_t *source) {
auto eventHandler = static_cast<EventHandler *>(param);
eventHandler->ConnectSourceSignals(source);
return true;
};
obs_enum_sources(enumInputs, private_data);
}
// Enumerate scenes and connect each one
{
auto enumScenes = [](void *param, obs_source_t *source) {
auto eventHandler = static_cast<EventHandler *>(param);
eventHandler->ConnectSourceSignals(source);
return true;
};
obs_enum_scenes(enumScenes, private_data);
}
// Enumerate all scene transitions and connect each one
{
obs_frontend_source_list transitions = {};
obs_frontend_get_transitions(&transitions);
for (size_t i = 0; i < transitions.sources.num; i++) {
obs_source_t *transition = transitions.sources.array[i];
eventHandler->ConnectSourceSignals(transition);
}
obs_frontend_source_list_free(&transitions);
}
blog_debug("[EventHandler::OnFrontendEvent] Finished.");
if (eventHandler->_obsLoadedCallback)
eventHandler->_obsLoadedCallback();
eventHandler->FrontendFinishedLoadingMultiHandler();
break;
case OBS_FRONTEND_EVENT_EXIT:
eventHandler->HandleExitStarted();
blog_debug("[EventHandler::OnFrontendEvent] OBS is unloading. Disabling events...");
// Disconnect source signals and disable events when OBS starts unloading (to reduce extra logging).
eventHandler->_obsLoaded.store(false);
// In the case that plugins become hotloadable, this will have to go back into `EventHandler::~EventHandler()`
// Enumerate inputs and disconnect each one
{
auto enumInputs = [](void *param, obs_source_t *source) {
auto eventHandler = static_cast<EventHandler *>(param);
eventHandler->DisconnectSourceSignals(source);
return true;
};
obs_enum_sources(enumInputs, private_data);
}
// Enumerate scenes and disconnect each one
{
auto enumScenes = [](void *param, obs_source_t *source) {
auto eventHandler = static_cast<EventHandler *>(param);
eventHandler->DisconnectSourceSignals(source);
return true;
};
obs_enum_scenes(enumScenes, private_data);
}
// Enumerate all scene transitions and disconnect each one
{
obs_frontend_source_list transitions = {};
obs_frontend_get_transitions(&transitions);
for (size_t i = 0; i < transitions.sources.num; i++) {
obs_source_t *transition = transitions.sources.array[i];
eventHandler->DisconnectSourceSignals(transition);
}
obs_frontend_source_list_free(&transitions);
}
blog_debug("[EventHandler::OnFrontendEvent] Finished.");
break;
case OBS_FRONTEND_EVENT_STUDIO_MODE_ENABLED:
eventHandler->HandleStudioModeStateChanged(true);
break;
case OBS_FRONTEND_EVENT_STUDIO_MODE_DISABLED:
eventHandler->HandleStudioModeStateChanged(false);
eventHandler->FrontendExitMultiHandler();
break;
// Config
@ -427,12 +340,31 @@ void EventHandler::OnFrontendEvent(enum obs_frontend_event event, void *private_
// Outputs
case OBS_FRONTEND_EVENT_STREAMING_STARTING:
eventHandler->HandleStreamStateChanged(OBS_WEBSOCKET_OUTPUT_STARTING);
{
// Connect signals for stream output reconnects (hacky)
OBSOutputAutoRelease streamOutput = obs_frontend_get_streaming_output();
if (streamOutput) {
signal_handler_t *sh = obs_output_get_signal_handler(streamOutput);
signal_handler_connect(sh, "reconnect", StreamOutputReconnectHandler, private_data);
signal_handler_connect(sh, "reconnect_success", StreamOutputReconnectSuccessHandler, private_data);
}
}
break;
case OBS_FRONTEND_EVENT_STREAMING_STARTED:
eventHandler->HandleStreamStateChanged(OBS_WEBSOCKET_OUTPUT_STARTED);
break;
case OBS_FRONTEND_EVENT_STREAMING_STOPPING:
eventHandler->HandleStreamStateChanged(OBS_WEBSOCKET_OUTPUT_STOPPING);
{
// Disconnect signals for stream output reconnects
OBSOutputAutoRelease streamOutput = obs_frontend_get_streaming_output();
if (streamOutput) {
signal_handler_t *sh = obs_output_get_signal_handler(streamOutput);
signal_handler_disconnect(sh, "reconnect", StreamOutputReconnectHandler, private_data);
signal_handler_disconnect(sh, "reconnect_success", StreamOutputReconnectSuccessHandler,
private_data);
}
}
break;
case OBS_FRONTEND_EVENT_STREAMING_STOPPED:
eventHandler->HandleStreamStateChanged(OBS_WEBSOCKET_OUTPUT_STOPPED);
@ -477,11 +409,112 @@ void EventHandler::OnFrontendEvent(enum obs_frontend_event event, void *private_
eventHandler->HandleReplayBufferSaved();
break;
// Ui
case OBS_FRONTEND_EVENT_STUDIO_MODE_ENABLED:
eventHandler->HandleStudioModeStateChanged(true);
break;
case OBS_FRONTEND_EVENT_STUDIO_MODE_DISABLED:
eventHandler->HandleStudioModeStateChanged(false);
break;
case OBS_FRONTEND_EVENT_SCREENSHOT_TAKEN:
eventHandler->HandleScreenshotSaved();
break;
default:
break;
}
}
void EventHandler::FrontendFinishedLoadingMultiHandler()
{
blog_debug(
"[EventHandler::FrontendFinishedLoadingMultiHandler] OBS has finished loading. Connecting final handlers and enabling events...");
// Connect source signals and enable events only after OBS has fully loaded (to reduce extra logging).
_obsLoaded.store(true);
// In the case that plugins become hotloadable, this will have to go back into `EventHandler::EventHandler()`
// Enumerate inputs and connect each one
{
auto enumInputs = [](void *param, obs_source_t *source) {
auto eventHandler = static_cast<EventHandler *>(param);
eventHandler->ConnectSourceSignals(source);
return true;
};
obs_enum_sources(enumInputs, this);
}
// Enumerate scenes and connect each one
{
auto enumScenes = [](void *param, obs_source_t *source) {
auto eventHandler = static_cast<EventHandler *>(param);
eventHandler->ConnectSourceSignals(source);
return true;
};
obs_enum_scenes(enumScenes, this);
}
// Enumerate all scene transitions and connect each one
{
obs_frontend_source_list transitions = {};
obs_frontend_get_transitions(&transitions);
for (size_t i = 0; i < transitions.sources.num; i++) {
obs_source_t *transition = transitions.sources.array[i];
ConnectSourceSignals(transition);
}
obs_frontend_source_list_free(&transitions);
}
blog_debug("[EventHandler::FrontendFinishedLoadingMultiHandler] Finished.");
if (_obsLoadedCallback)
_obsLoadedCallback();
}
void EventHandler::FrontendExitMultiHandler()
{
HandleExitStarted();
blog_debug("[EventHandler::FrontendExitMultiHandler] OBS is unloading. Disabling events...");
// Disconnect source signals and disable events when OBS starts unloading (to reduce extra logging).
_obsLoaded.store(false);
// In the case that plugins become hotloadable, this will have to go back into `EventHandler::~EventHandler()`
// Enumerate inputs and disconnect each one
{
auto enumInputs = [](void *param, obs_source_t *source) {
auto eventHandler = static_cast<EventHandler *>(param);
eventHandler->DisconnectSourceSignals(source);
return true;
};
obs_enum_sources(enumInputs, this);
}
// Enumerate scenes and disconnect each one
{
auto enumScenes = [](void *param, obs_source_t *source) {
auto eventHandler = static_cast<EventHandler *>(param);
eventHandler->DisconnectSourceSignals(source);
return true;
};
obs_enum_scenes(enumScenes, this);
}
// Enumerate all scene transitions and disconnect each one
{
obs_frontend_source_list transitions = {};
obs_frontend_get_transitions(&transitions);
for (size_t i = 0; i < transitions.sources.num; i++) {
obs_source_t *transition = transitions.sources.array[i];
DisconnectSourceSignals(transition);
}
obs_frontend_source_list_free(&transitions);
}
blog_debug("[EventHandler::FrontendExitMultiHandler] Finished.");
}
// Only called for creation of a public source
void EventHandler::SourceCreatedMultiHandler(void *param, calldata_t *data)
{
@ -597,3 +630,17 @@ void EventHandler::SourceRenamedMultiHandler(void *param, calldata_t *data)
break;
}
}
void EventHandler::StreamOutputReconnectHandler(void *param, calldata_t *)
{
auto eventHandler = static_cast<EventHandler *>(param);
eventHandler->HandleStreamStateChanged(OBS_WEBSOCKET_OUTPUT_RECONNECTING);
}
void EventHandler::StreamOutputReconnectSuccessHandler(void *param, calldata_t *)
{
auto eventHandler = static_cast<EventHandler *>(param);
eventHandler->HandleStreamStateChanged(OBS_WEBSOCKET_OUTPUT_RECONNECTED);
}

View File

@ -61,6 +61,8 @@ private:
// Signal handler: frontend
static void OnFrontendEvent(enum obs_frontend_event event, void *private_data);
void FrontendFinishedLoadingMultiHandler();
void FrontendExitMultiHandler();
// Signal handler: libobs
static void SourceCreatedMultiHandler(void *param, calldata_t *data);
@ -76,9 +78,12 @@ private:
static void SourceMediaNextMultiHandler(void *param, calldata_t *data);
static void SourceMediaPreviousMultiHandler(void *param, calldata_t *data);
// Signal handler: output
static void StreamOutputReconnectHandler(void *param, calldata_t *data);
static void StreamOutputReconnectSuccessHandler(void *param, calldata_t *data);
// General
void HandleExitStarted();
void HandleStudioModeStateChanged(bool enabled);
// Config
void HandleCurrentSceneCollectionChanging();
@ -170,4 +175,8 @@ private:
static void HandleMediaInputPlaybackEnded(void *param,
calldata_t *data); // Direct callback
void HandleMediaInputActionTriggered(obs_source_t *source, ObsMediaInputAction action);
// Ui
void HandleStudioModeStateChanged(bool enabled);
void HandleScreenshotSaved();
};

View File

@ -200,7 +200,7 @@ void EventHandler::HandleInputMuteStateChanged(void *param, calldata_t *data)
* An input's volume level has changed.
*
* @dataField inputName | String | Name of the input
* @dataField inputVolumeMul | Number | New volume level in multimap
* @dataField inputVolumeMul | Number | New volume level multiplier
* @dataField inputVolumeDb | Number | New volume level in dB
*
* @eventType InputVolumeChanged

View File

@ -24,10 +24,12 @@ static bool GetOutputStateActive(ObsOutputState state)
switch (state) {
case OBS_WEBSOCKET_OUTPUT_STARTED:
case OBS_WEBSOCKET_OUTPUT_RESUMED:
case OBS_WEBSOCKET_OUTPUT_RECONNECTED:
return true;
case OBS_WEBSOCKET_OUTPUT_STARTING:
case OBS_WEBSOCKET_OUTPUT_STOPPING:
case OBS_WEBSOCKET_OUTPUT_STOPPED:
case OBS_WEBSOCKET_OUTPUT_RECONNECTING:
case OBS_WEBSOCKET_OUTPUT_PAUSED:
return false;
default:

View File

@ -38,3 +38,27 @@ void EventHandler::HandleStudioModeStateChanged(bool enabled)
eventData["studioModeEnabled"] = enabled;
BroadcastEvent(EventSubscription::Ui, "StudioModeStateChanged", eventData);
}
/**
* A screenshot has been saved.
*
* Note: Triggered for the screenshot feature available in `Settings -> Hotkeys -> Screenshot Output` ONLY.
* Applications using `Get/SaveSourceScreenshot` should implement a `CustomEvent` if this kind of inter-client
* communication is desired.
*
* @dataField savedScreenshotPath | String | Path of the saved image file
*
* @eventType ScreenshotSaved
* @eventSubscription Ui
* @complexity 2
* @rpcVersion -1
* @initialVersion 5.1.0
* @api events
* @category ui
*/
void EventHandler::HandleScreenshotSaved()
{
json eventData;
eventData["savedScreenshotPath"] = Utils::Obs::StringHelper::GetLastScreenshotFileName();
BroadcastEvent(EventSubscription::Ui, "ScreenshotSaved", eventData);
}

View File

@ -105,7 +105,7 @@ void ConnectInfo::SetClipboardText(QString text)
void ConnectInfo::DrawQr(QString qrText)
{
QPixmap map(230, 230);
QPixmap map(236, 236);
map.fill(Qt::white);
QPainter painter(&map);

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>451</width>
<height>412</height>
<height>432</height>
</rect>
</property>
<property name="minimumSize">
@ -19,7 +19,7 @@
<property name="maximumSize">
<size>
<width>451</width>
<height>412</height>
<height>432</height>
</size>
</property>
<property name="windowTitle">
@ -31,12 +31,21 @@
<x>10</x>
<y>10</y>
<width>431</width>
<height>101</height>
<height>121</height>
</rect>
</property>
<layout class="QFormLayout" name="formLayout">
<property name="formAlignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<item row="0" column="0">
<widget class="QLabel" name="serverIpLabel">
<property name="maximumSize">
<size>
<width>200</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>OBSWebSocket.ConnectInfo.ServerIp</string>
</property>
@ -46,6 +55,12 @@
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLineEdit" name="serverIpLineEdit">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="alignment">
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
@ -53,6 +68,12 @@
</item>
<item>
<widget class="QPushButton" name="copyServerIpButton">
<property name="maximumSize">
<size>
<width>75</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>OBSWebSocket.ConnectInfo.CopyText</string>
</property>
@ -62,6 +83,12 @@
</item>
<item row="1" column="0">
<widget class="QLabel" name="serverPortLabel">
<property name="maximumSize">
<size>
<width>200</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>OBSWebSocket.ConnectInfo.ServerPort</string>
</property>
@ -71,6 +98,12 @@
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLineEdit" name="serverPortLineEdit">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="alignment">
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
@ -78,6 +111,12 @@
</item>
<item>
<widget class="QPushButton" name="copyServerPortButton">
<property name="maximumSize">
<size>
<width>75</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>OBSWebSocket.ConnectInfo.CopyText</string>
</property>
@ -87,6 +126,12 @@
</item>
<item row="2" column="0">
<widget class="QLabel" name="serverPasswordLabel">
<property name="maximumSize">
<size>
<width>200</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>OBSWebSocket.ConnectInfo.ServerPassword</string>
</property>
@ -96,9 +141,15 @@
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLineEdit" name="serverPasswordLineEdit">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string>OBSWebSocket.ConnectInfo.ServerPasswordPlaceholderText</string>
</property>
<property name="alignment">
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
@ -106,6 +157,12 @@
</item>
<item>
<widget class="QPushButton" name="copyServerPasswordButton">
<property name="maximumSize">
<size>
<width>75</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>OBSWebSocket.ConnectInfo.CopyText</string>
</property>
@ -119,7 +176,7 @@
<property name="geometry">
<rect>
<x>10</x>
<y>120</y>
<y>140</y>
<width>431</width>
<height>281</height>
</rect>
@ -131,9 +188,9 @@
<property name="geometry">
<rect>
<x>100</x>
<y>40</y>
<width>230</width>
<height>230</height>
<y>30</y>
<width>236</width>
<height>236</height>
</rect>
</property>
<property name="text">

View File

@ -80,7 +80,7 @@
<item row="3" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="spacing">
<number>0</number>
<number>2</number>
</property>
<item>
<widget class="QCheckBox" name="enableDebugLoggingCheckBox">
@ -97,6 +97,12 @@
<property name="toolTip">
<string>OBSWebSocket.Settings.DebugEnableHoverText</string>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>

View File

@ -102,6 +102,20 @@ RequestResult RequestHandler::GetStats(const Request &)
return RequestResult::Success(responseData);
}
/**
* Custom event emitted by `BroadcastCustomEvent`.
*
* @dataField eventData | Object | Custom event data
*
* @eventType CustomEvent
* @eventSubscription General
* @complexity 1
* @rpcVersion -1
* @initialVersion 5.0.0
* @category general
* @api events
*/
/**
* Broadcasts a `CustomEvent` to all WebSocket clients. Receivers are clients which are identified and subscribed.
*
@ -311,8 +325,8 @@ RequestResult RequestHandler::TriggerHotkeyByKeySequence(const Request &request)
/**
* Sleeps for a time duration or number of frames. Only available in request batches with types `SERIAL_REALTIME` or `SERIAL_FRAME`.
*
* @requestField sleepMillis | Number | Number of milliseconds to sleep for (if `SERIAL_REALTIME` mode) | >= 0, <= 50000
* @requestField sleepFrames | Number | Number of frames to sleep for (if `SERIAL_FRAME` mode) | >= 0, <= 10000
* @requestField ?sleepMillis | Number | Number of milliseconds to sleep for (if `SERIAL_REALTIME` mode) | >= 0, <= 50000
* @requestField ?sleepFrames | Number | Number of frames to sleep for (if `SERIAL_FRAME` mode) | >= 0, <= 10000
*
* @requestType Sleep
* @complexity 2

View File

@ -889,6 +889,10 @@ RequestResult RequestHandler::GetInputPropertiesListPropertyItems(const Request
/**
* Presses a button in the properties of an input.
*
* Some known `propertyName` values are:
*
* - `refreshnocache` - Browser source reload button
*
* Note: Use this in cases where there is a button in the properties of an input that cannot be accessed in any other way. For example, browser sources, where there is a refresh button.
*
* @requestField inputName | String | Name of the input

View File

@ -279,6 +279,8 @@ RequestResult RequestHandler::GetLastReplayBufferReplay(const Request &)
/**
* Gets the list of available outputs.
*
* @responseField outputs | Array<Object> | Array of outputs
*
* @requestType GetOutputList
* @complexity 4
* @rpcVersion -1

View File

@ -23,7 +23,7 @@ with this program. If not, see <https://www.gnu.org/licenses/>
* Gets the status of the record output.
*
* @responseField outputActive | Boolean | Whether the output is active
* @responseField ouputPaused | Boolean | Whether the output is paused
* @responseField outputPaused | Boolean | Whether the output is paused
* @responseField outputTimecode | String | Current formatted timecode string for the output
* @responseField outputDuration | Number | Current duration in milliseconds for the output
* @responseField outputBytes | Number | Number of bytes sent by the output

View File

@ -52,7 +52,7 @@ RequestResult RequestHandler::GetSceneItemList(const Request &request)
/**
* Basically GetSceneItemList, but for groups.
*
* Using groups at all in OBS is discouraged, as they are very broken under the hood.
* Using groups at all in OBS is discouraged, as they are very broken under the hood. Please use nested scenes instead.
*
* Groups only
*

View File

@ -67,22 +67,105 @@ template<typename T> T *GetCalldataPointer(const calldata_t *data, const char *n
}
enum ObsOutputState {
/**
* Unknown state.
*
* @enumIdentifier OBS_WEBSOCKET_OUTPUT_UNKNOWN
* @enumType ObsOutputState
* @rpcVersion 1
* @initialVersion 5.0.0
* @api enums
*/
OBS_WEBSOCKET_OUTPUT_UNKNOWN,
/**
* The output is starting.
*
* @enumIdentifier OBS_WEBSOCKET_OUTPUT_STARTING
* @enumType ObsOutputState
* @rpcVersion 1
* @initialVersion 5.0.0
* @api enums
*/
OBS_WEBSOCKET_OUTPUT_STARTING,
/**
* The input has started.
*
* @enumIdentifier OBS_WEBSOCKET_OUTPUT_STARTED
* @enumType ObsOutputState
* @rpcVersion 1
* @initialVersion 5.0.0
* @api enums
*/
OBS_WEBSOCKET_OUTPUT_STARTED,
/**
* The output is stopping.
*
* @enumIdentifier OBS_WEBSOCKET_OUTPUT_STOPPING
* @enumType ObsOutputState
* @rpcVersion 1
* @initialVersion 5.0.0
* @api enums
*/
OBS_WEBSOCKET_OUTPUT_STOPPING,
/**
* The output has stopped.
*
* @enumIdentifier OBS_WEBSOCKET_OUTPUT_STOPPED
* @enumType ObsOutputState
* @rpcVersion 1
* @initialVersion 5.0.0
* @api enums
*/
OBS_WEBSOCKET_OUTPUT_STOPPED,
/**
* The output has disconnected and is reconnecting.
*
* @enumIdentifier OBS_WEBSOCKET_OUTPUT_RECONNECTING
* @enumType ObsOutputState
* @rpcVersion 1
* @initialVersion 5.0.0
* @api enums
*/
OBS_WEBSOCKET_OUTPUT_RECONNECTING,
/**
* The output has reconnected successfully.
*
* @enumIdentifier OBS_WEBSOCKET_OUTPUT_RECONNECTED
* @enumType ObsOutputState
* @rpcVersion 1
* @initialVersion 5.1.0
* @api enums
*/
OBS_WEBSOCKET_OUTPUT_RECONNECTED,
/**
* The output is now paused.
*
* @enumIdentifier OBS_WEBSOCKET_OUTPUT_PAUSED
* @enumType ObsOutputState
* @rpcVersion 1
* @initialVersion 5.1.0
* @api enums
*/
OBS_WEBSOCKET_OUTPUT_PAUSED,
/**
* The output has been resumed (unpaused).
*
* @enumIdentifier OBS_WEBSOCKET_OUTPUT_RESUMED
* @enumType ObsOutputState
* @rpcVersion 1
* @initialVersion 5.0.0
* @api enums
*/
OBS_WEBSOCKET_OUTPUT_RESUMED,
};
NLOHMANN_JSON_SERIALIZE_ENUM(ObsOutputState, {
{OBS_WEBSOCKET_OUTPUT_UNKNOWN, "OBS_WEBSOCKET_OUTPUT_UNKNOWN"},
{OBS_WEBSOCKET_OUTPUT_STARTING, "OBS_WEBSOCKET_OUTPUT_STARTING"},
{OBS_WEBSOCKET_OUTPUT_STARTED, "OBS_WEBSOCKET_OUTPUT_STARTED"},
{OBS_WEBSOCKET_OUTPUT_STOPPING, "OBS_WEBSOCKET_OUTPUT_STOPPING"},
{OBS_WEBSOCKET_OUTPUT_STOPPED, "OBS_WEBSOCKET_OUTPUT_STOPPED"},
{OBS_WEBSOCKET_OUTPUT_RECONNECTING, "OBS_WEBSOCKET_OUTPUT_RECONNECTING"},
{OBS_WEBSOCKET_OUTPUT_RECONNECTED, "OBS_WEBSOCKET_OUTPUT_RECONNECTED"},
{OBS_WEBSOCKET_OUTPUT_PAUSED, "OBS_WEBSOCKET_OUTPUT_PAUSED"},
{OBS_WEBSOCKET_OUTPUT_RESUMED, "OBS_WEBSOCKET_OUTPUT_RESUMED"},
})
@ -159,7 +242,6 @@ enum ObsMediaInputAction {
*/
OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PREVIOUS,
};
NLOHMANN_JSON_SERIALIZE_ENUM(ObsMediaInputAction,
{
{OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NONE, "OBS_WEBSOCKET_MEDIA_INPUT_ACTION_NONE"},
@ -181,6 +263,7 @@ namespace Utils {
std::string GetCurrentRecordOutputPath();
std::string GetLastRecordFileName();
std::string GetLastReplayBufferFileName();
std::string GetLastScreenshotFileName();
std::string DurationToTimecode(uint64_t);
}

View File

@ -94,20 +94,18 @@ std::string Utils::Obs::StringHelper::GetLastRecordFileName()
std::string Utils::Obs::StringHelper::GetLastReplayBufferFileName()
{
OBSOutputAutoRelease output = obs_frontend_get_replay_buffer_output();
if (!output)
return "";
char *replayBufferPath = obs_frontend_get_last_replay();
std::string ret = replayBufferPath;
bfree(replayBufferPath);
return ret;
}
calldata_t cd = {0};
proc_handler_t *ph = obs_output_get_proc_handler(output);
proc_handler_call(ph, "get_last_replay", &cd);
const char *savedReplayPath = calldata_string(&cd, "path");
calldata_free(&cd);
if (!savedReplayPath)
return "";
return savedReplayPath;
std::string Utils::Obs::StringHelper::GetLastScreenshotFileName()
{
char *screenshotPath = obs_frontend_get_last_screenshot();
std::string ret = screenshotPath;
bfree(screenshotPath);
return ret;
}
std::string Utils::Obs::StringHelper::DurationToTimecode(uint64_t ms)