# BitChat BLE File Transfer Fragmentation: Handling Large Media Over 512-Byte MTU

> Explore BitChat's BLE file transfer fragmentation for large media. Discover how it handles payloads over 512-byte MTU, reassembles data, and ensures complete file delivery.

- Repository: [permissionlesstech/bitchat](https://github.com/permissionlesstech/bitchat)
- Tags: internals
- Published: 2026-07-27

---

**BitChat automatically fragments any media payload exceeding the 512-byte BLE MTU into sequenced packets, reassembles them atomically on the receiving side, and only surfaces validated, complete files to the user interface.**

BitChat, an open-source messaging application maintained by permissionlesstech, implements a robust BLE file transfer fragmentation system to overcome Bluetooth Low Energy's inherent payload limitations. When users share photos, videos, or audio clips that exceed the standard 512-byte Maximum Transmission Unit (MTU), the protocol automatically handles packet segmentation and reassembly without exposing incomplete transfers to the UI.

## The BLE MTU Constraint

Bluetooth Low Energy (BLE) enforces a strict **512-byte MTU** limit on data payloads. Large media files—such as high-resolution images or audio recordings—quickly exceed this threshold. Rather than dropping these transfers, BitChat employs automatic fragmentation within [`BitchatPacket.swift`](https://github.com/permissionlesstech/bitchat/blob/main/BitchatPacket.swift), splitting oversized payloads into manageable chunks while preserving the integrity of the original media through sequence metadata.

## The Six-Step Fragmentation Pipeline

### 1. MTU-Aware Packet Fragmentation

The sender initiates transfer by constructing a `BitchatPacket` containing the raw media bytes. In [`BitchatPacket.swift`](https://github.com/permissionlesstech/bitchat/blob/main/BitchatPacket.swift), the initializer automatically detects payloads exceeding the BLE MTU and fragments them into a sequence of smaller packets. Each fragment embeds **fragmentation metadata**—including the fragment index and total fragment count—in the packet header, enabling ordered reconstruction on the receiving device.

### 2. CoreBluetooth Transport

Once fragmented, individual packets are dispatched via `BLEService`. The service leverages CoreBluetooth's `CBPeripheralManager` to transmit each fragment over the BLE link. Because the initial fragmentation ensures every chunk fits within the 512-byte limit, the lower-level Bluetooth stack never encounters oversized payloads, preventing transmission failures at the hardware level.

### 3. Ordered Fragment Reassembly

On the receiving side, the internal `BLEReceivePipeline` buffers incoming fragments as they arrive. Using the fragment ID and sequence numbers stored in the packet headers, the pipeline groups related fragments and reconstructs the original byte array only after the final fragment arrives. This guarantees that downstream components receive complete, contiguous media data.

### 4. Payload Validation

The fully reassembled payload passes to `BLEFileTransferHandler.handle(_:)`, which coordinates validation through `BLEIncomingFileValidator`. This stage verifies that the payload is well-formed, confirms the MIME type is supported, and checks that the file size complies with the app-wide **BCH-01-002** storage quota before allowing persistence.

### 5. Atomic File Persistence

Validated files are written to disk via `BLEIncomingFileStore.saveIncomingFile`. The store implements **atomic visibility** by first writing data to a temporary location with a *live-capture* prefix. This ensures partially received files never appear as user-visible media. Only after the complete file is successfully written does the store move it into the permanent "incoming" media directory.

### 6. UI Delivery and Cleanup

Finally, `BLEFileTransferHandler` instantiates a `BitchatMessage` referencing the saved file and delivers it to the UI layer through the `deliverMessage` closure supplied by `BLEService`. If the UI rejects the message or delivery fails, the handler immediately removes the temporary file, ensuring no orphaned fragments or incomplete media remain on the device.

## Key Implementation Details

**Fragmentation Metadata Structure.** Each packet header contains sequence information that `BLEReceivePipeline` uses to reassemble fragments in the correct order, even if they arrive out of sequence due to BLE link-layer retries.

**Quota Enforcement.** Before persistence, `BLEFileTransferHandler` invokes `environment.enforceStorageQuota` (specification BCH-01-002) to verify sufficient device storage exists, preventing transfers that would exhaust available space.

**Private Media Support.** For packets marked as private, the handler reserves a stable message ID and records a **durable receipt** during the transfer process. This mechanism allows senders to retry transmission if the receiver later discards the file, ensuring reliable delivery of sensitive content across the fragmented transport.

## Code Examples

The following Swift snippets demonstrate the fragmentation flow for sending and receiving large media files:

```swift
// Sending a large audio clip that exceeds 512 bytes
let rawData = try Data(contentsOf: audioURL)
let packet = BitchatPacket(payload: rawData, ...)
BLEService.shared.send(packet)

```

```swift
// Receiving side validation inside BLEFileTransferHandler
func handle(_ packet: BitchatPacket, from peerID: PeerID) -> Bool {
    return storeIncomingPayload(
        packet.payload,
        from: peerID,
        senderNickname: "Alice",
        timestamp: Date(),
        isPrivate: false,
        usesDurableReceipts: false,
        env: environment)
}

```

```swift
// Atomic persistence to prevent partial file visibility
let destination = environment.saveIncomingFile(
    filePacket.content,
    filePacket.fileName,
    "audio/incoming",
    "m4a",
    "audio")

```

## Summary

- **Automatic Fragmentation:** [`BitchatPacket.swift`](https://github.com/permissionlesstech/bitchat/blob/main/BitchatPacket.swift) splits payloads exceeding 512 bytes without developer intervention.
- **Ordered Reassembly:** The internal `BLEReceivePipeline` reconstructs media using fragment index metadata before validation.
- **Atomic Visibility:** `BLEIncomingFileStore` uses temporary *live-capture* prefixes to prevent users from seeing incomplete files.
- **Quota Protection:** The BCH-01-002 enforcement prevents storage overflow before files are committed to disk.
- **Reliable Delivery:** Durable receipts enable retry logic for private media transfers across potentially lossy BLE connections.

## Frequently Asked Questions

### What is the maximum file size BitChat can transfer over BLE?

While the BLE transport itself handles payloads through fragmentation, BitChat imposes upper limits via the **BCH-01-002** storage quota enforcement. The `BLEFileTransferHandler` validates available space using `environment.enforceStorageQuota` before calling `BLEIncomingFileStore.saveIncomingFile`, meaning the practical limit depends on device capacity rather than a fixed byte threshold.

### How does BitChat prevent partially received files from appearing in the gallery?

The system implements **atomic visibility** through `BLEIncomingFileStore`, which writes all incoming data to temporary files with a *live-capture* prefix. Only after `BLEFileTransferHandler` validates the complete reassembled payload and successfully moves the file into the permanent media directory does it create the `BitchatMessage` and invoke `deliverMessage` to surface the content in the UI. Failed deliveries trigger immediate cleanup of temporary fragments.

### How are fragmented packets sequenced during transfer?

During packet creation in [`BitchatPacket.swift`](https://github.com/permissionlesstech/bitchat/blob/main/BitchatPacket.swift), fragmentation metadata—including the **fragment index** and **total fragment count**—is embedded in each packet header. The `BLEReceivePipeline` buffers incoming fragments and uses this metadata to concatenate them in the correct order before passing the complete payload to `BLEFileTransferHandler.handle(_:)`.

### What distinguishes private media handling in BitChat's BLE file transfer?

For private transfers, `BLEFileTransferHandler` reserves a stable message ID and records a **durable receipt** before completing the transfer. This allows the sender to retry transmission if the receiver later discards the file, ensuring reliable delivery of sensitive content even when operating across the fragmented BLE transport layer.