---
title: roPcap
slug: develop/ropcap
docTags: 
createdAt: 2026-07-22T15:42:22.221Z
---

`roPcap` is used to analyze PCAP files for UDP traffic flows, prepare them for
replay (optionally filtering and rewriting headers), replay them onto a network
interface with drift-free pacing, and extract raw UDP payload streams from PCAP
captures. It is available as of BOS 9.1.143.

If a message port is set via `SetPort()`, the object posts `roPcapEvent` messages
for replay lifecycle events (started, stopped, looped, underrun, dropped).

Only one `roPcap` instance may exist at a time. `CreateObject("roPcap")` returns
`Invalid` if another instance is already alive.

:::hint{type="warning"}
If using *tmp\:/* you need to be mindful of how big the PCAP is. If its large, it won’t fit into a RAM-based *tmp\:/* and you should use local storage instead (for example, *sd:/*)
:::

***

## ifPcap

### Analyze(filename As String) As Object

Scans all packets in `filename` and returns a `roArray` of `roAssociativeArray`,
one entry per UDP flow found. Flows are sorted by packet count in descending
order. Returns an empty array if the file cannot be opened or contains no UDP
flows.

Each entry in the returned array contains the following keys:

| **Key**        | **Type** | **Description**                   |
| -------------- | -------- | --------------------------------- |
| `src_ip`       | String   | Source IPv4 address               |
| `src_port`     | Integer  | Source UDP port                   |
| `dst_ip`       | String   | Destination IPv4 address          |
| `dst_port`     | Integer  | Destination UDP port              |
| `packet_count` | Integer  | Number of UDP packets in the flow |

***

### Prepare(params As roAssociativeArray) As Integer

Filters packets from the input PCAP and writes a replay-ready output PCAP,
optionally rewriting destination IP and UDP port headers. The source MAC address
and source IP address in every output packet are always rewritten to the values
of the specified network interface.

If `RewriteOutputDestAddress` is a multicast address, the destination MAC is
derived using the RFC 1112 formula. If it is a unicast address, the destination
MAC is resolved via the kernel ARP cache; the destination must already be
reachable (e.g. via a prior ping) before calling `Prepare()`.

Returns a `PcapEngineError` integer code; `0` on success. See [Error Codes](./#error-codes).

**Required parameters:**

| **Key**      | **Type** | **Description**                                                              |
| ------------ | -------- | ---------------------------------------------------------------------------- |
| `InputFile`  | String   | Path to the source PCAP file                                                 |
| `OutputFile` | String   | Path to write the prepared PCAP (must differ from `InputFile`)               |
| `Interface`  | String   | Network interface name used to resolve the source MAC and IP (e.g. `"eth0"`) |

**Optional filter parameters:**

| **Key**                    | **Type** | **Description**                                             |
| -------------------------- | -------- | ----------------------------------------------------------- |
| `FilterInputSourceAddress` | String   | Keep only packets with this IPv4 source address             |
| `FilterInputSourcePort`    | Integer  | Keep only UDP packets from this source port (1024–65535)    |
| `FilterInputDestAddress`   | String   | Keep only packets with this IPv4 destination address        |
| `FilterInputDestPort`      | Integer  | Keep only UDP packets to this destination port (1024–65535) |
| `AutoFlowSelect`           | Boolean  | See note below                                              |

**Optional rewrite parameters:**

| **Key**                    | **Type** | **Description**                                           |
| -------------------------- | -------- | --------------------------------------------------------- |
| `RewriteOutputDestAddress` | String   | Rewrite the destination IP address (unicast or multicast) |
| `RewriteOutputDestPort`    | Integer  | Rewrite the UDP destination port (1024–65535)             |

**AutoFlowSelect default behavior:**
When no `FilterInput*` keys are supplied, `AutoFlowSelect` defaults to `true`:
the flow with the highest packet count is selected automatically. When any
`FilterInput*` key is present, `AutoFlowSelect` defaults to `false`: if the
filter criteria match more than one flow, `Prepare()` returns
`PCAP_ERR_AMBIGUOUS_FLOW (-7)` instead of picking one. An explicit
`AutoFlowSelect` key always overrides the default.

***

### ExtractStream(params As roAssociativeArray) As Integer

Concatenates the raw UDP payload bytes of every matching packet in `InputFile`
and writes them to `OutputFile`. No prior `Prepare()` call is required. This is
useful for recovering the original byte stream from a UDP capture — for example,
extracting an MPEG-TS file from a TS-over-UDP recording.

The filter criteria must resolve to exactly one UDP flow. Use `AutoFlowSelect`
to select the highest-count flow automatically when the filter is broad.

Returns a `PcapEngineError` integer code; `0` on success. See [Error Codes](./#error-codes).
May return `PCAP_ERR_READ_FAILED (-8)` if the input file is corrupt or truncated.

**Required parameters:**

| **Key**      | **Type** | **Description**                                          |
| ------------ | -------- | -------------------------------------------------------- |
| `InputFile`  | String   | Path to the source PCAP file                             |
| `OutputFile` | String   | Path to write the extracted stream; created or truncated |

**Optional filter parameters:**

Same as `Prepare()`: `FilterInputSourceAddress`, `FilterInputSourcePort`,
`FilterInputDestAddress`, `FilterInputDestPort`, `AutoFlowSelect` (same default
logic as `Prepare()`).

***

### Start(params As roAssociativeArray) As Boolean

Starts replaying the prepared PCAP file on the specified network interface.
Packets are paced at their original inter-packet intervals using
absolute monotonic timestamps so timing overshoot on one packet cannot accumulate
into drift over subsequent packets.

Blocks until the sender thread has started or failed to start. Posts a
`roPcapEvent` with type `1` (Started) to the message port on success.

Returns `True` on success; `False` if the sender thread could not be started.

**Required parameters:**

| **Key**     | **Type** | **Description**                                   |
| ----------- | -------- | ------------------------------------------------- |
| `Filename`  | String   | Path to the prepared PCAP file to replay          |
| `Interface` | String   | Network interface name to send on (e.g. `"eth0"`) |

**Optional parameters:**

| **Key**             | **Type** | **Description**                                                                                                                                                                                                                                                                                                           |
| ------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `LoopCount`         | Integer  | Number of times to loop through the file; `0` (default) loops forever                                                                                                                                                                                                                                                     |
| `PreloadIntoMemory` | Boolean  | If `True`, loads the entire file into RAM before replay begins (capped at 50% of total system RAM). Use this when deterministic per-packet timing is required and the file fits comfortably in memory. Default is streaming mode, which reads from disk with a 20 MiB readahead buffer and is suitable for any file size. |

***

### Stop() As Void

Returns `True` while the sender thread is executing the replay loop. Returns
`False` once the loop count is exhausted, `Stop()` is called, or a fatal error
occurs after `Start()` returned `True`.

***

### GetStats() As roAssociativeArray

Returns a snapshot of replay statistics. Safe to call at any time, including
while replay is running.

| **Key**               | **Type** | **Description**                                                                                  |
| --------------------- | -------- | ------------------------------------------------------------------------------------------------ |
| `packets_sent`        | Integer  | Frames successfully transmitted since the last `Start()`                                         |
| `packets_dropped`     | Integer  | Frames dropped due to no buffer space / busy, since the last `Start()`                           |
| `loops_completed`     | Integer  | Full loop passes that have finished cleanly                                                      |
| `underruns`           | Integer  | Times the streaming readahead buffer was empty; always `0` when `PreloadIntoMemory` is `True`    |
| `elapsed_ms`          | Integer  | Wall-clock milliseconds since the last `Start()` or `ResetStats()` call; `0` when stopped        |
| `timing_sample_count` | Integer  | Number of packets contributing to the timing fields below                                        |
| `timing_mean_us`      | Integer  | Mean timing error in microseconds; positive means the packet went out late, negative means early |
| `timing_min_us`       | Integer  | Minimum (most-early) timing error in microseconds                                                |
| `timing_max_us`       | Integer  | Maximum (most-late) timing error in microseconds                                                 |
| `timing_stddev_us`    | Integer  | Sample standard deviation of timing error in microseconds                                        |

Timing fields are `0` until at least one packet has been sent.

***

### ResetStats() As Void

Resets all replay statistics to zero. Safe to call while replay is running.
Counters updated by the replay thread after the call reflect only activity since
the reset.

***

## ifMessagePort

### SetPort(port As roMessagePort)

Posts messages of type `roPcapEvent` to the attached message port.

***

## ifUserData

### SetUserData(user\_data As Object)

Sets the user data that will be returned when events are raised.

### GetUserData() As Object

Returns the user data previously set via `SetUserData()`. Returns `Invalid` if
no data has been set.

***

## roPcapEvent

`roPcapEvent` is posted to the message port set on `roPcap` whenever a replay
lifecycle event occurs.

### ifPcapEvent

### GetInt() As Integer

Returns the event type code:

| **Value** | **Name** | **Description**                                                                             |
| --------- | -------- | ------------------------------------------------------------------------------------------- |
| 1         | Started  | Replay thread started and is sending packets                                                |
| 2         | Stopped  | Replay thread stopped (loop count exhausted, `Stop()` called, or fatal error)               |
| 3         | Looped   | One full pass completed; `GetData()` returns the 1-indexed loop number                      |
| 4         | Underrun | Streaming readahead buffer was empty; replay timing may have been affected                  |
| 5         | Dropped  | A packet was dropped; `GetData()` returns the cumulative drop count at the time of the drop |

### GetData() As Integer

Returns event-specific data. See the table above. Returns `0` for events where
no additional data applies.

***

## Error Codes

`Prepare()` and `ExtractStream()` return one of the following integer codes:

| **Value** | **Name**                       | **Description**                                                                                                                                                                          |
| --------- | ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 0         | PCAP\_OK                       | Success                                                                                                                                                                                  |
| -1        | PCAP\_ERR\_FILE\_NOT\_FOUND    | `InputFile` does not exist or cannot be opened                                                                                                                                           |
| -2        | PCAP\_ERR\_INVALID\_FLOW\_PORT | A port value is outside the valid range \[1024, 65535]                                                                                                                                   |
| -3        | PCAP\_ERR\_WRITE\_FAILED       | `OutputFile` could not be written                                                                                                                                                        |
| -4        | PCAP\_ERR\_INVALID\_INTERFACE  | The interface name is invalid or not found on the system                                                                                                                                 |
| -5        | PCAP\_ERR\_INVALID\_PARAM      | An invalid parameter was supplied: bad IP address format, `InputFile` and `OutputFile` are the same path, or a unicast `RewriteOutputDestAddress` could not be resolved to a MAC via ARP |
| -6        | PCAP\_ERR\_NO\_MATCHING\_FLOW  | The filter criteria matched no flows; supply a less restrictive filter or verify the input file contains the expected traffic                                                            |
| -7        | PCAP\_ERR\_AMBIGUOUS\_FLOW     | The filter criteria matched more than one distinct flow; tighten the filter to select exactly one, or set `AutoFlowSelect: True` to pick the highest-count flow automatically            |
| -8        | PCAP\_ERR\_READ\_FAILED        | `ExtractStream()` only: the input file is corrupt or truncated                                                                                                                           |

***

## Examples

### Analyze a PCAP File

Print all UDP flows found in a capture file:

```brightscript
pcap = CreateObject("roPcap")
flows = pcap.Analyze("SD:/capture.pcap")

for each flow in flows
    print flow.src_ip + ":" + flow.src_port.ToStr() + " -> " + _
          flow.dst_ip + ":" + flow.dst_port.ToStr() + _
          "  packets=" + flow.packet_count.ToStr()
end for
```

***

### Prepare and Replay with Event Handling

Select a flow, rewrite it to a local multicast group, and replay it three times
while monitoring events:

```brightscript
pcap = CreateObject("roPcap")
port = CreateObject("roMessagePort")
pcap.SetPort(port)

' Step 1 — inspect the capture to find the flow
flows = pcap.Analyze("SD:/source.pcap")
if flows.Count() = 0
    print "No UDP flows found"
    stop
end if

' Step 2 — prepare: filter to the largest flow, rewrite destination
params = CreateObject("roAssociativeArray")
params.InputFile  = "SD:/source.pcap"
params.OutputFile = "tmp:/prepared.pcap"
params.Interface  = "eth0"
' AutoFlowSelect defaults to true when no FilterInput* keys are given,
' so the highest-count flow is selected automatically.
params.RewriteOutputDestAddress = "239.1.2.3"
params.RewriteOutputDestPort    = 1234

result = pcap.Prepare(params)
if result <> 0
    print "Prepare failed: " + result.ToStr()
    stop
end if

' Step 3 — replay three times
startParams = CreateObject("roAssociativeArray")
startParams.Filename  = "tmp:/prepared.pcap"
startParams.Interface = "eth0"
startParams.LoopCount = 3

if not pcap.Start(startParams)
    print "Start failed"
    stop
end if

' Step 4 — event loop
while True
    msg = Wait(0, port)
    if type(msg) = "roPcapEvent"
        select case msg.GetInt()
            case 3 ' Looped
                print "Completed loop " + msg.GetData().ToStr()
            case 5 ' Dropped
                print "Drop count: " + msg.GetData().ToStr()
            case 2 ' Stopped
                print "Replay finished"
                exit while
        end select
    end if
end while

stats = pcap.GetStats()
print "Sent=" + stats.packets_sent.ToStr() + _
      " Dropped=" + stats.packets_dropped.ToStr() + _
      " Underruns=" + stats.underruns.ToStr()
```

***

### Extract a Raw Stream from a PCAP

Recover an MPEG-TS file from a TS-over-UDP capture. No `Prepare()` or network
interface is needed:

```brightscript
pcap = CreateObject("roPcap")

params = CreateObject("roAssociativeArray")
params.InputFile  = "SD:/recording.pcap"
params.OutputFile = "SD:/extracted.ts"
' AutoFlowSelect defaults to true when no FilterInput* keys are given.
' Set explicit filter keys to target a specific flow in a multi-flow capture.
params.FilterInputDestAddress = "239.10.20.30"
params.FilterInputDestPort    = 1234
' AutoFlowSelect defaults to false because FilterInput* keys are present;
' set it explicitly to true to auto-pick if the filter still matches multiple flows.
params.AutoFlowSelect = True

result = pcap.ExtractStream(params)
if result = 0
    print "Stream extracted successfully"
else
    print "ExtractStream failed: " + result.ToStr()
end if
```

