Skip to content

Desuq Cafe

Documentation menu

Architecture & Developer Reference

This page is the “how it works under the hood” reference for developers extending the plugin. It covers the module structure, the handler-based client, the Sequencer integration, the editor details-panel system, key types, and the patterns for adding new features.

For the full list of native C++ delegates (the Native-suffixed events that support lambda binding), see Native Delegates.

Module Structure

The plugin consists of three modules:

ModuleTypePurpose
InhyeongOBSWebSocketRuntimeCore functionality, subsystems, components, Sequencer integration
InhyeongOBSWebSocketEditorEditorDetails panel customization, editor subsystem, Sequencer track editor
InhyeongOBSWebSocketTakeRecorderEditorTake Recorder sync (loads PostEngineInit, only when the Takes plugin is enabled)

Take Recorder Sync Config

Settings are stored in Config/DefaultInhyeongOBS.ini:

[/Script/InhyeongOBSWebSocketTakeRecorder.InhyeongOBSTakeRecorderSync]
bEnabled=True
bShowNotifications=True
bWarnIfOBSNotConnected=True
bAutoStartRecord=True
bAutoStopRecord=True
PostRollSeconds=0.000000
bAutoStartVirtualCam=False
bAutoStopVirtualCam=False
bAutoStartStream=False
bAutoStopStream=False
bSwitchSceneOnStart=False
StartSceneName=
bSwitchSceneOnStop=False
StopSceneName=
bCreateChaptersOnMarkedFrames=True
bAddStartChapterWithMetadata=True
bMatchRecordDirectory=False
bLogFileCorrelation=True

Utility Classes

ClassLocationPurpose
FOBSRequestBatchBuilderUtilities/Fluent builder for batch requests
FOBSJsonBuilderUtilities/Fluent JSON object construction

Request Type Constants

All OBS WebSocket request types and field names are centralized in Core/Types/InhyeongOBSRequestTypes.h:

#include "Core/Types/InhyeongOBSRequestTypes.h"

// Request types
OBSRequests::GetSceneList            // "GetSceneList"
OBSRequests::SetCurrentProgramScene  // "SetCurrentProgramScene"
OBSRequests::StartRecord             // "StartRecord"

// Field names
OBSFields::SceneName                 // "sceneName"
OBSFields::InputName                 // "inputName"
OBSFields::SceneItemId               // "sceneItemId"

This prevents typos and makes protocol updates easier to manage.

JSON Builder Utility

FOBSJsonBuilder provides fluent JSON construction for OBS requests:

#include "Utilities/InhyeongOBSJsonBuilder.h"

// Basic usage
TSharedPtr<FJsonObject> Data = FOBSJsonBuilder::Create()
    .Add(TEXT("sceneName"), SceneName)
    .Add(TEXT("sceneItemId"), SceneItemId)
    .Add(TEXT("sceneItemEnabled"), true)
    .Build();

// Conditional additions
TSharedPtr<FJsonObject> Settings = FOBSJsonBuilder::Create()
    .Add(TEXT("sourceName"), SourceName)
    .Add(TEXT("imageFormat"), TEXT("png"))
    .AddIfPositive(TEXT("imageWidth"), Width)      // Only adds if > 0
    .AddIfPositive(TEXT("imageHeight"), Height)
    .AddIfInRange(TEXT("imageCompressionQuality"), Quality, 0, 100)
    .Build();

// Nested objects
TSharedPtr<FJsonObject> Transform = FOBSJsonBuilder::Create()
    .Add(TEXT("positionX"), 100.0f)
    .Add(TEXT("positionY"), 200.0f)
    .Build();

TSharedPtr<FJsonObject> Request = FOBSJsonBuilder::Create()
    .Add(TEXT("sceneName"), SceneName)
    .Add(TEXT("sceneItemId"), ItemId)
    .Add(TEXT("sceneItemTransform"), Transform)
    .Build();

Available Methods:

MethodDescription
Add(Key, Value)Add string, int32, int64, float, double, bool, or JSON object
AddIfNotEmpty(Key, String)Add only if string is not empty
AddIfPositive(Key, Number)Add only if number > 0
AddIfInRange(Key, Value, Min, Max)Add only if value is within range
Build()Returns the constructed TSharedPtr<FJsonObject>
HasFields()Check if any fields were added

Handler Architecture

The WebSocket client uses modular handlers for organization:

UInhyeongOBSWebSocketClient
├── UInhyeongOBSOutputs       (Stream, Record, VirtualCam, ReplayBuffer)
├── UInhyeongOBSScenes        (Scene switching, scene items)
├── UInhyeongOBSAudio         (Audio inputs, volume, mute)
├── UInhyeongOBSInputSettings (Text, browser, image, media source settings)
├── UInhyeongOBSMediaInputs   (Media playback control)
├── UInhyeongOBSStudioMode    (Preview scene, studio transitions)
├── UInhyeongOBSTransitions   (Scene transitions, duration, settings)
├── UInhyeongOBSFilters       (Source filter management)
├── UInhyeongOBSScreenshots   (Screenshot capture and texture conversion)
├── UInhyeongOBSConfig        (Scene collections, profiles, video settings, persistent data)
└── UInhyeongOBSGeneral       (Stats, hotkeys, vendor requests, custom events)

Access handlers via:

Client->GetOutputs()
Client->GetScenes()
Client->GetAudio()
Client->GetInputSettings()
Client->GetMediaInputs()
Client->GetStudioMode()
Client->GetTransitions()
Client->GetFilters()
Client->GetScreenshots()
Client->GetConfig()
Client->GetGeneral()

Sequencer Architecture

The Sequencer integration follows Unreal’s movie scene pattern:

Runtime Module (InhyeongOBSWebSocket)
├── EventTriggersTrack/                   Discrete action tracks
│   ├── UMovieSceneOBSTrack              Track container with playback settings
│   ├── UMovieSceneOBSSection            Section with action parameters
│   ├── FMovieSceneOBSTemplate           Evaluation template (boundary detection)
│   ├── FOBSExecutionToken               Execution token for firing actions
│   └── PreAnimatedState/                State restoration handlers
│       ├── FOBSOutputPreAnimatedState
│       ├── FOBSScenesPreAnimatedState
│       ├── FOBSAudioPreAnimatedState
│       ├── FOBSTransitionsPreAnimatedState
│       ├── FOBSStudioModePreAnimatedState
│       ├── FOBSFiltersPreAnimatedState
│       └── FOBSSourcesPreAnimatedState
├── KeyframeableTrack/                   Interpolated property tracks
│   ├── Audio/
│   │   ├── UMovieSceneOBSVolumeTrack    Volume track (targets InputName)
│   │   ├── UMovieSceneOBSVolumeSection  Float channel for volume dB
│   │   ├── FMovieSceneOBSVolumeTemplate Continuous evaluation
│   │   ├── FOBSVolumePreAnimatedState   Capture/restore volume
│   │   ├── UMovieSceneOBSBalanceTrack   Balance track (targets InputName)
│   │   ├── UMovieSceneOBSBalanceSection Float channel for L/R balance
│   │   ├── FMovieSceneOBSBalanceTemplate Continuous evaluation
│   │   └── FOBSBalancePreAnimatedState  Capture/restore balance
│   ├── Scene/
│   │   ├── UMovieSceneOBSTransformTrack Transform track (targets Scene+Source)
│   │   ├── UMovieSceneOBSTransformSection Float/Int channels for transform
│   │   ├── FMovieSceneOBSTransformTemplate Continuous evaluation
│   │   └── FOBSTransformPreAnimatedState Capture/restore transform
│   ├── Sources/
│   │   ├── UMovieSceneOBSColorSourceTrack    Color source track (targets InputName)
│   │   ├── UMovieSceneOBSColorSourceSection  4 float channels for RGBA
│   │   ├── FMovieSceneOBSColorSourceTemplate Continuous evaluation, ABGR conversion
│   │   └── FOBSColorSourcePreAnimatedState   Capture/restore with format conversion
│   ├── Media/
│   │   ├── UMovieSceneOBSMediaCursorTrack    Media cursor track (targets InputName)
│   │   ├── UMovieSceneOBSMediaCursorSection  Single float channel for cursor (ms)
│   │   ├── FMovieSceneOBSMediaCursorTemplate Continuous evaluation, float→int64
│   │   └── FOBSMediaCursorPreAnimatedState   Capture/restore cursor position
│   ├── Filters/
│   │   ├── UMovieSceneOBSFilterSettingTrack    Generic filter setting track (targets Source+Filter+Setting)
│   │   ├── UMovieSceneOBSFilterSettingSection  Float channel for any numeric setting
│   │   ├── FMovieSceneOBSFilterSettingTemplate Continuous evaluation with JSON overlay
│   │   ├── FOBSFilterSettingPreAnimatedState   Capture/restore from filter cache
│   │   └── FOBSCommonFilterSettings            UI hints for known filter types
│   └── Transitions/
│       ├── UMovieSceneOBSTransitionDurationTrack    Duration track (current transition)
│       ├── UMovieSceneOBSTransitionDurationSection  Float channel for duration ms
│       ├── FMovieSceneOBSTransitionDurationTemplate Continuous evaluation, handles fixed transitions
│       └── FOBSTransitionDurationPreAnimatedState   Capture/restore duration
├── ContinuousStateTrack/                State-holding tracks (no keyframes)
│   ├── Audio/
│   │   ├── OBSMuteStatePreAnimatedState             Capture/restore mute state
│   │   ├── MovieSceneOBSMuteStateSection            Section with bMuteState property
│   │   ├── MovieSceneOBSMuteStateTrack              Track targeting InputName
│   │   ├── MovieSceneOBSMuteStateTemplate           Setup/Evaluate/TearDown
│   │   ├── OBSMonitorTypeStatePreAnimatedState      Capture/restore monitor type
│   │   ├── MovieSceneOBSMonitorTypeStateSection     Section with MonitorType enum
│   │   ├── MovieSceneOBSMonitorTypeStateTrack       Track targeting InputName
│   │   └── MovieSceneOBSMonitorTypeStateTemplate    Setup/Evaluate/TearDown
│   ├── Scene/
│   │   ├── OBSVisibilityStatePreAnimatedState       Capture/restore visibility
│   │   ├── MovieSceneOBSVisibilityStateSection      Section with bVisible property
│   │   ├── MovieSceneOBSVisibilityStateTrack        Track targeting Scene+ItemId
│   │   ├── MovieSceneOBSVisibilityStateTemplate     Setup/Evaluate/TearDown
│   │   ├── OBSBlendModeStatePreAnimatedState        Capture/restore blend mode
│   │   ├── MovieSceneOBSBlendModeStateSection       Section with BlendMode enum
│   │   ├── MovieSceneOBSBlendModeStateTrack         Track targeting Scene+ItemId
│   │   ├── MovieSceneOBSBlendModeStateTemplate      Setup/Evaluate/TearDown
│   │   ├── OBSLockStatePreAnimatedState             Capture/restore lock state
│   │   ├── MovieSceneOBSLockStateSection            Section with bLocked property
│   │   ├── MovieSceneOBSLockStateTrack              Track targeting Scene+ItemId
│   │   └── MovieSceneOBSLockStateTemplate           Setup/Evaluate/TearDown
│   ├── Filter/
│   │   ├── OBSFilterEnabledStatePreAnimatedState    Capture/restore filter enabled
│   │   ├── MovieSceneOBSFilterEnabledStateSection   Section with bEnabled property
│   │   ├── MovieSceneOBSFilterEnabledStateTrack     Track targeting Source+Filter
│   │   └── MovieSceneOBSFilterEnabledStateTemplate  Setup/Evaluate/TearDown
│   ├── StudioMode/
│   │   ├── OBSStudioModeStatePreAnimatedState       Capture/restore studio mode
│   │   ├── MovieSceneOBSStudioModeStateSection      Section with bEnabled property
│   │   ├── MovieSceneOBSStudioModeStateTrack        Global track (no target)
│   │   └── MovieSceneOBSStudioModeStateTemplate     Setup/Evaluate/TearDown
│   └── Transitions/
│       ├── OBSTransitionStatePreAnimatedState       Capture/restore current transition
│       ├── MovieSceneOBSTransitionStateSection      Section (presence = apply)
│       ├── MovieSceneOBSTransitionStateTrack        Track with TransitionName target
│       └── MovieSceneOBSTransitionStateTemplate     Setup/Evaluate/TearDown
├── MediaSyncTrack/                      Timeline-synchronized media playback
│   ├── OBSMediaSyncPreAnimatedState                 Capture/restore media state+position
│   ├── MovieSceneOBSMediaSyncSection                Section defines sync window
│   ├── MovieSceneOBSMediaSyncTrack                  Track targeting MediaInputName
│   └── MovieSceneOBSMediaSyncTemplate               Play/pause/seek synchronization
Editor Module (InhyeongOBSWebSocketEditor)
├── Sequencer/
│   ├── Shared/
│   │   └── OBSSequencerMenuRegistry         Centralized menu building (prevents duplicates)
│   ├── EventTriggersTrack/
│   │   ├── FMovieSceneOBSTrackEditor        Track editor for event trigger
│   │   └── FMovieSceneOBSSectionInterface   Section display
│   ├── KeyframeableTrack/
│   │   ├── FOBSKeyframeableTrackEditorBase  Shared base for all keyframeable editors
│   │   └── [Category]/FOBSXxxTrackEditor    Per-track editors (Volume, Balance, etc.)
│   ├── ContinuousStateTrack/
│   │   ├── FOBSContinuousStateTrackEditorBase    Shared base for all continuous state editors
│   │   ├── FOBSContinuousStateSectionInterface   Shared section display (colored bar)
│   │   └── [Category]/FOBSXxxStateTrackEditor    Per-track editors (Mute, Visibility, etc.)
│   └── MediaSyncTrack/
│       ├── FOBSMediaSyncTrackEditor         Track editor with media input picker
│       └── FOBSMediaSyncSectionInterface    Section display with offset indicator
└── DetailsCustomization/
    └── Sequencer/
        ├── EventTriggersTrack/               Action params customization
        ├── KeyframeableTrack/               Target pickers (Input, Scene+Item, etc.)
        ├── ContinuousStateTrack/            Target pickers per track type
        └── MediaSyncTrack/                  Track + Section customizations
├── FOBSSequencerActionExecutor          Routes to correct OBS client
├── FOBSSequencerActionQueue             Throttling, deduplication, batching
└── FOBSSequencerActionRegistry          Action metadata registry

Key Classes:

ClassPurpose
FOBSSequencerActionRegistryStatic registry of all 40+ actions with metadata
FOBSSequencerActionQueueSingleton queue with 33ms throttling (~30fps), deduplication, batch optimization (up to 48 actions/batch)
FOBSOutputPreAnimatedStateCaptures output states before playback for restoration
FOBSSequencerActionExecutorRoutes actions to the correct OBS client (Editor vs Game subsystem)

Adding New Sequencer Actions

  1. Add an enum value to EOBSSequencerAction in InhyeongOBSSequencerTypes.h.
  2. Add a REGISTER_ACTION block in InhyeongOBSSequencerTypes.cpp.
  3. Add an execution case in OBSSequencerActionExecutor.cpp.
  4. Add batch request building in OBSSequencerActionQueue.cpp (if using batching).

Adding Pre-Animated State Support

For State-type actions that modify OBS settings, implement restoration:

  1. Create FOBS[Handler]PreAnimatedState in Sequencer/EventTriggersTrack/.
  2. Inherit from IPersistentEvaluationData.
  3. Implement CaptureFrom() using the handler’s cached values (no async!).
  4. Implement RestoreTo() with 150ms debouncing.
  5. Update MovieSceneOBSTemplate::SupportsPreAnimatedState() to include the category.
  6. Add Setup/TearDown blocks in MovieSceneOBSTemplate.cpp.

Pre-Animated State Pattern:

// In Setup() - capture before section modifies OBS
FOBS[Handler]PreAnimatedState& State = PersistentData.GetOrAddSectionData();
if (!State.bHasCapturedState)
{
    State.CaptureFrom(Handler, EntryAction);
}

// In TearDown() - restore when section becomes inactive
FOBS[Handler]PreAnimatedState* State = PersistentData.FindSectionData();
if (State && State->bHasCapturedState)
{
    State->RestoreTo(Handler);
}

Adding New Continuous State Tracks

Each continuous state track requires 4 files in Sequencer/ContinuousStateTrack/[Handler]/:

FilePurpose
OBS[State]PreAnimatedState.h/.cppCapture/restore, idempotent ApplyState()
MovieSceneOBS[State]Section.h/.cppSimple property (bool/enum), NO channels
MovieSceneOBS[State]Track.h/.cppContainer with target identification
MovieSceneOBS[State]Template.h/.cppSetup captures, Evaluate applies, TearDown restores

Critical Implementation Rules:

  1. PreAnimatedState inherits IPersistentEvaluationData (NOT USTRUCT).
  2. ApplyState() MUST be idempotent (check bStateIsApplied before sending).
  3. Track::CreateTemplateForSection uses direct return (NOT *new).
  4. Section has NO FMovieSceneFloatChannel, just simple properties.
  5. Section constructor sets EvalOptions.CompletionMode = RestoreState.
  6. Template uses GetOrAddTrackData<>() / FindTrackData<>() for persistent data.

Adding New Keyframeable Tracks

Each keyframeable property requires 4 files in Sequencer/KeyframeableTrack/[Category]/:

FilePurpose
OBS[Property]PreAnimatedState.h/.cppCapture/restore original OBS state
MovieSceneOBS[Property]Section.h/.cppStore FMovieSceneFloatChannel keyframes
MovieSceneOBS[Property]Track.h/.cppContainer with target identification
MovieSceneOBS[Property]Template.h/.cppContinuous evaluation, delta threshold sending

Critical Implementation Rules:

  1. PreAnimatedState inherits IPersistentEvaluationData (NOT USTRUCT).
  2. Track::CreateTemplateForSection uses direct return (NOT *new).
  3. Template uses GetOrAddSectionData<>() / FindSectionData<>() for persistent data.
  4. Setup() caches the client via FOBSSequencerActionExecutor::GetClientForContext() into PreAnimatedState.
  5. Evaluate() retrieves the client from State->CachedClient.Get() (not the Player context, which is unavailable in Evaluate).
  6. Evaluate() routes through FOBSSequencerActionQueue::Get().EnqueueAction() for throttling/batching.
  7. The delta threshold check happens BEFORE enqueueing to avoid unnecessary action creation.

Sequencer Editor UI

All tracks feature a polished editor experience:

Track Outliner:

  • Connection status indicator (green/red dot)
  • Quick ”+” button to add sections at the playhead
  • Automatic curve editor integration via FMovieSceneFloatChannel

Details Panel Customizations:

TrackTarget SelectionNotes
Volume / BalanceAudio input dropdownFiltered to audio-capable inputs only
TransformScene → Scene Item cascadingScene item shows “SourceName (ID: 123)” format
Filter SettingSource → Filter cascadingSetting name entered manually (OBS internal key)
Transition DurationNone (affects current)Shows current transition info when connected
Color SourceColor source dropdownFiltered to color_source inputs only
Media CursorMedia input dropdownFiltered to ffmpeg_source/vlc_source only

Dropdown Population:

  • All dropdowns are populated from the OBS client cache.
  • The Refresh button triggers a full data refresh from OBS.
  • Placeholder text “(Connect to OBS first)” appears when disconnected.
  • Cascading selections clear the child when the parent changes.

Editor Module Architecture

The editor module uses a section builder pattern for details panel customization:

FInhyeongOBSComponentCustomization
├── FOBSConnectionSectionBuilder
├── FOBSScenesSectionBuilder
├── FOBSSceneItemTransformsSectionBuilder
├── FOBSStudioModeSectionBuilder
├── FOBSTransitionsSectionBuilder
├── FOBSRecordingStreamingSectionBuilder
├── FOBSVirtualCamSectionBuilder
├── FOBSReplayBufferSectionBuilder
├── FOBSAdvancedOutputsSectionBuilder
├── FOBSAudioInputsSectionBuilder
├── FOBSMediaInputsSectionBuilder
├── FOBSInputSettingsSectionBuilder
├── FOBSFiltersSectionBuilder
├── FOBSScreenshotsSectionBuilder
├── FOBSWatchedScenesSectionBuilder
└── FOBSConfigSectionBuilder

FInhyeongOBSTriggerVolumeCustomization
├── FOBSTriggerShapeSectionBuilder
├── FOBSTriggerSettingsSectionBuilder
├── FOBSTriggerConditionsSectionBuilder
├── FOBSTriggerActionsSectionBuilder
└── FOBSTriggerTestSectionBuilder

Section Builder Base Classes

FOBSSectionBuilderBase: Base for OBS Component sections:

class FOBSSectionBuilderBase : public TSharedFromThis<FOBSSectionBuilderBase>
{
public:
    void Initialize(const TSharedRef<FOBSSectionContext>& InContext);
    virtual void BuildSection(IDetailCategoryBuilder& Category) = 0;
    virtual FText GetSectionTitle() const = 0;
    virtual bool IsInitiallyCollapsed() const { return false; }
    virtual void BindToEvents() {}
    virtual void UnbindFromEvents() {}
    void RequestRefresh();

protected:
    bool IsConnected() const;
    UInhyeongOBSEditorSubsystem* GetSubsystem() const;
    UInhyeongOBSWebSocketClient* GetClient() const;
    TAttribute<bool> MakeEnabledWhenConnected() const;
};

FOBSTriggerVolumeSectionBuilderBase: Base for Trigger Volume sections:

class FOBSTriggerVolumeSectionBuilderBase : public TSharedFromThis<FOBSTriggerVolumeSectionBuilderBase>
{
public:
    void Initialize(const TSharedRef<FOBSTriggerVolumeSectionContext>& InContext);
    virtual void BuildSection(IDetailCategoryBuilder& Category) = 0;
    virtual FText GetSectionTitle() const = 0;

protected:
    AInhyeongOBSTriggerVolume* GetTriggerVolume() const;
    // ... same helpers as FOBSSectionBuilderBase
};

Section Context Structs

FOBSSectionContext: Shared data for component sections:

struct FOBSSectionContext
{
    UInhyeongOBSEditorSubsystem* Subsystem;
    UInhyeongOBSWebSocketClient* Client;
    TWeakObjectPtr<UInhyeongOBSComponent> Component;
    IDetailLayoutBuilder* DetailBuilder;
    TSharedPtr<bool> ValidityFlag;  // Set false on destruction

    bool IsValid() const;
    bool IsConnected() const;
    UInhyeongOBSOutputs* GetOutputs() const;
    UInhyeongOBSScenes* GetScenes() const;
    UInhyeongOBSAudio* GetAudio() const;
    UInhyeongOBSInputSettings* GetInputSettings() const;
    UInhyeongOBSMediaInputs* GetMediaInputs() const;
};

FOBSTriggerVolumeSectionContext: Shared data for trigger volume sections:

struct FOBSTriggerVolumeSectionContext
{
    UInhyeongOBSEditorSubsystem* Subsystem;
    UInhyeongOBSWebSocketClient* Client;
    TWeakObjectPtr<AInhyeongOBSTriggerVolume> TriggerVolume;
    IDetailLayoutBuilder* DetailBuilder;
    TSharedPtr<bool> ValidityFlag;

    bool IsValid() const;
    bool IsConnected() const;
    // ... handler accessors
};

Key Types

Enums:

  • EOBSConnectionState: Disconnected, Connecting, Authenticating, Connected
  • EOBSOutputState: Starting, Started, Stopping, Stopped, Paused, Resumed, etc.
  • EOBSMediaInputAction: None, Play, Pause, Stop, Restart, Next, Previous
  • EOBSMediaState: Unknown, None, Playing, Paused, Stopped, Buffering, Ended, Error, Opening
  • EOBSTriggerActionType: All supported trigger actions
  • EOBSTriggerShape: Box, Sphere
  • EOBSTriggerEvent: OnEnter, OnExit, Both
  • EOBSRequestBatchExecutionType: SerialRealtime, SerialFrame, Parallel
  • EOBSMonitorType: None, MonitorOnly, MonitorAndOutput

Structs:

  • FOBSScene: Scene name, UUID, index
  • FOBSSceneItem: Source info within a scene (includes lock state, blend mode)
  • FOBSSceneWithItems: Scene with all its items
  • FOBSInput: Input with volume/mute info
  • FOBSStreamStatus / FOBSRecordStatus: Output status with timecode
  • FOBSMediaInputStatus: Media state, duration, cursor position
  • FOBSTriggerAction: Action configuration for trigger volumes
  • FOBSTriggerConditions: Condition configuration for triggers
  • FOBSBatchRequest / FOBSBatchResult: Batch request/response data
  • FOBSTransition: Transition name, UUID, kind, configurable, fixed flags
  • FOBSSourceFilter: Filter name, kind, index, enabled state, settings
  • FOBSCurrentTransitionInfo: Full transition details including settings
  • FOBSSceneItemTransform: Position, scale, rotation, crop, bounds, source dimensions
  • EOBSBoundsType: None, Stretch, ScaleInner, ScaleOuter, ScaleToWidth, ScaleToHeight, MaxOnly
  • EOBSBlendMode: Normal, Additive, Subtract, Screen, Multiply, Lighten, Darken
  • FOBSScreenshotRequest: Screenshot capture parameters (source, format, size, quality, path)
  • FOBSScreenshotResult: Capture result with base64 image data
  • FOBSScreenshotSavedResult: Save result with file path confirmation
  • FOBSSceneTransitionOverride: Per-scene transition override (name, duration, bHasOverride)
  • FOBSProfileParameter: Parameter value and default value
  • FOBSStreamServiceSettings: Stream destination configuration (server, key, auth)
  • FOBSAudioTracks: Track 1 to 6 enable states with helper methods
  • FOBSSpecialInputs: Default audio device names (Desktop1/2, Mic1 to 4)
  • FOBSOutput: Generic output info (name, kind, dimensions, active state, flags)
  • FOBSOutputStatus: Generic output status (name, active, reconnecting, timecode, duration, congestion, bytes, frames)

Caching:

  • Input settings are cached in UInhyeongOBSInputSettings after fetching via GetInputSettings().
  • Use GetCachedInputSettings() / GetCachedInputSettingsString() to access cached data.
  • Use HasCachedSettings() to check if data is available.
  • Use ClearCachedSettings() / ClearAllCachedSettings() to invalidate the cache.

Details Panel Customization

The plugin uses a modular section builder pattern for details panels:

  • FOBSSectionBuilderBase: Base class for OBS Component sections
  • FOBSTriggerVolumeSectionBuilderBase: Base class for Trigger Volume sections
  • FOBSDetailsPanelStyle: Shared style constants and widget builders

Each section (Connection, Scenes, Recording, etc.) is implemented as a separate builder class.

Identity Resolver (name → UUID rebind)

OBS keys scene items by a numeric SceneItemId that designers never see, and that id changes if the source is renamed mid-stream. Core/InhyeongOBSIdentityResolver.h (OBSIdentity::FindSceneItemByName / FindSceneItemByUuids + FOBSIdentityBindingCache) resolves a source by name, remembers its scene/source UUIDs, and rebinds by UUID on a later by-name miss, so a trigger that targets a source by name keeps working after a rename. It is wired into the Trigger Volume’s “Set Source Visibility” action. The cache is runtime-only and resets on scene-collection swaps.

Authentication

The plugin implements SHA256 authentication internally without platform dependencies. See InhyeongOBSAuth.h for the implementation.

Request Batching

Use FOBSRequestBatchBuilder for efficient batch requests:

FOBSRequestBatchBuilder::Create(Client)
    .SetCurrentProgramScene("Scene1")
    .StartRecord()
    .SetInputMute("Mic", false)
    .HaltOnFailure(true)
    .SetExecutionType(EOBSRequestBatchExecutionType::SerialRealtime)
    .ExecuteWithCallback([](const FOBSBatchResult& Result) {
        // Handle results
    });

Available batch methods:

  • Scene: GetSceneList(), SetCurrentProgramScene(), GetCurrentProgramScene(), CreateScene(), RemoveScene(), SetSceneName(), GetSceneSceneTransitionOverride(), SetSceneSceneTransitionOverride(), SetSceneItemEnabled(), CreateSceneItem(), RemoveSceneItem(), DuplicateSceneItem(), GetSceneItemLocked(), SetSceneItemLocked(), GetSceneItemIndex(), SetSceneItemIndex(), GetSceneItemBlendMode(), SetSceneItemBlendMode()
  • Config: GetSceneCollectionList(), SetCurrentSceneCollection(), CreateSceneCollection(), GetProfileList(), SetCurrentProfile(), CreateProfile(), RemoveProfile(), GetProfileParameter(), SetProfileParameter(), GetVideoSettings(), SetVideoSettings(), SetBaseResolution(), SetOutputResolution(), SetFPS()
  • Stream: StartStream(), StopStream(), ToggleStream(), GetStreamStatus()
  • Record: StartRecord(), StopRecord(), ToggleRecord(), PauseRecord(), ResumeRecord(), GetRecordStatus()
  • VirtualCam: StartVirtualCam(), StopVirtualCam(), ToggleVirtualCam(), GetVirtualCamStatus()
  • ReplayBuffer: StartReplayBuffer(), StopReplayBuffer(), ToggleReplayBuffer(), SaveReplayBuffer(), GetReplayBufferStatus()
  • Record Directory: GetRecordDirectory(), SetRecordDirectory()
  • Record Split/Chapters: SplitRecordFile(), CreateRecordChapter()
  • Generic Outputs: GetOutputList(), GetOutputStatus(), GetOutputSettings(), SetOutputSettings(), StartOutput(), StopOutput(), ToggleOutput()
  • Stream Captions: SendStreamCaption()
  • Audio: GetInputList(), SetInputMute(), ToggleInputMute(), SetInputVolume(), GetInputKindList(), CreateInput(), RemoveInput(), RemoveInputByUuid(), SetInputName(), GetInputAudioBalance(), GetInputAudioBalanceByUuid(), SetInputAudioBalance(), SetInputAudioBalanceByUuid(), GetInputAudioSyncOffset(), GetInputAudioSyncOffsetByUuid(), SetInputAudioSyncOffset(), SetInputAudioSyncOffsetByUuid(), GetInputAudioMonitorType(), GetInputAudioMonitorTypeByUuid(), SetInputAudioMonitorType(), SetInputAudioMonitorTypeByUuid(), GetInputAudioTracks(), GetInputAudioTracksByUuid(), SetInputAudioTracks(), SetInputAudioTracksByUuid(), GetSpecialInputs()
  • Input Settings: GetInputSettings(), SetInputSettings(), GetInputDefaultSettings(), SetTextSourceText(), SetBrowserSourceUrl(), SetImageSourceFile(), SetMediaSourceFile(), SetColorSourceColor()
  • Media: TriggerMediaInputAction(), GetMediaInputStatus(), SetMediaInputCursor(), OffsetMediaInputCursor()
  • StudioMode: GetStudioModeEnabled(), SetStudioModeEnabled(), GetCurrentPreviewScene(), SetCurrentPreviewScene(), SetCurrentPreviewSceneByUuid(), TriggerStudioModeTransition()
  • Transitions: GetSceneTransitionList(), GetCurrentSceneTransition(), SetCurrentSceneTransition(), SetCurrentSceneTransitionDuration(), SetCurrentSceneTransitionSettings(), GetCurrentSceneTransitionCursor()
  • Screenshots: GetSourceScreenshot(), GetSourceScreenshotByUuid(), GetSourceScreenshotWithOptions(), SaveSourceScreenshot(), SaveSourceScreenshotByUuid(), SaveSourceScreenshotWithOptions()
  • Filters: GetSourceFilterKindList(), GetSourceFilterList(), GetSourceFilterListByUuid(), GetSourceFilter(), GetSourceFilterDefaultSettings(), CreateSourceFilter(), RemoveSourceFilter(), SetSourceFilterName(), SetSourceFilterIndex(), SetSourceFilterEnabled(), SetSourceFilterSettings()

Internal Organization:

The batch builder implementation is split across multiple files for maintainability:

FileContents
InhyeongOBSRequestBatch.cppCore, configuration, execution
InhyeongOBSRequestBatch_Scenes.cppScene and scene item requests
InhyeongOBSRequestBatch_Outputs.cppStream, record, virtual cam, replay buffer
InhyeongOBSRequestBatch_Audio.cppAudio, media inputs, input settings
InhyeongOBSRequestBatch_Filters.cppSource filter management
InhyeongOBSRequestBatch_StudioMode.cppStudio mode and transitions
InhyeongOBSRequestBatch_Config.cppScreenshots, profiles, scene collections, video settings

Adding New Features

  1. Add types/delegates to InhyeongOBSTypes.h.
  2. Implement in the appropriate handler (Outputs, Scenes, Inputs, MediaInputs).
  3. Add convenience methods to Client, Subsystem, and Component if needed.
  4. Handle events in ProcessOBSEvent() in the client.
  5. Add UI in the appropriate section builder.

Adding New Editor Sections

  1. Create a new section builder class inheriting from FOBSSectionBuilderBase or FOBSTriggerVolumeSectionBuilderBase.
  2. Implement BuildSection(), GetSectionTitle(), and optionally IsInitiallyCollapsed().
  3. Override BindToEvents() and UnbindFromEvents() if the section needs live updates.
  4. Add the builder to the customization class’s CreateSectionBuilders() method.
  5. Use FOBSDetailsPanelStyle for consistent styling.