flutter_sip_ua
Pure-Dart SIP user agent and Flutter client for the dart-pbx server. The UI is modelled on InnovateAsterisk Browser-Phone with a Riverpod-driven state layer and a modular widget tree.
Repository: github.com/KellyKinyama/flutter_sip_ua
Features
- Pure-Dart SIP signalling stack (
lib/sip/) — registration, calls, MESSAGE, digest auth, SDP, RTP/RTCP helpers. - Pure-Dart media path — G.711 codec, RTP packetizer, jitter buffer. No
flutter_webrtc, no libwebrtc binary. - Multiple transports out of the box: WS/WSS, UDP, and optional
RTP-over-QUIC datagrams (
pure_dart_quic). - Riverpod-based state management (
lib/providers/sip_providers.dart). - Browser-Phone-style UI:
- Two-pane shell with buddy sidebar + active stream.
- Modular call screen (
lib/ui/widgets/call/). - Dialer sheet, message composer, transfer sheet.
- Light and dark themes that mirror
phone.light.css/phone.dark.css. Theme choice is persisted via SharedPreferences and toggled from the sidebar toolbar (system → light → dark).
Why not dart-sip-ua + flutter_webrtc?
dart-sip-ua is a JsSIP port that
delegates all media to flutter_webrtc,
which bundles libwebrtc — roughly 10M lines of C++ extracted from Chromium,
shipped as tens of megabytes of native binaries per platform. flutter_sip_ua
keeps the entire stack — signalling, transport, RTP, codecs — in pure Dart,
targeting the same capability surface as
dart-webrtc without the
native dependency.
dart-sip-ua + flutter_webrtc |
flutter_sip_ua |
|
|---|---|---|
| Language end-to-end | Dart + ~10M LOC C++ (libwebrtc) | Pure Dart |
| Binary footprint | Tens of MB of native libs per ABI/platform | Kilobytes |
| Native toolchain | NDK / CocoaPods / MSVC / depot_tools | None |
| Web support | Browser's WebRTC (different impl) | Same Dart code |
| Transports | WS / WSS only | WS / WSS / UDP / QUIC datagrams (TCP/TLS/SCTP pluggable) |
| Memory safety | C++ attack surface | Dart, memory-safe |
| Debuggability | RTC_LOG + Chromium source | Set a breakpoint |
Transports beyond WebSockets
dart-sip-ua is effectively WebSocket-only — a browser-era constraint
inherited from JsSIP. flutter_sip_ua ships:
- WS / WSS via
web_socket_channel(works ondart:ioand web). - UDP via
RawDatagramSocket(lib/sip/transport_udp_io.dart) — talk directly to Asterisk / FreeSWITCH / Kamailio on:5060with no WS gateway. - RTP-over-QUIC datagrams via
pure_dart_quic— multiplexed, congestion-controlled, NAT/firewall-friendly. - A pluggable transport interface so TCP, TLS, SCTP, or WebTransport can be added without native plugin work.
Current state vs. roadmap
Today: G.711 audio, RTP/RTCP, jitter buffer, SIP REGISTER / INVITE / MESSAGE, RFC 2617 digest, WS/WSS/UDP, optional QUIC datagrams.
Planned (pure-Dart parity with dart-webrtc): ICE / STUN / TURN, DTLS-SRTP,
Opus, video codecs (VP8 / H.264), data channels, AEC / AGC.
dart-sip-ua + flutter_webrtc is more battle-tested today because it
inherits everything from libwebrtc. flutter_sip_ua is the better fit when you
want a small, auditable, web-friendly client that speaks to a real SIP server
without dragging a Chromium-derived binary into your app.
Getting started
flutter pub get
flutter run -d windows # or chrome / android / ios / linux / macos
Tests:
flutter test
Project layout
lib/
main.dart
providers/sip_providers.dart # Riverpod facade over the SIP UA + UI state
sip/ # Pure-Dart SIP UA, SDP, transport, audio/video
ui/
theme.dart # Light/dark ThemeData built from BP palette
bp_palette.dart # Browser-Phone color tokens + ThemeExtension
home_page.dart # Two-pane shell + dialer sheet
call_page.dart # Slim call orchestrator
widgets/
buddy_sidebar.dart # Left rail incl. theme toggle
dial_pad.dart
dialer_action_row.dart
call/ # Modular call UI pieces
Links
- Source: github.com/KellyKinyama/flutter_sip_ua
- Issues: github.com/KellyKinyama/flutter_sip_ua/issues
- Browser-Phone reference: github.com/InnovateAsterisk/Browser-Phone
Libraries
- main
- providers/log_path_io
- Native (
dart:io) log-path builder. Picks a temp directory per launch. - providers/log_path_stub
- Web stub for log-path resolution. The web logger is a no-op so the path is meaningless — return an empty string.
- providers/sip_providers
- Riverpod providers for the SIP user agent and the UI-facing state derived from its event streams.
- sip/audio/audio_sink
- sip/audio/g711
- G.711 μ-law and A-law codec — pure Dart.
- sip/audio/jitter_buffer
- sip/audio/media_session
- Media plane for SIP calls.
- sip/audio/media_session_platform
- Platform facade for MediaSession.
- sip/audio/media_session_stub
- No-op stub for MediaSession used on platforms without
dart:io(e.g. web). Constructing it throws UnsupportedError so callers that forget to gate media setup behind a platform check fail loudly. - sip/audio/pcm_audio_sink
- Cross-platform AudioSink that pushes decoded PCM into
flutter_pcm_sound. Works on Windows / macOS / Linux / Android / iOS. - sip/audio/rtcp
- Minimal RFC 3550 RTCP packet codec — pure Dart.
- sip/audio/rtp
- Minimal RFC 3550 RTP packet builder + parser — pure Dart.
- sip/audio/rtp_quic_session
- Public surface for RTP-over-QUIC support.
- sip/audio/rtp_quic_session_io
dart:ioimplementation of RtpQuicSession backed bypackage:pure_dart_quic.- sip/audio/rtp_quic_session_platform
- Platform facade for RtpQuicSession. Re-exports the native
dart:io-backed implementation when available, otherwise the web stub. - sip/audio/rtp_quic_session_stub
- Web stub for RtpQuicSession. RTP-over-QUIC requires UDP sockets,
which
dart:html-based web builds cannot provide. - sip/audio/rtp_stats
- RTP send/receive bookkeeping needed to emit RFC 3550 SR/RR reports.
- sip/audio/rtp_types
- Pure-Dart RTP / codec types shared by signalling (SDP) and the platform-specific media plane.
- sip/digest
- Client side of RFC 2617 / RFC 3261 §22.4 digest authentication.
- sip/is_web
- Web detection for the pure-Dart SIP layer (no Flutter dep).
- sip/is_web_io
- Native override of isWeb used when
dart:iois available. - sip/sdp
- Tiny SDP helper — only what the SIP UA needs to negotiate G.711 audio (and optional VP8 video) against dart-pbx. Not a full RFC 4566 parser.
- sip/sip_file_logger
- Append-only SIP wire-format logger.
- sip/sip_file_logger_io
dart:ioimplementation of SipFileLogger.- sip/sip_file_logger_stub
- No-op SipFileLogger used on platforms without
dart:io(web). - sip/sip_message
- Minimal RFC 3261 message model — enough to talk to the dart-pbx server.
- sip/sip_user_agent
- Pure-Dart SIP user agent.
- sip/transport
- SIP transports.
- sip/transport_udp_io
dart:ioUDP implementation of SipTransport.- sip/transport_udp_stub
- UDP transport stub used on platforms without
dart:io(web). - sip/video/video_codec
- Pluggable video codec for VideoSession.
- sip/video/video_session
- Video media plane: RTP/RTCP transport for VP8 frames over RFC 7741.
- sip/video/video_session_platform
- Platform facade for VideoSession.
- sip/video/video_session_stub
- No-op stub for VideoSession used on platforms without
dart:io(e.g. web). Constructing it throws UnsupportedError. - sip/video/video_types
- Web-safe video media types shared by signalling, the native impl, and
the web stub. No
dart:io. - sip/video/vp8_rtp
- RFC 7741 — RTP payload format for VP8.
- ui/bp_palette
- ui/call_page
- ui/home_page
- ui/login_page
- ui/theme
- ui/widgets/buddy_stream
- ui/widgets/call/call_action_panels
- ui/widgets/call/call_backdrop
- ui/widgets/call/call_party_card
- ui/widgets/call/call_stats_panel
- ui/widgets/call/call_top_bar
- ui/widgets/call/transfer_sheet
- ui/widgets/dial_pad
- ui/widgets/dialer_action_row
- ui/widgets/status_chip
- ui/widgets/welcome_pane