Skip to content

Commit 991c6f0

Browse files
committed
Add volmeter audio volume level
1 parent fe3d90e commit 991c6f0

File tree

2 files changed

+146
-2
lines changed

2 files changed

+146
-2
lines changed

README.md

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ Also check out [issues](https://github.com/upgradeQ/OBS-Studio-Python-Scripting-
3434
- [Play sound](#play-sound)
3535
- [Read and write private data from scripts or plugins](#read-and-write-private-data-from-scripts-or-plugins)
3636
- [Browser source interaction](#browser-source-interaction)
37+
- [Acess source dB volume level](#access-source-db-volume-level)
3738
- [Debug](#debug)
39+
- [Security](#security)
3840
- [Docs and code examples](#docs-and-code-examples)
3941
- [Links](#links)
4042
- [Contribute](#contribute)
@@ -671,10 +673,39 @@ def press_shift_tab(*p):
671673
```
672674
- [Full example read](src/browser_source_interaction.py)
673675

676+
# Acess source dB volume level
677+
There is FFI `ctypes` module in Python to wrap native `obs` lib.
678+
However,to run it on GNU/Linux you must start obs with `LD_PRELOAD`.
679+
```bash
680+
ubsdrive3@usbdrive3:~$ LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libpython3.9.so obs
681+
```
682+
It might be in different directory, use `find /usr -name 'libpython*' ` to
683+
find exact location.
684+
685+
```python
686+
volmeter_callback_t = CFUNCTYPE(
687+
None, c_void_p, POINTER(c_float), POINTER(c_float), POINTER(c_float)
688+
)
689+
...
690+
wrap(
691+
"obs_volmeter_add_callback",
692+
None,
693+
argtypes=[POINTER(Volmeter), volmeter_callback_t, c_void_p],
694+
)
695+
...
696+
@volmeter_callback_t
697+
def volmeter_callback(data, mag, peak, input):
698+
G.noise = float(peak[0])
699+
```
700+
701+
- [Full example read](src/volmeter_via_ffi.py)
702+
674703
# Debug
675704
There is no stdin therefore you can't use pdb , options are:
676705
- using `print`
706+
- using generated log file (contains information about memory leaks)
677707
- using pycharm remote debugging (localhost)
708+
- using threading
678709
- using [vscode](https://code.visualstudio.com/docs/python/debugging) attach to the process:
679710
- Load python extension
680711
- open script file , `pip install debugpy` , place `debugpy.breakpoint()` somewhere
@@ -685,9 +716,21 @@ There is no stdin therefore you can't use pdb , options are:
685716

686717
![screenshot](src/assets/debug.png)
687718

719+
# Security
720+
- "Calling home" - see [`#4044`](https://github.com/obsproject/obs-studio/issues/4044)
721+
- On GNU/Linux there is handy program called `tcpdump`, to run a check against OBS Studio - use this command (it is active on 443 port on start and on end)
722+
```bash
723+
# tcpdump -i <your_interface_e_g_wifi_or_wire> 'port 443'
724+
```
725+
- Avoid using `sudo` or admin, check hashsums, do backups, do updates, etc...
726+
- There is no confirmation for loading Lua or Python scripts - they can be added/overwritten via .json key
727+
- Also solutions for Python source code obfuscation & loading from shared (compiled) library do exist.Applying that will make it a bit harder to reverse-engineer your code.
728+
688729
# Docs and code examples
689730

690-
[Generated export.md](src/export.md) contains all variables and functions available in `obspython` formatted with markdown. Table consist of links to appropriate search terms in OBS Studio repository, and obswebsocket,links to scripts in `obspython` and `obslua` with each script within github code search.`gs_*` and `matrix_*` functions exluded from that table.
731+
- [`Generated export.md`](src/export.md)
732+
733+
contains all variables and functions available in `obspython` formatted with markdown. Table consist of links to appropriate search terms in OBS Studio repository and obswebsocket,links to scripts in `obspython` and `obslua` with each script within github code search.`gs_*` and `matrix_*` functions exluded from that table.
691734
[Full example](src/export_md.py)
692735
`Note` : starting from 2020.12.17 Github Code Search no longer works as it was, see also this [thread](https://github.community/t/feedback-on-changes-to-code-search-indexing/150660)
693736

@@ -696,7 +739,7 @@ There is no stdin therefore you can't use pdb , options are:
696739
- [Scripts forum](https://obsproject.com/forum/resources/categories/scripts.5/) , [Github topic `obs-scripts`](https://github.com/topics/obs-scripts) , [Github topic `obs-script`](https://github.com/topics/obs-script)
697740
- [OBS Studio Repo](https://github.com/obsproject/obs-studio) , [obs-scripting-python.c](https://github.com/obsproject/obs-studio/blob/master/deps/obs-scripting/obs-scripting-python.c)
698741
- [Docs](https://obsproject.com/docs/) , [Docs/scripting](https://obsproject.com/docs/scripting.html) , [Docs/plugins](https://obsproject.com/docs/plugins.html) , [Docs index](https://obsproject.com/docs/genindex.html)
699-
- obspython [Gist](https://gist.github.com/search?l=Python&q=obspython) , [Github](https://github.com/search?l=Python&o=desc&q=obspython&s=indexed&type=Code) , [grep.app](https://grep.app/search?q=obspython&filter[lang][0]=Python)
742+
- obspython [Gist](https://gist.github.com/search?l=Python&q=obspython&s=updated) , [Github](https://github.com/search?l=Python&o=desc&q=obspython&s=indexed&type=Code) , [grep.app](https://grep.app/search?q=obspython&filter[lang][0]=Python)
700743
- obslua [Gist](https://gist.github.com/search?l=Lua&o=desc&q=obslua&s=updated) , [Github](https://github.com/search?l=Lua&o=desc&q=obslua&s=indexed&type=Code) , [grep.app](https://grep.app/search?q=obslua&filter[lang][0]=Lua)
701744
- [A Python bundle for integration with OBS scripting](https://github.com/zooba/obs-python)
702745
- [Lua tips and tricks](https://obsproject.com/forum/threads/tips-and-tricks-for-lua-scripts.132256/)

src/volmeter_via_ffi.py

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import obspython as S # studio
2+
from types import SimpleNamespace
3+
from ctypes import *
4+
from ctypes.util import find_library
5+
6+
obsffi = CDLL(find_library("obs"))
7+
G = SimpleNamespace()
8+
9+
10+
def wrap(funcname, restype, argtypes):
11+
"""Simplify wrapping ctypes functions in obsffi"""
12+
func = getattr(obsffi, funcname)
13+
func.restype = restype
14+
func.argtypes = argtypes
15+
globals()["g_" + funcname] = func
16+
17+
18+
class Source(Structure):
19+
pass
20+
21+
22+
class Volmeter(Structure):
23+
pass
24+
25+
26+
volmeter_callback_t = CFUNCTYPE(
27+
None, c_void_p, POINTER(c_float), POINTER(c_float), POINTER(c_float)
28+
)
29+
wrap("obs_get_source_by_name", POINTER(Source), argtypes=[c_char_p])
30+
wrap("obs_source_release", None, argtypes=[POINTER(Source)])
31+
wrap("obs_volmeter_create", POINTER(Volmeter), argtypes=[c_int])
32+
wrap("obs_volmeter_destroy", None, argtypes=[POINTER(Volmeter)])
33+
wrap(
34+
"obs_volmeter_add_callback",
35+
None,
36+
argtypes=[POINTER(Volmeter), volmeter_callback_t, c_void_p],
37+
)
38+
wrap(
39+
"obs_volmeter_remove_callback",
40+
None,
41+
argtypes=[POINTER(Volmeter), volmeter_callback_t, c_void_p],
42+
)
43+
wrap(
44+
"obs_volmeter_attach_source",
45+
c_bool,
46+
argtypes=[POINTER(Volmeter), POINTER(Source)],
47+
)
48+
49+
50+
@volmeter_callback_t
51+
def volmeter_callback(data, mag, peak, input):
52+
G.noise = float(peak[0])
53+
54+
55+
def output_to_file(volume):
56+
with open("current_db_volume_of_source_status.txt", "w", encoding="utf-8") as f:
57+
f.write(str(volume))
58+
59+
60+
OBS_FADER_LOG = 2
61+
G.lock = False
62+
G.start_delay = 3
63+
G.duration = 0
64+
G.noise = 999
65+
G.tick = 16
66+
G.tick_mili = G.tick * 0.001
67+
G.interval_sec = 0.05
68+
G.tick_acc = 0
69+
G.source_name = "Media Source"
70+
G.volmeter = "not yet initialized volmeter instance"
71+
G.callback = output_to_file
72+
73+
74+
def event_loop():
75+
"""wait n seconds, then execute callback with db volume level within interval"""
76+
if G.duration > G.start_delay:
77+
if not G.lock:
78+
print("setting volmeter")
79+
source = g_obs_get_source_by_name(G.source_name.encode("utf-8"))
80+
G.volmeter = g_obs_volmeter_create(OBS_FADER_LOG)
81+
g_obs_volmeter_add_callback(G.volmeter, volmeter_callback, None)
82+
if g_obs_volmeter_attach_source(G.volmeter, source):
83+
g_obs_source_release(source)
84+
G.lock = True
85+
print("Attached to source")
86+
return
87+
G.tick_acc += G.tick_mili
88+
if G.tick_acc > G.interval_sec:
89+
G.callback(G.noise)
90+
G.tick_acc = 0
91+
else:
92+
G.duration += G.tick_mili
93+
94+
95+
def script_unload():
96+
g_obs_volmeter_remove_callback(G.volmeter, volmeter_callback, None)
97+
g_obs_volmeter_destroy(G.volmeter)
98+
print("Removed volmeter & volmeter_callback")
99+
100+
101+
S.timer_add(event_loop, G.tick)

0 commit comments

Comments
 (0)