require "waitutil" require_relative "base" require_relative "error" require_relative "util" require_relative "mixin" module OBSWS module Requests class Client include Error include Mixin::TearDown include Mixin::OPCodes def initialize(**kwargs) @base_client = Base.new(**kwargs) @base_client.add_observer(self) @response = { requestId: 0 } end def run yield ensure close WaitUtil.wait_for_condition( "driver has closed", delay_sec: 0.01, timeout_sec: 1 ) { @base_client.closed } end def update(op_code, data) @response = data if op_code == Mixin::OPCodes::REQUESTRESPONSE end def call(req, data = nil) id = rand(1..1000) @base_client.req(id, req, data) WaitUtil.wait_for_condition( "reponse id matches request id", delay_sec: 0.001, timeout_sec: 3 ) { @response[:requestId] == id } if !@response[:requestStatus][:result] error = [ "Request #{@response[:requestType]} returned code #{@response[:requestStatus][:code]}" ] if @response[:requestStatus].key?(:comment) error += ["With message: #{@response[:requestStatus][:comment]}"] end raise OBSWSError.new(error.join("\n")) end @response[:responseData] rescue WaitUtil::TimeoutError msg = "no response with matching id received" LOGGER.error(msg) raise OBSWSError.new(msg) end def get_version resp = call("GetVersion") Mixin::Response.new(resp, resp.keys) end def get_stats resp = call("GetStats") Mixin::Response.new(resp, resp.keys) end def broadcast_custom_event(data) call("BroadcastCustomEvent", data) end def call_vendor_request(name, type_, data = nil) call(requestType, requestData) end def get_hotkey_list resp = call("GetHotkeyList") Mixin::Response.new(resp, resp.keys) end def trigger_hotkey_by_name(name) payload = { hotkeyName: name } call("TriggerHotkeyByName", payload) end def trigger_hotkey_by_key_sequence( key_id, press_shift, press_ctrl, press_alt, press_cmd ) payload = { keyId: key_id, keyModifiers: { shift: press_shift, control: press_ctrl, alt: press_alt, cmd: press_cmd } } call("TriggerHotkeyByKeySequence", payload) end def sleep(sleep_millis = nil, sleep_frames = nil) payload = { sleepMillis: sleep_millis, sleepFrames: sleep_frames } call("Sleep", payload) end def get_persistent_data(realm, slot_name) payload = { realm: realm, slotName: slot_name } resp = call("GetPersistentData", payload) Mixin::Response.new(resp, resp.keys) end def set_persistent_data(realm, slot_name, slot_value) payload = { realm: realm, slotName: slot_name, slotValue: slot_value } call("SetPersistentData", payload) end def get_scene_collection_list resp = call("GetSceneCollectionList") Mixin::Response.new(resp, resp.keys) end def set_current_scene_collection(name) payload = { sceneCollectionName: name } call("SetCurrentSceneCollection", payload) end def create_scene_collection(name) payload = { sceneCollectionName: name } call("CreateSceneCollection", payload) end def get_profile_list resp = call("GetProfileList") Mixin::Response.new(resp, resp.keys) end def set_current_profile(name) payload = { profileName: name } call("SetCurrentProfile", payload) end def create_profile(name) payload = { profileName: name } call("CreateProfile", payload) end def remove_profile(name) payload = { profileName: name } call("RemoveProfile", payload) end def get_profile_parameter(category, name) payload = { parameterCategory: category, parameterName: name } resp = call("GetProfileParameter", payload) Mixin::Response.new(resp, resp.keys) end def set_profile_parameter(category, name, value) payload = { parameterCategory: category, parameterName: name, parameterValue: value } call("SetProfileParameter", payload) end def get_video_settings resp = call("GetVideoSettings") Mixin::Response.new(resp, resp.keys) end def set_video_settings( numerator, denominator, base_width, base_height, out_width, out_height ) payload = { fpsNumerator: numerator, fpsDenominator: denominator, baseWidth: base_width, baseHeight: base_height, outputWidth: out_width, outputHeight: out_height } call("SetVideoSettings", payload) end def get_stream_service_settings resp = call("GetStreamServiceSettings") Mixin::Response.new(resp, resp.keys) end def set_stream_service_settings(ss_type, ss_settings) payload = { streamServiceType: ss_type, streamServiceSettings: ss_settings } call("SetStreamServiceSettings", payload) end def get_record_directory resp = call("GetRecordDirectory") Mixin::Response.new(resp, resp.keys) end def get_source_active(name) payload = { sourceName: name } resp = call("GetSourceActive", payload) Mixin::Response.new(resp, resp.keys) end def get_source_screenshot(name, img_format, width, height, quality) payload = { sourceName: name, imageFormat: img_format, imageWidth: width, imageHeight: height, imageCompressionQuality: quality } resp = call("GetSourceScreenshot", payload) Mixin::Response.new(resp, resp.keys) end def save_source_screenshot( name, img_format, file_path, width, height, quality ) payload = { sourceName: name, imageFormat: img_format, imageFilePath: file_path, imageWidth: width, imageHeight: height, imageCompressionQuality: quality } resp = call("SaveSourceScreenshot", payload) Mixin::Response.new(resp, resp.keys) end def get_scene_list resp = call("GetSceneList") Mixin::Response.new(resp, resp.keys) end def get_group_list resp = call("GetSceneList") Mixin::Response.new(resp, resp.keys) end def get_current_program_scene resp = call("GetCurrentProgramScene") Mixin::Response.new(resp, resp.keys) end def set_current_program_scene(name) payload = { sceneName: name } call("SetCurrentProgramScene", payload) end def get_current_preview_scene resp = call("GetCurrentPreviewScene") Mixin::Response.new(resp, resp.keys) end def set_current_preview_scene(name) payload = { sceneName: name } call("SetCurrentPreviewScene", payload) end def create_scene(name) payload = { sceneName: name } call("CreateScene", payload) end def remove_scene(name) payload = { sceneName: name } call("RemoveScene", payload) end def set_scene_name(old_name, new_name) payload = { sceneName: old_name, newSceneName: new_name } call("SetSceneName", payload) end def get_scene_scene_transition_override(name) payload = { sceneName: name } resp = call("GetSceneSceneTransitionOverride", payload) Mixin::Response.new(resp, resp.keys) end def set_scene_scene_transition_override(scene_name, tr_name, tr_duration) payload = { sceneName: scene_name, transitionName: tr_name, transitionDuration: tr_duration } call("SetSceneSceneTransitionOverride", payload) end def get_input_list(kind = nil) payload = { inputKind: kind } resp = call("GetInputList", payload) Mixin::Response.new(resp, resp.keys) end def get_input_kind_list(unversioned) payload = { unversioned: unversioned } resp = call("GetInputKindList", payload) Mixin::Response.new(resp, resp.keys) end def get_special_inputs resp = call("GetSpecialInputs") end def create_input( scene_name, input_name, input_kind, input_settings, scene_item_enabled ) payload = { sceneName: scene_name, inputName: input_name, inputKind: input_kind, inputSettings: input_settings, sceneItemEnabled: scene_item_enabled } resp = call("CreateInput", payload) end def remove_input(name) payload = { inputName: name } call("RemoveInput", payload) end def set_input_name(old_name, new_name) payload = { inputName: old_name, newInputName: new_name } call("SetInputName", payload) end def get_input_default_settings(kind) payload = { inputKind: kind } resp = call("GetInputDefaultSettings", payload) Mixin::Response.new(resp, resp.keys) end def get_input_settings(name) payload = { inputName: name } resp = call("GetInputSettings", payload) Mixin::Response.new(resp, resp.keys) end def set_input_settings(name, settings, overlay) payload = { inputName: name, inputSettings: settings, overlay: overlay } call("SetInputSettings", payload) end def get_input_mute(name) payload = { inputName: name } resp = call("GetInputMute", payload) Mixin::Response.new(resp, resp.keys) end def set_input_mute(name, muted) payload = { inputName: name, inputMuted: muted } call("SetInputMute", payload) end def toggle_input_mute(name) payload = { inputName: name } resp = call("ToggleInputMute", payload) Mixin::Response.new(resp, resp.keys) end def get_input_volume(name) payload = { inputName: name } resp = call("GetInputVolume", payload) Mixin::Response.new(resp, resp.keys) end def set_input_volume(name, vol_mul = nil, vol_db = nil) payload = { inputName: name, inputVolumeMul: vol_mul, inputVolumeDb: vol_db } call("SetInputVolume", payload) end def get_input_audio_balance(name) payload = { inputName: name } resp = call("GetInputAudioBalance", payload) Mixin::Response.new(resp, resp.keys) end def set_input_audio_balance(name, balance) payload = { inputName: name, inputAudioBalance: balance } call("SetInputAudioBalance", payload) end def get_input_audio_sync_offset(name) payload = { inputName: name } resp = call("GetInputAudioSyncOffset", payload) Mixin::Response.new(resp, resp.keys) end def set_input_audio_sync_offset(name, offset) payload = { inputName: name, inputAudioSyncOffset: offset } call("SetInputAudioSyncOffset", payload) end def get_input_audio_monitor_type(name) payload = { inputName: name } resp = call("GetInputAudioMonitorType", payload) Mixin::Response.new(resp, resp.keys) end def set_input_audio_monitor_type(name, mon_type) payload = { inputName: name, monitorType: mon_type } call("SetInputAudioMonitorType", payload) end def get_input_audio_tracks(name) payload = { inputName: name } resp = call("GetInputAudioTracks", payload) Mixin::Response.new(resp, resp.keys) end def set_input_audio_tracks(name, track) payload = { inputName: name, inputAudioTracks: track } call("SetInputAudioTracks", payload) end def get_input_properties_list_property_items(input_name, prop_name) payload = { inputName: input_name, propertyName: prop_name } resp = call("GetInputPropertiesListPropertyItems", payload) Mixin::Response.new(resp, resp.keys) end def press_input_properties_button(input_name, prop_name) payload = { inputName: input_name, propertyName: prop_name } call("PressInputPropertiesButton", payload) end def get_transition_kind_list resp = call("GetTransitionKindList") Mixin::Response.new(resp, resp.keys) end def get_scene_transition_list resp = call("GetSceneTransitionList") Mixin::Response.new(resp, resp.keys) end def get_current_scene_transition resp = call("GetCurrentSceneTransition") Mixin::Response.new(resp, resp.keys) end def set_current_scene_transition(name) payload = { transitionName: name } call("SetCurrentSceneTransition", payload) end def set_current_scene_transition_duration(duration) payload = { transitionDuration: duration } call("SetCurrentSceneTransitionDuration", payload) end def set_current_scene_transition_settings(settings, overlay = nil) payload = { transitionSettings: settings, overlay: overlay } call("SetCurrentSceneTransitionSettings", payload) end def get_current_scene_transition_cursor resp = call("GetCurrentSceneTransitionCursor") Mixin::Response.new(resp, resp.keys) end def trigger_studio_mode_transition call("TriggerStudioModeTransition") end def set_t_bar_position(pos, release = nil) payload = { position: pos, release: release } call("SetTBarPosition", payload) end def get_source_filter_list(name) payload = { sourceName: name } resp = call("GetSourceFilterList", payload) Mixin::Response.new(resp, resp.keys) end def get_source_filter_default_settings(kind) payload = { filterKind: kind } resp = call("GetSourceFilterDefaultSettings", payload) Mixin::Response.new(resp, resp.keys) end def create_source_filter( source_name, filter_name, filter_kind, filter_settings = nil ) payload = { sourceName: source_name, filterName: filter_name, filterKind: filter_kind, filterSettings: filter_settings } call("CreateSourceFilter", payload) end def remove_source_filter(source_name, filter_name) payload = { sourceName: source_name, filterName: filter_name } call("RemoveSourceFilter", payload) end def set_source_filter_name(source_name, old_filter_name, new_filter_name) payload = { sourceName: source_name, filterName: old_filter_name, newFilterName: new_filter_name } call("SetSourceFilterName", payload) end def get_source_filter(source_name, filter_name) payload = { sourceName: source_name, filterName: filter_name } resp = call("GetSourceFilter", payload) Mixin::Response.new(resp, resp.keys) end def set_source_filter_index(source_name, filter_name, filter_index) payload = { sourceName: source_name, filterName: filter_name, filterIndex: filter_index } call("SetSourceFilterIndex", payload) end def set_source_filter_settings( source_name, filter_name, settings, overlay = nil ) payload = { sourceName: source_name, filterName: filter_name, filterSettings: settings, overlay: overlay } call("SetSourceFilterSettings", payload) end def set_source_filter_enabled(source_name, filter_name, enabled) payload = { sourceName: source_name, filterName: filter_name, filterEnabled: enabled } call("SetSourceFilterEnabled", payload) end def get_scene_item_list(name) payload = { sceneName: name } resp = call("GetSceneItemList", payload) Mixin::Response.new(resp, resp.keys) end def get_group_scene_item_list(name) payload = { sceneName: name } resp = call("GetGroupSceneItemList", payload) Mixin::Response.new(resp, resp.keys) end def get_scene_item_id(scene_name, source_name, offset = nil) payload = { sceneName: scene_name, sourceName: source_name, searchOffset: offset } resp = call("GetSceneItemId", payload) Mixin::Response.new(resp, resp.keys) end def create_scene_item(scene_name, source_name, enabled = nil) payload = { sceneName: scene_name, sourceName: source_name, sceneItemEnabled: enabled } resp = call("CreateSceneItem", payload) Mixin::Response.new(resp, resp.keys) end def remove_scene_item(scene_name, item_id) payload = { sceneName: scene_name, sceneItemId: item_id } call("RemoveSceneItem", payload) end def duplicate_scene_item(scene_name, item_id, dest_scene_name = nil) payload = { sceneName: scene_name, sceneItemId: item_id, destinationSceneName: dest_scene_name } resp = call("DuplicateSceneItem", payload) Mixin::Response.new(resp, resp.keys) end def get_scene_item_transform(scene_name, item_id) payload = { sceneName: scene_name, sceneItemId: item_id } resp = call("GetSceneItemTransform", payload) Mixin::Response.new(resp, resp.keys) end def set_scene_item_transform(scene_name, item_id, transform) payload = { sceneName: scene_name, sceneItemId: item_id, sceneItemTransform: transform } call("SetSceneItemTransform", payload) end def get_scene_item_enabled(scene_name, item_id) payload = { sceneName: scene_name, sceneItemId: item_id } resp = call("GetSceneItemEnabled", payload) Mixin::Response.new(resp, resp.keys) end def set_scene_item_enabled(scene_name, item_id, enabled) payload = { sceneName: scene_name, sceneItemId: item_id, sceneItemEnabled: enabled } call("SetSceneItemEnabled", payload) end def get_scene_item_locked(scene_name, item_id) payload = { sceneName: scene_name, sceneItemId: item_id } resp = call("GetSceneItemLocked", payload) Mixin::Response.new(resp, resp.keys) end def set_scene_item_locked(scene_name, item_id, locked) payload = { sceneName: scene_name, sceneItemId: item_id, sceneItemLocked: locked } call("SetSceneItemLocked", payload) end def get_scene_item_index(scene_name, item_id) payload = { sceneName: scene_name, sceneItemId: item_id } resp = call("GetSceneItemIndex", payload) Mixin::Response.new(resp, resp.keys) end def set_scene_item_index(scene_name, item_id, item_index) payload = { sceneName: scene_name, sceneItemId: item_id, sceneItemLocked: item_index } call("SetSceneItemIndex", payload) end def get_scene_item_blend_mode(scene_name, item_id) payload = { sceneName: scene_name, sceneItemId: item_id } resp = call("GetSceneItemBlendMode", payload) Mixin::Response.new(resp, resp.keys) end def set_scene_item_blend_mode(scene_name, item_id, blend) payload = { sceneName: scene_name, sceneItemId: item_id, sceneItemBlendMode: blend } call("SetSceneItemBlendMode", payload) end def get_virtual_cam_status resp = call("GetVirtualCamStatus") Mixin::Response.new(resp, resp.keys) end def toggle_virtual_cam resp = call("ToggleVirtualCam") Mixin::Response.new(resp, resp.keys) end def start_virtual_cam call("StartVirtualCam") end def stop_virtual_cam call("StopVirtualCam") end def get_replay_buffer_status resp = call("GetReplayBufferStatus") Mixin::Response.new(resp, resp.keys) end def toggle_replay_buffer resp = call("ToggleReplayBuffer") Mixin::Response.new(resp, resp.keys) end def start_replay_buffer call("StartReplayBuffer") end def stop_replay_buffer call("StopReplayBuffer") end def save_replay_buffer call("SaveReplayBuffer") end def get_last_replay_buffer_replay resp = call("GetLastReplayBufferReplay") Mixin::Response.new(resp, resp.keys) end def get_output_list resp = call("GetOutputList") Mixin::Response.new(resp, resp.keys) end def get_output_status(name) payload = { outputName: name } resp = call("GetOutputStatus", payload) Mixin::Response.new(resp, resp.keys) end def toggle_output(name) payload = { outputName: name } resp = call("ToggleOutput", payload) Mixin::Response.new(resp, resp.keys) end def start_output(name) payload = { outputName: name } call("StartOutput", payload) end def stop_output(name) payload = { outputName: name } call("StopOutput", payload) end def get_output_settings(name) payload = { outputName: name } resp = call("GetOutputSettings", payload) Mixin::Response.new(resp, resp.keys) end def set_output_settings(name, settings) payload = { outputName: name, outputSettings: settings } call("SetOutputSettings", payload) end def get_stream_status resp = call("GetStreamStatus") Mixin::Response.new(resp, resp.keys) end def toggle_stream resp = call("ToggleStream") Mixin::Response.new(resp, resp.keys) end def start_stream call("StartStream") end def stop_stream call("StopStream") end def send_stream_caption(caption) call("SendStreamCaption") end def get_record_status resp = call("GetRecordStatus") Mixin::Response.new(resp, resp.keys) end def toggle_record call("ToggleRecord") end def start_record call("StartRecord") end def stop_record resp = call("StopRecord") end def toggle_record_pause call("ToggleRecordPause") end def pause_record call("PauseRecord") end def resume_record call("ResumeRecord") end def get_media_input_status(name) payload = { inputName: name } resp = call("GetMediaInputStatus", payload) Mixin::Response.new(resp, resp.keys) end def set_media_input_cursor(name, cursor) payload = { inputName: name, mediaCursor: cursor } call("SetMediaInputCursor", payload) end def offset_media_input_cursor(name, offset) payload = { inputName: name, mediaCursorOffset: offset } call("OffsetMediaInputCursor", payload) end def trigger_media_input_action(name, action) payload = { inputName: name, mediaAction: action } call("TriggerMediaInputAction", payload) end def get_studio_mode_enabled resp = call("GetStudioModeEnabled") Mixin::Response.new(resp, resp.keys) end def set_studio_mode_enabled(enabled) payload = { studioModeEnabled: enabled } call("SetStudioModeEnabled", payload) end def open_input_properties_dialog(name) payload = { inputName: name } call("OpenInputPropertiesDialog", payload) end def open_input_filters_dialog(name) payload = { inputName: name } call("OpenInputFiltersDialog", payload) end def open_input_interact_dialog(name) payload = { inputName: name } call("OpenInputInteractDialog", payload) end def get_monitor_list resp = call("GetMonitorList") Mixin::Response.new(resp, resp.keys) end end end end