> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/opentrack/opentrack/llms.txt
> Use this file to discover all available pages before exploring further.

# Output Protocol Setup

> Configure output protocols to connect OpenTrack to games and simulators

Output protocols send processed head tracking data to games and applications. OpenTrack supports numerous output formats for compatibility with virtually any software.

## Protocol Module System

Protocols are plugins that implement the IProtocol interface:

```cpp theme={null}
struct OTR_API_EXPORT IProtocol : module_status_mixin {
    // Called 250 times per second with processed pose data
    virtual void pose(const double* pose, const double* raw) = 0;
    
    // Return game name or placeholder text
    virtual QString game_name() = 0;
};
```

### Module Selection

```cpp theme={null}
struct module_settings {
    bundle b { make_bundle("modules") };
    value<QString> protocol_dll { b, "protocol-dll", "freetrack" };
};
```

## Available Protocols

<Tabs>
  <Tab title="Gaming">
    ### FreeTrack

    Industry-standard protocol used by many games.

    **Supported Games**:

    * Arma series
    * DCS World
    * War Thunder
    * Euro Truck Simulator
    * American Truck Simulator
    * Many others

    **Interface**: Shared memory

    **Data Format**: 6DOF position and rotation

    ### TrackIR

    Compatible with TrackIR-enabled games.

    <Warning>
      Some games require the official TrackIR software to be installed, even when using OpenTrack.
    </Warning>
  </Tab>

  <Tab title="Flight Simulation">
    ### FlightGear

    Native integration with FlightGear flight simulator.

    **Protocol**: UDP socket

    **Configuration**:

    ```cpp theme={null}
    // IP address: 127.0.0.1 (local) or remote IP
    // Port: 5542 (default)
    ```

    ### FSUIPC

    Integration with Microsoft Flight Simulator via FSUIPC.

    **Requirements**:

    * FSUIPC installed
    * Compatible Flight Simulator version

    ### SimConnect

    Direct integration with Microsoft Flight Simulator.

    **Supported Versions**:

    * FSX
    * Prepar3D
    * MSFS 2020
  </Tab>

  <Tab title="Universal">
    ### UDP Output

    Send tracking data over UDP to any application.

    **Data Format**:

    ```cpp theme={null}
    struct UDPPacket {
        double x, y, z;           // Translation (cm)
        double yaw, pitch, roll;  // Rotation (degrees)
    };
    ```

    **Configuration**:

    * Target IP address
    * Target port
    * Optional data format customization

    ### OSC (Open Sound Control)

    Send tracking data using OSC protocol.

    **Use Cases**:

    * VR applications
    * Creative tools
    * Custom integrations

    ### Mouse

    Control mouse cursor with head movements.

    **Axes**: Typically Yaw → X, Pitch → Y
  </Tab>

  <Tab title="Platform-Specific">
    ### Wine/Proton (Linux)

    FreeTrack support for Windows games on Linux.

    **Requirements**:

    * Wine or Proton
    * Compatible game

    ### libevdev (Linux)

    Create virtual input device on Linux.

    ### IOKit/Foohid (macOS)

    Virtual HID device for macOS.
  </Tab>
</Tabs>

## Protocol Data Flow

The pipeline calls the protocol at 250Hz:

```cpp theme={null}
void pipeline::logic() {
    // ... tracking and processing ...
    
    // Final output
    libs.pProtocol->pose(value, raw);
    
    {
        QMutexLocker foo(&mtx);
        m_output_pose = value;  // Mapped/processed
        m_raw_6dof = raw;       // Raw tracker data
    }
}
```

<Steps>
  <Step title="Receive Data">
    Protocol receives both processed and raw pose data:

    ```cpp theme={null}
    void pose(const double* pose, const double* raw) {
        // pose[0-5]: Fully processed output
        // raw[0-5]:  Raw tracker data
    }
    ```
  </Step>

  <Step title="Transform Data">
    Convert OpenTrack format to protocol-specific format:

    ```cpp theme={null}
    // OpenTrack uses cm and degrees
    // Some protocols need different units
    float x_inches = pose[TX] * 0.393701f;
    float yaw_radians = pose[Yaw] * (M_PI / 180.0);
    ```
  </Step>

  <Step title="Transmit">
    Send data via protocol-specific method:

    * Shared memory (FreeTrack, TrackIR)
    * Network socket (UDP, FlightGear)
    * System APIs (Mouse, SimConnect)
  </Step>
</Steps>

## FreeTrack Protocol Details

FreeTrack is the most commonly used protocol:

### Shared Memory Structure

```cpp theme={null}
struct FTData {
    uint32_t DataID;           // Packet identifier
    int32_t CamWidth;          // Camera width
    int32_t CamHeight;         // Camera height
    
    // Raw head pose (1:1 with head)
    float Yaw;                 // +left / -right
    float Pitch;               // +up / -down  
    float Roll;                // +left / -right
    float X;                   // +right / -left
    float Y;                   // +up / -down
    float Z;                   // +forward / -backward
    
    // Raw values
    float RawX, RawY, RawZ;
    float RawYaw, RawPitch, RawRoll;
    
    // Extra data
    float X1, Y1, X2, Y2, X3, Y3, X4, Y4;
};
```

### Memory Mapping

```cpp theme={null}
HANDLE hMapFile = OpenFileMappingA(
    FILE_MAP_WRITE,
    false,
    "FT_SharedMem"
);

FTData* pMemData = (FTData*)MapViewOfFile(
    hMapFile,
    FILE_MAP_WRITE,
    0, 0,
    sizeof(FTData)
);
```

## UDP Protocol Details

UDP output is highly flexible:

### Basic Configuration

```cpp theme={null}
struct UDPSettings {
    QString ip_address { "127.0.0.1" };
    int port { 5005 };
};
```

### Sending Data

```cpp theme={null}
void UDPProtocol::pose(const double* data, const double*) {
    QByteArray datagram;
    QDataStream stream(&datagram, QIODevice::WriteOnly);
    
    for (int i = 0; i < 6; i++) {
        stream << data[i];
    }
    
    socket.writeDatagram(datagram, address, port);
}
```

<Note>
  UDP is connectionless and doesn't guarantee delivery. This is acceptable for tracking data since new data arrives every 4ms.
</Note>

## Game-Specific Setup

<Tabs>
  <Tab title="DCS World">
    <Steps>
      <Step title="Enable FreeTrack">
        1. Open DCS options
        2. Go to Controls → Head Tracking
        3. Select "Enable head tracking"
      </Step>

      <Step title="Configure OpenTrack">
        1. Select **FreeTrack 2.0** protocol
        2. Start tracking
        3. Configure mapping curves for best response
      </Step>

      <Step title="Fine-tune">
        * Reduce translation sensitivity for cockpit views
        * Increase yaw/pitch sensitivity for better awareness
        * Enable relative translation for comfortable operation
      </Step>
    </Steps>
  </Tab>

  <Tab title="Arma 3">
    <Steps>
      <Step title="Install FreePIE Bridge">
        Required for FreeTrack support in Arma 3.
      </Step>

      <Step title="Configure Game">
        Enable TrackIR in game options.
      </Step>

      <Step title="Mapping Recommendations">
        * Moderate yaw sensitivity (1:1 or 2:1)
        * Lower pitch sensitivity (avoid looking too far up/down)
        * Minimal translation (can be disorienting)
      </Step>
    </Steps>
  </Tab>

  <Tab title="Euro/American Truck Sim">
    <Steps>
      <Step title="Enable FreeTrack">
        In game options, enable head tracking.
      </Step>

      <Step title="Recommended Settings">
        ```cpp theme={null}
        // Yaw: 45° input → 75° output (1.67:1)
        // Pitch: 30° input → 45° output (1.5:1)
        // Roll: Disabled or minimal
        // Translation: Moderate for depth perception
        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="Elite Dangerous">
    <Steps>
      <Step title="Enable Camera Suite">
        Elite requires Camera Suite binding for head look.
      </Step>

      <Step title="Protocol Selection">
        Use **TrackIR** or **FreeTrack** protocol.
      </Step>

      <Step title="Important">
        <Warning>
          Disable "Rotation Lock" in Elite's head look settings for smooth tracking.
        </Warning>
      </Step>
    </Steps>
  </Tab>
</Tabs>

## Protocol Dialog

Protocols can provide configuration dialogs:

```cpp theme={null}
struct OTR_API_EXPORT IProtocolDialog : public BaseDialog {
    virtual void register_protocol(IProtocol *protocol) = 0;
    virtual void unregister_protocol() = 0;
};
```

The dialog receives the active protocol instance for live updates.

## Creating Custom Protocols

<Steps>
  <Step title="Implement IProtocol">
    ```cpp theme={null}
    class MyProtocol : public IProtocol {
        void pose(const double* data, const double* raw) override {
            // Send data to your application
        }
        
        QString game_name() override {
            return "My Game";
        }
        
        module_status initialize() override {
            // Set up connection
            return status_ok();
        }
    };
    ```
  </Step>

  <Step title="Handle Threading">
    Protocol methods are called from the tracking thread:

    ```cpp theme={null}
    void pose(const double* data, const double* raw) override {
        // Don't block here!
        // Queue data and send from separate thread if needed
        
        QMutexLocker lock(&mutex);
        latest_data = Pose(data);
        data_available.wakeOne();
    }
    ```
  </Step>

  <Step title="Register Plugin">
    ```cpp theme={null}
    class MyProtocolMeta : public Metadata {
        QString name() override { return "My Protocol"; }
        QIcon icon() override { return QIcon(":/icon.png"); }
    };

    OPENTRACK_DECLARE_PROTOCOL(
        MyProtocol,
        MyProtocolDialog,
        MyProtocolMeta
    )
    ```
  </Step>
</Steps>

## Performance Considerations

The protocol runs at 250Hz, so efficiency matters:

<Warning>
  **Never block** in the pose() method. Network I/O, file operations, and heavy computation should use separate threads.
</Warning>

### Good Practice

```cpp theme={null}
void pose(const double* data, const double*) override {
    // Fast: Copy data
    memcpy(shared_memory, data, sizeof(double) * 6);
    
    // Fast: Update atomic values
    latest_pose.store(Pose(data));
    
    // Fast: Lock-free queue
    data_queue.enqueue(data);
}
```

### Avoid

```cpp theme={null}
void pose(const double* data, const double*) override {
    // Slow: Blocking network I/O
    socket.write(data, sizeof(double) * 6);
    socket.waitForBytesWritten();  // DON'T DO THIS
    
    // Slow: File I/O
    file.write(data, sizeof(double) * 6);
    file.flush();
}
```

## Troubleshooting

<Accordion title="Game doesn't detect tracking">
  1. Verify protocol selection matches game requirements
  2. Start OpenTrack **before** launching game
  3. Check if game has head tracking enabled in settings
  4. Try running game and OpenTrack as administrator (Windows)
  5. Check for antivirus blocking shared memory access
</Accordion>

<Accordion title="Tracking works but is inverted">
  Use axis inversion in configuration:

  ```cpp theme={null}
  axis_opts::invert_post = true;  // Invert after processing
  ```

  Some games also have inversion settings.
</Accordion>

<Accordion title="Network protocol not connecting">
  1. Verify IP address and port
  2. Check firewall rules
  3. Test with localhost (127.0.0.1) first
  4. Use Wireshark to verify packets are sent
</Accordion>

<Accordion title="Poor performance in game">
  1. OpenTrack runs at 250Hz - check CPU usage
  2. Disable logging if enabled
  3. Reduce filter complexity
  4. Check for USB bandwidth issues (optical trackers)
</Accordion>

## Next Steps

<CardGroup cols={2}>
  <Card title="Filters" icon="sliders" href="/guides/filters">
    Add smoothing and stabilization
  </Card>

  <Card title="Mapping Curves" icon="chart-line" href="/guides/mapping-curves">
    Optimize tracking response
  </Card>

  <Card title="Configuration" icon="gear" href="/guides/configuration">
    Advanced configuration options
  </Card>
</CardGroup>
