15 Commits
Author SHA1 Message Date
onyx_online 799ae52b02 add prettier settings 2023-05-26 21:17:17 +01:00
onyx_online bc93654297 move identify payload out of auth block
patch bump
2022-11-25 18:05:10 +00:00
onyx_online 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
onyx_online 43ecfb37f5 upd gemfile.lock 2022-11-18 15:00:34 +00:00
onyx_online 2e70c63ae7 fix patch ver 2022-11-18 14:54:29 +00:00
onyx_online 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
View File
@@ -0,0 +1,4 @@
{
"singleQuote": false,
"tabWidth": 2
}
+1 -1
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)
+13
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:
+14
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
+2 -2
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"
+2 -2
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
+1 -1
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
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__
+9
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"
+27
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
+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__
+12 -12
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
+24 -27
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]
+15 -4
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
+1 -1
View File
@@ -7,7 +7,7 @@ module OBSWS
end end
def minor def minor
0 1
end end
def patch def patch