mirror of
				https://github.com/onyx-and-iris/OBS-to-XAir.git
				synced 2025-10-31 05:21:53 +00:00 
			
		
		
		
	update for websocket v5, obs 28
support reading conn info from toml add setup.py for easy dep installation
This commit is contained in:
		
							parent
							
								
									f96a80e6da
								
							
						
					
					
						commit
						ba3389882e
					
				
							
								
								
									
										3
									
								
								LICENSE
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								LICENSE
									
									
									
									
									
								
							| @ -1,6 +1,7 @@ | |||||||
| MIT License | MIT License | ||||||
| 
 | 
 | ||||||
| Copyright (c) 2019-2021 lebaston100 | Copyright (c) 2019-2022 lebaston100 | ||||||
|  | Copyright (c) 2022 Onyx-and-Iris | ||||||
| 
 | 
 | ||||||
| Permission is hereby granted, free of charge, to any person obtaining a copy | Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
| of this software and associated documentation files (the "Software"), to deal | of this software and associated documentation files (the "Software"), to deal | ||||||
|  | |||||||
							
								
								
									
										66
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										66
									
								
								README.md
									
									
									
									
									
								
							| @ -1,50 +1,58 @@ | |||||||
| # OBS-to-XAir | # OBS-to-XAir | ||||||
|  | 
 | ||||||
| This is a small script that mutes and unmutes channels on Behringer XAir Mixers depending on the current scene. | This is a small script that mutes and unmutes channels on Behringer XAir Mixers depending on the current scene. | ||||||
| 
 | 
 | ||||||
| ## Requirements | ## Requirements | ||||||
| 
 | 
 | ||||||
| - The [obs-websocket plugin](https://github.com/Palakis/obs-websocket/releases) (Version 4.5.1 - 4.9.1) | -   The [obs-websocket-v5 plugin](https://github.com/obsproject/obs-websocket/releases) (Version 5.0.0+) | ||||||
| - A fairly recent version of Python 3 |     -   Note, this now comes included with OBS 28+ | ||||||
| - [websocket-client](https://github.com/websocket-client/websocket-client) | -   [obsws-python](https://github.com/aatikturk/obsws-python) | ||||||
| - [python-osc](https://github.com/attwad/python-osc) | -   [xair-api](https://github.com/onyx-and-iris/xair-api-python) | ||||||
|  | -   Python 3.10 or greater | ||||||
| 
 | 
 | ||||||
| ## General Setup | ## Installation | ||||||
| 
 | 
 | ||||||
| - Install Python 3.x.x  | -   First install [latest version of Python](https://www.python.org/downloads/). | ||||||
|   - On Windows: Make sure you trick "Add Python 3.x to PATH" in the setup | 
 | ||||||
| - Make sure you also install pip |     -   Ensure you tick `Add Python 3.x to PATH` during setup. | ||||||
| - Open up a command line and execute these commands to install the required pip modules: | 
 | ||||||
|   - pip install python-osc | -   Download the repository files with git or the green `Code` button. Then in command prompt: | ||||||
|   - pip install websocket-client | 
 | ||||||
| - OBS Websocket: | ``` | ||||||
|   - Download the installer from the link above and run it | cd OBS-to-XAir | ||||||
|   - Start OBS, open the "Tools" menu and select "websocket server settings" | pip install . | ||||||
|   - Make sure that "Enable Websocket server" is checked, "Server Port" is 4444 and "Enable authentification" is unchecked | ``` | ||||||
| 
 | 
 | ||||||
| ## Configuration | ## Configuration | ||||||
| 
 | 
 | ||||||
| You have to configure your scene-to-channel mapping and the IP settings. Open up the .py file with a text editor. | -   Configure websocket settings within `OBS->Tools->obs-websocket Settings` | ||||||
| 
 | 
 | ||||||
| - The mapping: | -   Open the included `config.toml` and set OBS host, port and password as well as the xair mixers ip. | ||||||
| This python dict resolves the OBS scene names to the XAir channels. 3 Channels come pre-set as a template. |  | ||||||
| The format follows the rule "scene name": "mixer channel". |  | ||||||
| "scene name" is the scene name in OBS which you want to pair to a mixer channel. "mixer channel" is the channel on the XAir mixer. Important: If you use the lower channels 1-9 you have to add zero-padding so "1" becomes "01" and so on. You can find all available channel names besides the normal 01-16 in the "parameters.txt" when you download the latest mixer firmware zip. |  | ||||||
| 
 | 
 | ||||||
| - OBS IP and Port: |     -   You may also set the kind of mixer in the script. (`XR12, XR16, XR18, MR18`) | ||||||
| In line 9 and 10 you can set the IP and port from the machine that runs OBS. If you are running the script locally you don't need to change anything. |  | ||||||
| 
 | 
 | ||||||
| - XAir Mixer IP: | -   Set the scene to channel mutes mapping in the script. | ||||||
| In line 11 you need to set the IP address of your XAir Mixer. The OSC Port can't be changed so it's hardcoded. |  | ||||||
| 
 | 
 | ||||||
| ## Usage | ## Usage | ||||||
| 
 | 
 | ||||||
| Just run the script, either from the command line or with a double-click. There will be no further output besides "Websocket open" when it's running. If the connection to OBS is broken, you will get an error. | Simply run the script, there will be confirmation of mixer connection and OBS connection if everything is successful. Switch between the defined scenes. | ||||||
|  | 
 | ||||||
|  | Closing OBS will stop the script. | ||||||
|  | 
 | ||||||
|  | ## Further notes | ||||||
|  | 
 | ||||||
|  | Since this script relies upon two interfaces, `obsws-python` and `xair-api` this code can be readily modified to interact with any OBS events and set any xair parameters. Check the README files for each interface for further details. | ||||||
| 
 | 
 | ||||||
| ## Compatibility | ## Compatibility | ||||||
| 
 | 
 | ||||||
| This script was developed and tested with: | This script was developed and tested with: | ||||||
| - OBS 23.1.0 |  | ||||||
| - obs-websocket 4.5.1 |  | ||||||
| - A Behringer XR18 |  | ||||||
| 
 | 
 | ||||||
| It should theoretically also work with the XR12, XR16 and X32 but i cannot validate this myself. Feel free to let me know if it worked for you. | -   OBS 28.01 | ||||||
|  | -   obs-websocket 5.0.1 | ||||||
|  | -   A Behringer XR18 and Midas MR18 | ||||||
|  | 
 | ||||||
|  | ## Special Thanks | ||||||
|  | 
 | ||||||
|  | -   OBS team and the obs-websocket developers + Behringer/Midas for the OSC protocol. | ||||||
|  | -   [Adem](https://github.com/aatikturk) for contributions towards the obsws-python wrapper. | ||||||
|  | -   [Onyx-and-Iris](https://github.com/onyx-and-iris) for contributions towards the obsws-python and xair-api wrappers. | ||||||
|  | |||||||
							
								
								
									
										53
									
								
								__main__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								__main__.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,53 @@ | |||||||
|  | import time | ||||||
|  | 
 | ||||||
|  | import obsws_python as obs | ||||||
|  | import xair_api | ||||||
|  | 
 | ||||||
|  | mapping = { | ||||||
|  |     "START": 1, | ||||||
|  |     "BRB": 2, | ||||||
|  |     "END": 3, | ||||||
|  |     "LIVE": 4, | ||||||
|  | }  # set the mapping for the scene to channel mapping here. "scenename": "channel" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class Observer: | ||||||
|  |     def __init__(self, mixer): | ||||||
|  |         self._mixer = mixer | ||||||
|  |         self._request = obs.ReqClient() | ||||||
|  |         self._event = obs.EventClient() | ||||||
|  |         self._event.callback.register( | ||||||
|  |             (self.on_current_program_scene_changed, self.on_exit_started) | ||||||
|  |         ) | ||||||
|  |         self.running = True | ||||||
|  |         resp = self._request.get_version() | ||||||
|  |         info = ( | ||||||
|  |             f"Connected to OBS version:{resp.obs_version}", | ||||||
|  |             f"with websocket version:{resp.obs_web_socket_version}", | ||||||
|  |         ) | ||||||
|  |         print(" ".join(info)) | ||||||
|  | 
 | ||||||
|  |     def on_current_program_scene_changed(self, data): | ||||||
|  |         scene = data.scene_name | ||||||
|  |         print(f"Switched to scene {scene}") | ||||||
|  |         for k, v in mapping.items(): | ||||||
|  |             self._mixer.strip[v - 1].mix.on = k == scene | ||||||
|  | 
 | ||||||
|  |     def on_exit_started(self, _): | ||||||
|  |         print("OBS closing") | ||||||
|  |         self._event.unsubscribe() | ||||||
|  |         self.running = False | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def main(): | ||||||
|  |     with xair_api.connect(kind_mixer) as mixer: | ||||||
|  |         o = Observer(mixer) | ||||||
|  | 
 | ||||||
|  |         while o.running: | ||||||
|  |             time.sleep(0.5) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | if __name__ == "__main__": | ||||||
|  |     kind_mixer = "XR18" | ||||||
|  | 
 | ||||||
|  |     main() | ||||||
							
								
								
									
										8
									
								
								config.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								config.toml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | |||||||
|  | [connection] | ||||||
|  | # OBS connection info | ||||||
|  | host = "localhost" | ||||||
|  | port = 4455 | ||||||
|  | password = "strongpassword" | ||||||
|  | 
 | ||||||
|  | # xair mixer ip | ||||||
|  | ip = "mixer.local" | ||||||
| @ -1,50 +0,0 @@ | |||||||
| #!/usr/bin/env python |  | ||||||
| 
 |  | ||||||
| import websocket, json |  | ||||||
| from time import sleep |  | ||||||
| from pythonosc import osc_message_builder |  | ||||||
| from pythonosc import udp_client |  | ||||||
| 
 |  | ||||||
| mapping = {"scene1": "01", "scene2": "02", "scene3": "03"} #set the mapping for the scene to channel mapping here. "scenename": "channel" |  | ||||||
| obsip = "localhost"     #set the obs machine ip here. localhost works if you run this script on the same machine. |  | ||||||
| obsport = "4444"        #set the ob websocket port here. 4444 is defult |  | ||||||
| xairip = "192.168.1.10" #set the xairip here |  | ||||||
| 
 |  | ||||||
| def ws1_on_message(ws, message): |  | ||||||
|     jsn = json.loads(message) |  | ||||||
|     if jsn["update-type"] == "SwitchScenes": |  | ||||||
|         for scene in mapping: |  | ||||||
|             if scene == jsn["scene-name"]: |  | ||||||
|                 client.send_message("/ch/" + mapping[scene] + "/mix/on", 1) |  | ||||||
|             else: |  | ||||||
|                 client.send_message("/ch/" + mapping[scene] + "/mix/on", 0) |  | ||||||
|     elif jsn["update-type"] == "TransitionBegin": |  | ||||||
|         for scene in mapping: |  | ||||||
|             if scene == jsn["to-scene"]: |  | ||||||
|                 client.send_message("/ch/" + mapping[scene] + "/mix/on", 1) |  | ||||||
|             elif scene == jsn["from-scene"] and not jsn["name"] == "Cut": |  | ||||||
|                 client.send_message("/ch/" + mapping[scene] + "/mix/on", 1) |  | ||||||
|             else: |  | ||||||
|                 client.send_message("/ch/" + mapping[scene] + "/mix/on", 0) |  | ||||||
| 
 |  | ||||||
| def ws1_on_error(ws, error): |  | ||||||
|     print(error) |  | ||||||
| 
 |  | ||||||
| def ws1_on_close(ws): |  | ||||||
|     print("Websocket close") |  | ||||||
| 
 |  | ||||||
| def ws1_on_open(ws): |  | ||||||
|     print("Websocket open") |  | ||||||
| 
 |  | ||||||
| def ws1_start(): |  | ||||||
|     while True: |  | ||||||
|         ws1.run_forever() |  | ||||||
|         print("Websocket restart") |  | ||||||
|         print("This most likely means that OBS is not open or you lost network connection.") |  | ||||||
|         sleep(1) |  | ||||||
| 
 |  | ||||||
| if __name__ == "__main__": |  | ||||||
|     client = udp_client.SimpleUDPClient(xairip, 10024) |  | ||||||
|     ws1 = websocket.WebSocketApp("ws://" + obsip + ":" + obsport, on_message = ws1_on_message, on_error = ws1_on_error, on_close = ws1_on_close) |  | ||||||
|     ws1.on_open = ws1_on_open |  | ||||||
|     ws1_start() |  | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user