← Back to blog

The Story of Kallo

The idea

Flutter is a wonderful way to build an app once and ship it to both Android and iOS — but the moment you need real phone calls inside that app, the ecosystem goes quiet. Almost everything points you at WebRTC, which is built for browser-to-browser video and fights you the instant you try to speak plain SIP to a PBX or a carrier. If you run a call center, a support desk, or any product that lives on top of an existing SIP/VoIP backend, there was no clean answer: you either rebuilt your telephony around WebRTC gateways, or you wrote and maintained native calling code twice — once in Kotlin, once in Swift — wrapping a C library most teams have never heard of.

Kallo started from that gap. The bet was simple: take a real, battle-tested native SIP engine, do the hard native work once, and hand Flutter developers a clean Dart API and a single dependency. No WebRTC detour, no native expertise required, TLS + SRTP on by default. You add one line to your pubspec.yaml and you can place a secure call.

The journey

What looked like "wrap a C library" turned into the real engineering story, and almost all of it happened below the API surface.

Making one package behave like two. Flutter plugins aren't designed to ship a closed binary that secretly contains both an Android .aar and an iOS xcframework, build the correct half per target, and never leak a line of C source. Getting that to work — and stay reproducible — meant a two-machine release pipeline: a Windows agent builds the Android half, a Mac agent builds iOS and assembles the combined package, with a throwaway intermediate tag carrying the Android artifact across. A "closed-binary guard" runs on every release and must pass, so the native source can never accidentally end up in the distributed tarball. The tell that everything worked was almost comically simple: the combined package is ~19MB, the Android-only one ~8MB. Size became the smoke test.

The downlink-silence saga. The longest, hardest chapter was audio you couldn't hear. Calls would connect, the mic worked, but the other side's voice would go silent. It took version after version — instrumentation builds, self-healing buffer logic, format audits — to chase it down. The real culprit was brutal and subtle: cross–translation-unit corruption of an audio buffer's sizing inside the native layer. The fix in 0.1.13 was almost anticlimactic next to the hunt — but that stable build, byte-confirmed on real devices, was the moment Kallo became a thing you could actually trust on a call.

Then iOS, then audio routing. After Android stabilized, iOS got the same native treatment and shipped combined in one package. Most recently (0.1.16), Kallo learned to route audio — list and switch the live output between earpiece, speakerphone, wired headset, and Bluetooth, with route-change events — while keeping the old setSpeaker(bool) toggle working. Each of these had to land without disturbing that hard-won audio fix.

The unglamorous half: turning it into a product. A working SDK isn't a business. Around it grew a full commercial stack — a bilingual (English/Arabic, RTL-first) portal with gated downloads and live docs, a Fastify license API on Supabase, an admin dashboard for issuing licenses and tracking usage, Resend for transactional email, Stripe wired in for payments. And because Kallo is built from Libya, the "easy" parts weren't easy: standing up a real domain and email (kallosdk.com), navigating that the apex domain only resolves as www, and confronting that mainstream payment processing simply isn't straightforward from where it's being built. That constraint is honest and still open — Kallo ships a free Basic plan today, with paid tiers gated behind getting payments solved.

Where we are now

Kallo is live and stable at 0.1.16 — native SIP calling on both Android and iOS, secured with TLS and SRTP, distributed as a single closed-binary Flutter package, with call controls and audio-output selection, registration/audio/DTMF all device-confirmed. The commercial platform is deployed and running: portal, docs, license API, and admin dashboard, in two languages. A developer can request access, get a license, and drop real voice calling into their Flutter app.

What we aim for

  • Unblock payments and open paid tiers — the single biggest gate between "a working product" and "a sustainable one," made harder by the Libyan banking context, and worth solving properly.
  • Broaden the SDK surface — deeper call features and platform polish, building on the audio-routing foundation, without ever re-risking the core audio path.
  • Lower the time-to-first-call — make the quickstart so clean that a developer goes from "added the dependency" to "heard a voice" in minutes.
  • Earn trust at scale — more device coverage, real customers in production, and a track record that says: if you need calling in Flutter, you reach for Kallo.

The throughline is the original bet, now proven once: the hard native work is done, so you don't have to do it.