Skip to main content

What Problem Does This Solve?

ILCKStreamingFeature abstracts live streaming so multiple backends can coexist:
  • LIV cloud streaming (built-in)
  • Custom RTMP backends
  • Third-party streaming services
The interface uses Unreal’s modular features system, allowing streaming implementations to register at runtime without compile-time dependencies.

When to Use This

Read this if:
  • Building a custom streaming backend
  • Integrating a third-party streaming service
  • Understanding how ULCKService discovers streaming providers
Skip this if: You’re using the built-in streaming subsystem. Use ULCKStreamingSubsystem directly.

Interface Definition

class LCKCORE_API ILCKStreamingFeature : public IModularFeature
{
public:
    virtual ~ILCKStreamingFeature() = default;

    DECLARE_MULTICAST_DELEGATE_OneParam(FOnPairingCode, const FString&);
    DECLARE_MULTICAST_DELEGATE(FOnAuthenticated);
    DECLARE_MULTICAST_DELEGATE(FOnStreamStarted);
    DECLARE_MULTICAST_DELEGATE(FOnStreamStopped);
    DECLARE_MULTICAST_DELEGATE_OneParam(FOnStreamError, const FString&);
    DECLARE_MULTICAST_DELEGATE(FOnLoggedOut);
    DECLARE_MULTICAST_DELEGATE(FOnStreamingConfigChanged);

    FOnPairingCode OnPairingCodeDelegate;
    FOnAuthenticated OnAuthenticatedDelegate;
    FOnStreamStarted OnStreamStartedDelegate;
    FOnStreamStopped OnStreamStoppedDelegate;
    FOnStreamError OnStreamErrorDelegate;
    FOnLoggedOut OnLoggedOutDelegate;
    FOnStreamingConfigChanged OnStreamingConfigChangedDelegate;

    static FName GetModularFeatureName() noexcept;

    virtual void StartLogin() = 0;
    virtual void CancelLogin() = 0;
    virtual void Logout() = 0;
    virtual bool IsAuthenticated() const = 0;

    virtual bool StartStreaming() = 0;
    virtual void StopStreaming() = 0;
    virtual bool IsStreaming() const = 0;
    virtual bool IsStartingOrStreaming() const;

    virtual void LaunchHub() = 0;
    virtual bool IsHubInstalled() const;
    virtual FString GetStreamingTargetName() const;
    virtual FString GetLastLogoutReason() const;
    virtual int32 GetPriority() const;
};

Delegates

DelegateSignatureDescription
OnPairingCodeDelegateFOnPairingCode(const FString& Code)New pairing code generated during login
OnAuthenticatedDelegateFOnAuthenticated()User successfully authenticated
OnStreamStartedDelegateFOnStreamStarted()Live stream has started
OnStreamStoppedDelegateFOnStreamStopped()Live stream ended normally
OnStreamErrorDelegateFOnStreamError(const FString& Error)Streaming error occurred
OnLoggedOutDelegateFOnLoggedOut()User logged out or was logged out
OnStreamingConfigChangedDelegateFOnStreamingConfigChanged()Streaming configuration changed remotely

Methods

Authentication

MethodSignatureDescription
StartLoginvirtual void StartLogin() = 0Begin device-code login flow
CancelLoginvirtual void CancelLogin() = 0Cancel in-progress login
Logoutvirtual void Logout() = 0Log out and clear credentials
IsAuthenticatedvirtual bool IsAuthenticated() const = 0Check if user is authenticated

Streaming

MethodSignatureDescription
StartStreamingvirtual bool StartStreaming() = 0Start the live stream (returns false on failure)
StopStreamingvirtual void StopStreaming() = 0Stop the live stream
IsStreamingvirtual bool IsStreaming() const = 0Check if currently streaming
IsStartingOrStreamingvirtual bool IsStartingOrStreaming() constTrue during startup or active streaming (default: IsStreaming())

Platform & Utility

MethodSignatureDefaultDescription
LaunchHubvirtual void LaunchHub() = 0Open the LIV Hub companion app
IsHubInstalledvirtual bool IsHubInstalled() consttrueCheck if LIV Hub is installed
GetStreamingTargetNamevirtual FString GetStreamingTargetName() const""Display name of streaming target
GetLastLogoutReasonvirtual FString GetLastLogoutReason() const""Reason for last automatic logout
GetPriorityvirtual int32 GetPriority() const0Priority when multiple backends registered

Discovery via Modular Features

The modular feature name is "LCKStreamingFeature". Streaming features are discovered at runtime:
#include "LCKStreamingFeature.h"

ILCKStreamingFeature* FindStreamingFeature()
{
    auto& ModularFeatures = IModularFeatures::Get();
    FName FeatureName = ILCKStreamingFeature::GetModularFeatureName();

    if (ModularFeatures.IsModularFeatureAvailable(FeatureName))
    {
        TArray<ILCKStreamingFeature*> Features =
            ModularFeatures.GetModularFeatureImplementations<ILCKStreamingFeature>(
                FeatureName);

        // Sort by priority (highest first)
        Features.Sort([](const ILCKStreamingFeature& A, const ILCKStreamingFeature& B)
        {
            return A.GetPriority() > B.GetPriority();
        });

        return Features.Num() > 0 ? Features[0] : nullptr;
    }

    return nullptr;
}

Usage Example

void UMyStreamingWidget::StartStream()
{
    ILCKStreamingFeature* Feature = FindStreamingFeature();
    if (!Feature) return;

    Feature->OnPairingCodeDelegate.AddLambda([this](const FString& Code)
    {
        ShowPairingCode(Code);
    });

    Feature->OnStreamStartedDelegate.AddLambda([this]()
    {
        ShowLiveIndicator();
    });

    if (!Feature->IsAuthenticated())
    {
        Feature->StartLogin();
    }
    else
    {
        Feature->StartStreaming();
    }
}

Key Takeaways

Modular features — Runtime discovery, no compile-time coupling
Priority system — Multiple backends can coexist, highest priority wins
Delegate-driven — Subscribe to events for async state changes
Auth before stream — Always check IsAuthenticated() before StartStreaming()