> ## 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.

# ILCKPacketSink (Unreal)

> Abstract packet sink interface for custom streaming transport backends in Unreal Engine.

## 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

```cpp theme={null}
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

```cpp theme={null}
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.

### OnVideoFormatReady

```cpp theme={null}
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.

### OnAudioFormatReady

```cpp theme={null}
virtual void OnAudioFormatReady(uint32 SampleRate, uint32 NumChannels) = 0;
```

Called when audio encoder format parameters are finalized.

### SendVideoPacket

```cpp theme={null}
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

```cpp theme={null}
virtual void SendAudioPacket(const uint8* Data, uint32 Size,
                             int64 TimestampMs) = 0;
```

Deliver a compressed AAC audio packet (raw AAC, no ADTS header).

### Close / IsOpen

```cpp theme={null}
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`:

```cpp theme={null}
Encoder->AddPacketSink(MySink.Get());

// When done:
Encoder->RemovePacketSink(MySink.Get());
```

<Warning>
  Call `RemovePacketSink()` before destroying the sink. On Windows, late-attached sinks receive cached codec headers automatically.
</Warning>

***

## Thread Safety

<Warning>
  `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.
</Warning>

***

## Implementation Example

```cpp theme={null}
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

<Check>**Transport abstraction** — Decouples encoding from delivery</Check>
<Check>**H.264 + AAC** — Packets are compressed, ready to transmit</Check>
<Check>**Thread safety required** — Packet methods called from encoder thread</Check>
<Check>**Multiple sinks** — Encoder supports multiple simultaneous sinks</Check>

***

## Related

* [Encoder Interface](/api-reference/unreal/encoder-interface) — Encoder that feeds this sink
* [Streaming Feature Interface](/api-reference/unreal/streaming-feature-interface) — High-level streaming control
* [Streaming Subsystem](/api-reference/unreal/streaming-subsystem) — Blueprint-friendly streaming API
