Device capabilities and configuration

It can be important for a developer to understand the capabilities and configuration of the television device their applications will run on. HbbTV provides a number of mechanism by which capabilities and configurations can be retrieved.

This sub-section of the developers guide covers:

  • Accessing the supported HbbTV version number
  • Accessing capabilities details
  • Accessing configuration details
  • Accessing a distinctive identifier

An example application containing the code from this tutorial can be found on GitHub.

HbbTV version number

The most fundamental thing to understand is the version of HbbTV the television device supports. Details on the different HbbTV versions can be found here.

To determine the version of HbbTV that a television supports from within an HbbTV application, you can query the HbbTV user agent string. This string contains information about the HbbTV version supported by the device. Here’s a step-by-step guide on how to do this:

Step-by-Step Guide

  1. Access the User Agent String
    • The user agent string can be accessed via JavaScript using the navigator.userAgent property. This string contains various details about the device, including the HbbTV version.
  2. Extract HbbTV Version from User Agent
    • The user agent string includes a segment that indicates the HbbTV version in use. This segment is formatted as “HbbTV/x.y.z“, where x.y.z represents the formal ETSI version number (e.g. 1.2.1).

Example Code:

function getHbbTVVersion() {
    // fetch the user agent string from the navigator object
    var userAgent = navigator.userAgent; 
    // find the version number within the user agent string 
    var hbbtvVersion = userAgent.match(/HbbTV\/([0-9.]+)/);
    if (hbbtvVersion && hbbtvVersion[1]) {
        return hbbtvVersion[1];
    } else {
        return null;
    }
}

The getHbbTVVersion() function retrieves the user agent string using navigator.userAgent.

It uses a regular expression to match the HbbTV version within the user agent string.

You may choose to change the functionality of an application based on an HbbTV version number, including having it stop. As the version number is not an actual number, you need to compare each of the components of version with your target version.

Example code:

function isVersionGreaterOrEqual(version1, version2) {
    var v1Parts = version1.split('.').map(Number);
    var v2Parts = version2.split('.').map(Number);
    for (var i = 0; i < Math.max(v1Parts.length, v2Parts.length); i++) {
        var v1 = v1Parts[i] || 0;
        var v2 = v2Parts[i] || 0;
        if (v1 > v2) return true;
        if (v1 < v2) return false;
    }
    return true; // If all parts are equal, return true
}

Version comparison logic:

  • The isVersionGreaterOrEqual() function splits both version strings into arrays of numbers.
  • It compares each corresponding part of the version numbers. If any part of the first version is greater than the corresponding part of the second version, the function returns true. If any part of the first version is less, it returns false. If all parts are equal, it returns true, indicating that the version is equal to or greater than the specified version.

HbbTV devices support the standard HTML navigator object. This can be used by an application to access basic details about the device/browser. For instance this can be used to access the userAgent string to determine the HbbTV version number of the device.

Capabilities

An HbbTV application can determine the capabilities of the television it is running on by using the [application/oipfCapabilities](/references/configuration-and-setting-apis/the-application-oipfcapabilities-embedded-object) object, which is part of the HbbTV and Open IPTV Forum (OIPF) specifications. This object provides information about various capabilities of the device, such as supported video codecs, network interfaces, and DRM systems.

The object can be accessed in the same way as the oipfApplciationManager. The object is declared in the body of the HTML document and then accessed in JavaScript using getElementById().

In the HTML file this would be:

<body>
...
     <object type="application/oipfCapabilities" id="capabilities"></object>
...
</body>

In the JavaScript file this would be:

<script>
...
      Function getCapabilities(){
         const capabilities = document.getElementById('capabilities');
     }
...
<script>

xmlCapabilities property

This object can be used in two ways, it can be used to fetch an XML document with all the devices capabilities listed through the xmlCapabilities property of the object.

const capabilities = document.getElementById('capabilities');
const xmlCapabilities = capabilities.xmlCapabilities;

An example of xmlCapabilities is:

<profilelist>
  <ui_profile name="OITF_HD_UIPROF+META_EIT+META_SI+HTML5_MEDIA+DVB_S+DVB_T+DRM">
    <ext>
      <video_broadcast type="ID_DVB_T">true</video_broadcast>
      <parentalcontrol scheme="dvb-si">true</parentalcontrol>
      <drm DRMSystemID="urn:dvb:casystemid:19219">TS MP4</drm>
    </ext>
  </ui_profile>
  <audio_profile name="MPEG1_L3" type="audio/mpeg"/>
  <audio_profile name="HEAAC" type="audio/mp4"/>
  <video_profile name="TS_AVC_SD_25_MPEG1_L2" type="video/mpeg"/>
  <video_profile name="TS_AVC_HD_25_MPEG1_L2" type="video/mpeg"/>
  <video_profile name="TS_AVC_SD_25_HEAAC" type="video/mpeg"/>
  <video_profile name="TS_AVC_HD_25_HEAAC" type="video/mpeg"/>
  <video_profile name="TS_AVC_SD_25_AC3" type="video/mpeg"/>
  <video_profile name="TS_AVC_HD_25_AC3" type="video/mpeg"/>
  <video_profile name="MP4_AVC_SD_25_HEAAC" type="video/mp4" transport="dash" DRMSystemID="urn:dvb:casystemid:19219"/>
  <video_profile name="MP4_AVC_HD_25_HEAAC" type="video/mp4" transport="dash" DRMSystemID="urn:dvb:casystemid:19219"/>
  <html5_media>true</html5_media>
  <video_display_format width="3840" height="2160" frame_rate="50" bit_depth="10" colorimetry="bt709 bt2020"/>
</profilelist>

Elements can be accessed using getElementsbyTagName(). Attributes of an element can be accessed using getAttribute().

const uiProfiles = capabilities.xmlCapabilities.getElementsByTagName("ui_profile");
        for (let uiProfile of uiProfiles) {
            const uiComponents = uiProfile.getAttribute("name").split("+");
            for (let uiComponent of uiComponents) {
                ...
            }
            const uiProfileExts = uiProfile.getElementsByTagName("ext");
            for (let uiProfileExt of uiProfileExts) {
                for (let node of uiProfileExt.childNodes) {
                    const name = node.nodeName;
                    const value = node.childNodes[0].nodeValue;
                    ...
                    for (let attr of node.attributes) {
                        const attrName = attr.name;
                        const attrValue = attr.value;
                        ...
                    }
                }
            }
        }

hasCapability() Method

The object can also be used to check the status of a capability using the hasCapability() method.

const capabilities = document.getElementById('capabilities');
const HDProf = capabilities.hasCapability('+DRM');

The valid capabilities are DL, PVR, DRM, IPC and AFS.

Extra Video Decodes

An oipfCapabilities object has three additional properties, which determine how many extra SD, HD and UHD decodes a television device is capable of decoding. These properties are:

  • extraSDVideoDecodes
  • extraHDVideoDecodes
  • extraUHDVideoDecodes

These are useful if an application wants to decode multiple videos at once. The values of these prosperities are affected by the ongoing decodes and can change as decodes are started and stopped.

The reasons to decode multiple videos at once is to have a picture in picture interface where both ‘pictures’ are moving videos. The other reason is to start decoding a video in the background so that an application can switch seamlessly between them.

Example code is:

const capabilities = document.getElementById('capabilities');
const extraHDVideoDecodes = capabilities.extraHDVideoDecodes;

Implementation note: it is unlikely that even if a TV has multiple video decode capabilities that these will be directly exposed to an HbbTV application, so in most cases these values will be zero.

Configuration

The configuration of a device is retrieved using the [application/oipfConfiguration](/references/configuration-and-setting-apis/the-application-oipfconfiguration-embedded-object) embedded object. The application/oipfConfiguration embedded object has a single configuration property, which returns a Configuration object.

The Configuration object allows configuration items within the system to be read. This includes settings such as preferred audio and subtitle languages, whether subtitles are enabled, the DTT network ID and a distinctive identifier.

The embedded object is accessed by first declaring in the body of the HTML of an HbbTV application:

<object type="application/oipfConfiguration" id="configuration"></object>

The configuration can then be retrieved in JavaScript:

const configObj = document.getElementById('configuration').configuration

The configuration object has a number of readonly properties through which the device’s configuration can be accessed.

Distinctive Identifier

The deviceId property of the [Configuration](/references/configuration-and-setting-apis/the-configuration-class) object returns a distinctive identifier that is unique for the combination of the device and the HTML document origin of the HbbTV application. This is useful to uniquely identify devices. However there may be restriction to accessing this identifier. If there are restrictions the property will return a status code starting with a ‘#’.

If ‘#1’ is returned the application user must be asked for permission for the application to access the distinctive identifier. This is done through the requestAccessToDistinctiveIdentifier method, which is called with a callback function to handle to response. This callback function is called with a first argument that is either true if access is now available or false if is is not.

const configObj = document.getElementById('configuration').configuration
const deviceId = configObj.deviceId;
  if(deviceId.startsWith("#")){
    if(deviceId === "#1"){
      configObj.requestAccessToDistinctiveIdentifier(identifierCallBack)
    }
    esle{
      // Handle other status codes
      ...
    }
}
...

function identifierCallBack(result) {
  if(result){
    const configObj = document.getElementById('configuration').configuration;
    const deviceId = configObj.deviceId;
    // Handle success
    ...
  }
  else{
    // Handle failure
    ...
  }
}