Documentation Index
Fetch the complete documentation index at: https://docs.liv.tv/llms.txt
Use this file to discover all available pages before exploring further.
What Problem Does This Solve?
ILCKPacketSink defines the transport layer for live streaming. Once the encoder produces compressed H.264 video and AAC audio packets, something needs to send them — to an RTMP server, a WebRTC peer, or a custom protocol.
This interface decouples encoding from transport, so you can stream to any custom backend or send packets to multiple destinations simultaneously.
When to Use This
Read this if:
- Building a custom streaming backend (RTMP, SRT, WebRTC)
- Implementing multi-destination streaming
- Debugging packet-level streaming issues
Skip this if: You’re using the built-in LIV streaming. The default FLCKNativePacketBridge handles RTMP transport automatically.
Interface Definition
class LCKCORE_API ILCKPacketSink
{
public:
virtual ~ILCKPacketSink();
virtual bool Open(uint32 Width, uint32 Height, uint32 Framerate,
uint32 Samplerate, uint32 NumChannels) = 0;
virtual void Close() = 0;
virtual bool IsOpen() const = 0;
virtual void OnVideoFormatReady(const uint8* ExtraData, uint32 ExtraDataSize) = 0;
virtual void OnAudioFormatReady(uint32 SampleRate, uint32 NumChannels) = 0;
virtual void SendVideoPacket(const uint8* Data, uint32 Size,
int64 TimestampMs, bool bIsKeyframe) = 0;
virtual void SendAudioPacket(const uint8* Data, uint32 Size,
int64 TimestampMs) = 0;
};
Methods
Open
virtual bool Open(uint32 Width, uint32 Height, uint32 Framerate,
uint32 Samplerate, uint32 NumChannels) = 0;
Initialize the sink and prepare for packet delivery.
| Parameter | Type | Description |
|---|
Width | uint32 | Video width in pixels |
Height | uint32 | Video height in pixels |
Framerate | uint32 | Target video framerate |
Samplerate | uint32 | Audio sample rate in Hz |
NumChannels | uint32 | Audio channel count (typically 2) |
Returns: true if the sink opened successfully.
virtual void OnVideoFormatReady(const uint8* ExtraData, uint32 ExtraDataSize) = 0;
Called when H.264 codec extra data (SPS/PPS in AVCDecoderConfigurationRecord format) is available. Store and transmit this before any video frames.
virtual void OnAudioFormatReady(uint32 SampleRate, uint32 NumChannels) = 0;
Called when audio encoder format parameters are finalized.
SendVideoPacket
virtual void SendVideoPacket(const uint8* Data, uint32 Size,
int64 TimestampMs, bool bIsKeyframe) = 0;
Deliver a compressed H.264 video packet.
| Parameter | Type | Description |
|---|
Data | const uint8* | H.264 NAL unit data |
Size | uint32 | Packet size in bytes |
TimestampMs | int64 | Presentation timestamp in milliseconds |
bIsKeyframe | bool | true if this is an IDR frame |
SendAudioPacket
virtual void SendAudioPacket(const uint8* Data, uint32 Size,
int64 TimestampMs) = 0;
Deliver a compressed AAC audio packet (raw AAC, no ADTS header).
Close / IsOpen
virtual void Close() = 0;
virtual bool IsOpen() const = 0;
Shut down the sink and release resources. IsOpen() returns current state.
Registering a Packet Sink
Add sinks to the encoder at runtime via ILCKEncoder:
Encoder->AddPacketSink(MySink.Get());
// When done:
Encoder->RemovePacketSink(MySink.Get());
Call RemovePacketSink() before destroying the sink. On Windows, late-attached sinks receive cached codec headers automatically.
Thread Safety
SendVideoPacket and SendAudioPacket are called from the encoder thread, not the game thread. Your implementation must be thread-safe. Open and Close are called from the game thread.
Implementation Example
class FMyPacketSink : public ILCKPacketSink
{
public:
virtual bool Open(uint32 Width, uint32 Height, uint32 Framerate,
uint32 Samplerate, uint32 NumChannels) override
{
bOpen = ConnectToServer(Width, Height, Framerate);
return bOpen;
}
virtual void OnVideoFormatReady(const uint8* ExtraData,
uint32 ExtraDataSize) override
{
CachedSPSPPS.SetNum(ExtraDataSize);
FMemory::Memcpy(CachedSPSPPS.GetData(), ExtraData, ExtraDataSize);
SendStreamHeader(CachedSPSPPS);
}
virtual void OnAudioFormatReady(uint32 SampleRate,
uint32 NumChannels) override
{
SendAudioHeader(SampleRate, NumChannels);
}
virtual void SendVideoPacket(const uint8* Data, uint32 Size,
int64 TimestampMs, bool bIsKeyframe) override
{
// Called from encoder thread
SendToServer(Data, Size, TimestampMs, bIsKeyframe);
}
virtual void SendAudioPacket(const uint8* Data, uint32 Size,
int64 TimestampMs) override
{
SendToServer(Data, Size, TimestampMs);
}
virtual void Close() override { DisconnectFromServer(); bOpen = false; }
virtual bool IsOpen() const override { return bOpen; }
private:
TArray<uint8> CachedSPSPPS;
bool bOpen = false;
};
Key Takeaways
Transport abstraction — Decouples encoding from delivery
H.264 + AAC — Packets are compressed, ready to transmit
Thread safety required — Packet methods called from encoder thread
Multiple sinks — Encoder supports multiple simultaneous sinks