import logging import obsws_python as obsws from . import configuration from .layer import ILayer from .states import OBSWSState from .util import ensure_obsws logger = logging.getLogger(__name__) class OBSWS(ILayer): def __init__(self, duckypad): super().__init__(duckypad) self.request = self.event = None self._state = OBSWSState() @property def identifier(self): return type(self).__name__ @property def state(self): return self._state @state.setter def state(self, val): self._state = val def reset_states(self): resp = self.request.get_input_mute("Mic/Aux") self.state.mute_mic = resp.input_muted resp = self.request.get_stream_status() self._duckypad.stream.is_live = resp.output_active def obs_connect(self): try: conn = configuration.get("obsws") assert conn is not None, "expected configuration for obs" self.request = obsws.ReqClient(**conn) self.reset_states() self.event = obsws.EventClient(**conn) self.event.callback.register( [ self.on_stream_state_changed, self.on_input_mute_state_changed, self.on_current_program_scene_changed, self.on_exit_started, ] ) except (ConnectionRefusedError, TimeoutError) as e: self.logger.error(f"{type(e).__name__}: {e}") raise def on_current_program_scene_changed(self, data): self._duckypad.stream.current_scene = data.scene_name self.logger.info(f"scene switched to {self._duckypad.stream.current_scene}") if self._duckypad.stream.current_scene in ("START", "BRB", "END"): self.mute_mic_state(True) def on_input_mute_state_changed(self, data): if data.input_name == "Mic/Aux": self.state.mute_mic = data.input_muted self.logger.info(f"mic was {'muted' if self.state.mute_mic else 'unmuted'}") def on_stream_state_changed(self, data): self._duckypad.stream.is_live = data.output_active self.logger.info( f"stream is {'live' if self._duckypad.stream.is_live else 'offline'}" ) def on_exit_started(self, _): self.event.unsubscribe() @ensure_obsws def call(self, fn_name, *args): fn = getattr(self.request, fn_name) resp = fn(*args) return resp def start(self): self.call("set_current_program_scene", "START") def brb(self): self.call("set_current_program_scene", "BRB") def end(self): self.call("set_current_program_scene", "END") def live(self): self.call("set_current_program_scene", "LIVE") def mute_mic_state(self, val): self.call("set_input_mute", "Mic/Aux", val) def toggle_mute_mic(self): self.call("toggle_input_mute", "Mic/Aux") def toggle_stream(self): self.call("toggle_stream")