<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Benjamin Wallberg</title>
    <description>The latest articles on Forem by Benjamin Wallberg (@bwallberg).</description>
    <link>https://forem.com/bwallberg</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F566847%2Fa4d02cec-92cf-4623-bc3c-ecd532c20a6c.png</url>
      <title>Forem: Benjamin Wallberg</title>
      <link>https://forem.com/bwallberg</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/bwallberg"/>
    <language>en</language>
    <item>
      <title>HLS Interstitials in Safari</title>
      <dc:creator>Benjamin Wallberg</dc:creator>
      <pubDate>Mon, 29 Nov 2021 14:01:51 +0000</pubDate>
      <link>https://forem.com/video/hls-interstitials-on-safari-go7</link>
      <guid>https://forem.com/video/hls-interstitials-on-safari-go7</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;As mentioned in our &lt;a href="https://dev.to/video/inserting-hls-interstitials-for-an-existing-vod-library-gbi"&gt;previous post&lt;/a&gt; HLS interstitials doesn't work natively in Safari or in any other HTML5 player, but that doesn't mean that it &lt;em&gt;can't&lt;/em&gt; work.&lt;/p&gt;

&lt;p&gt;"Interstitial playback on Apple devices is accomplished using two players"(GettingStartedWithHLSInterstitials.pdf, p.3)&lt;/p&gt;

&lt;p&gt;This is a common technique used in may AVOD services today, albeit without the ads being part of the HLS manifest, the client creates two &lt;code&gt;&amp;lt;video /&amp;gt;&lt;/code&gt; elements and puts them on top of each other and simply switch between which &lt;code&gt;&amp;lt;video /&amp;gt;&lt;/code&gt; element is visible.&lt;/p&gt;

&lt;p&gt;This means that the only thing we are limited by is our ability to read the HLS interstitials from the manifest.&lt;/p&gt;

&lt;p&gt;In this post we will focus on how to achieve this in Safari.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reading the manifest
&lt;/h2&gt;

&lt;p&gt;Since HLS interstitials are added using the existing &lt;code&gt;EXT-X-DATERANGE&lt;/code&gt; tag we can use the built-in browser APIs to read them.&lt;br&gt;
In Safari they have achieved this using the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/TextTrack"&gt;TextTrack&lt;/a&gt; interface&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// listen to the `addtrack` event to detect when a texttrack is added to the video element&lt;/span&gt;
&lt;span class="nx"&gt;video&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textTracks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;addtrack&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;track&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;TrackEvent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// check if the track is of kind "metadata", this is where Safari adds any EXT-X-DATERANGE information&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;track&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;track&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kind&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;metadata&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// by default the track is disabled, set it to "hidden" to allow it to start parsing any EXT-X-DATERANGE&lt;/span&gt;
    &lt;span class="nx"&gt;track&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hidden&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// track.cues will now be populated with all available EXT-X-DATERANGES in the entire manifest!&lt;/span&gt;
    &lt;span class="nx"&gt;track&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cuechange&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;evt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// if this event is dispatched the `track.activeCues` property will contain the active EXT-X-DATERANGE&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The EXT-X-DATERANGEs will show up in the &lt;code&gt;cues/activeCues&lt;/code&gt; field of the metadata text track as &lt;a href="https://wicg.github.io/datacue/"&gt;DataCue&lt;/a&gt;, the specification for those cues are just in draft so they are subject to change. The relevant part for HLS interstitials is the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="err"&gt;value:&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="err"&gt;key:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"X-ASSET-LIST"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="err"&gt;data:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;url to X-ASSET-LIST&amp;gt;"&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="err"&gt;startTime:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;55&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that each &lt;code&gt;X-*&lt;/code&gt; attribute of the daterange will show up as separate cues, so if you want full support for HLS interstitials you need to read from multiple cues to get a complete HLS interstitial configuration.&lt;/p&gt;

&lt;p&gt;Using this technique we were able to create &lt;a href="https://poc.eyevinn.technology/hls-interstitials/index.html"&gt;this&lt;/a&gt; simple PoC demo show-casing how HLS interstitials can look today in Safari.&lt;br&gt;
The demo contains a preroll and two midrolls, one at 20s and one at 1m 40s.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learnings
&lt;/h2&gt;

&lt;p&gt;When implementing this little PoC we discovered two specific things that one needs to workaround to get this to work.&lt;/p&gt;

&lt;h3&gt;
  
  
  The metadata track becomes disabled.
&lt;/h3&gt;

&lt;p&gt;When the interstitial video is playing the master video will disable the &lt;code&gt;metadata&lt;/code&gt; track, which means that we can no longer read the EXT-X-DATERANGEs from the manifest.&lt;br&gt;
Luckily the browser does dispatch the "onchange" event on the textTracks so we can force enable it if needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Safari reads a PDT of 0 as false
&lt;/h2&gt;

&lt;p&gt;If you set the PDT of the HLS to &lt;code&gt;#EXT-X-PROGRAM-DATE-TIME:1970-01-01T00:00:00.000Z&lt;/code&gt; Safari will not set the &lt;code&gt;startTime&lt;/code&gt; field of the EXT-X-DATERANGE cue correctly, it will set all &lt;code&gt;startTime&lt;/code&gt; fields to &lt;code&gt;0&lt;/code&gt;. A simple workaround if you control the HLS is to set it to 1 eg. &lt;code&gt;#EXT-X-PROGRAM-DATE-TIME:1970-01-01T00:00:00.001Z&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  About Eyevinn Technology
&lt;/h2&gt;

&lt;p&gt;Eyevinn Technology is an independent consultant firm specialized in video and streaming. Independent in a way that we are not commercially tied to any platform or technology vendor.&lt;/p&gt;

&lt;p&gt;At Eyevinn, every software developer consultant has a dedicated budget reserved for open source development and contribution to the open source community. This give us room for innovation, team building and personal competence development. And also gives us as a company a way to contribute back to the open source community.&lt;/p&gt;

&lt;p&gt;Want to know more about Eyevinn and how it is to work here. Contact us at &lt;a href="mailto:work@eyevinn.se"&gt;work@eyevinn.se&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>hls</category>
      <category>video</category>
      <category>safari</category>
    </item>
  </channel>
</rss>
