@@ -47,14 +47,19 @@ WebSocketApi::WebSocketApi()
47
47
48
48
proc_handler_add (_procHandler, " bool get_api_version(out int version)" , &get_api_version, nullptr );
49
49
proc_handler_add (_procHandler, " bool call_request(in string request_type, in string request_data, out ptr response)" ,
50
- &call_request, nullptr );
50
+ &call_request, this );
51
+ proc_handler_add (_procHandler, " bool register_event_callback(in ptr callback, out bool success)" , ®ister_event_callback,
52
+ this );
53
+ proc_handler_add (_procHandler, " bool unregister_event_callback(in ptr callback, out bool success)" ,
54
+ &unregister_event_callback, this );
51
55
proc_handler_add (_procHandler, " bool vendor_register(in string name, out ptr vendor)" , &vendor_register_cb, this );
52
- proc_handler_add (_procHandler, " bool vendor_request_register(in ptr vendor, in string type, in ptr callback)" ,
56
+ proc_handler_add (_procHandler,
57
+ " bool vendor_request_register(in ptr vendor, in string type, in ptr callback, out bool success)" ,
53
58
&vendor_request_register_cb, this );
54
- proc_handler_add (_procHandler, " bool vendor_request_unregister(in ptr vendor, in string type)" ,
59
+ proc_handler_add (_procHandler, " bool vendor_request_unregister(in ptr vendor, in string type, out bool success )" ,
55
60
&vendor_request_unregister_cb, this );
56
- proc_handler_add (_procHandler, " bool vendor_event_emit(in ptr vendor, in string type, in ptr data) " , &vendor_event_emit_cb ,
57
- this );
61
+ proc_handler_add (_procHandler, " bool vendor_event_emit(in ptr vendor, in string type, in ptr data, out bool success) " ,
62
+ &vendor_event_emit_cb, this );
58
63
59
64
proc_handler_t *ph = obs_get_proc_handler ();
60
65
assert (ph != NULL );
@@ -70,6 +75,10 @@ WebSocketApi::~WebSocketApi()
70
75
71
76
proc_handler_destroy (_procHandler);
72
77
78
+ size_t numEventCallbacks = _eventCallbacks.size ();
79
+ _eventCallbacks.clear ();
80
+ blog_debug (" [WebSocketApi::~WebSocketApi] Deleted %ld event callbacks" , numEventCallbacks);
81
+
73
82
for (auto vendor : _vendors) {
74
83
blog_debug (" [WebSocketApi::~WebSocketApi] Deleting vendor: %s" , vendor.first .c_str ());
75
84
delete vendor.second ;
@@ -80,10 +89,19 @@ WebSocketApi::~WebSocketApi()
80
89
81
90
void WebSocketApi::BroadcastEvent (uint64_t requiredIntent, const std::string &eventType, const json &eventData, uint8_t rpcVersion)
82
91
{
83
- UNUSED_PARAMETER (requiredIntent);
84
- UNUSED_PARAMETER (eventType);
85
- UNUSED_PARAMETER (eventData);
86
- UNUSED_PARAMETER (rpcVersion);
92
+ if (!_obsReady)
93
+ return ;
94
+
95
+ // Only broadcast events applicable to the latest RPC version
96
+ if (rpcVersion && rpcVersion != CURRENT_RPC_VERSION)
97
+ return ;
98
+
99
+ std::string eventDataString = eventData.dump ();
100
+
101
+ std::shared_lock l (_mutex);
102
+
103
+ for (auto &cb : _eventCallbacks)
104
+ cb.callback (requiredIntent, eventType.c_str (), eventDataString.c_str (), cb.priv_data );
87
105
}
88
106
89
107
enum WebSocketApi::RequestReturnCode WebSocketApi::PerformVendorRequest (std::string vendorName, std::string requestType,
@@ -128,14 +146,27 @@ void WebSocketApi::get_api_version(void *, calldata_t *cd)
128
146
RETURN_SUCCESS ();
129
147
}
130
148
131
- void WebSocketApi::call_request (void *, calldata_t *cd)
149
+ void WebSocketApi::call_request (void *priv_data , calldata_t *cd)
132
150
{
151
+ auto c = static_cast <WebSocketApi *>(priv_data);
152
+
153
+ #if !defined(PLUGIN_TESTS)
154
+ if (!c->_obsReady )
155
+ RETURN_FAILURE ();
156
+ #endif
157
+
133
158
const char *request_type = calldata_string (cd, " request_type" );
134
159
const char *request_data = calldata_string (cd, " request_data" );
135
160
136
161
if (!request_type)
137
162
RETURN_FAILURE ();
138
163
164
+ #ifdef PLUGIN_TESTS
165
+ // Allow plugin tests to complete, even though OBS wouldn't be ready at the time of the test
166
+ if (!c->_obsReady && std::string (request_type) != " GetVersion" )
167
+ RETURN_FAILURE ();
168
+ #endif
169
+
139
170
auto response = static_cast <obs_websocket_request_response *>(bzalloc (sizeof (struct obs_websocket_request_response )));
140
171
if (!response)
141
172
RETURN_FAILURE ();
@@ -164,6 +195,52 @@ void WebSocketApi::call_request(void *, calldata_t *cd)
164
195
RETURN_SUCCESS ();
165
196
}
166
197
198
+ void WebSocketApi::register_event_callback (void *priv_data, calldata_t *cd)
199
+ {
200
+ auto c = static_cast <WebSocketApi *>(priv_data);
201
+
202
+ void *voidCallback;
203
+ if (!calldata_get_ptr (cd, " callback" , &voidCallback) || !voidCallback) {
204
+ blog (LOG_WARNING, " [WebSocketApi::register_event_callback] Failed due to missing `callback` pointer." );
205
+ RETURN_FAILURE ();
206
+ }
207
+
208
+ auto cb = static_cast <obs_websocket_event_callback *>(voidCallback);
209
+
210
+ std::unique_lock l (c->_mutex );
211
+
212
+ int64_t foundIndex = c->GetEventCallbackIndex (*cb);
213
+ if (foundIndex != -1 )
214
+ RETURN_FAILURE ();
215
+
216
+ c->_eventCallbacks .push_back (*cb);
217
+
218
+ RETURN_SUCCESS ();
219
+ }
220
+
221
+ void WebSocketApi::unregister_event_callback (void *priv_data, calldata_t *cd)
222
+ {
223
+ auto c = static_cast <WebSocketApi *>(priv_data);
224
+
225
+ void *voidCallback;
226
+ if (!calldata_get_ptr (cd, " callback" , &voidCallback) || !voidCallback) {
227
+ blog (LOG_WARNING, " [WebSocketApi::register_event_callback] Failed due to missing `callback` pointer." );
228
+ RETURN_FAILURE ();
229
+ }
230
+
231
+ auto cb = static_cast <obs_websocket_event_callback *>(voidCallback);
232
+
233
+ std::unique_lock l (c->_mutex );
234
+
235
+ int64_t foundIndex = c->GetEventCallbackIndex (*cb);
236
+ if (foundIndex == -1 )
237
+ RETURN_FAILURE ();
238
+
239
+ c->_eventCallbacks .erase (c->_eventCallbacks .begin () + foundIndex);
240
+
241
+ RETURN_SUCCESS ();
242
+ }
243
+
167
244
void WebSocketApi::vendor_register_cb (void *priv_data, calldata_t *cd)
168
245
{
169
246
auto c = static_cast <WebSocketApi *>(priv_data);
@@ -174,7 +251,7 @@ void WebSocketApi::vendor_register_cb(void *priv_data, calldata_t *cd)
174
251
RETURN_FAILURE ();
175
252
}
176
253
177
- // Theoretically doesn't need a mutex, but it's good to be safe.
254
+ // Theoretically doesn't need a mutex due to module load being single-thread , but it's good to be safe.
178
255
std::unique_lock l (c->_mutex );
179
256
180
257
if (c->_vendors .count (vendorName)) {
0 commit comments