Introduction
While tidying up the blog last weekend, a question suddenly came to mind: no matter how long an article is, readers can realistically only finish the first few hundred words. This is especially true for technical articles—thousands of words long, and many people swipe away halfway through. If I could turn articles into audio, letting visitors listen during their commute or while doing chores, wouldn’t that be a better way to consume content?
With this idea, I surveyed a range of speech synthesis options and finally settled on the Doubao Podcast TTS from Volcano Engine. Its feature is that it can generate a two-host podcast format, where two AI hosts discuss the article’s content in a question-and-answer style, which sounds far more natural than a monotonous single-voice reading. This article documents the complete integration process and the pitfalls I hit.

Solution Selection and Core Approach
Why Choose Doubao Podcast TTS
There are quite a few TTS vendors on the market; I mainly compared these:
| Solution | Features | Drawbacks |
|---|---|---|
| Alibaba Cloud Speech Synthesis | Stable, cheap | Single-voice reading only, no sense of dialogue |
| iFlytek Voiceover | Rich emotion | Billed per character, costly for long text |
| Doubao Podcast TTS | Two-host dialogue, high naturalness | Only a WebSocket interface, slightly complex to integrate |
The reason I ultimately chose Doubao is simple: it can generate a true “podcast,” not dry reading. The two hosts are named Liu Fei and Xiao Lei—one leads the topic, the other asks questions and adds details—and the listening experience is very close to a real podcast show.
Overall Pipeline Design
The whole feature’s pipeline is like this:
|
The whole flow is wrapped in a Python script: running python3 tools/generate_podcast.py source/_posts/xxx.md completes it in one command.
Key Technology: Parsing the WebSocket Binary Protocol
Doubao Podcast TTS’s interface is WebSocket, but it isn’t ordinary JSON over WebSocket—it’s a proprietary binary frame protocol. This was also the most troublesome part of the integration.
Protocol Frame Structure
Each frame consists of four parts: Header (4 bytes) + Optional (optional) + PayloadLength (4 bytes) + Payload.
|
There are several key points to note:
- Big-endian: all multi-byte fields are big-endian (
>Imeans big-endian unsigned int). - The event field: only when the flag
FLAG_WITH_EVENT = 0b0100is set will the frame carry the event field. - message_type: requests are
0b0001, audio responses0b1011, text responses0b1001, errors0b1111.
Connection and Authentication
The WebSocket handshake must carry authentication headers:
|
Here app_id and access_key need to be obtained after creating an application in the Volcano Engine console.
Three Steps: From Text to Audio
The whole generation flow has three steps, each corresponding to an action parameter.
Step One: Generate the Dialogue Text (action=0)
First, have the AI generate a podcast dialogue script from the article content. There’s a trick here: add only_nlp_text=True, and the API will directly return the text of each round of dialogue instead of audio.
|
The returned data format is a JSON array, each element containing speaker and text. I usually print it out first to see the effect, and only move on to the next step after confirming the dialogue logic is smooth.
Step Two: Fix the Dialogue Content
Sometimes the Doubao-generated dialogue lacks an opening, or contains some overly brief transitions. I added a layer of post-processing:
|
Here it’s forced that the podcast begins with “Welcome to Awen’s podcast, I’m Awen……” to strengthen the branding.
Step Three: Generate the Audio (action=3)
Once you have the corrected dialogue text, call the WebSocket again—this time with action=3, carrying the complete dialogue list:
|
The API returns MP3-format binary audio data. Each round of dialogue triggers three events: PODCAST_ROUND_START, PODCAST_ROUND_RESPONSE (the audio data), and PODCAST_ROUND_END. You need to collect, in order, the payloads from all PODCAST_ROUND_RESPONSE events and finally merge them into a complete MP3 file.
Here’s a point to note: the Doubao API has a limit on the number of rounds per batch of dialogue—at most 25 rounds per call. If an article is long and the dialogue exceeds 25 rounds, you need to generate in batches and finally splice the multiple MP3 segments together. MP3 is a streaming format, so direct byte concatenation works—no re-encoding needed.
Preprocessing the Article Text
To make the podcast sound better, I did a lot of cleanup when extracting text from Markdown:
|
In addition, to let the AI generate a better podcast, I added a piece of guiding text (a prompt) before the article text, explicitly telling the AI that the two hosts should discuss the article from a third-person perspective and must not assume the author’s identity. This prompt has a big impact on the final effect—it directly determines whether the podcast is a “discussion” or a “reading.”
Complete Usage Flow
Once the script is written, daily use is very simple:
|
After running, the console outputs the progress of each step:
|
The generated podcast link is written into the article’s front matter: podcast: https://file.awen.me/podcast/.../xxx.mp3. Add a podcast player component to the front-end theme, read this field, and it will display on the article page.
Cost and Effect
Currently, Volcano Engine’s Doubao Podcast TTS has no public billing documentation (it’s in internal testing). From actual tests, generating a podcast for a 3,000-word article takes about 30–60 seconds, with audio duration of about 8–12 minutes. Estimating by Volcano’s billing standard, the cost is roughly a few fen to a tenth of a yuan—entirely acceptable for a personal blog.
In terms of effect, Doubao’s two-host dialogue mode really does sound much better than single-voice TTS. Liu Fei’s timbre is steady, suited to leading; Xiao Lei is more lively, suited to asking questions and adding details. The two also have a very natural sense of rhythm, with no obvious “machine feel.” The only minor flaw is occasional repetitive phrasing; filtering short sentences through post-processing already alleviates most of it.
Pitfalls I Stepped In
- WebSocket timeout: generating long articles easily times out; you need to set
timeoutlarger (60 seconds or more) and add a retry mechanism. - Binary frame parsing error: at first I parsed in little-endian, so all the payload lengths came out wrong. Only after carefully reading the docs did I discover it was big-endian.
- Dialogue rounds exceeding the limit: more than 25 rounds in a single batch triggers an error directly, so you must do batch processing.
- Audio splicing problems: MP3s generated in batches can’t be spliced directly—you need to first strip the ID3 tags from each segment. Actually, MP3 streaming concatenation is feasible, but if there’s a complete ID3v2 header in the middle it can cause problems. My approach was to ensure that only the first batch has opening music and only the last batch has ending music, with no music in the middle batches, so the spliced result is clean.
Conclusion
Adding an AI podcast to the blog is essentially about expanding the scenarios in which content is consumed. Not everyone is willing to sit down and read through a long article, but listening to a 10-minute podcast lowers the barrier a lot. Doubao Podcast TTS makes achieving this very cheap—no need for real-person recording, no need for editing; one command generates usable audio content.
If you also have a blog or a content site, why not give it a try. The technical solution isn’t complex; the core is parsing the WebSocket binary protocol and orchestrating the dialogue flow.
But a reminder as well: an AI podcast is suitable as a supplementary way to consume content and can’t fully replace reading text. Some technical details and code snippets are hard to remember after hearing them once—you still need to return to the original text and read carefully. The best approach is to provide both text and podcast entries on the article page, letting readers choose for themselves.
评论
0 条评论