Gandr TTS in FreeSWITCH.
Fetch a WAV file from the Gandr API and hand it to mod_dptools playback, or pipe raw PCM directly into your audio pipeline at 24000 Hz.
Render and play
Fetch a WAV file with curl, drop it where FreeSWITCH can read it, then play it from the dialplan. The example below uses mod_dptools playback, the built-in application for file-based audio.
# 1. Render to WAV and save to the FreeSWITCH sounds directory
curl -sS -X POST https://tts.gandr.ai/v1/audio/speech \
-H "Authorization: Bearer gnd_..." \
-H "Content-Type: application/json" \
-d '{"model":"tts-1","input":"Thank you for calling. How can I help you today?","voice":"gandr-mia","response_format":"wav"}' \
-o /var/lib/freeswitch/sounds/gandr-reply.wav
# 2. In your dialplan XML:
#
# <extension name="tts-demo">
# <condition field="destination_number" expression="^1234$">
# <action application="playback" data="/var/lib/freeswitch/sounds/gandr-reply.wav"/>
# </condition>
# </extension>
The API returns a standard WAV file. Any path FreeSWITCH can read will work: local disk, a mounted network volume, or a pre-populated sounds directory.
What you need
What it takes
| A Gandr API key | Bearer gnd_... in the Authorization header |
| curl | available on any modern Linux system |
| FreeSWITCH | any version that ships mod_dptools |
| Write access | to the FreeSWITCH sounds directory |
PCM for pipeline use
When you need to feed audio into a custom pipeline without writing a file, use response_format pcm. Gandr returns headerless signed 16-bit little-endian PCM, mono, 24000 Hz, as a plain chunked HTTP response body. There is no WAV header, no container: the bytes come off the socket and go straight into your pipeline.
The example below pipes the PCM stream into aplay for verification. Replace aplay with your actual audio sink.
- Format: headerless s16le mono 24000 Hz
- Transport: plain chunked HTTP body, no wrapper
- Input cap: 2000 characters per request
PCM curl example
The command below requests PCM and pipes it to aplay at the matching sample rate. Swap aplay for your pipeline sink.
- curl -sS -X POST https://tts.gandr.ai/v1/audio/speech \ -H "Authorization: Bearer gnd_..." \ -H "Content-Type: application/json" \ -d '{"model":"tts-1","input":"Hold for one moment.","voice":"gandr-mia","response_format":"pcm"}' | \ aplay -r 24000 -f S16_LE -c 1 -t raw
Voice and language options
The API ships six voices: gandr-mia, gandr-ava, gandr-jenny, gandr-dane, gandr-leo, and gandr-lewis. All six cover the same 23 languages. Every render is watermarked.
Latency for a warm request: first audio byte in 146 ms over the open internet, 116 ms p50 first audio, server side warm.
Pre-rendering vs. real-time render
For fixed hold messages, IVR prompts, and error phrases, render at deploy time and serve from disk. FreeSWITCH reads the WAV file without making any network call during the call.
For dynamic text that changes per call, run the curl command in a script or ESL application before the playback application fires. The 2000 character cap per request applies.
Notes
What sample rates does Gandr return for WAV?
The WAV response uses 24000 Hz. FreeSWITCH resamples on playback if your profile runs at 8000 Hz or 16000 Hz; no extra conversion step is needed.
Can I play PCM directly without saving a file?
Yes. Request response_format pcm and pipe the response body into your audio sink. The stream is headerless s16le mono 24000 Hz. For mod_native_file or a custom endpoint, write to a named pipe or socket; for testing, pipe to aplay.
Is there a limit on input length?
Each request accepts up to 2000 characters. For longer text, split into chunks and queue the requests.
Does the API block until the whole file is ready?
No. The response streams. For WAV, the header arrives first and audio data follows chunk by chunk. For PCM, bytes arrive as they are produced. You can write the stream directly to a file or pipe it to a sink without waiting for the full render.
A key and one curl command, and your dialplan can speak in any of 23 languages.
Get a keyFull API reference , gandr.ai/docs