Production engineering
Digital signage: one CMS, three device ecosystems
Getting the right media onto displays that run on hardware from three vendors, over networks nobody controls.
- Java
- Play Framework
- MyBatis
- SQL
- Angular
- TypeScript
- Samsung Tizen
- LG webOS
- Android
Context
A digital signage platform is deceptively simple to describe: an operator uploads content, assigns it to displays, and the displays play it. The complexity is in every word of that sentence. The displays are televisions and media players from different manufacturers, sitting in shops and lobbies on whatever network the venue happens to have, running embedded browser engines that are often several years behind anything you would target on the desktop. They are expected to keep playing when the server is unreachable, and to be correct again when it comes back.
Written at the level a public case study can go: the shape of the problems and how I reasoned about them. No proprietary code, internal endpoints, schemas, customer details or unreleased work appears here.
How content reaches a display
Every arrow is a place where the two sides can disagree about state — which is where most of the interesting bugs live.
The engineering
Three platforms, three definitions of "the web"
Samsung Tizen (SSSP), LG webOS and Android devices each ship their own browser engine and their own device APIs. The same player application has to run on all of them. Feature detection beats user-agent sniffing almost every time, but device APIs — the ones that control power state, capture a snapshot, or read hardware info — have no common interface at all, so the honest answer is a thin platform abstraction with a genuinely separate implementation per vendor behind it.
Media that plays on one device and silently fails on another
The most common report is "the video does not play", and it almost never means one thing. A file is a container holding streams in particular codecs at a particular profile and level, and playback depends on the hardware decoder, not on whether the file is technically valid. A device can accept the container, report no error, and still show black. Debugging this means separating container from codec from profile from decoder — and then deciding, at the platform level, what the supported set actually is.
Remote operations against devices you cannot reach
Remote control, snapshots and live view all share the same hard part: the device, the network and the server have to agree on state that is constantly drifting. A command issued to a display that rebooted thirty seconds ago has to fail in a way the operator understands, rather than hanging. That pushes you toward acknowledged commands, explicit timeouts, and a device state model that admits "I do not currently know".
Backward compatibility as a hard constraint
A device in the field is not on the latest build and cannot be assumed to update on command. That makes the API between server and device the most conservative interface in the system: new fields are additive, old behaviour keeps working, and a change that requires every device to update at once is not a change you can make. Most of the design discipline in this work comes from that single constraint.
Three platforms, compared
Where the differences actually show up, and what each one costs in practice.
| Aspect | SamsungTizen / SSSP | LGwebOS Signage | Androidplayers & displays |
|---|---|---|---|
| RuntimeDecides which language and API features you can use without a polyfill. | Vendor web engine, versioned with the firmware | Vendor web engine, versioned with the firmware | System WebView or a native shell |
| Device APIsPower state, hardware info, capture. No cross-vendor equivalent exists. | Vendor-specific JavaScript APIs | Vendor-specific JavaScript APIs | Android APIs via the host application |
| Feature detectionUser-agent strings on these devices are unreliable and change with firmware. | Detect capabilities, not the device | Detect capabilities, not the device | Detect capabilities, not the device |
| Media playbackSupport is a property of the hardware decoder, not of the file being valid. | Hardware decoder limits by model and firmware | Hardware decoder limits by model and firmware | Varies widely with the SoC |
| Failure modeThe reason “it does not play” is rarely a useful bug report on its own. | Can fail silently — no error, black output | Can fail silently — no error, black output | More likely to surface an error |
| DebuggingHow much you can see when something goes wrong on a device you cannot reach. | Remote inspector, when the device allows it | Remote inspector, when the device allows it | Remote debugging over ADB |
| Update cadenceFirmware in the field sets the real floor for what you can ship. | Firmware-bound; fleets run mixed versions | Firmware-bound; fleets run mixed versions | Varies by vendor and device policy |