<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Engineering on Everyone Has a Story</title><link>https://bhaveshsgupta.com/categories/engineering/</link><description>Recent content in Engineering on Everyone Has a Story</description><generator>Hugo</generator><language>en-us</language><managingEditor>BhaveshSGupta@disroot.org (Bhavesh S. Gupta)</managingEditor><webMaster>BhaveshSGupta@disroot.org (Bhavesh S. Gupta)</webMaster><lastBuildDate>Tue, 06 Oct 2026 18:26:36 +0530</lastBuildDate><atom:link href="https://bhaveshsgupta.com/categories/engineering/index.xml" rel="self" type="application/rss+xml"/><item><title>It only fails in Safari: two HLS engines, and how to debug across hops</title><link>https://bhaveshsgupta.com/blog/hls-cdn-4-only-fails-in-safari/</link><pubDate>Tue, 06 Oct 2026 09:03:00 +0530</pubDate><author>BhaveshSGupta@disroot.org (Bhavesh S. Gupta)</author><guid>https://bhaveshsgupta.com/blog/hls-cdn-4-only-fails-in-safari/</guid><description>&lt;p&gt;When a live stream breaks in Safari and plays in Chrome, the tempting conclusion is that Safari&amp;rsquo;s player is the problem. Often it isn&amp;rsquo;t. Both browsers receive the same files from the same CDN. They differ in what they do when one of those files is wrong, so a delivery fault that Chrome quietly recovers from becomes a Safari bug report.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;In short:&lt;/strong&gt; Chrome, Edge and Firefox usually play HLS through hls.js, which retries failed requests and skips small gaps; Safari uses its native player, which surfaces the same faults as errors or stalls. Both get identical bytes, so a problem that only shows in Safari is usually a delivery problem. Find it by measuring each hop separately: compare responses at the origin and the CDN, probe from many regions, group logs by browser, and inspect the segments.&lt;/p&gt;</description></item><item><title>Slide sync over HLS with ID3 timed metadata</title><link>https://bhaveshsgupta.com/blog/hls-cdn-3-id3-slide-sync/</link><pubDate>Tue, 06 Oct 2026 09:02:00 +0530</pubDate><author>BhaveshSGupta@disroot.org (Bhavesh S. Gupta)</author><guid>https://bhaveshsgupta.com/blog/hls-cdn-3-id3-slide-sync/</guid><description>&lt;p&gt;A webcast with slides has to change the slide at the moment the presenter does, as the viewer sees it. Viewers are 10 to 30 seconds behind live, each by a different amount, so a message sent &amp;ldquo;now&amp;rdquo; from the presenter&amp;rsquo;s page arrives at the wrong time for everyone. The fix is to put the slide change inside the stream itself, at the right timestamp. In HLS that means ID3 timed metadata.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;In short:&lt;/strong&gt; To change slides at the exact moment the presenter did, put the change inside the stream as ID3 timed metadata. Each tag rides in the segment on its own data stream with a presentation timestamp, so the player fires it at the right frame however far behind live the viewer is. Put every tag in every quality, re-send the current slide regularly for late joiners, and read the tags through the video element&amp;rsquo;s metadata text track, which works in hls.js and Safari.&lt;/p&gt;</description></item><item><title>Putting a live HLS origin behind a CDN</title><link>https://bhaveshsgupta.com/blog/hls-cdn-2-live-origin-behind-a-cdn/</link><pubDate>Tue, 06 Oct 2026 09:01:00 +0530</pubDate><author>BhaveshSGupta@disroot.org (Bhavesh S. Gupta)</author><guid>https://bhaveshsgupta.com/blog/hls-cdn-2-live-origin-behind-a-cdn/</guid><description>&lt;p&gt;A CDN in front of a live HLS origin should mean each segment leaves your server a handful of times, however many people watch. Whether it does depends on details that are easy to get wrong and hard to see: the URLs your origin hands out, the headers on each kind of file, and every layer between the origin and the viewer that has its own opinion about caching.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;In short:&lt;/strong&gt; A CDN only protects a live origin if every viewer requests the same URLs: no per-viewer session ids, and no query strings in the cache key. Give media playlists about a one-second lifetime, segments about a minute, and errors no-store so an early 404 isn&amp;rsquo;t served to everyone. Check headers at every hop, send CORS headers when the player is on another domain, and confirm request collapsing and an origin shield with the CDN that pulls from you.&lt;/p&gt;</description></item><item><title>HLS for backend engineers: playlists, segments and keyframes</title><link>https://bhaveshsgupta.com/blog/hls-cdn-1-hls-for-backend-engineers/</link><pubDate>Tue, 06 Oct 2026 09:00:00 +0530</pubDate><author>BhaveshSGupta@disroot.org (Bhavesh S. Gupta)</author><guid>https://bhaveshsgupta.com/blog/hls-cdn-1-hls-for-backend-engineers/</guid><description>&lt;p&gt;If you run the servers behind a live stream, you don&amp;rsquo;t need to know much about codecs. You do need to know what files a player asks for, how often, and what decides their size and timing. That&amp;rsquo;s what this post covers, with commands you can run against any HLS stream.&lt;/p&gt;&#10;&lt;p&gt;The series is about standard HLS, with MPEG-TS or fragmented MP4 (CMAF) segments. The same principles carry over to Low-Latency HLS, though its partial segments and blocking playlist reloads aren&amp;rsquo;t covered here. Real-time streaming, such as WebRTC at under a second of delay, works differently and isn&amp;rsquo;t covered at all: it has no playlists or segments for a CDN to cache.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;In short:&lt;/strong&gt; A live HLS stream is a master playlist of qualities, one media playlist per quality, and short segments. Each segment must start on a keyframe, so a fixed keyframe interval of 1 or 2 seconds keeps segments even. The target duration is the ceiling on segment length; players reload about once per target duration and start three target durations behind live, so it sets your latency. Every quality needs the same boundaries and timestamps for switching to be smooth.&lt;/p&gt;</description></item></channel></rss>