StreamController / StreamController

An elegant Linux app for the Elgato Stream Deck with support for plugins
https://core447.com
GNU General Public License v3.0
297 stars 35 forks source link

OBS Plugin time look ahead #170

Open marvin1099 opened 4 months ago

marvin1099 commented 4 months ago

Describe the feature idea Right now the time shown in obs is off by about 2 seconds, the reason for this is probably that you grab the obs rec time and then display it but that takes time, it probably takes about 2 secs to prosses it all and disply it. So here is my idea, have a look ahead time imput box. I had something like this in streamdeck-linux-gui over the cli. I mentioned a bit about it here #164. How the look ahead time would work is simple, lets say the time input box is 1.6 therefore we calculate the obs time plus 1.6 seconds, in this case we want to wait 0.4 seconds before actually showing any time and after that we show plus 2 seconds, after that we always add the 1.6 secs after reading the obs rec time and sync the button updates by that. Of corse if the recording is paused we don't add the look ahead time.

Additional context Here is a image on what this may look like: obs look ahead also yes i spend the the manually editing a screenshot of the program to make this

Core447 commented 4 months ago

Ok, so the specified time gets simply added to the retrieved value? Maybe we can also track how long it takes to get a respond and display it, take the average of the last 5 requests and automatically add it?

marvin1099 commented 4 months ago

Ok, so the specified time gets simply added to the retrieved value? Maybe we can also track how long it takes to get a respond and display it, take the average of the last 5 requests and automatically add it?

Well i think it also takes a bit of time to display it but I'm not sure that that overhead is, maybe its not that bad, I had assumed the reason why it takes so long is mostly the overhead time to display stuff on the streamdeck, since we don't know what that time is my idea was the manual look ahead. But if you think the time delay comes from the requests you can add that. It still might be a good idea to have the manual look ahead, since it definitely takes time to display something on the steamdeck.

Well that's what i thought at least.

Also as mentioned if the recording is paused we don't need to add anything.

Core447 commented 4 months ago

Yeah, I'll try the average and your way and test what works best.

marvin1099 commented 4 months ago

Yeah, I'll try the average and your way and test what works best.

Thanks.

Core447 commented 3 months ago

The problem seems to be that the action only refreshes the label once every second which results into this delay. Knowing this, I think asking the user to manually enter the difference is no real solution, because the difference will be different for each started recording. The only solution is probably to decrease the update interval to something like 1/4s

Core447 commented 3 months ago

What are your thoughts on this?

marvin1099 commented 3 months ago

Interesting, what might be doable is gabbing the milliseconds of the active recording as well, I'm pretty sure obs web-sockets provides milliseconds. what we can then do is to ajust the look ahead time based on the obs milliseconds. For example: lets say the obs milliseconds are 466, in seconds that is 0.466, so add 1 second to the obs record time, then we wait 1 - 0.466 seconds = 0.534 secs and display the seconds. now if we want to use the user look ahead time, we have to change this up a bit, lets say: obs milliseconds (in seconds) are 0.466 (as before) and user look ahead time is 1.6. Next we calculate 0.466 + 1.6 = 2.066. Then we calculate 2.066 % 1 = 2 and 2.066 / 1 = 0.066. Now we can use 1 - 0.066 = 0.934 as wait time and use: current obs time + 2 + 1 = obs time + 3 to display on the steam deck.

I think i got the calculation correct, and this wait in for displaying the action refresh time could stay the same. So there could be something like a thread that is started after the refresh gets the obs time.

Well that was how i did it in the past with streamdeck-linux-gui at least, you can use you own judgement, if you think this is a thing that is doable or worth it.

Core447 commented 3 months ago

Yes, it's possible to get the time in milliseconds (request), the simplest solution might be to start an update thread independent from on_tick that adapts itself to the interval of the recording. @G4PLS is currently working on a big rewrite of the OBS plugin, so I will probably not implement this anymore in the current version

marvin1099 commented 3 months ago

@G4PLS is currently working on a big rewrite of the OBS plugin, so I will probably not implement this anymore in the current version

Got it, well i guess i will wait for that then

G4PLS commented 3 months ago

Will take a while, this thing is messing me up But after its working Actions should be rolling out

G4PLS commented 3 months ago

With my current implementation of the Record action i dont have that difference. I fetch every tick (So every second) for me this is always 1:1 with OBS itself.

I hope shortly users can add this as a custom Plugin so it can be tested, will ping you in here when this is doable

marvin1099 commented 3 months ago

Thanks, looking forward to it.

G4PLS commented 3 months ago

@marvin1099 you can now add the Plugin as a custom plugin under: Settings -> Store -> Custom Plugins

There you add: url: https://github.com/G4PLS/OBSController branch: main

In the store its listed as OBS Controller (The Image and description show Audio Control so make sure to read the name of the Plugin)

marvin1099 commented 3 months ago

@G4PLS it says no password provided, even when i provide one in the config. Here a screenshot:

Click for image ![image](https://github.com/user-attachments/assets/0600891e-e851-4de6-9e4c-58d9cbb6d549)

also here is the traceback from the screenshot (might be important):

Click for trace back log snippet ``` Traceback (most recent call last): File "/home/marvin/.var/app/com.core447.StreamController/data/plugins/com_gapls_OBSController/internal/PluginConfig.py", line 62, in open_config_window config_window.load_config_ui() File "/home/marvin/.var/app/com.core447.StreamController/data/plugins/com_gapls_OBSController/internal/OBSConfig.py", line 322, in load_config_ui if self.plugin_base.backend.get_connected(): ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/mnt/Programmspeicher/Marvin/Documents/Coding/Python/StreamController/.venv/lib/python3.12/site-packages/rpyc/core/netref.py", line 152, in __getattr__ return syncreq(self, consts.HANDLE_GETATTR, name) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/mnt/Programmspeicher/Marvin/Documents/Coding/Python/StreamController/.venv/lib/python3.12/site-packages/rpyc/core/netref.py", line 63, in syncreq return conn.sync_request(handler, proxy, *args) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/mnt/Programmspeicher/Marvin/Documents/Coding/Python/StreamController/.venv/lib/python3.12/site-packages/rpyc/core/protocol.py", line 744, in sync_request return _async_res.value ^^^^^^^^^^^^^^^^ File "/mnt/Programmspeicher/Marvin/Documents/Coding/Python/StreamController/.venv/lib/python3.12/site-packages/rpyc/core/async_.py", line 111, in value raise self._obj _get_exception_class..Derived: 'Backend' object has no attribute 'get_connected' ========= Remote Traceback (1) ========= Traceback (most recent call last): File "/home/marvin/.var/app/com.core447.StreamController/data/plugins/com_gapls_OBSController/backend/.venv/lib/python3.12/site-packages/rpyc/core/protocol.py", line 369, in _dispatch_request res = self._HANDLERS[handler](self, *args) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/marvin/.var/app/com.core447.StreamController/data/plugins/com_gapls_OBSController/backend/.venv/lib/python3.12/site-packages/rpyc/core/protocol.py", line 879, in _handle_getattr return self._access_attr(obj, name, (), "_rpyc_getattr", "allow_getattr", getattr) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/marvin/.var/app/com.core447.StreamController/data/plugins/com_gapls_OBSController/backend/.venv/lib/python3.12/site-packages/rpyc/core/protocol.py", line 807, in _access_attr return accessor(obj, name, *args) ^^^^^^^^^^^^^^^^^^^^^^^^^^ AttributeError: 'Backend' object has no attribute 'get_connected'. Did you mean: 'test_connection'? OBSSDKError: authentication enabled but no password provided 2024-08-14 19:46:09.105 | ERROR | OBSController:_connect:45 - Error while connecting to OBS: authenticationenabled but no password provided | Used args: {'host': '192.168.2.112', 'port': 4455, 'password': '', 'timeout': 60} ```

Also here is the full command-line log of streamcontroller: https://pastebin.com/PZQMVUKf

G4PLS commented 3 months ago

Ohhhh, i forgot to remove some lines... Can you for now just use the default OBS Config or is the password, ip and port critical?

[EDIT]: Everything is fixed! You should now be able to actually connect when settings the password and port to something different. Also Test Connection is now just to reconnect to OBS

marvin1099 commented 3 months ago

There seems to be some store issue:

2024-08-14 21:12:35.249 | ERROR    | src.backend.Store.StoreBackend:request_from_url:109 - HTTPSConnectionPool(host='raw.githubusercontent.com', port=443): Max retries exceeded with url: /StreamController/StreamController-Store/versions/versions.json (Caused by NameResolutionError("<urllib3.connection.HTTPSConnection object at 0x71d637daac30>: Failed to resolve 'raw.githubusercontent.com' ([Errno -3] Temporary failure in name resolution)"))
2024-08-14 21:12:35.566 | ERROR    | src.backend.Store.StoreBackend:fetch_and_parse_store_json:214 - the JSON object must be str, bytes or bytearray, not NoneType

Any idea that that is all about

Edit: Now i got this, the store is not happy right now:

Click for store issue ``` 2024-08-14 21:43:26.561 | ERROR | threading:run:1010 - An error has been caught in function 'run', process 'MainProcess' (1040007), thread 'load_wallpaper_page' (127271715210944): Traceback (most recent call last): File "/usr/lib/python3.12/threading.py", line 1030, in _bootstrap self._bootstrap_inner() │ └ File "/usr/lib/python3.12/threading.py", line 1073, in _bootstrap_inner self.run() │ └ > File "/usr/lib/python3.12/threading.py", line 1010, in run self._target(*self._args, **self._kwargs) │ │ │ │ │ └ {} │ │ │ │ └ │ │ │ └ () │ │ └ │ └ File "/mnt/Programmspeicher/Marvin/Documents/Coding/Python/StreamController/src/windows/Store/Wallpapers/WallpaperPage.py", line 59, in load wallpapers = asyncio.run(self.store.backend.get_all_wallpapers()) │ │ │ │ │ └ │ │ │ │ └ │ │ │ └ │ │ └ File "/usr/lib/python3.12/asyncio/runners.py", line 194, in run return runner.run(main) │ │ └ │ └ File "/usr/lib/python3.12/asyncio/runners.py", line 118, in run return self._loop.run_until_complete(task) │ │ └ File "/usr/lib/python3.12/asyncio/base_events.py", line 687, in run_until_complete return future.result() │ └ │ │ │ └ │ │ └ │ └ File "/mnt/Programmspeicher/Marvin/Documents/Coding/Python/StreamController/src/backend/Store/StoreBackend.py", line 241, in process_store_data results = await asyncio.gather(*prepare_tasks) │ │ └ [] │ └ File "/mnt/Programmspeicher/Marvin/Documents/Coding/Python/StreamController/src/backend/Store/StoreBackend.py", line 518, in prepare_wallpaper official=author in self.official_authors or False, │ │ └ │ └ └ 'Core447' TypeError: argument of type 'NoConnectionError' is not iterable 2024-08-14 21:43:28.852 | ERROR | threading:run:1010 - An error has been caught in function 'run', process 'MainProcess' (1040007), thread 'load_icon_page' (127271757153984): Traceback (most recent call last): File "/usr/lib/python3.12/threading.py", line 1030, in _bootstrap self._bootstrap_inner() │ └ File "/usr/lib/python3.12/threading.py", line 1073, in _bootstrap_inner self.run() │ └ > File "/usr/lib/python3.12/threading.py", line 1010, in run self._target(*self._args, **self._kwargs) │ │ │ │ │ └ {} │ │ │ │ └ │ │ │ └ () │ │ └ │ └ File "/mnt/Programmspeicher/Marvin/Documents/Coding/Python/StreamController/src/windows/Store/Icons/IconPage.py", line 61, in load icons: list[IconData] = asyncio.run(self.store.backend.get_all_icons()) │ │ │ │ │ │ └ │ │ │ │ │ └ │ │ │ │ └ │ │ │ └ │ │ └ │ └ File "/usr/lib/python3.12/asyncio/runners.py", line 194, in run return runner.run(main) │ │ └ │ └ File "/usr/lib/python3.12/asyncio/runners.py", line 118, in run return self._loop.run_until_complete(task) │ │ └ File "/usr/lib/python3.12/asyncio/base_events.py", line 687, in run_until_complete return future.result() │ └ │ │ │ └ │ │ └ │ └ File "/mnt/Programmspeicher/Marvin/Documents/Coding/Python/StreamController/src/backend/Store/StoreBackend.py", line 241, in process_store_data results = await asyncio.gather(*prepare_tasks) │ │ └ [, File "/mnt/Programmspeicher/Marvin/Documents/Coding/Python/StreamController/src/backend/Store/StoreBackend.py", line 449, in prepare_icon official=author in self.official_authors or False, │ │ └ │ └ └ 'Core447' TypeError: argument of type 'NoConnectionError' is not iterable 2024-08-14 21:43:55.369 | ERROR | src.backend.Store.StoreBackend:request_from_url:109 - HTTPSConnectionPool(host='raw.githubusercontent.com', port=443): Max retries exceeded with url: /StreamController/Pi-hole/1ff777747cec594c7709dae71b4e85d47881ad4b/manifest.json (Caused by NameResolutionError(": Failed to resolve 'raw.githubusercontent.com' ([Errno -3] Temporary failure in name resolution)")) ```

Edit 2: I think i will try to reset my config folder, there might be a problem whit that

marvin1099 commented 3 months ago

@G4PLS now it works, but for me the time is behind, about half a second still. Its not as bad as it was before but its still lagging behind a bit. here a video of that: https://github.com/user-attachments/assets/a85ab1b9-4e9c-4ce1-8ce1-a95d98b7059d

That's why i suggested the "look ahead". I think its still worth it. I would like it. Well tell me what you think.

marvin1099 commented 3 months ago

@G4PLS can you also set it so it just shows a triangle when there is no obs connection, the constant triangle blinking is quite distracting, i only run obs when i need it, so if there is no connection the button should probably just show a static warn triangle.

G4PLS commented 3 months ago

@G4PLS now it works, but for me the time is behind, about half a second still. Its not as bad as it was before but its still lagging behind a bit. here a video of that: https://github.com/user-attachments/assets/a85ab1b9-4e9c-4ce1-8ce1-a95d98b7059d

That's why i suggested the "look ahead". I think its still worth it. I would like it. Well tell me what you think.

Before adding that I will play around with other methods to make it more responsive. Probably the problem is that the respond gets send every second, obs has to process it and send it back and then it needs to be displayed. I think instead of making the user try to figure out what the look ahead is I will make it so you can increase the interval the status is being asked for

@G4PLS can you also set it so it just shows a triangle when there is no obs connection, the constant triangle blinking is quite distracting, i only run obs when i need it, so if there is no connection the button should probably just show a static warn triangle.

Im already looking into that because I find it annoying aswell

G4PLS commented 3 months ago

I have now changed the icon for the lost connection, this icon will be present until the connection to OBS is established (It wont blink) image

marvin1099 commented 3 months ago

I have now changed the icon for the lost connection, this icon will be present until the connection to OBS is established (It wont blink) image

Thanks

marvin1099 commented 3 months ago

Before adding that I will play around with other methods to make it more responsive. Probably the problem is that the respond gets send every second, obs has to process it and send it back and then it needs to be displayed. I think instead of making the user try to figure out what the look ahead is I will make it so you can increase the interval the status is being asked for

we could also measure how long it takes to get the response, and do some calculators to then pull the obs record info a bit earlier. I'm mean lets say it takes 0.5 seconds to get a response, and obs reported 0:00:02:300 (300 is ms here) then we need to pull the status on 0:00:02:500, then we add 0.5 secs, done. how long it takes may be hard to predetermine, so i say we do something like: it takes around 0.1 for somthing to show up on the steam deck + messurement of obs response time.

Well what do you think of that one?

G4PLS commented 3 months ago

I personally dont think this feature is worth the effort (For now). I need to start implementing other actions for the Plugin and im already way to long stuck on the Record Actions (I just did my third or fourth refactor on them)

Maybe someone else will add it while im doing other actions or it will be added later on. For now I just added a simple offset function with the spin row (For some reason it only saves when you use "+" or "-" buttons). Its not perfect either but its good enough for now. I personally think being 1 second behind the actual recording is not that bad

This feature will overall be kept in the back of my mind and when no one is doing it I will come back and try implementing a measuring tool for the response times to make it more accurate, the approach overall is quite nice

marvin1099 commented 3 months ago

I personally dont think this feature is worth the effort (For now). I need to start implementing other actions for the Plugin and im already way to long stuck on the Record Actions (I just did my third or fourth refactor on them)

Maybe someone else will add it while im doing other actions or it will be added later on. For now I just added a simple offset function with the spin row (For some reason it only saves when you use "+" or "-" buttons). Its not perfect either but its good enough for now. I personally think being 1 second behind the actual recording is not that bad

This feature will overall be kept in the back of my mind and when no one is doing it I will come back and try implementing a measuring tool for the response times to make it more accurate, the approach overall is quite nice

Ok, the offset sound good enough, thanks for your work.

G4PLS commented 3 months ago

@marvin1099 I actually noticed that OBS is the one thats probably off

This is what OBS Shows me image

Those are the actual milliseconds I get from the websocket image

When rapidly pausing im able to get a distance of around 3 seconds (I stopped after that). Meaning OBS is displaying the time wrong, the record file in the end was the length of the shown milliseconds, not what OBS showed

Here is a more extreme example: image

marvin1099 commented 3 months ago

Interesting, OK then. What's your next move then? Isn't the response still a bit behind at the beginning, so the offset can't hurt right? Or are you just going to leave it out?

G4PLS commented 3 months ago

I now switched to use the milliseconds directly and left the offset in, doesnt hurt anyone and you can adjust things if needed that way.

For me i cant tell if the response is behind

marvin1099 commented 3 months ago

I now switched to use the milliseconds directly and left the offset in, doesnt hurt anyone and you can adjust things if needed that way.

For me i cant tell if the response is behind

Got it.

G4PLS commented 3 months ago

If you notice any delay keep me posted

marvin1099 commented 3 months ago

Shure.

marvin1099 commented 2 months ago

One thing, I noticed, is it on purpuse that the plugin from: https://github.com/G4PLS/OBSController On: main Is no longer in the list of plugins after it is downloaded? I still have it listed in the store but after installing it, its not listed under installed plugins.

G4PLS commented 2 months ago

Yes, Im currently working on a branch that has some features that are not yet in StreamController so that OBS Plugin will be down for a bit.

But I will probably swap branches and make it so the older version of that OBS Plugin works