HLS custom data tags

This describes how to configure the application to listen for custom tags embedded in HLS playlists.

The principal use for this is to enable the client application to receive advertising data (e.g. time of ad, URL of ad) that has been inserted into the HLS playlist on the server side, however, data for any purpose can be embedded in an HLS playlist and processed in a client application. The API allows an application to provide as many different NMPTagListener implementations as are required.

Process

NMPVideoView contains the callback interface NMPTagListener that the client application must implement:

  public interface NMPTagListener {
    void onTags(String xTagsInJson);
  }

Each time the playlist is refreshed, the NMPTagListeners will receive a stringified JSON structure containing:

  • The playlist URL
  • An array of the custom tags requested
  • An array of time periods, which in turn contain the custom data for that period, grouped by tag - this is more clearly explained in the example below.

Within this NMPTagListener implementation, the client application may parse the JSON data structure and act accordingly e.g. by displaying a specified advertisement at a specified time.

NMPVideoView has a public API enabling the management of NMPTagListener objects:

  public void addTagListener(List<String> xTagsToParse, NMPTagListener xListener);

  public void removeTagListener(NMPTagListener xListener);

  public void clearTagListeners();

Important It is recommended that the application calls addTagListener() prior to starting playback so that the listener is available in time to receive the tag data, as the playlist will be parsed immediately after it is downloaded.

Example code

Typical example

The following playlist (http://www.cdn.com/content/media/iamamediaplaylist.m3u8) will be checked for the tags "ExampleTag1", "ExampleTag2" and "ExampleTag3":

  #EXTM3U
  #EXT-X-VERSION:3
  #EXT-X-MEDIA-SEQUENCE:0
  #EXT-X-TARGETDURATION:2.000
  #EXTINF:2.0
  segment0.ts
  #ExampleTag1:key=value,key2=value2
  #EXTINF:2.0
  segment1.ts
  #ExampleTag1:key3=value3,key4=value4
  #EXTINF:2.0
  segment2.ts
  #ExampleTag1:key5=value5,key6=value6
  #EXTINF:2.0
  segment3.ts
  #EXTINF:2.0
  segment4.ts
  ...

The NMPTagListener's onTags() method will receive the following argument:

{
    "playlistUrl" : "http://www.cdn.com/content/media/iamamediaplaylist.m3u8",
    "requestedTags" :
    [
        "ExampleTag1",
        "ExampleTag2",
        "ExampleTag3"
    ],
    "parsedTags" :
    [
        {
            "contentTimeMs" : 2000,
            "tags" :
            [
                {
                    "name" : "ExampleTag1",
                    "data" :
                    [
                        {
                            "key" : "value",
                            "key2" : "value2"
                        }
                    ]
                },
                {
                    "name" : "ExampleTag2",
                    "data" :
                    [
                        {
                            "key" : "value",
                            "key2" : "value2"
                        }
                    ]
                }
            ]
        },
        {
            "contentTimeMs" : 4000,
            "tags" :
            [
                {
                    "name" : "ExampleTag1",
                    "data" :
                    [
                        {
                            "key3" : "value3",
                            "key4" : "value4"
                        }
                    ]
                },
                {
                    "name" : "ExampleTag3",
                    "data" :
                    [
                        {
                            "key" : "value",
                            "key1" : "value1"
                        }
                    ]
                }
            ]
        },
        {
            "contentTimeMs" : 6000,
            "tags" :
            [
                {
                    "name" : "ExampleTag2",
                    "data" :
                    [
                        {
                            "key3" : "value3",
                            "key4" : "value4"
                        }
                    ]
                },
                {
                    "name" : "ExampleTag3",
                    "data" :
                    [
                        {
                            "key3" : "value3",
                            "key4" : "value4"
                        }
                    ]
                }
            ]
        }
    ]
}

Data is not in the "name=value" format

The following playlist (http://www.cdn.com/content/media/iamamediaplaylist.m3u8) will be checked for the tags "EXT-X-BEACON":

#EXT-X-BEACON:error,hostname1
#EXT-X-BEACON:EVENT=error,hostname1
#EXT-X-BEACON:error,URL=hostname1
#EXT-X-BEACON:EVENT=error,URL=hostname1  <-- only this line is formatted in comma-separated name-value pairs, and this is reflected in the resulting JSON

If a line in the playlist is not in the form "name=value" - as is the case in several lines above - the data in that line will simply be reported verbatim, with the following result:

{
  "playlistUrl" : "http://www.cdn.com/content/media/iamamediaplaylist.m3u8",
  "requestedTags" :
  [
    "#EXT-X-BEACON"
  ],
  "parsedTags" :
  [
    {
      "contentTimeMs" : 0,
      "tags" : [
        {
          "name" : "#EXT-X-BEACON",
          "data" : [
            "error,hostname1",
            "EVENT=error,hostname1",
            "error,URL=hostname1",
            {
              "EVENT": "error",
              "URL": "hostname1"
            }
          ]
        }
      ]
    }
  ]
}

No custom tags found

The following playlist (http://www.cdn.com/content/media/iamamediaplaylist.m3u8) will be checked for the tags "ExampleTag4":

  #EXTM3U
  #EXT-X-VERSION:3
  #EXT-X-MEDIA-SEQUENCE:0
  #EXT-X-TARGETDURATION:2.000
  #EXTINF:2.0
  segment0.ts
  #EXTINF:2.0
  segment1.ts
  #EXTINF:2.0
  segment2.ts
  #EXTINF:2.0
  segment3.ts
  #EXTINF:2.0
  segment4.ts
  ...

As "Example4" is not present, the following will be received by onTags():

{
    "playlistUrl" : "http://www.cdn.com/content/media/iamamediaplaylist.m3u8",
    "requestedTags" :
    [
        "ExampleTag4"
    ],
    "parsedTags" :
    [
    ]
}