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

# webrtc.signaling.iceCandidate

> WebRTC ICE candidate signaling event

Triggered when a WebRTC ICE candidate is received through the unified WebSocket connection. ICE candidates are used to establish the optimal network path for WebRTC media streaming.

## Event Properties

<ResponseField name="type" type="string">
  Event type. Always `"webrtc.signaling.iceCandidate"` for this event.
</ResponseField>

<ResponseField name="data" type="object">
  Event data object containing ICE candidate information.
</ResponseField>

<ResponseField name="data.candidate" type="object">
  The RTCIceCandidate object containing candidate information for network path discovery.

  **Example**:

  ```json theme={null}
  {
    "candidate": "candidate:1 1 UDP 2130706431 192.168.1.1 54321 typ host",
    "sdpMLineIndex": 0,
    "sdpMid": "0"
  }
  ```
</ResponseField>

<ResponseExample>
  ```json Example theme={null}
  {
    "type": "webrtc.signaling.iceCandidate",
    "data": {
      "candidate": {
        "candidate": "candidate:1 1 UDP 2130706431 192.168.1.1 54321 typ host",
        "sdpMLineIndex": 0,
        "sdpMid": "0"
      }
    }
  }
  ```
</ResponseExample>

## Sending ICE Candidate

When ICE candidates are generated by your RTCPeerConnection, you need to send them immediately. Here's how to send ICE candidates:

```javascript theme={null}
const NavTalkMessageType = Object.freeze({
    WEB_RTC_ICE_CANDIDATE: "webrtc.signaling.iceCandidate",
    // ... other event types
});

// Function to send ICE candidate
function sendIceMessage(candidate) {
    const message = {
        type: NavTalkMessageType.WEB_RTC_ICE_CANDIDATE,
        data: { candidate: candidate }
    };
    socket.send(JSON.stringify(message));
    console.log('Sent ICE candidate:', message);
}

// Set up ICE candidate handler - send candidates as they're generated
peerConnection.onicecandidate = (event) => {
    console.log('onicecandidate:', event.candidate ? 'new candidate' : 'gathering complete');
    if (event.candidate) {
        // event.candidate is an RTCIceCandidate object
        sendIceMessage(event.candidate);
    }
};
```

**Message Structure:**

When sending an ICE candidate, the message structure should be:

```json theme={null}
{
  "type": "webrtc.signaling.iceCandidate",
  "data": {
    "candidate": {
      "candidate": "candidate:1666409998 1 udp 2122129151 192.168.1.81 64301 typ host generation 0 ufrag lwyK network-id 1",
      "sdpMid": "0",
      "sdpMLineIndex": 0,
      "usernameFragment": "lwyK"
    }
  }
}
```

**RTCIceCandidate Object Properties:**

The `candidate` object should have the following properties:

* `candidate` (string): The candidate string, e.g., `"candidate:1666409998 1 udp 2122129151 192.168.1.81 64301 typ host generation 0 ufrag lwyK network-id 1"`
* `sdpMLineIndex` (number, optional): The SDP media line index, typically `0` for video or `1` for audio
* `sdpMid` (string, optional): The SDP media identification tag, typically `"0"` for video or `"1"` for audio
* `usernameFragment` (string, optional): The ICE username fragment (ufrag)

**Key Points:**

* The `candidate` parameter in `data.candidate` should be an `RTCIceCandidate` object (or equivalent plain object)
* Send ICE candidates **immediately** when they're generated in the `onicecandidate` event handler
* Only send candidates when `event.candidate` is not null (when it's null, ICE gathering is complete)
* You may receive multiple ICE candidates - send each one as it's generated

## Receiving ICE Candidate

When you receive an ICE candidate, handle it like this:

```javascript theme={null}
async function handleReceivedMessage(data) {
    const nav_data = data.data;
    
    switch (data.type) {
        case NavTalkMessageType.WEB_RTC_ICE_CANDIDATE:
            const candidate = new RTCIceCandidate(nav_data.candidate);
            await peerConnection.addIceCandidate(candidate);
            console.log('ICE candidate added');
            break;
    }
}
```

**Complete Example:**

```javascript theme={null}
// Set up peer connection
const peerConnection = new RTCPeerConnection(configuration);

// Send ICE candidates as they're generated
peerConnection.onicecandidate = (event) => {
    console.log('onicecandidate:', event.candidate ? 'new candidate' : 'gathering complete');
    if (event.candidate) {
        sendIceMessage(event.candidate);
    }
};

// Handle received ICE candidates
async function handleReceivedMessage(data) {
    const nav_data = data.data;
    
    switch (data.type) {
        case NavTalkMessageType.WEB_RTC_ICE_CANDIDATE:
            const candidate = new RTCIceCandidate(nav_data.candidate);
            await peerConnection.addIceCandidate(candidate);
            console.log('ICE candidate added');
            break;
    }
}
```

<Note>
  * **When to send**: Send ICE candidates immediately when they're generated in the `peerConnection.onicecandidate` event handler
  * **What to send**: Send `event.candidate` (which is an RTCIceCandidate object) as the `candidate` value
  * **Multiple candidates**: You may receive multiple ICE candidates - send each one as it's generated
  * ICE candidates are sent through the unified WebSocket connection
</Note>
