sip_service

Example of the component espressif/esp_sip_service v0.5.0
# SIP Service Example

- [Chinese Version](./README_CN.md)

- Regular Example: ![alt text](../../../../docs/_static/level_regular.png "Regular Example") - demonstrates a full-duplex `esp_sip_service` call

## Example Brief

- This example wires one `esp_sip_service` instance for a full-duplex P2P call and places the call. P2P mode skips registration, so no registrar or account is involved. The copy-ready flow lives in `main/simple_sip.c`.
- A dummy source is linked on the uplink and a dummy sink drains the downlink, so no microphone or speaker is required. The dummy advertises an OPUS track so `start` can take the codec from the link. Because SIP is the repository's only `ESP_MEDIA_ROLE_SRC_SINK` service, both links attach to the same instance.
- The peer defaults to the device itself over loopback, so the example runs with a single board. Nothing answers that INVITE; point `SIP_PEER_IP` in `main/settings.h` at another SIP endpoint to establish media and see the downlink frame count.

### Prerequisites

- Familiarity with [`esp_sip_service`](../../README.md) and [`esp_media_service`](../../../esp_media_service/README.md)
- Nothing else for the default run; a reachable SIP endpoint if you want real media

### Folder Contents

```text
sip_service/
├── main/
│   ├── app_main.c          NVS, media adapter, SoftAP netif, and the demo call
│   ├── simple_sip.c        Copy-ready P2P call flow
│   ├── simple_sip.h
│   └── settings.h          Peer address, port, users, and durations
└── pytest_esp_sip_service_example.py  Boot and call smoke test
```

## Environment Setup

### Hardware Required

- An ESP development board with PSRAM (recommended: ESP32-S3 or ESP32-P4)
- USB cable for the console

A SoftAP is started at boot even when the call stays local: lwIP needs an interface to be up before the UDP sockets can be bound.

## Build and Flash

This example supports ESP-IDF release/v5.5 and later branches. By default, it uses ADF's built-in `$ADF_PATH/esp-idf`.

The default run needs no configuration. Build and flash:

```bash
cd components/esp_sip_service/examples/sip_service
idf.py set-target esp32s3
idf.py build
idf.py -p PORT flash monitor
```

Exit the monitor with `Ctrl-]`.

To call a real endpoint, set `SIP_PEER_IP`, `SIP_PEER_PORT` and `SIP_PEER_USER` in `main/settings.h`, and replace the SoftAP in `app_main.c` with a station connection to the network that endpoint is on.

## How It Works

The instance is created with `p2p_mode = true` and an account whose "server" is the peer:

| Field | Value | Meaning |
| --- | --- | --- |
| `SIP_LOCAL_USER` | 1001 | The user in the local URI |
| `SIP_PEER_USER` | 1002 | The user that is invited |
| `SIP_PEER_IP` / `SIP_PEER_PORT` | 127.0.0.1:5062 | Where the INVITE is sent |

One instance carries both media directions:

```
dummy_src ──link(0 → uplink)──> esp_sip_service ──link(downlink → 0)──> dummy_sink
                                       ⇅ RTP
                                     peer
```

The flow is: create the instance, add an OPUS track on the dummy source, link both directions, start the consumers before the producers, `call`, wait for `CALL_ANSWERED`, run for five seconds, read the sink frame count, then `bye` and tear everything down.

In P2P mode the protocol stack binds the port taken from the URI rather than the configured local port, so `esp_sip_service_set_local_port()` is called with `SIP_PEER_PORT` only to keep the two consistent on paper. The same behavior is why two instances on one device cannot call each other: they would have to share one socket.

## Example Output

```text
I (645) SIP_EX: SIP service example is ready
I (719) SIP_EX: Calling 1002 at 127.0.0.1:5062
I (1098) SIP_EX: CALLING
W (5849) SIP_EX: Nobody answered at 127.0.0.1:5062, set SIP_PEER_IP to a real endpoint for media
I (5985) SIP_EX: HANGUP reason=
W (6190) SIP_EX: ERROR reject_reason=0
I (6426) SIP_EX: SIP_SERVICE_EXAMPLE_PASSED
I (6430) SIP_EX: SIP_SERVICE_EXAMPLE_DONE
```

With a real peer, `CALL_ANSWERED` and `AUDIO_SESSION_BEGIN` arrive instead of the warning, and the run ends with `Downlink received N audio frames`. The example fails only when no `CALLING` event was published, which means the INVITE never left the device.

## Troubleshooting

- No `CALLING` event: the SoftAP did not come up, so the sockets could not bind. Check the boot log for Wi-Fi errors.
- `Downlink received 0 audio frames` with a real peer: the peer answered but sent nothing, or `CONFIG_ESP_SIP_SERVICE_DOWNLINK_SUPPORT` is disabled.
- To try SRTP, set `srtp_mode` in `sip_create()`; with `required` the call is rejected unless both sides offer a crypto line.

## Technical Support

- Technical support: [esp32.com](https://esp32.com/viewforum.php?f=20) forum
- Issue reports and feature requests: [GitHub issue](https://github.com/espressif/esp-adf/issues)

To create a project from this example, run:

idf.py create-project-from-example "espressif/esp_sip_service=0.5.0:sip_service"

or download archive (~11.51 KB)