Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/sphinx/reference-core.rst
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,9 @@ Primary signal/procedure handlers
Core OBS Signals
----------------

Use :c:func:`signal_handler_connect()` to connect callbacks to the following
core OBS signals:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
core OBS signals:
global core libobs signals:


**source_create** (ptr source)

Called when a source has been created.
Expand Down
233 changes: 225 additions & 8 deletions docs/sphinx/reference-libobs-callback.rst
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ handlers or to procedure handlers.

.. function:: void calldata_set_ptr(calldata_t *data, const char *name, void *ptr)

Sets a pointer parameter.
Sets a pointer parameter. This does not have to be a pointer to a pointer.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This seems superfluous to me.


:param data: Calldata structure
:param name: Parameter name
Expand All @@ -80,6 +80,18 @@ handlers or to procedure handlers.

---------------------

.. function:: void calldata_set_data(calldata_t *data, const char *name, const void *in, size_t new_size)

Sets a parameter with any type. For common parameter types, use the functions
above.

:param data: Calldata structure
:param name: Parameter name
:param in: Pointer to the value to be stored
:param new_size: Size of the value to be stored
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

cc @RytoEX "of value to be stored" sounds off to me, but I'm not a native English speaker. Is this correct?


---------------------

.. function:: long long calldata_int(const calldata_t *data, const char *name)

Gets an integer parameter.
Expand Down Expand Up @@ -132,6 +144,75 @@ handlers or to procedure handlers.

---------------------

.. function:: bool calldata_get_int(const calldata_t *data, const char *name, long long *val)

Gets an integer parameter. See :c:func:`calldata_int` for a simpler call.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Maybe just this?

Suggested change
Gets an integer parameter. See :c:func:`calldata_int` for a simpler call.
Gets an integer parameter. See also :c:func:`calldata_int`.

Alternatively, explain the use cases for the respective functions in the docs for both functions. See the relevant header file:

/* ------------------------------------------------------------------------- */
/* call if you know your data is valid */
static inline long long calldata_int(const calldata_t *data, const char *name)
{


:param data: Calldata structure
:param name: Parameter name
:param val: Pointer to an integer receiving the parameter
:return: ``true`` if the stored value is successfully cast
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

IMO "is successfully cast" implies more type safety guarantees than there actually are. I guess saying it does a cast is technically correct, but since it doesn't check for anything other than the size of the data (unlike e.g. an std::variant), I find "successful" a bit misleading.

I would just do something like this:

Suggested change
:return: ``true`` if the stored value is successfully cast
:return: ``true`` on success, ``false`` otherwise


---------------------

.. function:: bool calldata_get_float(const calldata_t *data, const char *name, double *val)

Gets a floating point parameter. See :c:func:`calldata_float` for a simpler
call.

:param data: Calldata structure
:param name: Parameter name
:param val: Pointer to a floating point receiving the parameter
:return: ``true`` if the stored value is successfully cast

---------------------

.. function:: bool calldata_get_bool(const calldata_t *data, const char *name, bool *val)

Gets a boolean parameter. See :c:func:`calldata_bool` for a simpler call.

:param data: Calldata structure
:param name: Parameter name
:param val: Pointer to a boolean receiving the parameter
:return: ``true`` if the stored value is successfully cast

---------------------

.. function:: bool calldata_get_ptr(const calldata_t *data, const char *name, void *p_ptr)

Gets a pointer parameter. See :c:func:`calldata_ptr` for a simpler call.

:param data: Calldata structure
:param name: Parameter name
:param p_ptr: Pointer to a pointer receiving the parameter
:return: ``true`` if the stored value is successfully cast

---------------------

.. function:: bool calldata_get_string(const calldata_t *data, const char *name, const char **str)

Gets a string parameter. See :c:func:`calldata_string` for a simpler call.

:param data: Calldata structure
:param name: Parameter name
:param str: Pointer to a string receiving the parameter
:return: ``true`` if the stored value is successfully cast

---------------------

.. function:: bool calldata_get_data(const calldata_t *data, const char *name, void *out, size_t size);

Gets a parameter of any type. For common parameter types, use the functions
above.

:param data: Calldata structure
:param name: Parameter name
:param out: Pointer receiving the parameter
:param size: Size of the parameter type
:return: ``true`` if the stored value has the correct size

---------------------


Signals
-------
Expand Down Expand Up @@ -173,20 +254,61 @@ Signals are used for all event-based callbacks.

.. function:: bool signal_handler_add(signal_handler_t *handler, const char *signal_decl)

Adds a signal to a signal handler.
Adds a signal to a signal handler. Will fail if the declaration string has
invalid syntax or a signal with the same name was already added. Other than
the function identifier, the ``decl_string`` is mostly for documentation, as
libobs does not strictly enforce how the parameters are handled.

:param handler: Signal handler object
:param signal_decl: Signal declaration string
:param signal_decl: C-style function declaration string of the signal. The
function identifier dictates the signal name. Parameter
types can be ``int``, ``float``, ``bool``, ``ptr``,
``string``, which indicates the appropriate calldata
function to get the parameters. May also be preceded by
``in`` or ``out`` indicating how the parameters are used.
:return: ``true`` if the signal is successfully added.

Example declaration strings:

- ``void restart()``
- ``void slide_changed(int index, string path)``
- ``void current_index(out int current_index)``
- ``int current_index()``
- ``void toggled()``

Example code:

.. code:: cpp

signal_handler_t *sh = obs_source_get_signal_handler(source);
signal_handler_add(sh, "void file_changed(string next_file)");

---------------------

.. function:: bool signal_handler_add_array(signal_handler_t *handler, const char **signal_decls)

Adds multiple signals to a signal handler.
Adds multiple signals to a signal handler. This will process all signals even
if some can not be successfully added.

:param handler: Signal handler object
:param signal_decls: An array of signal declaration strings,
terminated by *NULL*
:return: ``true`` if all signals are successfully added.
``false`` if any of the signals can not be added

Example:

.. code:: cpp

static const char *source_signals[] = {
"void destroy(ptr source)",
"void remove(ptr source)",
"void update(ptr source)",
NULL,
};

signal_handler_t *sh = obs_source_get_signal_handler(source);
signal_handler_add_array(sh, source_signals);

---------------------

Expand All @@ -203,6 +325,40 @@ Signals are used for all event-based callbacks.

For scripting, use :py:func:`signal_handler_connect`.

Example connecting to ``rename`` signal from :ref:`source_signal_handler_reference`,
declared as ``void rename(ptr source, string new_name, string prev_name)``:

.. code:: cpp

/* Sample source data */
struct my_source {
obs_source_t *source;
char *prev_name;
...
};

void rename_cb(void *data, calldata_t *cd) {
struct my_source *ms = data;
obs_source_t *source = calldata_ptr(cd, "source");
/* We could also just access the source from our source data */
source = ms->source;
const char *new_name = calldata_string(cd, "new_name");
const char *prev_name = calldata_string(cd, "prev_name");

/* Do processing here */

/* `prev_name` will be freed after the callback, so if we want a
* reference to it after the callback, we must duplicate it.
*/
bfree(ms->prev_name);
ms->prev_name = bstrdup(prev_name);
}

/* Assuming `ms` already contains our source data */
struct my_source *ms;
signal_handler_t *sh = obs_source_get_signal_handler(ms->source);
signal_handler_connect(sh, "rename", rename_cb, ms);

Comment on lines +328 to +361
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Not a fan of how long this example is. I think it should be fine to cut it down a bit:

Suggested change
Example connecting to ``rename`` signal from :ref:`source_signal_handler_reference`,
declared as ``void rename(ptr source, string new_name, string prev_name)``:
.. code:: cpp
/* Sample source data */
struct my_source {
obs_source_t *source;
char *prev_name;
...
};
void rename_cb(void *data, calldata_t *cd) {
struct my_source *ms = data;
obs_source_t *source = calldata_ptr(cd, "source");
/* We could also just access the source from our source data */
source = ms->source;
const char *new_name = calldata_string(cd, "new_name");
const char *prev_name = calldata_string(cd, "prev_name");
/* Do processing here */
/* `prev_name` will be freed after the callback, so if we want a
* reference to it after the callback, we must duplicate it.
*/
bfree(ms->prev_name);
ms->prev_name = bstrdup(prev_name);
}
/* Assuming `ms` already contains our source data */
struct my_source *ms;
signal_handler_t *sh = obs_source_get_signal_handler(ms->source);
signal_handler_connect(sh, "rename", rename_cb, ms);
Example connecting to ``rename`` signal from :ref:`source_signal_handler_reference`:
.. code:: cpp
obs_source_t *source = ...;
void rename_cb(void *data, calldata_t *cd) {
obs_source_t *source = calldata_ptr(cd, "source");
const char *new_name = calldata_string(cd, "new_name");
const char *prev_name = calldata_string(cd, "prev_name");
/* Do processing here */
}
signal_handler_t *sh = obs_source_get_signal_handler(source);
signal_handler_connect(sh, "rename", rename_cb, NULL);

If you want to emphasize the lifetime of the calldata_t object, just a comment like this below /* Do processing here */:

/* Keep in mind that any pointers from ``cd`` are only valid in the scope of the callback */

---------------------

.. function:: void signal_handler_connect_ref(signal_handler_t *handler, const char *signal, signal_callback_t callback, void *data)
Expand Down Expand Up @@ -237,12 +393,28 @@ Signals are used for all event-based callbacks.

.. function:: void signal_handler_signal(signal_handler_t *handler, const char *signal, calldata_t *params)

Triggers a signal, calling all connected callbacks.
Emits a signal, calling all connected callbacks.

:param handler: Signal handler object
:param signal: Name of signal to trigger
:param signal: Name of signal to emit
:param params: Parameters to pass to the signal

Example:

.. code:: cpp

obs_source_t *source = obs_get_source_by_name("Image Slideshow Source");

/* Declaration string: void slide_changed(int index, string path) */
calldata_t cd = {0};
calldata_set_int(&cd, "index", 1);
calldata_set_string(&cd, "path", "path/to/image.png");

signal_handler_t *sh = obs_source_get_signal_handler(source);
signal_handler_signal(sh, "slide_changed", &cd);
calldata_free(&cd);
obs_source_release(source);

---------------------


Expand Down Expand Up @@ -287,13 +459,46 @@ direct access to declarations or callback pointers.

.. function:: void proc_handler_add(proc_handler_t *handler, const char *decl_string, proc_handler_proc_t proc, void *data)

Adds a procedure to a procedure handler.
Adds a procedure to a procedure handler. Will fail if the declaration string
has invalid syntax or a procedure with the same name was already added. Other
than the function identifier, the ``decl_string`` is mostly for
documentation, as libobs does not strictly enforce how the parameters are
handled.
Comment on lines +462 to +466
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I would remove anything after "Will fail if the declaration string has invalid syntax or a procedure with the same name was already added.", I'd say the missing verification is more of a somewhat unfortunate implementation detail.


:param handler: Procedure handler object
:param decl_string: Procedure declaration string
:param decl_string: C-style function declaration string of the procedure. The
function identifier dictates the procedure name.
Parameter types can be ``int``, ``float``, ``bool``,
``ptr``, ``string``, which indicates the appropriate
calldata function to get the parameters. May also be
preceded by ``in`` or ``out`` indicating how the
parameters are used.
:param proc: Procedure callback
:param data: Private data to pass to the callback

Example code:

.. code:: cpp

/* Sample source data */
struct my_source {
obs_source_t *source;
bool active;
...
};

static void proc_activate(void *data, calldata_t *cd)
{
struct my_source *ms = data;
ms->active = calldata_bool(cd, "active");
}

/* Assuming `ms` already contains our source data */
struct my_source *ms;
proc_handler_t *ph = obs_source_get_proc_handler(ms->source);
proc_handler_add(ph, "void activate(bool active)",
proc_activate, ms);
Comment on lines +483 to +500
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Shorter version:

Suggested change
/* Sample source data */
struct my_source {
obs_source_t *source;
bool active;
...
};
static void proc_activate(void *data, calldata_t *cd)
{
struct my_source *ms = data;
ms->active = calldata_bool(cd, "active");
}
/* Assuming `ms` already contains our source data */
struct my_source *ms;
proc_handler_t *ph = obs_source_get_proc_handler(ms->source);
proc_handler_add(ph, "void activate(bool active)",
proc_activate, ms);
obs_source_t *source = ...;
static void proc_activate(void *data, calldata_t *cd)
{
bool active = calldata_bool(cd, "active");
/* Do processing here */
}
proc_handler_t *ph = obs_source_get_proc_handler(source);
proc_handler_add(ph, "void activate(bool active)", proc_activate, NULL);


---------------------

.. function:: bool proc_handler_call(proc_handler_t *handler, const char *name, calldata_t *params)
Expand All @@ -303,3 +508,15 @@ direct access to declarations or callback pointers.
:param handler: Procedure handler object
:param name: Name of procedure to call
:param params: Calldata structure to pass to the procedure
:return: ``true`` if the procedure exists

Example:

.. code:: cpp

/* Assuming we already have a `source` */
proc_handler_t *ph = obs_source_get_proc_handler(source);
calldata_t cd = {0};
calldata_set_bool(&cd, "active", false);
proc_handler_call(ph, "activate", &cd);
calldata_free(&cd);
16 changes: 16 additions & 0 deletions docs/sphinx/reference-sources.rst
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,11 @@ Source Definition Structure (obs_source_info)
Common Source Signals
---------------------

Sources can emit signals on specific events using signal handlers, with
callbacks connected via :c:func:`signal_handler_connect()`. Define signals with
:c:func:`signal_handler_add()` or :c:func:`signal_handler_add_array()`, and emit
them using :c:func:`signal_handler_signal()`.

The following signals are defined for every source type:

**destroy** (ptr *source*)
Expand Down Expand Up @@ -719,6 +724,10 @@ The following signals are defined for every source type:
Source-specific Signals
-----------------------

The following is a list of signals defined by sources included with official OBS
Studio releases. For sources defined by third-party plugins, refer to the
plugin's documentation or source code to see the defined signals.

**slide_changed** (int index, string path)

Called when the source's currently displayed image changes.
Expand Down Expand Up @@ -760,6 +769,13 @@ Source-specific Signals
Source-specific Procedures
--------------------------

Using procedure handlers, sources can allow external code to execute specific
actions. These actions are defined using :c:func:`proc_handler_add()` and called
by external code using :c:func:`proc_handler_call()`. For sources created by
plugins not included in official OBS Studio releases, check the plugin's
documentation or source code to determine whether custom procedures are defined
and what they do.

The following procedures are defined for specific sources only:

**current_index** (out int current_index)
Expand Down
Loading