DEV Community

Tahir Almas
Tahir Almas

Posted on • Originally published at ictinnovations.com

We Released Two More Open Source Libraries: Streaming TTS for Calls and 21 CRM Connectors

Originally published at ictinnovations.com

The short version

  • piper-tts-server gives you paced, streaming Piper text to speech for real time voice, over Asterisk AudioSocket, RTP or a browser WebSocket. On PyPI now.
  • php-crm-connectors puts 21 CRMs behind a single PHP interface, so pushing a call outcome into Zoho or Salesforce is the same line of code. On Packagist now.
  • Both came out of ICTContact, generalized so they no longer depend on any ICT product.
  • MIT licensed, and both live under github.com/ictinnovations with the rest of our open source work.

We've open sourced two more libraries from our own stack. The first solves paced streaming text to speech on live phone calls, which is harder than it sounds. The second collapses 21 different CRM integrations into one PHP interface. Both are MIT licensed, both install from the package manager your ecosystem already uses, and neither needs any ICT product to run.

piper-tts-server: open source VoIP text to speech that survives a live call

If you've tried bolting Piper onto a phone call, you already know the symptoms. Dead air before the greeting. The first couple of words missing. Callers who only hear the tail end of every sentence. We hit all three building the AI voice agent in ICTContact, and the fixes turned out to be the same three things every time.

Loading the voice per request is the obvious one, once you measure it. PiperVoice.load() costs somewhere between 2.5 and 5.5 seconds on our hardware, so doing it per utterance means that much silence before the caller hears anything. The library caches voices process wide and reuses them.

The second one bit us for a while before we understood it. Piper phonemizes through espeak-ng, and that C API isn't thread safe. Two calls synthesizing at the same moment produced audio that sounded like a bad radio. All synthesis now runs behind a single lock.

The third is the one I'd never have guessed, and it's the reason this library exists at all rather than being a fifty line wrapper.

Same sentence and same synthesis. The only thing that changes is when each frame is released.

Real time transports forward each frame the instant it arrives. Push a whole utterance at once and you overrun the far end's jitter buffer, so the caller hears the end of the sentence and none of the start. The fix is to release exactly one frame per interval on a monotonic deadline. Here's the subtle part that took us longest: if synthesis stalls, that deadline goes stale, and the frames after the stall burst to catch up and clip the words right behind them. So the writer re-clamps the deadline to now on every single frame, not just at the start of a talk spurt.

Defaults are 8 kHz slin16 at 20 ms frames, which is what telephony wants. Set one environment variable for 16 kHz if you're doing wideband. There's an HTTP service if you want one, but you can also import it as a library and keep HTTP out of the media path entirely, which is what we'd recommend for anything latency sensitive.

One licensing note, because it matters and gets glossed over elsewhere. The package itself is MIT and ships no Piper code. Piper is an optional extra that's imported lazily, so the core installs with numpy alone. The maintained Piper release is GPL-3.0-or-later, so if you install the piper extra, that combined installation is subject to GPL terms. We'd rather say that plainly than let someone find out at their own legal review.

php-crm-connectors: one interface, 21 CRMs

This one comes from a much less glamorous problem. Every contact center deployment wants its own CRM wired in, and after enough of them you're maintaining a heap of near identical integration classes that each do the same job in a slightly different dialect. ICTContact has 28 CRM modules in production. That's a lot of surface area for what is, honestly, one repeated task.

Adding a CRM means implementing one interface, not teaching your application another SDK.

The library is deliberately narrower than a general CRM SDK. The job it does is find a contact by phone or email, create it if it isn't there, then attach the call outcome as a note and an activity. That's a single call. If you don't want the campaign orchestration, the smaller methods are public too, so you can authenticate, look a contact up, create it and annotate it directly.

Auth is where CRM vendors differ most and where integration code usually rots. OAuth2 with refresh tokens for Zoho, Salesforce, Dynamics 365, Creatio, Sugar and Suite. API keys or plain tokens for the rest. Your calling code doesn't have to know which, and access tokens cache through a pluggable store, so you can drop in Redis or a database instead of the in memory default.

The design decision I expect to get argued about is that there's no PSR-18 HTTP client. Every request goes through a single http() method on each connector. The upside is real: that seam is the only place I/O happens, so a connector is tested by overriding one method and the test suite never touches a live CRM. If you think the dependency earns its keep, the issue tracker is open.

Covered so far: Zoho, Pipedrive, Salesforce, Dynamics 365, SugarCRM, SuiteCRM, Freshsales, Copper, Capsule, ActiveCampaign, Close, Keap, Zendesk Sell, monday, Streak, Vtiger, Apptivo, Agile, Creatio, Less Annoying and YetiForce. No HubSpot yet, which is the one people ask about most.

Why we keep pulling pieces out of our products

We've been shipping open source VoIP software since 2006, and the pattern that keeps proving itself is that the reusable part of a product is rarely the product. It's the layer underneath. Pacing frames correctly, or normalizing 21 CRM APIs, has nothing to do with what makes ICTContact worth buying, and both are things other teams shouldn't have to rediscover.

There's a selfish reason too. Code that gets published gets read, and code that gets read gets better. The SIP libraries we wrote about years ago are still doing the rounds because someone kept maintaining them in public. We'd like these two to age the same way.

If you're building in this space, the wider trend is worth reading up on as well. Our take on AI powered voice services beyond SIP trunking covers where we think the on call AI layer is going, and piper-tts-server is one concrete piece of that.

Where to get them

Every open source project we release goes through GitHub first. The full list, products and libraries both, now lives on our open source projects page.

FAQ

Do I need an ICT product to use either library?
No. Both were stripped of anything ICT specific before release. piper-tts-server needs a Piper voice file, and php-crm-connectors needs PHP 7.4 or newer with curl and json. That's it.

Is piper-tts-server tied to Asterisk?
No, though that's where we use it. It emits raw paced frames, so anything that consumes 20 ms slin16 works, including RTP legs and browser WebSockets. The AudioSocket example in the repo is just the wiring we know best.

Does the GPL licence of Piper affect my project?
Only if you install the optional piper extra. The package itself is MIT and contains no Piper source, and the core installs with numpy alone. Install the extra and your combined installation falls under GPL-3.0 terms.

Can I add a CRM that isn't in the list?
Yes, and there's a porting guide in the repo docs. You implement one interface and one http method. Pull requests are welcome, and HubSpot is the obvious gap if someone wants a first contribution.

Are these maintained or dumped over the wall?
Maintained. Both are in production inside our own products, which is the only maintenance promise worth anything. Issues and pull requests come to the same team that ships ICTContact.

Related resources

Building something with either library and hit a wall? Open an issue on the repo, or send us a ticket if it's about running them alongside an ICT product.

Top comments (0)