OBS WebSocket RemoteControl¶
Introduction¶
What’s this?¶
obs-ws-rc is a Python 3.5+ library that allows you to establish client connections to the obs-websocket plugin for OBS Studio.
It’s based on asyncio-approach which it inherited from the underlying WebSocket library - websockets
Performing requests¶
Firstly, obs-websocket‘s protocol provides you with the ability to send requests and retrieve responses to and from OBS Studio.
Let’s see how it’s done with obs-ws-rc:
"""Example shows how to send requests and get responses."""
import asyncio
from obswsrc import OBSWS
from obswsrc.requests import ResponseStatus, StartStreamingRequest
from obswsrc.types import Stream, StreamSettings
async def main():
async with OBSWS('localhost', 4444, "password") as obsws:
# We can send an empty StartStreaming request (in that case the plugin
# will use OBS configuration), but let's provide some settings as well
stream_settings = StreamSettings(
server="rtmp://example.org/my_application",
key="secret_stream_key",
use_auth=False
)
stream = Stream(
settings=stream_settings,
type="rtmp_custom",
)
# Now let's actually perform a request
response = await obsws.require(StartStreamingRequest(stream=stream))
# Check if everything is OK
if response.status == ResponseStatus.OK:
print("Streaming has started")
else:
print("Couldn't start the stream! Reason:", response.error)
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()
Listening to events¶
Secondly, the plugin sends events from time to time. This library lets you listen to these events and handle them:
"""Example shows how to listen to events."""
import asyncio
import logging
import sys
from obswsrc import OBSWS
from obswsrc.logs import logger
# We will output logging to sys.stdout, as many events might raise errors
# on creation (that's because protocol.json is not perfect) - such errors
# are logged by obs-ws-rc automatically, we just need to see them
logger.setLevel(logging.ERROR)
logger.addHandler(logging.StreamHandler(stream=sys.stdout))
async def main():
async with OBSWS('localhost', 4444, "password") as obsws:
print("Connection established.")
# We will receive events here by awaiting for them (you can await for
# an event of a specific type by providing `type_name` argument to
# the obsws.event() method)
event = await obsws.event()
# Awaited event might be None if connection is closed
while event is not None:
print("Awaited for '{}' event!".format(event.type_name))
event = await obsws.event()
print("Connection terminated.")
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()
Protocol description¶
The protocol requrests, responses and events are declared in the PROTOCOL.md by the authors of the obs-websocket plugin.
However, there are minor mistakes in that file.
And the field naming of the original protocol is inconsistent.
For example, there’re fields like authRequired
, at the same time there’re
plenty of fields that use a hyphen as a word separator (like
kbits-per-sec
).
This library internally maps such fields to more pythonic names
(auth_required
and kbits_per_sec
as such) - that allows for convenient
passing fields as keyword arguments.
The version of the protocol used by this library can be found in
./obswsrc/protocol.json
.
Package: obswsrc¶
Submodules¶
obswsrc.client module¶
-
exception
obswsrc.client.
AuthError
[source]¶ Bases:
Exception
Raised by
OBSWS.connect()
if authentication has failed.
-
class
obswsrc.client.
OBSWS
(host, port=4444, password=None, *, skip_auth=False, loop=None)[source]¶ Bases:
object
Main class used for obs-websocket communication. Can be used as a context manager (given you use it in
async with
statement).Example usage:
async with OBSWS("localhost") as obsws: ...
This is an equivalent to the following:
obsws = OBSWS("localhost") await obsws.connect() try: ... finally: await obsws.close()
This class also supports Future-like protocol (it implements
__await__()
method). You can await for the OBSWS instance for it to close:await obsws
Note
When entering the context manager (using
async with
statement), you should be ready to exceptAuthError
that might raise due to failed auth, orOSError
that can be raised by the underlying websockets library in case of being unable to connect to OBS Studio.Parameters: - host (str) – Server host
- port (int) – Server port
- password (str|None) – Server password (if needed)
- skip_auth (bool) – Whether or not to skip authentication
- loop (asyncio.AbstractEventLoop|None) – Event loop to use
-
close
()[source]¶ Clean shutdown. Consequent calls on an already closed instance have not effect.
Note
This method is a coroutine.
-
closed
¶ Return whether or not this OBSWS instance is closed.
-
connect
()[source]¶ Establish connection to the server, start the event loop and perform authentication (the latter can be skipped with
skip_auth
argument in__init__()
).Raises: - ValueError – if already connected
- AuthError – if auth is enabled but password is invalid or not not set
- OSError – raised by the underlying websockets library if connection attempt is failed
Note
This method is a coroutine.
-
event
(type_name=None)[source]¶ Return a future that, when awaited for, returns an event of type
type_name
. Iftype_name
is None, the future result will be the first occurred event. If connection is closed while future is not done, the future result is None.Parameters: type_name (str|None) – Event type to await for, None
to await for an event of any typeReturns: Future Return type: asyncio.Future Raises: ValueError – if not connected Changed in version 2.3.0: This method is not a coroutine now, but it returns a
asyncio.Future
object.
-
host
¶ The host that OBSWS was instantiated with (read-only).
Returns: Server host Return type: str
-
password
¶ The port that OBSWS was instantiated with (read-only).
Returns: Server password ( None
if not given)Return type: str|None
-
port
¶ The port that OBSWS was instantiated with (read-only).
Returns: Server port Return type: int
-
register_event_handler
(type_name, callback)[source]¶ Register event handler (either a regular one or an async-coroutine).
Parameters: - type_name – Event name
- callback (callable) – Function or coroutine function
Raises: ValueError – if callback is already registered for the event
Deprecated since version 2.2: Use
event()
instead.
-
require
(request)[source]¶ Send a request to the server and await, return the response.
Parameters: request (requests.BaseRequest) – Fully formed request Returns: Response from the server (None if the connection was closed during communication) Return type: requests.BaseResponse|None Raises: ValueError – if not connected Note
This method is a coroutine.
obswsrc.events module¶
This module holds dynamically generated classes. For more info see protocol.py and protocol.json.
-
class
obswsrc.events.
BaseEvent
(*args, **kwargs)[source]¶ Bases:
obswsrc.struct.Struct
-
type_name
¶
-
-
class
obswsrc.events.
BaseEventMeta
(name, bases, namespace)[source]¶ Bases:
obswsrc.struct.StructMeta
obswsrc.protocol module¶
obswsrc.requests module¶
This module holds dynamically generated classes. For more info see protocol.py and protocol.json.
-
class
obswsrc.requests.
BaseRequest
(*args, **kwargs)[source]¶ Bases:
obswsrc.struct.Struct
-
BaseRequest.
type_name
¶
-
-
class
obswsrc.requests.
BaseResponse
(*args, **kwargs)[source]¶ Bases:
obswsrc.struct.Struct
-
class
obswsrc.requests.
BaseResponseMeta
(name, bases, namespace)[source]¶ Bases:
obswsrc.struct.StructMeta
obswsrc.struct module¶
-
class
obswsrc.struct.
Struct
(*args, **kwargs)[source]¶ Bases:
obswsrc.struct.BaseStruct
-
class
obswsrc.struct.
StructField
(attr_name, field_name, value_type, optional=False)[source]¶ Bases:
object
-
class
obswsrc.struct.
VariableStruct
(**kwargs)[source]¶ Bases:
obswsrc.struct.BaseStruct
obswsrc.types module¶
This module holds dynamically generated classes. For more info see protocol.py and protocol.json.
Protocol Reference¶
Types¶
bool¶
- Style: This type is native to Python
float¶
- Style: This type is native to Python
int¶
- Style: This type is native to Python
str¶
- Style: This type is native to Python
Font¶
- Style: This type contains statically typed fields
- Fields:
Profile¶
- Style: This type contains statically typed fields
- Fields:
- PROFILE NAME
- type: str
- pythonic name:
profile_name
- internal name: profile-name
- is optional? No
- PROFILE NAME
scene_collection_list¶
- Style: This type represents a list of objects of other type
- Item type: SceneCollection
scene_list¶
- Style: This type represents a list of objects of other type
- Item type: source_list
SceneCollection¶
- Style: This type contains statically typed fields
- Fields:
- SC NAME
- type: str
- pythonic name:
sc_name
- internal name: sc-name
- is optional? No
- SC NAME
SceneSource¶
- Style: This type contains statically typed fields
- Fields:
- NAME
- type: str
- pythonic name:
name
- internal name: name
- is optional? No
- TYPE
- type: str
- pythonic name:
type
- internal name: type
- is optional? No
- VOLUME
- type: float
- pythonic name:
volume
- internal name: volume
- is optional? No
- X
- type: float
- pythonic name:
x
- internal name: x
- is optional? No
- Y
- type: float
- pythonic name:
y
- internal name: y
- is optional? No
- SOURCE CX
- type: int
- pythonic name:
source_cx
- internal name: source_cx
- is optional? No
- SOURCE CY
- type: int
- pythonic name:
source_cy
- internal name: source_cy
- is optional? No
- CX
- type: float
- pythonic name:
cx
- internal name: cx
- is optional? No
- CY
- type: float
- pythonic name:
cy
- internal name: cy
- is optional? No
- RENDER
- type: bool
- pythonic name:
render
- internal name: render
- is optional? No
- NAME
source_list¶
- Style: This type represents a list of objects of other type
- Item type: SceneSource
Stream¶
- Style: This type contains statically typed fields
- Fields:
- SETTINGS
- type: StreamSettings
- pythonic name:
settings
- internal name: settings
- is optional? Yes
- TYPE
- type: str
- pythonic name:
type
- internal name: type
- is optional? Yes
- METADATA
- type: StreamMetadata
- pythonic name:
metadata
- internal name: metadata
- is optional? Yes
- SETTINGS
StreamMetadata¶
StreamSettings¶
- Style: This type contains statically typed fields
- Fields:
- SERVER
- type: str
- pythonic name:
server
- internal name: server
- is optional? Yes
- KEY
- type: str
- pythonic name:
key
- internal name: key
- is optional? Yes
- USE AUTH
- type: bool
- pythonic name:
use_auth
- internal name: use-auth
- is optional? Yes
- USERNAME
- type: str
- pythonic name:
username
- internal name: username
- is optional? Yes
- PASSWORD
- type: str
- pythonic name:
password
- internal name: password
- is optional? Yes
- SERVER
Transition¶
transition_name_list¶
- Style: This type represents a list of objects of other type
- Item type: TransitionName
Requests¶
Authenticate¶
- Description: view PROTOCOL.md entry on ‘Authenticate’
- Request Fields:
- AUTH
- type: str
- pythonic name:
auth
- internal name: auth
- is optional? No
- AUTH
- Response Fields:
DisableStudioMode¶
- Description: view PROTOCOL.md entry on ‘DisableStudioMode’
- Request Fields:
- Response Fields:
EnableStudioMode¶
- Description: view PROTOCOL.md entry on ‘EnableStudioMode’
- Request Fields:
- Response Fields:
GetAuthRequired¶
- Description: view PROTOCOL.md entry on ‘GetAuthRequired’
- Request Fields:
- Response Fields:
GetCurrentProfile¶
- Description: view PROTOCOL.md entry on ‘GetCurrentProfile’
- Request Fields:
- Response Fields:
- PROFILE NAME
- type: str
- pythonic name:
profile_name
- internal name: profile-name
- is optional? No
- PROFILE NAME
GetCurrentScene¶
- Description: view PROTOCOL.md entry on ‘GetCurrentScene’
- Request Fields:
- Response Fields:
- NAME
- type: str
- pythonic name:
name
- internal name: name
- is optional? No
- SOURCES
- type: source_list
- pythonic name:
sources
- internal name: sources
- is optional? No
- NAME
GetCurrentSceneCollection¶
- Description: view PROTOCOL.md entry on ‘GetCurrentSceneCollection’
- Request Fields:
- Response Fields:
- SC NAME
- type: str
- pythonic name:
sc_name
- internal name: sc-name
- is optional? No
- SC NAME
GetCurrentTransition¶
- Description: view PROTOCOL.md entry on ‘GetCurrentTransition’
- Request Fields:
- Response Fields:
GetMute¶
- Description: view PROTOCOL.md entry on ‘GetMute’
- Request Fields:
- SOURCE
- type: str
- pythonic name:
source
- internal name: source
- is optional? No
- SOURCE
- Response Fields:
GetPreviewScene¶
- Description: view PROTOCOL.md entry on ‘GetPreviewScene’
- Request Fields:
- Response Fields:
- NAME
- type: str
- pythonic name:
name
- internal name: name
- is optional? No
- SOURCES
- type: source_list
- pythonic name:
sources
- internal name: sources
- is optional? No
- NAME
GetRecordingFolder¶
- Description: view PROTOCOL.md entry on ‘GetRecordingFolder’
- Request Fields:
- Response Fields:
- REC FOLDER
- type: str
- pythonic name:
rec_folder
- internal name: rec-folder
- is optional? No
- REC FOLDER
GetSceneList¶
- Description: view PROTOCOL.md entry on ‘GetSceneList’
- Request Fields:
- Response Fields:
- CURRENT SCENE
- type: str
- pythonic name:
current_scene
- internal name: current-scene
- is optional? No
- SCENES
- type: scene_list
- pythonic name:
scenes
- internal name: scenes
- is optional? No
- CURRENT SCENE
GetSpecialSources¶
- Description: view PROTOCOL.md entry on ‘GetSpecialSources’
- Request Fields:
- Response Fields:
- DESKTOP1
- type: str
- pythonic name:
desktop1
- internal name: desktop-1
- is optional? Yes
- DESKTOP2
- type: str
- pythonic name:
desktop2
- internal name: desktop-2
- is optional? Yes
- MIC1
- type: str
- pythonic name:
mic1
- internal name: mic-1
- is optional? Yes
- MIC2
- type: str
- pythonic name:
mic2
- internal name: mic-2
- is optional? Yes
- MIC3
- type: str
- pythonic name:
mic3
- internal name: mic-3
- is optional? Yes
- DESKTOP1
GetStreamingStatus¶
- Description: view PROTOCOL.md entry on ‘GetStreamingStatus’
- Request Fields:
- Response Fields:
- STREAMING
- type: bool
- pythonic name:
streaming
- internal name: streaming
- is optional? No
- RECORDING
- type: bool
- pythonic name:
recording
- internal name: recording
- is optional? No
- STREAM TIMECODE
- type: str
- pythonic name:
stream_timecode
- internal name: stream-timecode
- is optional? Yes
- REC TIMECODE
- type: str
- pythonic name:
rec_timecode
- internal name: rec-timecode
- is optional? Yes
- PREVIEW ONLY
- type: bool
- pythonic name:
preview_only
- internal name: preview-only
- is optional? No
- STREAMING
GetStreamSettings¶
- Description: view PROTOCOL.md entry on ‘GetStreamSettings’
- Request Fields:
- Response Fields:
- TYPE
- type: str
- pythonic name:
type
- internal name: type
- is optional? No
- SETTINGS
- type: StreamSettings
- pythonic name:
settings
- internal name: settings
- is optional? No
- TYPE
GetStudioModeStatus¶
- Description: view PROTOCOL.md entry on ‘GetStudioModeStatus’
- Request Fields:
- Response Fields:
- STUDIO MODE
- type: bool
- pythonic name:
studio_mode
- internal name: studio-mode
- is optional? No
- STUDIO MODE
GetTextGDIPlusProperties¶
- Description: view PROTOCOL.md entry on ‘GetTextGDIPlusProperties’
- Request Fields:
- Response Fields:
- ALIGN
- type: str
- pythonic name:
align
- internal name: align
- is optional? No
- BK COLOR
- type: int
- pythonic name:
bk_color
- internal name: bk_color
- is optional? No
- BK OPACITY
- type: int
- pythonic name:
bk_opacity
- internal name: bk_opacity
- is optional? No
- CHATLOG
- type: bool
- pythonic name:
chatlog
- internal name: chatlog
- is optional? No
- CHATLOG LINES
- type: int
- pythonic name:
chatlog_lines
- internal name: chatlog_lines
- is optional? No
- COLOR
- type: int
- pythonic name:
color
- internal name: color
- is optional? No
- EXTENTS
- type: bool
- pythonic name:
extents
- internal name: extents
- is optional? No
- EXTENTS WRAP
- type: bool
- pythonic name:
extents_wrap
- internal name: extents_wrap
- is optional? No
- EXTENTS CX
- type: int
- pythonic name:
extents_cx
- internal name: extents_cx
- is optional? No
- EXTENTS CY
- type: int
- pythonic name:
extents_cy
- internal name: extents_cy
- is optional? No
- FILE
- type: str
- pythonic name:
file
- internal name: file
- is optional? No
- READ FROM FILE
- type: bool
- pythonic name:
read_from_file
- internal name: read_from_file
- is optional? No
- FONT
- type: Font
- pythonic name:
font
- internal name: font
- is optional? No
- GRADIENT
- type: bool
- pythonic name:
gradient
- internal name: gradient
- is optional? No
- GRADIENT COLOR
- type: int
- pythonic name:
gradient_color
- internal name: gradient_color
- is optional? No
- GRADIENT DIR
- type: float
- pythonic name:
gradient_dir
- internal name: gradient_dir
- is optional? No
- GRADIENT OPACITY
- type: int
- pythonic name:
gradient_opacity
- internal name: gradient_opacity
- is optional? No
- OUTLINE
- type: bool
- pythonic name:
outline
- internal name: outline
- is optional? No
- OUTLINE COLOR
- type: int
- pythonic name:
outline_color
- internal name: outline_color
- is optional? No
- OUTLINE SIZE
- type: int
- pythonic name:
outline_size
- internal name: outline_size
- is optional? No
- OUTLINE OPACITY
- type: int
- pythonic name:
outline_opacity
- internal name: outline_opacity
- is optional? No
- TEXT
- type: str
- pythonic name:
text
- internal name: text
- is optional? No
- VALIGN
- type: bool
- pythonic name:
valign
- internal name: valign
- is optional? No
- VERTICAL
- type: bool
- pythonic name:
vertical
- internal name: vertical
- is optional? No
- RENDER
- type: bool
- pythonic name:
render
- internal name: render
- is optional? No
- ALIGN
GetTransitionDuration¶
- Description: view PROTOCOL.md entry on ‘GetTransitionDuration’
- Request Fields:
- Response Fields:
- TRANSITION DURATION
- type: int
- pythonic name:
transition_duration
- internal name: transition-duration
- is optional? No
- TRANSITION DURATION
GetTransitionList¶
- Description: view PROTOCOL.md entry on ‘GetTransitionList’
- Request Fields:
- Response Fields:
- CURRENT TRANSITION
- type: str
- pythonic name:
current_transition
- internal name: current-transition
- is optional? No
- TRANSITIONS
- type: transition_name_list
- pythonic name:
transitions
- internal name: transitions
- is optional? No
- CURRENT TRANSITION
GetVersion¶
- Description: view PROTOCOL.md entry on ‘GetVersion’
- Request Fields:
- Response Fields:
- VERSION
- type: float
- pythonic name:
version
- internal name: version
- is optional? No
- OBS WEBSOCKET VERSION
- type: str
- pythonic name:
obs_websocket_version
- internal name: obs-websocket-version
- is optional? No
- OBS STUDIO VERSION
- type: str
- pythonic name:
obs_studio_version
- internal name: obs-studio-version
- is optional? No
- VERSION
GetVolume¶
- Description: view PROTOCOL.md entry on ‘GetVolume’
- Request Fields:
- SOURCE
- type: str
- pythonic name:
source
- internal name: source
- is optional? No
- SOURCE
- Response Fields:
ListProfiles¶
- Description: view PROTOCOL.md entry on ‘ListProfiles’
- Request Fields:
- Response Fields:
- PROFILES
- type: profile_list
- pythonic name:
profiles
- internal name: profiles
- is optional? No
- PROFILES
ListSceneCollections¶
- Description: view PROTOCOL.md entry on ‘ListSceneCollections’
- Request Fields:
- Response Fields:
- SCENE COLLECTIONS
- type: scene_collection_list
- pythonic name:
scene_collections
- internal name: scene-collections
- is optional? No
- SCENE COLLECTIONS
SaveStreamSettings¶
- Description: view PROTOCOL.md entry on ‘SaveStreamSettings’
- Request Fields:
- Response Fields:
SetCurrentProfile¶
- Description: view PROTOCOL.md entry on ‘SetCurrentProfile’
- Request Fields:
- PROFILE NAME
- type: str
- pythonic name:
profile_name
- internal name: profile-name
- is optional? No
- PROFILE NAME
- Response Fields:
SetCurrentScene¶
- Description: view PROTOCOL.md entry on ‘SetCurrentScene’
- Request Fields:
- SCENE NAME
- type: str
- pythonic name:
scene_name
- internal name: scene-name
- is optional? No
- SCENE NAME
- Response Fields:
SetCurrentSceneCollection¶
- Description: view PROTOCOL.md entry on ‘SetCurrentSceneCollection’
- Request Fields:
- SC NAME
- type: str
- pythonic name:
sc_name
- internal name: sc-name
- is optional? No
- SC NAME
- Response Fields:
SetCurrentTransition¶
- Description: view PROTOCOL.md entry on ‘SetCurrentTransition’
- Request Fields:
- TRANSITION NAME
- type: str
- pythonic name:
transition_name
- internal name: transition-name
- is optional? No
- TRANSITION NAME
- Response Fields:
SetMute¶
- Description: view PROTOCOL.md entry on ‘SetMute’
- Request Fields:
- Response Fields:
SetPreviewScene¶
- Description: view PROTOCOL.md entry on ‘SetPreviewScene’
- Request Fields:
- SCENE NAME
- type: str
- pythonic name:
scene_name
- internal name: scene-name
- is optional? No
- SCENE NAME
- Response Fields:
SetRecordingFolder¶
- Description: view PROTOCOL.md entry on ‘SetRecordingFolder’
- Request Fields:
- REC FOLDER
- type: str
- pythonic name:
rec_folder
- internal name: rec-folder
- is optional? No
- REC FOLDER
- Response Fields:
SetSceneItemCrop¶
- Description: view PROTOCOL.md entry on ‘SetSceneItemCrop’
- Request Fields:
- ITEM
- type: str
- pythonic name:
item
- internal name: item
- is optional? No
- SCENE NAME
- type: str
- pythonic name:
scene_name
- internal name: scene-name
- is optional? No
- TOP
- type: int
- pythonic name:
top
- internal name: top
- is optional? No
- BOTTOM
- type: int
- pythonic name:
bottom
- internal name: bottom
- is optional? No
- LEFT
- type: int
- pythonic name:
left
- internal name: left
- is optional? No
- RIGHT
- type: int
- pythonic name:
right
- internal name: right
- is optional? No
- ITEM
- Response Fields:
SetSceneItemPosition¶
- Description: view PROTOCOL.md entry on ‘SetSceneItemPosition’
- Request Fields:
- Response Fields:
SetSceneItemTransform¶
- Description: view PROTOCOL.md entry on ‘SetSceneItemTransform’
- Request Fields:
- ITEM
- type: str
- pythonic name:
item
- internal name: item
- is optional? No
- X SCALE
- type: float
- pythonic name:
x_scale
- internal name: x-scale
- is optional? No
- Y SCALE
- type: float
- pythonic name:
y_scale
- internal name: y-scale
- is optional? No
- ROTATION
- type: float
- pythonic name:
rotation
- internal name: rotation
- is optional? No
- SCENE NAME
- type: str
- pythonic name:
scene_name
- internal name: scene-name
- is optional? No
- ITEM
- Response Fields:
SetSourceRender¶
- Description: view PROTOCOL.md entry on ‘SetSourceRender’
- Request Fields:
- Response Fields:
SetStreamSettings¶
- Description: view PROTOCOL.md entry on ‘SetStreamSettings’
- Request Fields:
- TYPE
- type: str
- pythonic name:
type
- internal name: type
- is optional? No
- SETTINGS
- type: StreamSettings
- pythonic name:
settings
- internal name: settings
- is optional? No
- SAVE
- type: bool
- pythonic name:
save
- internal name: save
- is optional? No
- TYPE
- Response Fields:
- TYPE
- type: str
- pythonic name:
type
- internal name: type
- is optional? No
- SETTINGS
- type: StreamSettings
- pythonic name:
settings
- internal name: settings
- is optional? No
- TYPE
SetTransitionDuration¶
- Description: view PROTOCOL.md entry on ‘SetTransitionDuration’
- Request Fields:
- DURATION
- type: int
- pythonic name:
duration
- internal name: duration
- is optional? No
- DURATION
- Response Fields:
SetVolume¶
- Description: view PROTOCOL.md entry on ‘SetVolume’
- Request Fields:
- Response Fields:
StartRecording¶
- Description: view PROTOCOL.md entry on ‘StartRecording’
- Request Fields:
- Response Fields:
StartStopRecording¶
- Description: view PROTOCOL.md entry on ‘StartStopRecording’
- Request Fields:
- STREAM
- type: Stream
- pythonic name:
stream
- internal name: stream
- is optional? Yes
- STREAM
- Response Fields:
StartStopStreaming¶
- Description: view PROTOCOL.md entry on ‘StartStopStreaming’
- Request Fields:
- Response Fields:
StartStreaming¶
- Description: view PROTOCOL.md entry on ‘StartStreaming’
- Request Fields:
- STREAM
- type: Stream
- pythonic name:
stream
- internal name: stream
- is optional? Yes
- STREAM
- Response Fields:
StopRecording¶
- Description: view PROTOCOL.md entry on ‘StopRecording’
- Request Fields:
- Response Fields:
StopStreaming¶
- Description: view PROTOCOL.md entry on ‘StopStreaming’
- Request Fields:
- Response Fields:
ToggleMute¶
- Description: view PROTOCOL.md entry on ‘ToggleMute’
- Request Fields:
- SOURCE
- type: str
- pythonic name:
source
- internal name: source
- is optional? No
- SOURCE
- Response Fields:
ToggleStudioMode¶
- Description: view PROTOCOL.md entry on ‘ToggleStudioMode’
- Request Fields:
- Response Fields:
TransitionToProgram¶
- Description: view PROTOCOL.md entry on ‘TransitionToProgram’
- Request Fields:
- WITH TRANSITION
- type: Transition
- pythonic name:
with_transition
- internal name: with-transition
- is optional? No
- WITH TRANSITION
- Response Fields:
Events¶
Exiting¶
- Description: view PROTOCOL.md entry on ‘Exiting’
- Request Fields:
- Response Fields:
PreviewSceneChanged¶
- Description: view PROTOCOL.md entry on ‘PreviewSceneChanged’
- Request Fields:
- SCENE NAME
- type: str
- pythonic name:
scene_name
- internal name: scene-name
- is optional? No
- SOURCES
- type: source_list
- pythonic name:
sources
- internal name: sources
- is optional? No
- SCENE NAME
- Response Fields:
ProfileChanged¶
- Description: view PROTOCOL.md entry on ‘ProfileChanged’
- Request Fields:
- Response Fields:
ProfileListChanged¶
- Description: view PROTOCOL.md entry on ‘ProfileListChanged’
- Request Fields:
- Response Fields:
RecordingStarted¶
- Description: view PROTOCOL.md entry on ‘RecordingStarted’
- Request Fields:
- Response Fields:
RecordingStarting¶
- Description: view PROTOCOL.md entry on ‘RecordingStarting’
- Request Fields:
- Response Fields:
RecordingStopped¶
- Description: view PROTOCOL.md entry on ‘RecordingStopped’
- Request Fields:
- Response Fields:
RecordingStopping¶
- Description: view PROTOCOL.md entry on ‘RecordingStopping’
- Request Fields:
- Response Fields:
SceneCollectionChanged¶
- Description: view PROTOCOL.md entry on ‘SceneCollectionChanged’
- Request Fields:
- Response Fields:
SceneCollectionListChanged¶
- Description: view PROTOCOL.md entry on ‘SceneCollectionListChanged’
- Request Fields:
- Response Fields:
SceneItemAdded¶
- Description: view PROTOCOL.md entry on ‘SceneItemAdded’
- Request Fields:
- Response Fields:
SceneItemRemoved¶
- Description: view PROTOCOL.md entry on ‘SceneItemRemoved’
- Request Fields:
- Response Fields:
SceneItemVisibilityChanged¶
- Description: view PROTOCOL.md entry on ‘SceneItemVisibilityChanged’
- Request Fields:
- Response Fields:
ScenesChanged¶
- Description: view PROTOCOL.md entry on ‘ScenesChanged’
- Request Fields:
- Response Fields:
SourceOrderChanged¶
- Description: view PROTOCOL.md entry on ‘SourceOrderChanged’
- Request Fields:
- SCENE NAME
- type: str
- pythonic name:
scene_name
- internal name: scene-name
- is optional? No
- SCENE NAME
- Response Fields:
StreamStarted¶
- Description: view PROTOCOL.md entry on ‘StreamStarted’
- Request Fields:
- Response Fields:
StreamStarting¶
- Description: view PROTOCOL.md entry on ‘StreamStarting’
- Request Fields:
- PREVIEW ONLY
- type: bool
- pythonic name:
preview_only
- internal name: preview-only
- is optional? No
- PREVIEW ONLY
- Response Fields:
StreamStatus¶
- Description: view PROTOCOL.md entry on ‘StreamStatus’
- Request Fields:
- STREAMING
- type: bool
- pythonic name:
streaming
- internal name: streaming
- is optional? No
- RECORDING
- type: bool
- pythonic name:
recording
- internal name: recording
- is optional? No
- PREVIEW ONLY
- type: bool
- pythonic name:
preview_only
- internal name: preview-only
- is optional? No
- BYTES PER SEC
- type: int
- pythonic name:
bytes_per_sec
- internal name: bytes-per-sec
- is optional? No
- KBITS PER SEC
- type: int
- pythonic name:
kbits_per_sec
- internal name: kbits-per-sec
- is optional? No
- STRAIN
- type: float
- pythonic name:
strain
- internal name: strain
- is optional? No
- TOTAL STREAM TIME
- type: int
- pythonic name:
total_stream_time
- internal name: total-stream-time
- is optional? No
- NUM TOTAL FRAMES
- type: int
- pythonic name:
num_total_frames
- internal name: num-total-frames
- is optional? No
- NUM DROPPED FRAMES
- type: int
- pythonic name:
num_dropped_frames
- internal name: num-dropped-frames
- is optional? No
- FPS
- type: float
- pythonic name:
fps
- internal name: fps
- is optional? No
- STREAMING
- Response Fields:
StreamStopped¶
- Description: view PROTOCOL.md entry on ‘StreamStopped’
- Request Fields:
- Response Fields:
StreamStopping¶
- Description: view PROTOCOL.md entry on ‘StreamStopping’
- Request Fields:
- PREVIEW ONLY
- type: bool
- pythonic name:
preview_only
- internal name: preview-only
- is optional? No
- PREVIEW ONLY
- Response Fields:
StudioModeSwitched¶
- Description: view PROTOCOL.md entry on ‘StudioModeSwitched’
- Request Fields:
- NEW STATE
- type: bool
- pythonic name:
new_state
- internal name: new-state
- is optional? No
- NEW STATE
- Response Fields:
SwitchScenes¶
- Description: view PROTOCOL.md entry on ‘SwitchScenes’
- Request Fields:
- SCENE NAME
- type: str
- pythonic name:
scene_name
- internal name: scene-name
- is optional? No
- SOURCES
- type: source_list
- pythonic name:
sources
- internal name: sources
- is optional? No
- SCENE NAME
- Response Fields:
SwitchTransition¶
- Description: view PROTOCOL.md entry on ‘SwitchTransition’
- Request Fields:
- TRANSITION NAME
- type: str
- pythonic name:
transition_name
- internal name: transition-name
- is optional? No
- TRANSITION NAME
- Response Fields:
TransitionBegin¶
- Description: view PROTOCOL.md entry on ‘TransitionBegin’
- Request Fields:
- Response Fields:
TransitionDurationChanged¶
- Description: view PROTOCOL.md entry on ‘TransitionDurationChanged’
- Request Fields:
- NEW DURATION
- type: int
- pythonic name:
new_duration
- internal name: new-duration
- is optional? No
- NEW DURATION
- Response Fields:
TransitionListChanged¶
- Description: view PROTOCOL.md entry on ‘TransitionListChanged’
- Request Fields:
- Response Fields:
Introduction¶
What’s this?¶
obs-ws-rc is a Python 3.5+ library that allows you to establish client connections to the obs-websocket plugin for OBS Studio.
It’s based on asyncio-approach which it inherited from the underlying WebSocket library - websockets
Performing requests¶
Firstly, obs-websocket‘s protocol provides you with the ability to send requests and retrieve responses to and from OBS Studio.
Let’s see how it’s done with obs-ws-rc:
"""Example shows how to send requests and get responses."""
import asyncio
from obswsrc import OBSWS
from obswsrc.requests import ResponseStatus, StartStreamingRequest
from obswsrc.types import Stream, StreamSettings
async def main():
async with OBSWS('localhost', 4444, "password") as obsws:
# We can send an empty StartStreaming request (in that case the plugin
# will use OBS configuration), but let's provide some settings as well
stream_settings = StreamSettings(
server="rtmp://example.org/my_application",
key="secret_stream_key",
use_auth=False
)
stream = Stream(
settings=stream_settings,
type="rtmp_custom",
)
# Now let's actually perform a request
response = await obsws.require(StartStreamingRequest(stream=stream))
# Check if everything is OK
if response.status == ResponseStatus.OK:
print("Streaming has started")
else:
print("Couldn't start the stream! Reason:", response.error)
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()
Listening to events¶
Secondly, the plugin sends events from time to time. This library lets you listen to these events and handle them:
"""Example shows how to listen to events."""
import asyncio
import logging
import sys
from obswsrc import OBSWS
from obswsrc.logs import logger
# We will output logging to sys.stdout, as many events might raise errors
# on creation (that's because protocol.json is not perfect) - such errors
# are logged by obs-ws-rc automatically, we just need to see them
logger.setLevel(logging.ERROR)
logger.addHandler(logging.StreamHandler(stream=sys.stdout))
async def main():
async with OBSWS('localhost', 4444, "password") as obsws:
print("Connection established.")
# We will receive events here by awaiting for them (you can await for
# an event of a specific type by providing `type_name` argument to
# the obsws.event() method)
event = await obsws.event()
# Awaited event might be None if connection is closed
while event is not None:
print("Awaited for '{}' event!".format(event.type_name))
event = await obsws.event()
print("Connection terminated.")
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()
Protocol description¶
The protocol requrests, responses and events are declared in the PROTOCOL.md by the authors of the obs-websocket plugin.
However, there are minor mistakes in that file.
And the field naming of the original protocol is inconsistent.
For example, there’re fields like authRequired
, at the same time there’re
plenty of fields that use a hyphen as a word separator (like
kbits-per-sec
).
This library internally maps such fields to more pythonic names
(auth_required
and kbits_per_sec
as such) - that allows for convenient
passing fields as keyword arguments.
The version of the protocol used by this library can be found in
./obswsrc/protocol.json
.