├── AutoDisableSound.py ├── README.md └── SoundPlugin.py /AutoDisableSound.py: -------------------------------------------------------------------------------- 1 | import obspython as obs 2 | 3 | from time import sleep 4 | import os 5 | 6 | sourcename = "" 7 | audiofolder = "" 8 | testfile = "" 9 | 10 | wasplaying = False 11 | 12 | # ------------------------------------------------------------ 13 | 14 | def script_description(): 15 | return "Automatically disables a Media Source once it has finished playing a sound and clears the filename\n\nBy TheAstropath" 16 | 17 | 18 | def play_task(): 19 | global wasplaying 20 | 21 | if not is_source_playing(): 22 | if wasplaying: 23 | hidesource() 24 | wasplaying = False 25 | 26 | else: 27 | wasplaying = True 28 | 29 | def is_source_playing(): 30 | source = obs.obs_get_source_by_name(sourcename) 31 | mediastate = obs.obs_source_media_get_state(source) 32 | #obs.script_log(obs.LOG_DEBUG, "Media state: "+str(mediastate)) 33 | obs.obs_source_release(source) 34 | 35 | return mediastate == 1 #PLAYING is 1 36 | 37 | 38 | def script_update(settings): 39 | global sourcename 40 | 41 | sourcename = obs.obs_data_get_string(settings, "sourcename") 42 | 43 | hidesource() 44 | unsetfilename() 45 | 46 | 47 | 48 | def script_load(settings): 49 | obs.script_log(obs.LOG_DEBUG, "Loading script") 50 | hidesource() 51 | unsetfilename() 52 | obs.timer_add(play_task,100) 53 | 54 | def script_unload(): 55 | #obs.timer_remove(server_handle) 56 | hidesource() 57 | unsetfilename() 58 | obs.script_log(obs.LOG_DEBUG, "Unloading script") 59 | 60 | def hidesource(): 61 | #obs.script_log(obs.LOG_DEBUG,"Trying to hide source "+sourcename) 62 | 63 | frontendscenes = obs.obs_frontend_get_scenes() 64 | #obs.script_log(obs.LOG_DEBUG,str(frontendscenes)) 65 | 66 | for scenesource in frontendscenes: 67 | #obs.script_log(obs.LOG_DEBUG,str(scenesource)) 68 | 69 | #scenesource = obs.obs_frontend_get_current_scene() 70 | scene = obs.obs_scene_from_source(scenesource) 71 | #obs.script_log(obs.LOG_DEBUG,"Scene "+str(scene)) 72 | 73 | sceneitem = obs.obs_scene_find_source(scene,sourcename) 74 | if sceneitem: 75 | #obs.script_log(obs.LOG_DEBUG,"Scene item "+str(sceneitem)) 76 | 77 | obs.obs_sceneitem_set_visible(sceneitem,False) 78 | 79 | #obs.obs_source_release(scenesource) 80 | obs.source_list_release(frontendscenes) 81 | 82 | def unsetfilename(): 83 | source = obs.obs_get_source_by_name(sourcename) 84 | #obs.script_log(obs.LOG_DEBUG,"Source "+str(source)) 85 | 86 | settings = obs.obs_source_get_settings(source) 87 | #obs.script_log(obs.LOG_DEBUG,str(obs.obs_data_get_json(settings))) 88 | obs.obs_data_set_string(settings,"local_file","") 89 | #obs.script_log(obs.LOG_DEBUG,str(obs.obs_data_get_json(settings))) 90 | 91 | obs.obs_source_update(source,settings) 92 | 93 | obs.obs_data_release(settings) 94 | obs.obs_source_release(source) 95 | 96 | def set_source_speed(source,speed): 97 | settings = obs.obs_source_get_settings(source) 98 | speedpct = int(speed*100) 99 | obs.obs_data_set_int(settings,"speed_percent",speedpct) 100 | obs.obs_source_update(source,settings) 101 | obs.obs_data_release(settings) 102 | 103 | 104 | def script_defaults(settings): 105 | global sourcename 106 | 107 | sourcename= "" 108 | 109 | def script_properties(): 110 | props = obs.obs_properties_create() 111 | 112 | obs.obs_properties_add_text(props, "sourcename", "Media Source Name", obs.OBS_TEXT_DEFAULT) 113 | 114 | return props 115 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ObsSoundPlugin 2 | A Python script for OBS Studio that allows audio playback based on incoming HTTP messages 3 | 4 | Configuration: 5 | 6 | To set this up, you need to first create a "Media Source" in OBS which will be used for playback. Next, add the script to OBS under Tools>Scripts. Configure the "Media Source Name" to match the name of the Media Source you created earlier. The "Audio Folder" should be the path to the folder containing your audio clips (This should end with a backslash for now). The "Test File" lets you specify a filename of an audio clip in the audio folder that you can test with the "Test Playback" button. The "Port Number" allows you to choose what port you want to listen for the HTTP requests on. 7 | 8 | 9 | Sending playback requests: 10 | 11 | Sending playback requests is very simple. In the examples below, replace "yourpc" with the IP or hostname of the PC you are running OBS Studio on. Change 8888 to whatever port you chose to listen on when you configured the script 12 | 13 | For extremely basic playback, you can send a request to: 14 | 15 | http://yourpc:8888/testsound.mp3 16 | 17 | Which will play the clip at 100% volume. 18 | 19 | You can also adjust the volume by adding a "vol" parameter afterwards, for example: 20 | 21 | http://yourpc:8888/testsound.mp3?vol=0.5 22 | 23 | 1.0 is 100% volume and can be adjusted down to 0% or up to 200% (2.0) 24 | 25 | If you want to change the speed of playback, there is a "speed" parameter also: 26 | 27 | http://yourpc:8888/testsound.mp3?speed=0.5 28 | 29 | Like with volume, this can be adjusted from 0% speed up to 200% (2.0) 30 | 31 | The volume and speed parameters can also be combined: 32 | 33 | http://yourpc:8888/testsound.mp3?vol=0.5&speed=0.5 -------------------------------------------------------------------------------- /SoundPlugin.py: -------------------------------------------------------------------------------- 1 | import obspython as obs 2 | 3 | from time import sleep 4 | from threading import Thread 5 | from socketserver import ThreadingMixIn 6 | from http.server import HTTPServer,BaseHTTPRequestHandler 7 | import os 8 | 9 | sourcename = "" 10 | audiofolder = "" 11 | testfile = "" 12 | portnum = 8888 13 | oldportnum=0 14 | 15 | serverthread = None 16 | stopserver = False 17 | httpd = None 18 | 19 | wasplaying = False 20 | 21 | playlist = [] 22 | 23 | 24 | # ------------------------------------------------------------ 25 | 26 | class Handler(BaseHTTPRequestHandler): 27 | def do_GET(self): 28 | global playlist 29 | obs.script_log(obs.LOG_DEBUG,"Got GET!") 30 | 31 | opts = dict() 32 | 33 | command = self.path[1:] 34 | if "?" in command: 35 | split = command.split("?") 36 | filename = split[0] 37 | options = split[1].split("&") 38 | 39 | for option in options: 40 | splitopt = option.split("=") 41 | opts[splitopt[0]]=splitopt[1] 42 | 43 | obs.script_log(obs.LOG_DEBUG,str(opts)) 44 | 45 | else: 46 | filename = command 47 | 48 | #obs.script_log(obs.LOG_DEBUG,str(self.path)) 49 | if check_for_file(filename): 50 | #playsound(filename) 51 | playlist.append((filename,opts)) 52 | resp = "Played "+filename 53 | else: 54 | obs.script_log(obs.LOG_DEBUG,filename+" is not present") 55 | resp = "Could not find "+filename 56 | self.send_response_only(200) 57 | self.send_header("Content-type", "text/plain") 58 | self.end_headers() 59 | resp = resp.encode() 60 | self.wfile.write(resp) 61 | 62 | class ThreadingHTTPServer(ThreadingMixIn, HTTPServer): 63 | daemon_threads = True 64 | 65 | # ------------------------------------------------------------ 66 | 67 | def check_for_file(filename): 68 | return os.path.isfile(audiofolder+filename) 69 | 70 | def script_description(): 71 | return "Accepts audio file play requests via HTTP request\n\nBy TheAstropath" 72 | 73 | def server_handle(): 74 | global httpd 75 | #obs.script_log(obs.LOG_DEBUG,"Handling") 76 | 77 | if httpd: 78 | #Timeout must be very small, otherwise it impacts the 79 | #framerate of the stream 80 | httpd.timeout=0.001 81 | httpd.handle_request() 82 | 83 | 84 | def server_task(): 85 | global httpd 86 | global stopserver 87 | obs.script_log(obs.LOG_DEBUG, "Server task started") 88 | 89 | while not stopserver: 90 | httpd.timeout=0.001 91 | httpd.handle_request() 92 | sleep(1) 93 | 94 | obs.script_log(obs.LOG_DEBUG, "Server task stopped") 95 | 96 | 97 | stopserver = False 98 | 99 | def stop_server(): 100 | global httpd 101 | global serverthread 102 | global stopserver 103 | obs.script_log(obs.LOG_DEBUG, "Server stopped") 104 | 105 | if serverthread!=None: 106 | stopserver = True 107 | serverthread = None 108 | 109 | if httpd: 110 | httpd.server_close() 111 | 112 | httpd = None 113 | 114 | def start_server(): 115 | global httpd 116 | global serverthread 117 | 118 | obs.script_log(obs.LOG_DEBUG, "Server started") 119 | 120 | server_address = ('',portnum) 121 | httpd = ThreadingHTTPServer(server_address,Handler) 122 | 123 | if serverthread==None: 124 | serverthread = Thread(target = server_task) 125 | serverthread.start() 126 | 127 | #httpd = HTTPServer(server_address,Handler) 128 | 129 | def manage_server(): 130 | stop_server() 131 | start_server() 132 | 133 | def play_task(): 134 | global wasplaying 135 | global playlist 136 | 137 | if not is_source_playing(): 138 | if wasplaying: 139 | hidesource() 140 | wasplaying = False 141 | 142 | #Check to see if there is anything new to play 143 | if len(playlist)>0: 144 | sound = playlist.pop(0) 145 | filename = sound[0] 146 | opts = sound[1] 147 | volume = 1.0 148 | speed = 1.0 149 | 150 | if "vol" in opts: 151 | volume = float(opts["vol"]) 152 | 153 | if "speed" in opts: 154 | speed = float(opts["speed"]) 155 | 156 | playsound(filename,volume,speed) 157 | else: 158 | wasplaying = True 159 | 160 | def is_source_playing(): 161 | source = obs.obs_get_source_by_name(sourcename) 162 | mediastate = obs.obs_source_media_get_state(source) 163 | #obs.script_log(obs.LOG_DEBUG, "Media state: "+str(mediastate)) 164 | obs.obs_source_release(source) 165 | 166 | return mediastate == 1 #PLAYING is 1 167 | 168 | 169 | def script_update(settings): 170 | global sourcename 171 | global portnum 172 | global audiofolder 173 | global testfile 174 | global oldportnum 175 | 176 | sourcename = obs.obs_data_get_string(settings, "sourcename") 177 | audiofolder = obs.obs_data_get_string(settings, "audiofolder") 178 | testfile = obs.obs_data_get_string(settings, "testfile") 179 | portnum = obs.obs_data_get_int(settings, "portnum") 180 | 181 | hidesource() 182 | unsetfilename() 183 | 184 | if oldportnum!=portnum: 185 | manage_server() 186 | oldportnum = portnum 187 | 188 | 189 | 190 | def script_load(settings): 191 | obs.script_log(obs.LOG_DEBUG, "Loading script") 192 | hidesource() 193 | unsetfilename() 194 | #obs.timer_add(server_handle,100) 195 | start_server() 196 | obs.timer_add(play_task,100) 197 | 198 | def script_unload(): 199 | #obs.timer_remove(server_handle) 200 | hidesource() 201 | unsetfilename() 202 | stop_server() 203 | obs.script_log(obs.LOG_DEBUG, "Unloading script") 204 | 205 | def hidesource(): 206 | #obs.script_log(obs.LOG_DEBUG,"Trying to hide source "+sourcename) 207 | 208 | frontendscenes = obs.obs_frontend_get_scenes() 209 | #obs.script_log(obs.LOG_DEBUG,str(frontendscenes)) 210 | 211 | for scenesource in frontendscenes: 212 | #obs.script_log(obs.LOG_DEBUG,str(scenesource)) 213 | 214 | #scenesource = obs.obs_frontend_get_current_scene() 215 | scene = obs.obs_scene_from_source(scenesource) 216 | #obs.script_log(obs.LOG_DEBUG,"Scene "+str(scene)) 217 | 218 | sceneitem = obs.obs_scene_find_source(scene,sourcename) 219 | if sceneitem: 220 | #obs.script_log(obs.LOG_DEBUG,"Scene item "+str(sceneitem)) 221 | 222 | obs.obs_sceneitem_set_visible(sceneitem,False) 223 | 224 | #obs.obs_source_release(scenesource) 225 | obs.source_list_release(frontendscenes) 226 | 227 | def unsetfilename(): 228 | source = obs.obs_get_source_by_name(sourcename) 229 | #obs.script_log(obs.LOG_DEBUG,"Source "+str(source)) 230 | 231 | settings = obs.obs_source_get_settings(source) 232 | #obs.script_log(obs.LOG_DEBUG,str(obs.obs_data_get_json(settings))) 233 | obs.obs_data_set_string(settings,"local_file","") 234 | #obs.script_log(obs.LOG_DEBUG,str(obs.obs_data_get_json(settings))) 235 | 236 | obs.obs_source_update(source,settings) 237 | 238 | obs.obs_data_release(settings) 239 | obs.obs_source_release(source) 240 | 241 | def set_source_speed(source,speed): 242 | settings = obs.obs_source_get_settings(source) 243 | speedpct = int(speed*100) 244 | obs.obs_data_set_int(settings,"speed_percent",speedpct) 245 | obs.obs_source_update(source,settings) 246 | obs.obs_data_release(settings) 247 | 248 | def playsound(filename,volume,speed): 249 | obs.script_log(obs.LOG_DEBUG,"Trying to play "+filename+" to source "+sourcename) 250 | 251 | scenesource = obs.obs_frontend_get_current_scene() 252 | scene = obs.obs_scene_from_source(scenesource) 253 | #obs.script_log(obs.LOG_DEBUG,"Scene "+str(scene)) 254 | 255 | sceneitem = obs.obs_scene_find_source(scene,sourcename) 256 | #obs.script_log(obs.LOG_DEBUG,"Scene item "+str(sceneitem)) 257 | 258 | source = obs.obs_sceneitem_get_source(sceneitem) 259 | 260 | obs.obs_source_set_volume(source,volume) 261 | set_source_speed(source,speed) 262 | 263 | obs.obs_sceneitem_set_visible(sceneitem,False) 264 | 265 | settings = obs.obs_source_get_settings(source) 266 | #obs.script_log(obs.LOG_DEBUG,str(obs.obs_data_get_json(settings))) 267 | obs.obs_data_set_string(settings,"local_file",audiofolder+filename) 268 | #obs.script_log(obs.LOG_DEBUG,str(obs.obs_data_get_json(settings))) 269 | 270 | obs.obs_source_update(source,settings) 271 | 272 | obs.obs_sceneitem_set_visible(sceneitem,True) 273 | 274 | obs.obs_data_release(settings) 275 | obs.obs_source_release(scenesource) 276 | 277 | #obs.script_log(obs.LOG_DEBUG,"Should be visible now...") 278 | 279 | def testplay(props,prop): 280 | obs.script_log(obs.LOG_DEBUG, "Hit the test play button") 281 | playsound(testfile,100); 282 | 283 | def script_defaults(settings): 284 | global sourcename 285 | global audiofolder 286 | global testfile 287 | global portnum 288 | 289 | sourcename= "" 290 | audiofolder = "" 291 | testfile = "" 292 | portnum = 8888 293 | 294 | def script_properties(): 295 | props = obs.obs_properties_create() 296 | 297 | obs.obs_properties_add_text(props, "sourcename", "Media Source Name", obs.OBS_TEXT_DEFAULT) 298 | obs.obs_properties_add_text(props, "audiofolder", "Audio Folder", obs.OBS_TEXT_DEFAULT) 299 | obs.obs_properties_add_text(props, "testfile", "Test File", obs.OBS_TEXT_DEFAULT) 300 | 301 | obs.obs_properties_add_button(props, "testbutton", "Test Playback", testplay) 302 | 303 | obs.obs_properties_add_int(props,"portnum","Port Number",1000,10000,1) 304 | 305 | return props 306 | --------------------------------------------------------------------------------