What Problem Does This Solve?
ULCKService is your main entry point for LCK functionality:
- Start/stop/pause/resume recording
- Configure recording resolution, framerate, and bitrate
- Control microphone audio capture
- Take photos
- Monitor recording state and errors
Instead of interacting with low-level subsystems, you use this high-level service that handles the complexity for you.
When to Use This
Use ULCKService when:
- Building custom recording UI
- Implementing record buttons, settings menus
- Controlling recording from gameplay code
- Integrating recording into your game flow
Don’t use this directly if: You’re using the default LCK Tablet UI—it already handles everything.
Accessing the Service
From C++
ULCKSubsystem* Subsystem = GetWorld()->GetSubsystem<ULCKSubsystem>();
if (Subsystem)
{
ULCKService* Service = Subsystem->GetService();
// Use service...
}
From Blueprint
UFUNCTION(BlueprintCallable, Category = "LCK")
ULCKService* GetLCKService()
{
if (UWorld* World = GetWorld())
{
if (ULCKSubsystem* Subsystem = World->GetSubsystem<ULCKSubsystem>())
{
return Subsystem->GetService();
}
}
return nullptr;
}
Blueprint usage:
Recording Methods
StartRecording / StopRecording
// Start recording — returns true if recording started successfully
bool bSuccess = Service->StartRecording();
if (!bSuccess)
{
UE_LOG(LogLCK, Error, TEXT("Failed to start recording"));
}
// Stop recording — returns void
Service->StopRecording();
| Method | Returns | Description |
|---|
StartRecording() | bool | Starts recording. Returns true on success. Only valid when in Idle state. |
StopRecording() | void | Stops the current recording. Only valid when in Recording or Paused state. |
For async recording with callbacks and progress tracking, use ULCKRecorderSubsystem::StartRecordingAsync() and StopRecordingAsync() directly. See ULCKRecorderSubsystem for details.
PauseRecording / ResumeRecording
// Pause the current recording
Service->PauseRecording();
// Resume a paused recording
Service->ResumeRecording();
IsRecording / GetCurrentRecordingDuration
// Check if currently recording
bool bIsRecording = Service->IsRecording();
// Get recording duration in seconds
float Duration = Service->GetCurrentRecordingDuration();
// Update UI
if (bIsRecording)
{
FTimespan Time = FTimespan::FromSeconds(Duration);
TimerText->SetText(FText::Format(
LOCTEXT("RecordingTime", "{0}:{1:02}"),
Time.GetMinutes(),
Time.GetSeconds()
));
}
GetRecordingState
ELCKRecordingState State = Service->GetRecordingState();
switch (State)
{
case ELCKRecordingState::Idle:
// Ready to record
break;
case ELCKRecordingState::Recording:
// Currently recording
break;
// ...
}
Photo Capture
// Take a photo
Service->TakePhoto();
The photo is captured from the current scene capture component. There is no completion delegate on ULCKService for photo saves.
Recording Settings
ApplyRecordingSettings
Configure resolution, framerate, and bitrate for recordings:
Service->ApplyRecordingSettings(
1920, // Width
1080, // Height
30, // Framerate
8 << 20, // Video bitrate (8 Mbps)
256 << 10, // Audio bitrate (256 Kbps)
48000 // Sample rate (optional, defaults to 48000)
);
| Parameter | Type | Description |
|---|
Width | int32 | Video width in pixels |
Height | int32 | Video height in pixels |
Framerate | int32 | Frames per second |
VideoBitrate | int32 | Video bitrate in bits per second |
AudioBitrate | int32 | Audio bitrate in bits per second |
Samplerate | int32 | Audio sample rate (default: 48000) |
Quality and orientation presets (SD, HD, Landscape, Portrait) are managed via ULCKTabletDataModel, not ULCKService. See the Data Model Events section below.
Audio Control
Microphone
// Enable/disable microphone
Service->SetMicrophoneEnabled(true);
// Get current state
bool bMicEnabled = Service->IsMicrophoneEnabled();
// Get microphone audio level (0.0 to 1.0)
float MicLevel = Service->GetCurrentMicrophoneAudioLevel();
Volume indicator example:
void AMicIndicator::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
float Volume = Service->GetCurrentMicrophoneAudioLevel();
VolumeBar->SetPercent(Volume);
// Visual feedback
if (Volume > 0.7f)
{
VolumeBar->SetFillColorAndOpacity(FLinearColor::Red);
}
else if (Volume > 0.3f)
{
VolumeBar->SetFillColorAndOpacity(FLinearColor::Yellow);
}
else
{
VolumeBar->SetFillColorAndOpacity(FLinearColor::Green);
}
}
GetCurrentMicrophoneAudioLevel() is not exposed to Blueprint. It is available from C++ only.
Preview Mode
Preview mode (camera output without recording to disk) is managed by ULCKRecorderSubsystem, not ULCKService.
// Access via the recorder subsystem directly
ULCKRecorderSubsystem* Recorder = GetWorld()->GetSubsystem<ULCKRecorderSubsystem>();
Recorder->StartPreview();
Recorder->StopPreview();
See ULCKRecorderSubsystem for details.
Delegates on ULCKService
ULCKService exposes the following delegates directly:
| Delegate | Type | Description |
|---|
OnRecordingError | FOnRecordingError(FString ErrorMessage, int32 ErrorCode) | Fired when a recording error occurs |
OnCameraModeChanged | FOnCameraModeChanged(UClass* ModeClass) | Fired when the camera mode class changes |
OnRecordingSaveFinished | FOnRecordingSaveFinished(bool Success) | Fired when the async save process completes |
OnRecordingSaveProgress | FOnRecordingSaveProgress(float Progress) | Fired during save with progress from 0.0 to 1.0 |
Example: Subscribing to delegates
// Error handling
Service->OnRecordingError.AddDynamic(this, &UMyComponent::HandleRecordingError);
// Save completion
Service->OnRecordingSaveFinished.AddDynamic(this, &UMyComponent::HandleSaveFinished);
// Save progress
Service->OnRecordingSaveProgress.AddDynamic(this, &UMyComponent::HandleSaveProgress);
// Handlers
UFUNCTION()
void HandleRecordingError(FString ErrorMessage, int32 ErrorCode)
{
UE_LOG(LogLCK, Error, TEXT("Recording error %d: %s"), ErrorCode, *ErrorMessage);
}
UFUNCTION()
void HandleSaveFinished(bool bSuccess)
{
if (bSuccess)
{
ShowNotification(TEXT("Recording saved!"));
}
}
UFUNCTION()
void HandleSaveProgress(float Progress)
{
ProgressBar->SetPercent(Progress);
}
State Tracking via Data Model
For UI-level state notifications (recording state changes, quality changes, orientation changes, camera mode switches), use ULCKTabletDataModel.
Get the Data Model
void UMyComponent::BeginPlay()
{
Super::BeginPlay();
// Find tablet in world
ALCKTablet* Tablet = Cast<ALCKTablet>(
UGameplayStatics::GetActorOfClass(GetWorld(), ALCKTablet::StaticClass())
);
if (Tablet)
{
ULCKTabletDataModel* DataModel = Tablet->GetDataModel();
// Subscribe to recording state changes
DataModel->OnRecordStateChanged.AddUObject(
this, &UMyComponent::HandleStateChanged
);
}
}
The recording state delegate is OnRecordStateChanged (type FOnRecordStateChange), not OnRecordingStateChanged. These are non-dynamic multicast delegates — use AddUObject or AddLambda, not AddDynamic.
Available Data Model Events
| Event | Delegate Type | Parameter | Description |
|---|
OnRecordStateChanged | FOnRecordStateChange | ELCKRecordingState | Recording state changed (Idle, Recording, etc.) |
OnTabletCameraModeChanged | FOnTabletCameraModeChanged | UClass* | Camera mode class changed |
OnMicStateChanged | FOnMicStateChanged | ELCKMicState | Microphone state changed (On, Off, No_Access) |
OnVideoQualityChanged | FOnVideoQualityChanged | ELCKVideoQuality | Video quality preset changed |
OnScreenOrientationChanged | FOnScreenOrientationChanged | ELCKScreenOrientation | Screen orientation changed |
OnMicLevelChanged | FOnMicLevelChanged | float | Microphone audio level updated |
Example: State-driven UI
void URecordingUI::HandleStateChanged(ELCKRecordingState NewState)
{
switch (NewState)
{
case ELCKRecordingState::Idle:
RecordButton->SetText(FText::FromString("Start Recording"));
RecordButton->SetIsEnabled(true);
ProgressPanel->SetVisibility(ESlateVisibility::Collapsed);
break;
case ELCKRecordingState::Recording:
RecordButton->SetText(FText::FromString("Stop Recording"));
RecordButton->SetIsEnabled(true);
RecordingIndicator->SetVisibility(ESlateVisibility::Visible);
break;
case ELCKRecordingState::Saving:
RecordButton->SetIsEnabled(false);
ProgressPanel->SetVisibility(ESlateVisibility::Visible);
StatusText->SetText(FText::FromString("Saving..."));
break;
case ELCKRecordingState::Error:
RecordButton->SetIsEnabled(true);
ShowErrorDialog();
break;
}
}
Streaming Methods
ULCKService also provides streaming functionality when the streaming feature is available:
| Method | Returns | Description |
|---|
IsStreamingAvailable() | bool | Whether the streaming feature plugin is loaded |
StartLogin() | void | Begin the streaming login/pairing flow |
CancelLogin() | void | Cancel an in-progress login |
Logout() | void | Log out of the streaming service |
StartStreaming() | bool | Start streaming; returns true on success |
StopStreaming() | void | Stop the current stream |
IsStreaming() | bool | Whether currently streaming |
IsAuthenticated() | bool | Whether logged in to the streaming service |
LaunchHub() | void | Launch the LIV Hub companion app |
IsHubInstalled() | bool | Whether the LIV Hub app is installed |
GetLastLogoutReason() | FString | Reason for the last logout |
GetStreamingTargetName() | FString | Name of the current streaming target |
Streaming Delegates
These are non-dynamic multicast delegates (use AddUObject or AddLambda):
| Delegate | Type | Description |
|---|
OnStreamingPairingCode | FOnStreamingPairingCode(const FString&) | Pairing code received during login |
OnStreamingAuthenticated | FOnStreamingAuthenticated() | Successfully authenticated |
OnStreamingStarted | FOnStreamingStarted() | Streaming session started |
OnStreamingStopped | FOnStreamingStopped() | Streaming session stopped |
OnStreamingError | FOnStreamingError(const FString&) | Streaming error occurred |
OnStreamingLoggedOut | FOnStreamingLoggedOut() | Logged out of streaming service |
OnStreamingConfigChanged | FOnStreamingConfigChanged() | Streaming configuration changed |
Complete Example: Recording Manager
UCLASS()
class URecordingManager : public UActorComponent
{
GENERATED_BODY()
protected:
UPROPERTY()
ULCKService* Service;
UPROPERTY()
ULCKTabletDataModel* DataModel;
public:
virtual void BeginPlay() override
{
Super::BeginPlay();
// Get service
Service = GetLCKService();
if (!Service)
{
UE_LOG(LogLCK, Error, TEXT("LCK Service not available"));
return;
}
// Get data model for state tracking
ALCKTablet* Tablet = FindTablet();
if (Tablet)
{
DataModel = Tablet->GetDataModel();
DataModel->OnRecordStateChanged.AddUObject(
this, &URecordingManager::OnStateChanged
);
}
// Subscribe to service events
Service->OnRecordingSaveFinished.AddDynamic(
this, &URecordingManager::OnSaveFinished
);
Service->OnRecordingError.AddDynamic(
this, &URecordingManager::OnError
);
}
UFUNCTION(BlueprintCallable)
void ToggleRecording()
{
if (Service->IsRecording())
{
Service->StopRecording();
}
else
{
bool bSuccess = Service->StartRecording();
if (!bSuccess)
{
UE_LOG(LogLCK, Error, TEXT("Failed to start recording"));
}
}
}
void OnStateChanged(ELCKRecordingState NewState)
{
// Update UI based on state
BroadcastStateChange(NewState);
}
UFUNCTION()
void OnSaveFinished(bool bSuccess)
{
if (bSuccess)
{
ShowNotification(TEXT("Recording saved!"));
}
else
{
ShowError(TEXT("Failed to save recording"));
}
}
UFUNCTION()
void OnError(FString ErrorMessage, int32 ErrorCode)
{
UE_LOG(LogLCK, Error, TEXT("Recording error %d: %s"), ErrorCode, *ErrorMessage);
ShowErrorDialog(ErrorMessage);
}
private:
ULCKService* GetLCKService()
{
if (UWorld* World = GetWorld())
{
if (ULCKSubsystem* Subsystem = World->GetSubsystem<ULCKSubsystem>())
{
return Subsystem->GetService();
}
}
return nullptr;
}
ALCKTablet* FindTablet()
{
return Cast<ALCKTablet>(
UGameplayStatics::GetActorOfClass(GetWorld(), ALCKTablet::StaticClass())
);
}
};
Key Takeaways
Get via ULCKSubsystem — Don’t create or cache manually
Check IsRecording() — Before changing settings or starting
Use DataModel for state events — Subscribe to OnRecordStateChanged on ULCKTabletDataModel
Preview lives on ULCKRecorderSubsystem — Not on ULCKService
Quality and orientation are on DataModel — Use ULCKTabletDataModel to change presets