PressPlayed engineering

One audio stream, many RSS articles: keeping narration going behind a locked screen

An engineering note from PressPlayed on why treating an RSS listening queue as a playlist of separate audio files is fragile on Android.

Published by PressPlayed engineering. Permalink.

Most RSS readers assume that the screen stays available. A spoken reader has a different job: once someone presses play, the next article must begin without asking them to wake the phone, find the browser, and press play again.

That sounds like a queueing problem. On Android, it became an audio-lifecycle problem.

We build PressPlayed, a hosted RSS reader that narrates the readable article text a source makes available. During early locked-screen testing in Chrome on Android, each synthesized speech segment had its own audio URL. The player finished one segment, changed the audio element's src, and started the next. That worked while the page was visible. With the screen locked, playback repeatedly stopped at the source change: the media session on the hidden page ended before the next segment began. We could reproduce the boundary; we did not establish the exact browser or operating-system policy behind it.

The boundary that mattered was not between two articles. It was every source change, including the small speech segments inside one article.

What we tried not to rely on

A larger next-track preload reduced some gaps, but it did not remove the lifecycle boundary. Keeping a second audio element ready still required handing playback from one media source to another. Automatically pressing play again after an unexplained pause risked fighting the listener when the pause came from a phone call, a Bluetooth control, or another app.

The durable fix was to stop presenting the queue to the browser as many tracks.

One media session for the whole queue

PressPlayed now gives one audio element one MediaSource object URL and does not replace that src as the queue advances. Narration still arrives in small pieces: article text is split into chunks of roughly 850 characters and synthesized segment by segment. Those audio segments are appended to a single SourceBuffer in sequence mode, so the browser sees one continuing stream.

The queue can cross a segment boundary or an article boundary without creating a new media element or source URL. Article controls and metadata can change while the underlying audio session stays put.

That distinction matters. The application still thinks in feeds, articles, and speech segments. The browser is allowed to think in one uninterrupted media stream.

Buffer for the conditions you actually have

A continuous source is necessary, but it is not sufficient. A locked phone may throttle timers and background network work, so waiting until the current segment is nearly over is fragile. While the page is hidden, PressPlayed tries to keep roughly ten minutes of narration buffered ahead. The exact amount is a continuity choice, not a universal formula: it has to balance resilience, synthesis cost, memory, and how quickly a listener's queue may change. It is not offline support - the stream still depends on the network, and PressPlayed does not work offline.

We also keep request concurrency bounded and prioritize the segment the listener is audibly waiting for. Cached narration does not need to be synthesized again. None of that changes the one-source rule; it decides how reliably the stream remains fed.

Measure the hidden path

Desktop testing cannot prove locked-screen continuity. In production we record playback events with visibility state, media position, ready state, and the control that caused a pause. That lets us distinguish a listener's tap or a lock-screen command from a bare hidden-page pause.

In one live Android test, the current configuration crossed more than 1,000 hidden segment boundaries without the platform ending playback. That is not proof that phones never interrupt audio. Calls, Bluetooth controls, other audio apps, and battery restrictions still can. It is the narrower result we needed: advancing through our own queue no longer ended the media session.

The general lesson

If a browser audio product must survive the screen turning off, test the entire sequence as one lifecycle. Preloading the next file is not the same as preserving the current media session. UI-level tracks and transport-level sources do not have to share the same boundaries.

For PressPlayed, the winning model was simple: many RSS items for the listener, one audio stream for the browser.

Disclosure and try it

This is an engineering note from the team that builds PressPlayed, so read it as a vendor's account of its own system.

PressPlayed is a hosted RSS reader, not an IndieWeb social reader: it does not implement Microsub, IndieAuth, h-feed, replies, or other social-reader features. It is not an offline reader either.

The results above come from Android testing. Locked-screen playback depends on the device, operating-system version, browser, and battery settings, and can still be interrupted by the conditions described above. We have not verified it on every phone or browser.

You can hear a fixed three-story demonstration without signing up, or create a free account to try your own feeds.

Submitted to IndieNews