All projects
TMWPIX

Technical architecture

TMWPIX

Subscriber app for TMWPIX, the pay-TV streaming service run by Brazilian ISP TMW Telecom — one React Native codebase shipping to iOS, iPadOS and Android, unifying linear channels, on-demand film and series, rental titles, internet radio and a seven-day electronic programme guide behind a single subscriber token.

React Native
TypeScript
Swift
JavaScript
HLS · DASH Widevine DRM AVPlayer / ExoPlayer (media3) Media · Telecom OTT iOS · iPadOS · Android
1 codebase iOS · iPadOS · Android
5 Media modes in one shell
Widevine DRM-protected playback
iOS 13+ Deployment target (iPhone 5s up)
TMWPIX Android — channels home with live preview and branded channel rail
TMWPIX Android — home hub with featured title, continue watching and my list
TMWPIX Android — search and browse by genre
TMWPIX Android — programme guide channel list with now-playing
TMWPIX — title detail with synopsis, rating and runtime
TMWPIX — landscape channels hub with live channel rail
TMWPIX — two-pane programme guide across 160 channels
TMWPIX — player with subtitles, audio track selection and skip controls
TMWPIX iOS — subscriber token login
TMWPIX — iPad hub layout
TMWPIX iOS — seven-day EPG time grid
TMWPIX — video-on-demand catalogue grid
TMWPIX — iPad video-on-demand catalogue grid
Mobile (iOS & Android)
React Native — New Architecture Hermes React Navigation Reanimated FlatList virtualisation FastImage
Playback & media
react-native-video AVPlayer (iOS) ExoPlayer / media3 (Android) HLS · DASH Adaptive bitrate MediaSession
Content & delivery
Custom REST API Widevine DRM JSON EPG feed Token auth Multi-profile AsyncStorage
Duration
2024
Model
Full product build
Client
TMW Telecom (Tecmidiaweb EIRELI)
Market
Brazil · pt-BR
Platforms
iPhone · iPad · Android
Distribution
App Store · Google Play

Three engineering decisions that define the product

Playback abstraction
One player surface, two native pipelines, four stream types

Live TV, on-demand film, episodic series and internet radio have almost nothing in common at the transport layer: live channels arrive as a continuously rolling HLS or DASH manifest with no seekable duration, VOD arrives as a finite HLS manifest, and radio is a bare audio stream that has to survive the app going to the background. Rather than build four screens, we built one playback container over react-native-video that resolves to AVPlayer on iOS and ExoPlayer (androidx.media3) on Android, and switches behaviour off a single stream-kind descriptor — seek bar, adaptive-bitrate ladder, audio session category and Widevine DRM session are all derived from it. Lock-screen and background controls come from a single MediaSession the container owns, so radio keeps playing and stays controllable after the app is backgrounded. Adding a new content type became a descriptor change, not a new screen.

Catalogue virtualisation
Catalogues of tens of thousands of posters that still open instantly

An operator catalogue is not a feed — it is the ISP's entire library returned in one shot, and a naive fetch-then-render blocks cold start for as long as the payload takes to parse. The catalogue is instead fetched per category, normalised into a flat local store keyed by stream ID, and rendered through windowed FlatList grids that mount only the rows on screen plus a small overscan buffer. Poster art is fetched lazily with a disk-backed image cache, so scrolling back through a category costs nothing. The catalogue snapshot persists locally and is revalidated in the background, which means the second launch renders from cache before the network answers.

Two-axis EPG grid
A seven-day programme guide virtualised on both axes — in JavaScript

The programme guide is the hardest surface in any TV app: a grid where channels run down one axis and time runs across the other, every cell is variable-width because programmes have variable duration, and both axes have to scroll in lockstep with a pinned header and a pinned channel column. Feeding it is a dedicated EPG endpoint returning every channel’s schedule across the window in one JSON payload, large enough that normalising it naively on the JS thread would visibly stall the UI. We fold it into a time-indexed structure keyed by channel, lay cells out by computed offset rather than by flow, and virtualise horizontally as well as vertically so the number of mounted views stays bounded no matter how far the user scrolls into next week. No native module — it ships identically on both platforms.

TMWPIX is a closed subscriber client, not an open player: it ships with no content, no catalogue and no playlist of its own. TMW Telecom sells the service on tiered monthly plans — each plan carrying its own channel count and a concurrent-stream allowance of two to four screens — alongside per-title rentals for new releases. The app authenticates with a subscriber token, and every channel, category, rental window and guide entry is resolved at runtime from the operator’s endpoint against that subscriber’s entitlement, with multiple household profiles under one account. Rental purchases, profile management and playback telemetry each hit their own endpoint on the operator’s API, and protected titles play back under Widevine. Entitlement, concurrency and licensing all live on the operator side; the app is the delivery surface.

Evaluating our technical capability?

We're happy to go deeper on any architecture decision, share anonymised code samples, or walk through our engineering approach on a call.

Start a conversation →