Compare commits

15 Commits

Author SHA1 Message Date
799ae52b02 add prettier settings 2023-05-26 21:17:17 +01:00
bc93654297 move identify payload out of auth block
patch bump
2022-11-25 18:05:10 +00:00
aafcd185d0 patch bump
add full request payload to logger.

raise OBSWSError if auth enabled but no password provided

add example tasks to rake file

add logging section to README
2022-11-25 17:57:56 +00:00
43ecfb37f5 upd gemfile.lock 2022-11-18 15:00:34 +00:00
2e70c63ae7 fix patch ver 2022-11-18 14:54:29 +00:00
c67ce47026 pass payload for call_vendor_request
patch bump
2022-11-18 14:52:28 +00:00
norm
0bac7eaf3a added missing response classes
patch bump
2022-11-03 04:11:59 +00:00
norm
5b0ce79e46 fix bug in get_group_list
patch bump
2022-11-03 03:36:56 +00:00
norm
a0f5d8e57b add levels example 2022-10-27 06:45:52 +01:00
norm
f1a1c970e0 add low, high, all constants to SUBS 2022-10-27 06:45:21 +01:00
onyx-and-iris
449684c405 upd gemfile.lock files 2022-10-25 00:33:24 +01:00
onyx-and-iris
da5ef76c81 minor bump 2022-10-25 00:06:10 +01:00
onyx-and-iris
8752132012 scene rotate example added 2022-10-25 00:05:12 +01:00
onyx-and-iris
fb162ca195 logger level set to info in events example 2022-10-25 00:04:28 +01:00
onyx-and-iris
b33fe94cee moved logger auth success to req,event classes
override to_s for req,event classes

rename authenticate to identify in base class
2022-10-25 00:03:43 +01:00
15 changed files with 200 additions and 50 deletions

4
.prettierrc Normal file
View File

@@ -0,0 +1,4 @@
{
"singleQuote": false,
"tabWidth": 2
}

View File

@@ -1,7 +1,7 @@
PATH PATH
remote: . remote: .
specs: specs:
obsws (0.0.3) obsws (0.1.3)
observer (~> 0.1.1) observer (~> 0.1.1)
waitutil (~> 0.2.1) waitutil (~> 0.2.1)
websocket-driver (~> 0.7.5) websocket-driver (~> 0.7.5)

View File

@@ -115,6 +115,19 @@ If a request fails an `OBSWSError` will be raised with a status code.
For a full list of status codes refer to [Codes](https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#requeststatus) For a full list of status codes refer to [Codes](https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#requeststatus)
### Logging
To see the raw messages set log level to debug
example:
```ruby
require "obsws"
OBSWS::LOGGER.debug!
...
```
### Tests ### Tests
To run all tests: To run all tests:

View File

@@ -1,5 +1,7 @@
require "minitest/test_task" require "minitest/test_task"
HERE = File.expand_path File.dirname(__FILE__)
Minitest::TestTask.create(:test) do |t| Minitest::TestTask.create(:test) do |t|
t.libs << "test" t.libs << "test"
t.warning = false t.warning = false
@@ -7,3 +9,15 @@ Minitest::TestTask.create(:test) do |t|
end end
task default: :test task default: :test
task :events do
filepath = File.join(HERE, "examples", "events", "main.rb")
ruby filepath
end
task :levels do
filepath = File.join(HERE, "examples", "levels", "main.rb")
ruby filepath
end
task :scene_rotate do
filepath = File.join(HERE, "examples", "scene_rotate", "main.rb")
ruby filepath
end

View File

@@ -4,6 +4,6 @@ source "https://rubygems.org"
# gem "rails" # gem "rails"
gem "perfect_toml", "~> 0.9.0"
gem "obsws", path: "../.." gem "obsws", path: "../.."
gem "perfect_toml", "~> 0.9.0"

View File

@@ -1,7 +1,7 @@
PATH PATH
remote: ../.. remote: ../..
specs: specs:
obsws (0.0.2) obsws (0.1.0)
observer (~> 0.1.1) observer (~> 0.1.1)
waitutil (~> 0.2.1) waitutil (~> 0.2.1)
websocket-driver (~> 0.7.5) websocket-driver (~> 0.7.5)
@@ -24,4 +24,4 @@ DEPENDENCIES
perfect_toml (~> 0.9.0) perfect_toml (~> 0.9.0)
BUNDLED WITH BUNDLED WITH
2.3.24 2.3.22

View File

@@ -1,7 +1,7 @@
require "obsws" require "obsws"
require "perfect_toml" require "perfect_toml"
OBSWS::LOGGER.debug! OBSWS::LOGGER.info!
class Observer class Observer
attr_reader :running attr_reader :running

53
examples/levels/main.rb Normal file
View File

@@ -0,0 +1,53 @@
require "obsws"
require "perfect_toml"
OBSWS::LOGGER.info!
DEVICE = "Desktop Audio"
module LevelTypes
VU = 0
POSTFADER = 1
PREFADER = 2
end
class Observer
attr_reader :running
def initialize(**kwargs)
kwargs[:subs] = OBSWS::Events::SUBS::LOW_VOLUME | OBSWS::Events::SUBS::INPUTVOLUMEMETERS
@e_client = OBSWS::Events::Client.new(**kwargs)
@e_client.add_observer(self)
end
def on_input_mute_state_changed(data)
"""An input's mute state has changed."""
if data.input_name == DEVICE
puts "#{DEVICE} mute toggled"
end
end
def on_input_volume_meters(data)
def fget(x) = x > 0 ? (20 * Math.log(x, 10)).round(1) : -200.0
data.inputs.each do |d|
name = d[:inputName]
if name == DEVICE && !d[:inputLevelsMul].empty?
left, right = d[:inputLevelsMul]
puts "#{name} [L: #{fget(left[LevelTypes::POSTFADER])}, R: #{fget(right[LevelTypes::POSTFADER])}]"
end
end
end
end
def conn_from_toml
PerfectTOML.load_file("obs.toml", symbolize_names: true)[:connection]
end
def main
o = Observer.new(**conn_from_toml)
puts "press <Enter> to quit"
loop { exit if gets.chomp.empty? }
end
main if $0 == __FILE__

View File

@@ -0,0 +1,9 @@
# frozen_string_literal: true
source "https://rubygems.org"
# gem "rails"
gem "obsws", path: "../.."
gem "perfect_toml", "~> 0.9.0"

View File

@@ -0,0 +1,27 @@
PATH
remote: ../..
specs:
obsws (0.1.0)
observer (~> 0.1.1)
waitutil (~> 0.2.1)
websocket-driver (~> 0.7.5)
GEM
remote: https://rubygems.org/
specs:
observer (0.1.1)
perfect_toml (0.9.0)
waitutil (0.2.1)
websocket-driver (0.7.5)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5)
PLATFORMS
x64-mingw-ucrt
DEPENDENCIES
obsws!
perfect_toml (~> 0.9.0)
BUNDLED WITH
2.3.22

View File

@@ -0,0 +1,22 @@
require "obsws"
require "perfect_toml"
OBSWS::LOGGER.info!
def conn_from_toml
PerfectTOML.load_file("obs.toml", symbolize_names: true)[:connection]
end
def main
r_client = OBSWS::Requests::Client.new(**conn_from_toml)
r_client.run do
resp = r_client.get_scene_list
resp.scenes.reverse.each do |s|
puts "Switching to scene #{s[:sceneName]}"
r_client.set_current_program_scene(s[:sceneName])
sleep(0.5)
end
end
end
main if $0 == __FILE__

View File

@@ -45,12 +45,12 @@ module OBSWS
@closed = true @closed = true
end end
@driver.on :message do |msg| @driver.on :message do |msg|
LOGGER.debug("received [#{msg}] passing to handler") LOGGER.debug("received: #{msg.data}")
msg_handler(JSON.parse(msg.data, symbolize_names: true)) msg_handler(JSON.parse(msg.data, symbolize_names: true))
end end
start_driver start_driver
WaitUtil.wait_for_condition( WaitUtil.wait_for_condition(
"waiting successful identification", "successful identification",
delay_sec: 0.01, delay_sec: 0.01,
timeout_sec: 3 timeout_sec: 3
) { @identified } ) { @identified }
@@ -74,7 +74,7 @@ module OBSWS
) )
end end
def authenticate(auth = nil) def identify(auth)
payload = { payload = {
op: Mixin::OPCodes::IDENTIFY, op: Mixin::OPCodes::IDENTIFY,
d: { d: {
@@ -82,21 +82,21 @@ module OBSWS
eventSubscriptions: @subs eventSubscriptions: @subs
} }
} }
payload[:d][:authentication] = auth_token(**auth) if auth if auth
if @password.empty?
raise OBSWSError("auth enabled but no password provided")
end
LOGGER.info("initiating authentication")
payload[:d][:authentication] = auth_token(**auth)
end
@driver.text(JSON.generate(payload)) @driver.text(JSON.generate(payload))
end end
def msg_handler(data) def msg_handler(data)
case data[:op] case data[:op]
when Mixin::OPCodes::HELLO when Mixin::OPCodes::HELLO
if data[:d].key? :authentication identify(data[:d][:authentication])
LOGGER.debug("initiating authentication")
else
LOGGER.debug("authentication disabled... skipping.")
end
authenticate(data[:d][:authentication])
when Mixin::OPCodes::IDENTIFIED when Mixin::OPCodes::IDENTIFIED
LOGGER.debug("client succesfully identified with server")
@identified = true @identified = true
when Mixin::OPCodes::EVENT, Mixin::OPCodes::REQUESTRESPONSE when Mixin::OPCodes::EVENT, Mixin::OPCodes::REQUESTRESPONSE
changed changed
@@ -113,8 +113,8 @@ module OBSWS
} }
} }
payload[:d][:requestData] = data if data payload[:d][:requestData] = data if data
LOGGER.debug("sending request: #{payload}")
queued = @driver.text(JSON.generate(payload)) queued = @driver.text(JSON.generate(payload))
LOGGER.debug("request with id #{id} queued? #{queued}")
end end
end end
end end

View File

@@ -7,38 +7,30 @@ module OBSWS
module Events module Events
module SUBS module SUBS
NONE = 0 NONE = 0
GENERAL = (1 << 0) GENERAL = 1 << 0
CONFIG = (1 << 1) CONFIG = 1 << 1
SCENES = (1 << 2) SCENES = 1 << 2
INPUTS = (1 << 3) INPUTS = 1 << 3
TRANSITIONS = (1 << 4) TRANSITIONS = 1 << 4
FILTERS = (1 << 5) FILTERS = 1 << 5
OUTPUTS = (1 << 6) OUTPUTS = 1 << 6
SCENEITEMS = (1 << 7) SCENEITEMS = 1 << 7
MEDIAINPUTS = (1 << 8) MEDIAINPUTS = 1 << 8
VENDORS = (1 << 9) VENDORS = 1 << 9
UI = (1 << 10) UI = 1 << 10
def low_volume LOW_VOLUME = GENERAL | CONFIG | SCENES | INPUTS | TRANSITIONS | FILTERS | OUTPUTS |
GENERAL | CONFIG | SCENES | INPUTS | TRANSITIONS | FILTERS | OUTPUTS |
SCENEITEMS | MEDIAINPUTS | VENDORS | UI SCENEITEMS | MEDIAINPUTS | VENDORS | UI
end
INPUTVOLUMEMETERS = (1 << 16) INPUTVOLUMEMETERS = 1 << 16
INPUTACTIVESTATECHANGED = (1 << 17) INPUTACTIVESTATECHANGED = 1 << 17
INPUTSHOWSTATECHANGED = (1 << 18) INPUTSHOWSTATECHANGED = 1 << 18
SCENEITEMTRANSFORMCHANGED = (1 << 19) SCENEITEMTRANSFORMCHANGED = 1 << 19
def high_volume HIGH_VOLUME = INPUTVOLUMEMETERS | INPUTACTIVESTATECHANGED | INPUTSHOWSTATECHANGED |
INPUTVOLUMEMETERS | INPUTACTIVESTATECHANGED | INPUTSHOWSTATECHANGED |
SCENEITEMTRANSFORMCHANGED SCENEITEMTRANSFORMCHANGED
end
def all ALL = LOW_VOLUME | HIGH_VOLUME
low_volume | high_volume
end
module_function :low_volume, :high_volume, :all
end end
module Callbacks module Callbacks
@@ -75,11 +67,16 @@ module OBSWS
include Mixin::OPCodes include Mixin::OPCodes
def initialize(**kwargs) def initialize(**kwargs)
kwargs[:subs] = SUBS.low_volume kwargs[:subs] ||= SUBS::LOW_VOLUME
@base_client = Base.new(**kwargs) @base_client = Base.new(**kwargs)
LOGGER.info("#{self} succesfully identified with server")
@base_client.add_observer(self) @base_client.add_observer(self)
end end
def to_s
"#{self.class.name.split("::").last(2).join("::")}"
end
def update(op_code, data) def update(op_code, data)
if op_code == Mixin::OPCodes::EVENT if op_code == Mixin::OPCodes::EVENT
event = data[:eventType] event = data[:eventType]

View File

@@ -14,16 +14,21 @@ module OBSWS
def initialize(**kwargs) def initialize(**kwargs)
@base_client = Base.new(**kwargs) @base_client = Base.new(**kwargs)
LOGGER.info("#{self} succesfully identified with server")
@base_client.add_observer(self) @base_client.add_observer(self)
@response = { requestId: 0 } @response = { requestId: 0 }
end end
def to_s
"#{self.class.name.split("::").last(2).join("::")}"
end
def run def run
yield yield
ensure ensure
close close
WaitUtil.wait_for_condition( WaitUtil.wait_for_condition(
"driver has closed", "driver to close",
delay_sec: 0.01, delay_sec: 0.01,
timeout_sec: 1 timeout_sec: 1
) { @base_client.closed } ) { @base_client.closed }
@@ -37,7 +42,7 @@ module OBSWS
id = rand(1..1000) id = rand(1..1000)
@base_client.req(id, req, data) @base_client.req(id, req, data)
WaitUtil.wait_for_condition( WaitUtil.wait_for_condition(
"reponse id matches request id", "reponse id to match request id",
delay_sec: 0.001, delay_sec: 0.001,
timeout_sec: 3 timeout_sec: 3
) { @response[:requestId] == id } ) { @response[:requestId] == id }
@@ -72,7 +77,10 @@ module OBSWS
end end
def call_vendor_request(name, type_, data = nil) def call_vendor_request(name, type_, data = nil)
call(requestType, requestData) payload = { vendorName: name, requestType: type_ }
payload[:requestData] = data if data
resp = call("CallVendorRequest", payload)
Mixin::Response.new(resp, resp.keys)
end end
def get_hotkey_list def get_hotkey_list
@@ -256,7 +264,7 @@ module OBSWS
end end
def get_group_list def get_group_list
resp = call("GetSceneList") resp = call("GetGroupList")
Mixin::Response.new(resp, resp.keys) Mixin::Response.new(resp, resp.keys)
end end
@@ -324,6 +332,7 @@ module OBSWS
def get_special_inputs def get_special_inputs
resp = call("GetSpecialInputs") resp = call("GetSpecialInputs")
Mixin::Response.new(resp, resp.keys)
end end
def create_input( def create_input(
@@ -341,6 +350,7 @@ module OBSWS
sceneItemEnabled: scene_item_enabled sceneItemEnabled: scene_item_enabled
} }
resp = call("CreateInput", payload) resp = call("CreateInput", payload)
Mixin::Response.new(resp, resp.keys)
end end
def remove_input(name) def remove_input(name)
@@ -823,6 +833,7 @@ module OBSWS
def stop_record def stop_record
resp = call("StopRecord") resp = call("StopRecord")
Mixin::Response.new(resp, resp.keys)
end end
def toggle_record_pause def toggle_record_pause

View File

@@ -7,7 +7,7 @@ module OBSWS
end end
def minor def minor
0 1
end end
def patch def patch