sipbot 0.2.46

A simple SIP bot with RTP
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
# SipBot

[![Crates.io](https://img.shields.io/crates/v/sipbot.svg)](https://crates.io/crates/sipbot)
[![Documentation](https://docs.rs/sipbot/badge.svg)](https://docs.rs/sipbot)

A flexible, high-performance SIP bot implementation in Rust, designed for testing and simulating SIP call flows. It uses [rsipstack](https://github.com/restsend/rsipstack) for signaling and supports customizable call handling stages including ringing, answering, media playback, echo, and automatic hangup.

The media transport uses [rustrtc](https://github.com/restsend/rustrtc).

## Features

- **Multi-Account Support**: Configure multiple SIP accounts in a single instance.
- **Flexible Call Flow Stages**:
  - **Ringing (Stage 1)**: Send `180 Ringing` or `183 Session Progress` with custom ringback tone (WAV).
  - **Answer (Stage 2)**: Auto-answer calls with `200 OK`.
  - **Media Handling**:
    - **Play**: Play a specified `.wav` file.
    - **Echo**: Echo received RTP packets back to the sender (Latency testing).
    - **Local**: Use local audio device for playback and capture (Mic/Speaker).
  - **Hangup (Stage 3)**: Automatically hang up after a configurable duration or reject calls with specific SIP codes.
- **Outbound Calls**: Ability to initiate calls to a target URI.
- **Call Recording**: (Experimental) Record call audio to WAV files. (Requires configuration)
- **DTMF (RFC 2833)**: Send DTMF digits via keyboard during single calls; receive and log DTMF events from remote endpoints. Supports scheduled DTMF flows: `--dtmf-flows "1s:2,1.5s:#"`.
- **Hold/Resume (Re-INVITE)**: Automatically send hold/resume re-INVITEs at scheduled times. Supports `--reinvite-flows "5s:hold,10s:resume"` — ideal for testing RFC 3264 SDP direction negotiation and RTP silence during hold.
- **Audio Quality Analysis**: Per-call audio quality monitoring with RMS, clipping, DC offset, zero-crossing rate, spectral tilt, shrill/muffled classification, and sample-rate mismatch detection.
- **Registration**: Supports SIP registration with authentication (WIP).

## Quick start

Install the `sipbot` from `crates.io`.

```bash
cargo install sipbot
```

## Build from source

Linux users can build a static binary with musl for maximum compatibility:
```bash
cargo build -r --target x86_64-unknown-linux-musl --no-default-features
```

### CLI Usage

You can also run `sipbot` with CLI arguments for quick testing.

#### Global Options

- `-C, --conf <FILE>`: Path to the configuration file.
- `-E, --external <IP>`: External IP address for SDP (NAT traversal).
- `-v, --verbose`: Enable verbose logging.

#### Initiate a Call

```bash
cargo run -- call -t sip:user@domain -u sipbot --play audio.wav --hangup 10 --total 10 --cps 2
```

- `-t, --target <TARGET>`: Target URI (e.g., sip:user@domain).
- `-u, --username <USER>`: Username (e.g., sipbot). Alias: `--caller`.
- `--auth-user <USER>`: Auth username (optional).
- `--password <PASS>`: Auth password.
- `--register [DOMAIN]`: Register to SIP server before calling (optional domain).
- `--hangup <SECONDS>`: Hangup after seconds.
- `--play <FILE>`: Play file (wav).
- `--local`: Use local audio device for playback and capture.
- `--record <FILE>`: Record to file (wav). If multiple calls are made, the filename will be suffixed with the call index (e.g., `record_1.wav`).
- `--srtp`: Enable SRTP/SDES.
- `--nack`: Enable NACK.
- `--jitter`: Enable Jitter Buffer.
- `--total <COUNT>`: Total number of calls to make (default: 1).
- `--cps <COUNT>`: Calls per second (default: 1).
- `--cancel-prob <PROB>`: Cancel probability (0-99%) (default: 0).
- `--codecs <LIST>`: Codecs to use (e.g., opus,g722,pcmu).
- `--audio-quality`: Enable per-call audio quality analysis (RMS, clipping, DC offset, spectral tilt, shrill/muffled detection).
- `--csv-output <FILE>`: Output periodic statistics to CSV file.
- `--csv-interval <SECONDS>`: CSV output interval in seconds (default: 5).
- `--from <USER>`: From URI user part for outbound calls (e.g., anonymous).
- `-H, --header <HEADER>`: Add custom SIP header (e.g., `-H 'X-Custom: value'`). Can be used multiple times.
- `--dtmf-flows <FLOW>`: Scheduled DTMF flow after answer (e.g., `"1s:2,1.5s:#"` sends `2` after 1s, `#` after 1.5s).
- `--reinvite-flows <FLOW>`: Scheduled re-INVITE flow after answer (e.g., `"5s:hold,10s:resume"` sends hold after 5s, resume after 10s).

> **Tip**: When making a single call (`--total 1`), you can send DTMF digits by typing them in the terminal. Supported: `0-9`, `*`, `#`, `A-D`. Press `q` to quit the DTMF reader.

```bash
cargo run -- wait --addr 0.0.0.0:5060 -u sipbot --answer welcome.wav
```

- `-a, --addr <ADDR>`: Bind address (e.g., 0.0.0.0:5060).
- `-u, --username <USER>`: Username (e.g., sipbot).
- `-d, --domain <DOMAIN>`: Domain/Realm (e.g., 127.0.0.1). Alias: `--realm`.
- `--auth-user <USER>`: Auth username (optional).
- `-p, --password <PASS>`: Password for registration.
- `--register [DOMAIN]`: Register to SIP server (optional domain).
- `--ringback <FILE>`: Ringback file (wav).
- `--ring-duration <SECONDS>`: Ring duration in seconds.
- `--answer <FILE>`: Answer and play file (wav).
- `--echo`: Answer and echo.
- `--local`: Answer and use local audio device.
- `--hangup <SECONDS>`: Hangup after seconds.
- `--reject <CODE>`: Reject with code (e.g. 486, 603).
- `--reject-prob <PROB>`: Randomly reject call with probability 1-99% (default code 480).
- `--srtp`: Enable SRTP/SDES.
- `--nack`: Enable NACK.
- `--jitter`: Enable Jitter Buffer.
- `--codecs <LIST>`: Codecs to use (e.g., opus,g722,pcmu).
- `--audio-quality`: Enable per-call audio quality analysis.
- `-H, --header <HEADER>`: Add custom SIP header (e.g., `-H 'X-Custom: value'`). Can be used multiple times.

> **Note**: By default, `wait` mode does not record calls. To enable recording, you must use a configuration file and specify the `recorders` directory.

#### Other Commands

- `options`: Send OPTIONS request.
- `info`: Send INFO request.

## Typical Usage Examples

### 1. Echo Test (Latency & Connectivity)

Answer incoming calls and echo the audio back to the caller. This is perfect for testing network latency and packet loss.

```bash
sipbot wait --username echo-bot --echo
```

### 2. Intercom Mode (Local Audio)

Use your computer's microphone and speakers to talk to a SIP caller.

```bash
sipbot wait --username intercom --local
```

### 3. Automated Announcement

Answer calls, play a welcome message, and hang up after 10 seconds.

```bash
sipbot wait --username announcement --answer welcome.wav --hangup 10
```

### 4. Custom SIP Headers

Add custom SIP headers to outgoing calls and incoming responses:

```bash
# Outgoing call with custom headers
sipbot call -t sip:user@domain -u caller -H 'X-Call-Type: test' -H 'X-Session-ID: 12345' --hangup 5

# Incoming call handling with custom headers in response
sipbot wait --username responder --answer welcome.wav -H 'X-Server-ID: bot-01' -H 'X-Region: US-West'
```

```bash
sipbot wait --username announcer --answer welcome.wav --hangup 10
```

### 4. Load Testing (Outbound)

Make 100 calls to a target, with 5 calls per second, playing an audio file for 30 seconds each.

```bash
sipbot call -t sip:100@192.168.1.10 --play music.wav --total 100 --cps 5 --hangup 30
```

### 5. High-Quality Audio (G.722)

SipBot supports G.722 (16kHz) for high-definition audio. It automatically negotiates the best codec.

```bash
# Make a call using G.722 if supported by the remote end
sipbot call -t sip:hd-user@domain --play high_res.wav
```

### 6. Call Recording

Record all incoming calls to a specific directory. (Requires `recorders` path in `config.toml`)

```bash
# In config.toml:
# recorders = "./wavs"

sipbot wait --username recorder-bot
```

### 7. Send DTMF Digits During a Call

Make a single call and send DTMF digits interactively from the terminal:

```bash
sipbot call -t sip:user@domain -u sipbot --hangup 30
# Type digits (0-9, *, #, A-D) and press Enter to send DTMF
# Press 'q' to quit the DTMF reader
```

### 8. Hold/Resume (Re-INVITE) Testing

Test hold/resume re-INVITE flows between two sipbot instances. The caller sends a hold re-INVITE after 4s, then resume after 12s.

```bash
# Terminal 1 — Callee (echo mode)
sipbot wait --addr 0.0.0.0:5061 --username bob --echo

# Terminal 2 — Caller (auto hold at 4s, resume at 12s, hangup at 25s)
sipbot call --target sip:bob@127.0.0.1:5061 --username alice \
  --reinvite-flows "4s:hold,12s:resume" --hangup 25
```

### 9. Audio Quality Analysis

Enable per-call audio quality analysis to detect clipping, silence, shrill/muffled audio, and sample rate mismatches:

```bash
# Outbound call with audio quality monitoring
sipbot call -t sip:user@domain -u sipbot --hangup 30 --audio-quality

# Wait for calls with audio quality monitoring
sipbot wait --username quality-bot --echo --audio-quality
```

## Configuration

Create a `config.toml` file in the root directory. The configuration allows you to define the behavior for each account.

### Example `config.toml`

```toml
# Global settings
addr = "0.0.0.0:5060"           # Local bind address
external_ip = "1.2.3.4"         # External IP for SDP (NAT traversal)
recorders = "/tmp/recorders"    # Directory for recordings (Required for recording)

[[accounts]]
username = "1001"
domain = "sip.example.com"
password = "secretpassword"
register = true                 # Enable registration
reject_prob = 20                # Randomly reject 20% of calls with 480
codecs = ["opus", "g722", "pcmu"]  # Preferred codecs
headers = [                     # Custom SIP headers
    "X-Server-ID: sipbot-01",
    "X-Region: US-West",
    "X-Environment: production"
]

# --- Call Handling Flow ---

# Stage 1: Ringing
# Wait for 5 seconds before answering.
# If 'ringback' is provided, sends 183 Session Progress and plays the file.
# If 'ringback' is omitted, sends 180 Ringing.
[accounts.ring]
duration_secs = 5
# ringback = "sounds/ringback.wav" 

# Stage 2: Answer
# Answer the call (200 OK) and perform an action.
[accounts.answer]
action = "play"                 # Options: "play", "echo", "local"
wav_file = "sounds/welcome.wav" # Required if action is "play"

# [accounts.answer]
# action = "echo"               # Alternative: Echo test

# [accounts.answer]
# action = "local"              # Alternative: Use local audio device (Mic/Speaker)

# Stage 3: Hangup
# Automatically hang up after the media finishes or a timeout.
[accounts.hangup]
code = 200                      # SIP code (not fully used for BYE yet, mainly for rejection)
after_secs = 10                 # Send BYE after 10 seconds
```

### Configuration Reference

- **`addr`**: (Optional) The local IP and port to bind to. Defaults to `0.0.0.0:35060`.
- **`external_ip`**: (Optional) The external IP address to use in SDP offers/answers (useful for NAT).
- **`recorders`**: (Optional) Path to save call recordings.
- **`accounts`**: List of account configurations.
    - `username`: SIP username.
    - `auth_username`: (Optional) SIP authentication username.
    - `domain`: SIP domain/registrar.
    - `password`: SIP password.
    - `proxy`: (Optional) SIP proxy server address.
    - `register`: (Bool) Whether to register with the domain.
    - `reject_prob`: (Optional) Probability (1-99) to randomly reject incoming calls with 480.
    - `cancel_prob`: (Optional) Probability (1-99) to randomly cancel outgoing calls.
    - `target`: (Optional) URI to call on startup (for outbound bot).
    - `record`: (Optional) Recording file path.
    - `srtp_enabled`: (Bool) Enable SRTP/SDES.
    - `nack_enabled`: (Bool) Enable RTP NACK.
    - `jitter_buffer_enabled`: (Bool) Enable Jitter Buffer.
    - `dtmf_flows`: (String) Scheduled DTMF digits after answer (e.g., `"1s:2,1.5s:#"`).
    - `reinvite_flows`: (String) Scheduled hold/resume re-INVITEs after answer (e.g., `"5s:hold,10s:resume"`).
    - `codecs`: (Array) List of preferred codecs (e.g., `["opus", "g722", "pcmu"]`).
    - `headers`: (Array) List of custom SIP headers to include in INVITE requests and 200 OK responses (e.g., `["X-Custom-Header: value", "X-Call-ID: 12345"]`).
    - `audio_quality`: (Optional) Enable per-call audio quality analysis. Example:
        ```toml
        [accounts.audio_quality]
        enabled = true
        sample_rate_check = true
        clipping_threshold = 0.95
        shrill_threshold = 0.65
        muffled_threshold = 0.15
        silence_threshold_rms = 50.0
        report_interval = 100
        ```
    - `codecs`: (Optional) List of preferred codecs (e.g., `["opus", "g722", "pcmu"]`).
    - **`early_media`**: Configuration for the early media phase (183).
        - `wav_file`: (Optional) Path to WAV file.
        - `local`: (Optional) `true` to use local audio device for capture and playback.
    - **`ring`**: Configuration for the ringing phase.
        - `duration_secs`: How long to stay in ringing state.
        - `ringback`: (Optional) Path to WAV file for early media (183).
        - `local`: (Optional) `true` to use local audio device for capture and playback.
    - **`answer`**: Configuration for the answered phase.
        - `action`: `play`, `echo` or `local`.
        - `wav_file`: Path to WAV file (if action is `play`).
    - **`hangup`**: Configuration for ending the call.
        - `code`: SIP status code (used for rejection if no answer config exists).
        - `after_secs`: (Optional) Time in seconds to wait before sending BYE.

## Benchmarking and Testing

`SipBot` is designed to facilitate SIP performance testing and benchmarking by simulating multiple callers and callees with customizable behaviors.

### Example Scenario

To run a benchmark, you typically need two instances of `SipBot`: one for caller and another for callee. they will register on sip server with alice and bob respectively.

#### Callee Configuration (`callee.toml`)

This bot listens for incoming calls, rings for a few seconds, and randomly rejects 50% of the calls to test error handling.

```toml
# Local bind address for the callee
addr = "0.0.0.0:3333" 

[[accounts]]
register = true
proxy = "127.0.0.1:15060" # sip server address
username = "alice"
domain = "127.0.0.1"
password = "123456"
reject_prob = 20   # 20% probability to reject incoming calls

[accounts.hangup]
code = 486         # reject with code 486

[accounts.ring]
duration_secs = 3  # Wait for 3 seconds in ringing state before answering
```

#### Caller Configuration (`caller.toml`)

This bot initiates calls to a target, with a 30% chance of canceling the call before it is answered.

```toml
# Local bind address for the caller
addr = "0.0.0.0:4444" 

[[accounts]]
register = true
proxy = "127.0.0.1:15060"
username = "bob"
domain = "127.0.0.1"
password = "123456"
target = "sip:alice@127.0.0.1" # The destination to call

# Probability to randomly cancel calls
cancel_prob = 30

[accounts.hangup]
after_secs = 5     # If the call is answered, hang up (send BYE) after 5 seconds
code = 486         # currectly not used for caller
```

> Note: if cancel_prob is set, caller will randomly deside cancel before or after ringing 50:50.

### How to Run

0. **Start the Sip Server**

1. **Start the Callee**:
   The callee should be running first to receive calls.

   ```bash
   cargo run -- wait --conf callee.toml
   ```

2. **Start the Caller**:
   The caller initiates the calls. You can use `--total` and `--cps` to control the load.

   ```bash
   # Make 100 total calls, with a rate of 3 calls per second
   sipbot --conf caller.toml call --total 100 --cps 3
   ```

## License

MIT