A dart-lang version of the SIP UA stack, ported from JsSIP.
- Use pure dart-lang
- SIP over WebSocket && TCP (use real SIP in your flutter mobile, desktop, web apps)
- Audio/video calls (flutter-webrtc) and instant messaging
- Support with standard SIP servers such as OpenSIPS, Kamailio, Asterisk, 3CX and FreeSWITCH.
- Support RFC2833 or INFO to send DTMF.
- iOS
- Android
- Web
- macOS
- Windows
- Linux
- Fuchsia
- Proguard rules:
-keep class io.flutter.app.** { *; }
-keep class io.flutter.plugin.** { *; }
-keep class io.flutter.util.** { *; }
-keep class io.flutter.view.** { *; }
-keep class io.flutter.** { *; }
-keep class io.flutter.plugins.** { *; }
-keep class com.cloudwebrtc.webrtc.** {*;}
-keep class org.webrtc.** {*;}
Run example:
- dart-sip-ua-example
- or add your example.
Register with SIP server:
- Asterisk
- FreeSWITCH
- OpenSIPS
- 3CX
- Kamailio
- or add your server example.
expand
WEBRTC_SET_REMOTE_DESCRIPTION_ERROR: Failed to set remote offer sdp: Called with SDP without DTLS fingerprint.
Your server is not sending a DTLS fingerprint inside the SDP when inviting the sip_ua client to start a call.
WebRTC uses encryption by Default, all WebRTC communications (audio, video, and data) are encrypted using DTLS and SRTP, ensuring secure communication. Your PBX must be configured to use DTLS/SRTP when calling sip_ua.
This package uses a WS or TCP connection for the signalling processs to initiate or terminate a session (sip messages). Once the session is connected WebRTC transmits the actual media (audio/video) over UDP.
If anyone actually still wants to use UDP for the signalling process, feel free to submit a PR with the large amount of work needed to set it up, packet order checking, error checking, reliability timeouts, flow control, security etc etc.
The codecs on your PBX server don't match the codecs used by WebRTC
- opus (payload type 111, 48kHz, 2 channels)
- red (payload type 63, 48kHz, 2 channels)
- G722 (payload type 9, 8kHz, 1 channel)
- ILBC (payload type 102, 8kHz, 1 channel)
- PCMU (payload type 0, 8kHz, 1 channel)
- PCMA (payload type 8, 8kHz, 1 channel)
- CN (payload type 13, 8kHz, 1 channel)
- telephone-event (payload type 110, 48kHz, 1 channel for wideband, 8000Hz, 1 channel for narrowband)
Adds ICE disconnect recovery to lib/src/rtc_session.dart. Upstream has no recovery — a network drop kills the call silently.
- ICE Disconnected → 5s timer →
_iceRestart()(re-INVITE withIceRestart: true) - ICE Failed → attempt restart if not already in progress
- 15s safety timer → terminate if ICE never recovers
- Transport check before
_iceRestart()— skip if SIP WebSocket is down (see below) _scheduleIceRestartRetry()— retry re-INVITE every 2s when transport reconnects- TransportError/RequestTimeout during restart → retry instead of terminating
if (!(_ua.socketTransport?.isConnected() ?? false)) {
logger.i('Transport not connected, skipping ICE restart.');
} else {
_iceRestart();
}Without this: _iceRestart() → createLocalDescription generates new ICE ufrag/pwd → re-INVITE can't be sent (transport down) → ICE recovers on old candidate pairs → credential mismatch → outgoing audio breaks.
With this: ICE recovers on its own with consistent credentials. App-level 30s timer handles the case where ICE never recovers.
| Timer | Duration | Purpose |
|---|---|---|
_iceDisconnectTimer |
5s | Wait before ICE restart attempt |
_iceRestartTimer |
15s | Safety net → terminate if no recovery |
_iceRestartRetryTimer |
2s periodic | Retry re-INVITE when transport reconnects |
Thanks to the original authors of JsSIP for providing the JS version, which makes it possible to port the dart-lang.
The first version was sponsored by Suretec Systems Ltd. T/A SureVoIP.
The project is inseparable from the contributors of the community.
- SureVoIP - Sponsor
- CloudWebRTC - Original Author
- Robert Sutton - Contributor
- Gavin Henry - Contributor
- Perondas - Contributor
- Mikael Wills - Contributor
dart-sip-ua is released under the MIT license.