Skip to content

Latest commit

 

History

History
1068 lines (754 loc) · 55.7 KB

JSBRIDGE.md

File metadata and controls

1068 lines (754 loc) · 55.7 KB

OnSign TV Javascript API

OnSign TV players inject a Javascript object, named signage into all running Apps, which is accessible via the Window object. Through this object, your apps will be able to retrieve useful information regarding the player and content being played.

Important: Not all methods in the signage object are available on all platforms and most of them are not available before the "signageloaded" event is fired. Check the compatibility matrix at the bottom of this page to know when you can use each method and protect uses with a try {} catch (e) {}.

Adding the {{ __loadsdk__ }} Directive

In order to receive any event or use any method listed in this documentation you'll need to load the Signage SDK and wait for it to finish loading.

To load the SDK you must add a {{ __loadsdk__ }} directive to your app. This will be required for all apps with a <script> tag imported after February 2023.

Important: The {{ __loadsdk__ }} directive must be placed before any {{ __config__ }} or {{ __datafeed__ }} directives, as well as before any <script> tag on your app.

If you are using the signage.playbackLoops() API this directive must be changed to {{ __loadsdk__(contentinfo=True) }} in order to have the name and attributes of every content available locally in the player, otherwise only the Content ID is guaranteed to exist. Please mind that enabling names and attributes increases the bandwidth used by your player.

Click here to expand and view an example.

<!DOCTYPE html>
<html>
  <head lang="en">
    <title>Sample App with Events</title>
    {# When using Javascript you need to load the Signage SDK first #}
    {{ __loadsdk__ }}
    {# After loading you can add your configuration #}
    {{
        __config__(type="color", name="background_color",
            label="Text background color", value="#FFFFFF")
    }}
  </head>
  <div style="background-color: {{ background_color }};">
      SIZE: <span id="width">?</span>x<span id="height">?</span>
  </div>
  <script>
    // Now you can use sizechanged event.
    document.addEventListener("sizechanged").then(function (event) {
      document.getElementById("width").innerHTML = event.detail.width;
      document.getElementById("height").innerHTML = event.detail.height;
    });
  </script>
</html>

Signage Events

The Signage Javascript SDK injects some events into the document of your app. You can use document.addEventListener(eventName, fn) to listen to them.

Check below for more information on each event, specially the signageloaded and show events.

This event fires when methods in the window.signage object are ready to be called. Not all methods are available on every player version or operating system, so check the compatibility matrix before using them.

Important: This event is guaranteed to fire after the window.onload and is available on all platforms and versions, so it is safe to be used instead of the load event.

In case you need this event as a Promise you can use the window.signageLoaded Promise.

Document: 'show' Event

Most of the time your app will be loaded ahead of time to avoid displaying an unfinished page to end users. When that happens the player will load your app in an invisible area of the screen and then instantly display it when the time comes. The duration of this preload vary from platform to platform, from 1 to 5 seconds.

If you have animations or other time-based transitions you need to wait for your app to actually be displayed to the end users before starting those animations and timers.

For instance, a news app that displays one article every X seconds, can only start its internal timer once the show event is fired. Also, since timers in Javascript aren't synchronized with the Player timers it is usually a good idea to wait up to a second after the show event is received before initializing internal timers.

Important: This event is guaranteed to fire after the window.onload and the signageloaded event. For compatibility reasons it may take up to five seconds to fire on older player versions.

In case you need this event as a Promise you can use the window.signageVisible Promise.

Document: 'restart' Event

This event fires when the app is being looped, meaning it should refresh information. It's useful for when the app is permanently on screen. It's up to the developer to make use of this or not, depending on the application.

Do note that you can instead set the force-reload meta tag documented on Force App Reload, since that tag ensures the page always gets reloaded between consecutive app playbacks.

Document: 'sizechanged' Event

Event fired when the app changes size, either due to a resize by the end-user during preview or the player repositioning the iframe due to layout changes.

Contrary to the native window.onresize event, the sizechange event is properly debounced so you won't get hundreds of events for user-generated resizes.

  // Handle resize of the app. You can get the current size through event.detail
  document.addEventListener('sizechanged', function (event) {
    var width = event.detail.width;
    var height = event.detail.height;
  });

Signage Notification API

Some changes are not propagated through the document element, like player property or attribute changes. Those events require you to listen directly on the signage object and therefore cannot be registered before the signageloaded event is fired.

Signage: 'attrchanged' Event

This event fires when one of the player attribute changes. Player attributes can change when an user edits them on the platform or locally through the signage.getPlayerAttribute("name") and signage.setPlayerAttribute("name", "value") methods.

  signage.addEventListener('attrchanged', function (event) {
    // Name of the attribute that changed value
    var attrName = event.detail.name;
    // New value of the attribute. Can be a string, a number, or a list of strings.
    var attrValue = event.detail.value;
  });

Signage: 'propchanged' Event

This event fires when one of the player property changes. Property changes when user changes edit them on the platform, through a predetermined schedule or locally through the API.

There are two currently supported properties: "brightness" and "volume".

  signage.addEventListener('propchanged', function (event) {
    // Name of the property. Could be "brightness" or "volume".
    var propName = event.detail.name;
    // New value of the property.
    var propValue = event.detail.value;
  });

Signage: 'serialportdata' Event

This event fires when data is read from the RS-232 Serial Port named in the "alias" parameter. The serial port configuration and alias are set on your OnSign TV player settings page.

signage.addEventListener("serialportdata", "alias", function (event) {
  var portAlias = event.detail.name; // will contain the port alias.
  var readValue = event.detail.value; // will contain the data read.
});

The event.detail.value can either be an ASCII String containing a single character, an ASCII String containing a line of text or an ArrayBuffer containing the binary data read. This will depend on the configuration done by the user on OnSign TV.

Mode detail.value type Behavior
Binary ArrayBuffer Fires at fixed intervals depending on the source of the data.
Character ASCII String Fires one event per character read from the serial port.
Line ASCII String Fires one event per line of text read from the serial port. The event.detail.value will not include line ending characters.

Signage: 'contentchanged' Event

This event fires whenever the given ContentID is changed.

The ContentID must be acquired from a configuration option or from a media file. Any other method of acquiring that ID can't assume the file will exist in the player, because only published files are downloaded. Listening to changes of an unknown ContentID is not considered an error, the event will just never be fired.

signage.addEventListener("contentchanged", "ContentID", function (event) {
  var contentId = event.detail.id; // will contain the given "ContentID".
});

Signage: 'playbackloopschanged' Event

This event fires whenever the content currently playing changed.

If you need to keep track of playback changes use this event instead of calling signage.playbackLoops() periodically.

signage.addEventListener("playbackloopschanged", function (event) {
  var playback = event.detail.value; // has the same value as signage.playbackLoops().
});

Signage Promises

Some events are also available as top-level promises that can be used with other promises and combined in new ways.

The window.signageLoaded promise is guaranteed to only be resolved after the 'signageloaded' event fires, so you can also use this promise to check all your script files and the platform SDK have finished loading.

The window.signageVisible promise is guaranteed to only be resolved after the 'show' event fires so you can use it to start timers in your app.

Click here to expand and view an example.

<!DOCTYPE html>
<html>
  <head lang="en">
    <title>Sample App with Visible Promise</title>
    {# When using Javascript you need to load the Signage SDK first #}
    {{ __loadsdk__ }}
  </head>
  <div id="result"></div>
  <script>
    // Now you can use the signagevisible promise.
    window.signageVisible.then(function () {
      document.getElementById("result").innerHTML = "VISIBLE";
    });
  </script>
</html>

App Configuration Object API

App configuration options that have the js parameter set to True on the {{ __config__ }} directive will be available to scripts through the window.appConfig global object.

If the configuration was marked as optional and no value was defined by the user, accessing its value on the window.appConfig object will return undefined.

If at least one configuration option was marked as js=True and the app contains internationalization options, the current locale setting will also be available on window.appConfig.__lang__.

Important: Configuration types currently supported on the window.appConfig object: bool, choice, color, date, datetime, float, multichoice, number, paragraph, richtext, text, time, url.

Click here to expand and view an example.

<!DOCTYPE html>
<html lang="{{ __lang__ }}">
  <head>
    <title>appConfig Example</title>
    {{ __loadsdk__ }}

    {{ __config__(name="userDate", type="date", label="Date to be displayed", js=True) }}
  </head>
  <body>
    <div id="date-display"></div>

    <script type="text/javascript">
      window.signageLoaded.then(function() {
        var userDateInput = new Date(window.appConfig.userDate);
        var formatter = new Intl.DateTimeFormat(window.appConfig.__lang__);

        document.getElementById("date-display").innerText = formatter.format(userDateInput);
      });
    </script>
  </body>
</html>

Signage Object API

The following methods are on the window.signage object. They are available to use after the signageloaded event fires or the window.signageLoaded Promise is resolved.

Please check the compatibility matrix to view which method is supported on which player version.

There are a few methods that manipulate the player hardware:

Additionally there are a few methods for Text-To-Speech, on players that support such functionality.

signage.playbackInfo()

Returns a stringified JSON object that bundles information about the player and the current campaign. This object can be expanded in the future to contain other types of information.

Object Model:

  {
    // Reason this campaign was played. If there is no reason, type is defined as "unknown"
    "reason": {
      "type": "time", // Other values: "touch", "key", "geo", "timeout", "ondemand", "api" and "unknown"
      "timestamp": 15467551, // unix timestamp
      // For type === "touch"
      "x": 230, // X,Y values returned are based on a virtual screen of 100000x100000 pixels.
      "y": 470,
      // For type === "key"
      "keys": "abcd",
      // For type === "api", when using /trigger/text or signage.triggerInteractivity("text")
      "value": "text",
      // For type === "geo"
      "lat": -27.5967811,
      "long": -48.5201524,
      "direction": "in", // other possible value is "out".
      // For type === "ondemand" or type === "api"
      "params": { // Always an object, contains extra parameters passed through the URL.
        "foo": "bar"
      }
    },
    "campaign": {
      "id": "13132",
      "name": "campaign name",
      "duration": 20, // in seconds
      "tags": ["tag1", "tag2"], // Always an array, even without tags,
      "attrs": { // Always an object, even without attributes.
        "key 1": "value 1"
      }
    },
    "player": {
      "id": "21313",
      "name": "player name",
      "version": "5.2.0-develop",
      "tags": ["tag1", "tag2"], // Always an array, even without tags.
      "attrs": { // Always an object, even without attributes.
        "key 1": "value1",
        "key 2": "value2"
      }
    }
  }

Example:

  // In the example below, it is important to wrap the code using a try/catch statement for two reasons:
  // 1. The signage object might not be available;
  // 2. The JSON.parse() might throw an exception if data is not valid.
  try {
    // Get the stringified JSON object representing the `playbackInfo` data from the signage object.
    var data = signage.playbackInfo();
    // Parse data into a JSON object
    var playbackInfo = JSON.parse(data);
    // Log the player name:
    console.log(playbackInfo.player.name);
  } catch (ex) {
    console.error('Signage object not available or data var does not contain a valid JSON string.');
  }

signage.playbackLoops()

Returns a Promise that resolves to an object with information about what is currently being displayed on the screen.

While signage.playbackInfo() only returns information about the app that called the method, this API returns all content being played.

Content being played belongs to a loop and is playing for a reason. All loops play concurrently. A loop might be temporary, might be created by an interactivity or be scheduled through the platform.

In order to save bandwidth not all content have their name and attributes locally available on the player. If that information is required by your app, you must declare {{ __loadsdk__(contentinfo=True) }} when configuring the SDK. Without this only the Content ID is guaranteed to exist.

Please mind that this API returns a lot of data and is CPU-intensive. Calling it more than once a second might cause visible delays to playback, so use it with parsimony.

If you need to be notified on when the content being played changed, use the signage.addEventListener("playbackloopschanged") event.

window.signageLoaded.then(function() {
  signage.playbackLoops().then(function(info) {
    // Check the sample below to view the structure available on info.
  });
});
Click here to expand and view an example of the data returned.

{
  "ts": 1702061023000,
  "loops": [
    {
      "name": "PRIMARY",
      "start": 1702060000000,
      "rect": [0, 0, 1920, 1080],
      "content": {
        "id": "32UXjbLV",
        "playId": "#c122",
        "kind": "TRACKS",
        "name": "Playlist With Multiple Items",
        "attrs": {
          "__tags__": ["playlist-tag"],
          "Customer Name": "some brand"
        },
        "reason": "LOOP",
        "start": 1702061023000,
        "tracks": [
          {
            "name": "__32UXjbLV#0__",
            "rect": [0, 0, 1920, 1080],
            "content": {
              "id": "02Ub7L1x",
              "playId": "#c123",
              "kind": "TRACKS",
              "name": "Campaign With Two Timelines And Audio Track",
              "attrs": {
                "__tags__": ["some-tag", "other tag"],
                "__category__": "Category",
                "Customer Value": 55
              },
              "reason": "LOOP",
              "start": 1702061023000,
              "tracks": [
                {
                  "name": "user-defined track name",
                  "rect": [0, 0, 1920, 700],
                  "content": {
                    "id": "jaUpoPKV",
                    "playId": "#c124",
                    "kind": "IMAGE",
                    "name": "a.png",
                    "attrs": {
                      "__tags__": ["another-tag"]
                    },
                    "reason": "LOOP",
                    "start": 1702061023000,
                  }
                },
                {
                  "name": "__02Ub7L1x#0__",
                  "rect": [0, 700, 1920, 340],
                  "content": {
                    "id": "32UXZyPl",
                    "playId": "#c124",
                    "kind": "IMAGE",
                    "name": "b.png",
                    "attrs": {},
                    "reason": "TOUCH",
                    "start": 1702061028000,
                  }
                },
                {
                  "name": "empty named track",
                  "rect": [0, 0, 1920, 1080]
                }
                {
                  "name": "__02Ub7L1x#3__",
                  "content": {
                    "id": "jaUpoPKV",
                    "playId": "#c124",
                    "kind": "AUDIO",
                    "name": "misery.mp3",
                    "attrs": {},
                    "reason": "LOOP",
                    "start": 1702061023000
                  }
                }
              ]
            }
          }
        ]
      }
    }
  ]
}

Below is a description of all objects returned by this API.

Important: Fields marked with ? are optional. You should check if they exist before using them.

Property Type Description
"ts" number Current local time, in number of milliseconds elapsed since the epoch, as seen by the playback engine. Should be used instead of Date.now() to calculate durations in order to account for the inherent latency in calling this API.
"loops" LoopInfo Every loop that has content playing. Please mind that some loops are not visible on screen, for example audio loops, and some loops are ephemeral, as for loops created by on-demand content. Loops are stacked on top of each other. This list is ordered from bottom-most to top-most loop.

Type LoopInfo

Information about a particular loop being played.

Property Type Description
"name" LoopName The name of this loop. Check the linked documentation for more.
"start" number Local time of when this loop started, in number of milliseconds elapsed since the epoch.
"rect"? Array[number] An array of 4 numbers containing the values for x position, y position, width and height of the loop on the player window. Position 0, 0 is at top left. If absent, this loop is hidden.
"content" ContentInfo The content that is currently playing in this loop.

Type ContentInfo

Information about the content being played.

Property Type Description
"id" string The ID of this content. Matches the one visible on the platform and available through the GraphQL API.
"playId" string An identifier for each individual playback of this content in this player. It is not guaranteed to be unique across players or restarts of the player app.
"kind" ContentKind Kind of the content being played. Please be mindful that new kinds might be available in the future.
"name" string The user-defined name of this content on the platform. Might contain unescaped HTML characters.
"attrs" object User-defined attributes on the content. They might be custom attributes or platform-level ones. Platform-level attributes are: "__tags__" containing an Array[string] with the tags and "__category__" containing a string with the user-given category. Both properties and values of this object might contain unescaped HTML characters.
"reason" PlayReason The reason this content is currently playing. Check the linked documentation for more.
"start" number Local time of when this content started playing, in number of milliseconds elapsed since the epoch.
"tracks"? Array[TrackInfo] When "kind" === "TRACKS" these are the individual tracks that are playing content. Tracks are stacked on top of each other. This list is ordered from bottom-most to top-most track.

Type TrackInfo

Information about a particular track.

Property Type Description
"name" string The user-given name for this track. If the user did not name this track, the player will create a random name that exists only on this player. Might contain unescaped HTML characters.
"start" number Number of milliseconds elapsed since the epoch, in local time, when this loop started.
"rect"? Array[number] An array of 4 numbers containing the values for x position, y position, width and height of the track on the player window. Position 0, 0 is at top left. If absent, this track is hidden.
"content"? ContentInfo Content currently playing in this track. If absent, this track is empty.

Type LoopName

Name of the loop being played.

Name Description
"WELCOME" Played exactly once, every time the player starts. Does not loop once finished.
"PRIMARY" Played repeatedly once the "WELCOME" loop finishes.
"FALLBACK" Played when "PRIMARY" loop is empty or every item in "PRIMARY" was restricted from being played.
"AUDIO" Audio content that plays concurrently with other loops.
"AUTOMATION" HTML content that plays concurrently with other loops.
"SECONDARY" Content played on the secondary screen, for players that support two displays. Is played concurrently with other loops.
"DYNAMIC.${N}" Created by on-demand content or interactivity and played exactly once, concurrently with other loops. ${N} is a numeric value that increases every time a new loop is created.

Type ContentKind

Kind of the content being played.

Kind Description
"TRACKS" Contains one or more tracks of content. Please mind that campaigns, playlists and audio playlists all have the "TRACKS" kind on this API.
"APP" HTML app.
"AUDIO" Audio content, such as an MP3 file.
"VIDEO" Video content, such as an WebM file.
"IMAGE" Image content, such as a JPEG or a SVG file.

Type PlayReason

Reason why the content is playing.

Reason Description
"LOOP" Content was scheduled in a loop.
"GEO" Content was triggered by a change in player geolocation.
"TOUCH" Content was triggered by a touch.
"KEY" Content was triggered by input on a keyboard.
"TIMEOUT" Content was triggered because of a configured timeout interactivity.
"TIME" Content was triggered by a scheduled time trigger.
"ONDEMAND" Content was triggered through a remote on demand call.
"API" Content was triggered through a local API, either Local Web API or the signage.triggerInteractivity() method.
"ATTR" Content was triggered by a change in a player attribute.

signage.width()

Returns the region (where the App is being displayed) width in pixels.

Example:

  console.log('Width:', signage.width());

Please, note that the Webview viewport size might be different than the region resolution. "The screen density (the number of pixels per inch) on an Android-powered device affects the resolution and size at which a web page is displayed. The Android Browser and WebView compensate for variations in the screen density by scaling a web page so that all devices display the web page at the same perceivable size as a medium-density screen." More info here

signage.height()

Returns the region (where the App is being displayed) height in pixels.

Example:

  console.log('Height:', signage.height());

Please, note that the WebView viewport size might be different than the region resolution. "The screen density (the number of pixels per inch) on an Android-powered device affects the resolution and size at which a web page is displayed. The Android Browser and WebView compensate for variations in the screen density by scaling a web page so that all devices display the web page at the same perceivable size as a medium-density screen." More info here

signage.isVisible()

Returns a boolean representing the app visibility.

Example:

  console.log('App is visible?', signage.isVisible());

OnSign TV players usually preload all campaign assets, including apps, a few seconds before starting the playback. As soon as the campaign starts the apps are already loaded, creating a better visual experience.

signage.getCurrentPosition()

Returns a stringified JSON object containing the player location data. Might contain stale data if the app has not been reloaded in a while.

When possible use signage.getGeoLocation() to get the current location.

Position Model:

  {
    coords: {
      accuracy: null,
      altitude: null,
      altitudeAccuracy: null,
      heading: null,
      latitude: 43.01256284360166,
      longitude: -89.44531987692744,
      speed: null
    },

    timestamp: 1479930166006
  }

Example:

  try {
    // Get the stringified location data.
    var data = signage.getCurrentPosition();
    // Parse the location data into a Position object.
    // > The result object will be exactly the same as the one returned by the
    // native `Geolocation.getCurrentPosition()` method.
    var position = JSON.parse(data);
    // Log player's latitude and longitude
    console.log('Latitude:', position.coords.latitude);
    console.log('Longitude:', position.coords.longitude);
  } catch (ex) {
    console.log('Signage.getCurrentPosition() method is not available or data is not valid.');
  }

signage.getGeoLocation()

Returns a Promise that contains the player location, as good as can be determined.

In contrast to signage.getCurrentPosition(), this method will fallback to the location configured in the Player Settings page or derived from the Player IP address. The position obtained by this method will be the same used to check for geographic restrictions on content publications.

if (signage && signage.getGeoLocation) {
  signage.getGeoLocation().then(function(geo) {
    console.log(geo.src, geo.lat, geo.lng);
  });
}

When the promise is fulfilled the result will contain an object with three attributes: lat, lng and src.

{
  "src": "ip", // can be one of "gps", "user", or "ip", based on the source of the location.
  "lat": -27.5967811, // player latitude
  "lng": -48.5201524, // player longitude
}

signage.triggerInteractivity("value" [, {"param": "pvalue"}])

Triggers the Local API interactivity with user-defined "value".

For this method to have an effect a "Local API" interactivity needs to be defined – either on the player or the current content hierarchy – with a regular expression that matches the parameter "value" of this method.

What will happen when this interactivity is triggered is defined in the Interactivity Configuration UI.

Interactivity Sample

This method has an optional second parameter with a plain object containing keys and values that will be present in the signage.playbackInfo() of the triggered content, if any content is triggered.

For instance, in one app you can trigger an interactivity, passing an object containing parameters

  try {
    signage.triggerInteractivity('show-content', {
      'content': 'contentValue'
    });
  } catch (ex) {
    console.error('Signage object not available');
  }

If the interactivity matches any configuration those parameters can be retrieved in the content that just started playing.

  var playbackParams = {};

  // In the example below, it is important to wrap the code using a try/catch statement for two reasons:
  // 1. The signage object might not be available;
  // 2. The JSON.parse() might throw an exception if data is not valid.
  try {
    // Get the stringified JSON object representing the `playbackInfo` data from the signage object.
    var playbackInfo = JSON.parse(signage.playbackInfo());
    // Sanity checks to see whether the parameter was set.
    if (typeof playbackInfo.reason === 'object' && typeof playbackInfo.reason.params === 'object') {
      playbackParams = playbackInfo.reason.params;
    }
  } catch (ex) {
    console.error('Signage object not available or data var does not contain a valid JSON string.');
  }
  // If this content is playing because of that interactivity, this will be true.
  console.log(playbackParams['content'] === 'contentValue');

signage.stopCurrentCampaign()

Immediately stops the current campaign, moving to the next one in the loop. The campaign is reported as being partially played, so will only show in reports that have the "Include Partial Playback" option checked.

Usage of this method will result in flash of black or white screens because there is no time to preload the next content. Replace uses with signage.stopThisItem() with a few seconds of delay to give the player ample time to preload the next content and avoid blank screens.

signage.stopThisItem(delay, [stopParentCampaign, [isPartialPlayback]])

Stops the app that called this function in delay milliseconds. If delay parameter is 0 or missing the app is stopped immediately.

Given that all apps are "preloaded" before being displayed, if you call signage.stopThisItem(0) before the show event, the next content will be preloaded and displayed without causing a black screen.

The delay time starts running as soon as you call this function. In order to display an app for a specific duration you need to listen to the show event before calling signage.stopThisItem(), in order to account for the variable preload duration:

<!DOCTYPE html>
<title>This App is Displayed for 30 Seconds</title>
{# guarantee the show event works on all platforms by loading the SDK #}
{{ __loadsdk__ }}
<script type="text/javascript">
  document.addEventListener('show', function() {
    signage.stopThisItem(30000);
  });
</script>

If you call this function after the show event, ensure that the delay is at least 5000 milliseconds so there is enough time to preload the next content and avoid a black screen.

This function will have no effect if delay is greater than the remaining playback duration of this app, as configured through the signage platform. Calling it more than once, regardless of parameters, will also have no effect.

Heads up! If this function is used to skip different apps multiple times in a row there might not be enough time to preload a new content and a black screen might occur.

The stopParentCampaign parameter controls whether the campaign holding this item should also be stopped. It has no effect if this app was published directly to a playlist or player. If false or missing, the parent campaign is not stopped. Please mind that if the campaign duration is not set as Variable in the platform, this might cause a black screen depending on how your campaign is structured.

The isPartialPlayback controls whether this app was interrupted before its natural ending or not. Apps that are interrupted only show in reports created with the "Include Partial Playback" option checked. If not given or false the playback is not reported as partial.

signage.getPlayerAttribute("name")

Retrieves the current value of the player attribute called "name".

Attributes need to be created on the platform before they can be retrieved. If an attribute with that name doesn't exist or the value is not set for the current player this method will return null.

Otherwise it will return the value for the current player, which can be a Javascript number or string, according to the type specified when creating the attribute on the platform.

signage.setPlayerAttribute("name", "value")

Sets the current value of the player attribute called "name" to "value".

Player attributes need to be created on the platform before they can be set. The value parameter must be either a Javascript number or string, according to the type specified when creating the attribute on the platform.

If an attribute with the given name does not exist or the value type is incorrect, this call will have no effect.

Attributes set using this function are persisted only until the player reboots and affects attribute restrictions on content playback for this player until reboot.

signage.setPlayerAttribute({"name": "value", "other name": "other value"})

Update the current value of multiple player attributes based on the given object.

Player attributes need to be created on the platform before they can be set. The object values must be either a Javascript number or string, according to the type specified when creating the attribute on the platform.

If an attribute in the object does not exist or its value type is incorrect, it will be ignored.

Attributes set using this function are persisted only until the player reboots and affects attribute restrictions on content playback for this player until reboot.

signage.sendEvent("level", "code", [, "message", {"extra": "values object"}])

Adds custom messages to the event listing page of the player.

The first parameter is the level of this event. Must be one of the following strings: "debug", "info", "warning", "error" or "fatal". Events with "debug" level are hidden from the end-user, while "error" or "fatal" events will cause a notification to be sent to their email. Please use them sparingly.

The second parameter is a machine-readable event code. It is used to aggregate events of the same code. It must contain only letters, numbers, dashes and underscores, matching this regular expression ^[_a-zA-Z][-_0-9a-zA-Z]*$, with up to 128 characters in length.

The third parameter is the message that will be shown to the end-user, or sent to their email for "error" or "fatal" events. Can be up to 1024 characters in length.

The last parameter is an object containing data you want to attach to this event. The sum of the length of all keys and values must be less then 16 Kilobytes.

If the player is offline, the event will be saved in persistent storage and be sent when the player comes back online.

Events are rate-limited, with each player being able to send up to 200 events per hour.

signage.sendEvent("info", "connection-status", "Connected to the network.", {"status": true});

signage.sendEvent("error", "connection-status", "Unable to connect to the network.", {"status": false});

signage.serialPortWrite("alias", data)

Writes data to the given RS-232 Serial Port called "alias". The serial port configuration and alias are set on your OnSign TV player settings page.

The second parameter, data, is an ASCII String to be written. Trying to write non-ASCII characters might cause the write to fail or the non-ASCII characters to be rejected, depending on the platform.

Returns a Promise that is fulfilled when the write succeeds or is rejected when the write fails. A write might fail due to the serial port being disconnected, not configured or temporarily busy.

There is no automatic retry of writes. Writes are always enqueue before being executed, so that multiple apps can write to the same serial port without interweaving the data.

signage.readContent("ContentID", {encoding: "utf8"})

Reads a file as a String. The file is referenced by its ContentID and converted to string according to the given encoding.

The first parameter is the ContentID, which must be acquired from a configuration option or from a media file. Any other method of acquiring that ID can't assume the file will exist in the player, because only published files are downloaded.

The second parameter is an object specifying the encoding of the file. Currently the only supported encoding is "utf8", but other encodings might be supported in the future.

Returns a Promise that is fulfilled with the contents of the file as a String. The promise is rejected if the content does not exist, doesn't have an associated file, could not be read or its encoding is not valid UTF-8.

You can use signage.addEventListner("contentchanged", "ContentID", cb) to be notified of any changes to this content file.

Click here to expand and view an sample using this API.

<!DOCTYPE html>
<title>Example of reading an XML file</title>

{{ __loadsdk__ }}

{{ __config__(name="config_file", type="xml", label="XML config") }}

<script type="text/javascript">
  window.signageLoaded.then(function () {
    signage
      .readContent("{{ config_file.id }}", { encoding: "utf8" })
      .then(function (fileData) {
        // You can use the fileData string any way you want.
      }, function (error) {
        // something went wrong and we couldn't read the file.
      });
  });
</script>

signage.log("level", "domain", "message")

Logs internal messages that can be used by support staff to understand app issues. These messages are not end-user visible and are available on request.

This function is not rate-limited like signage.sendEvent, therefore it is suitable for debugging.

signage.playAudio("file:///uri")

Plays the local file referenced by the ID. Usually this file is uploaded alongside the app, so you can get the URI when rendering the template:

<!DOCTYPE html>
<title>Example of referencing an audio</title>
{{ __loadsdk__ }}
<script type="text/javascript">
  window.signageLoaded.then(function() {
    signage.playAudio("{{ media.bell_ring.url }}");
  });
</script>

signage.getBrightness()

Get the current value of screen brightness, from 0 to 100.

Brightness can be configured either through hardware or software and that configuration is done through the platform.

signage.setBrightness(value)

Set the current value of screen brightness, from 0 to 100.

Brightness can be set either through hardware or software, depending on the configuration done through the platform. If not configured there, using this method will cause the player to fallback to software brightness.

signage.getVolume()

Get the current hardware volume, from 0 to 100. This method represents the volume of the hardware itself, not the volume your app is configured to use.

Even if your app is muted, signage.getVolume() might return 100 if the operating system volume is at max value.

signage.setVolume(value)

Sets the current hardware volume, from 0 to 100. This method changes the volume of the hardware itself, not the volume your app is configured to use.

signage.ledOn(red, green, blue)

For players that have a status LED around the screen, such as the Philips T-Line devices, it is possible to control that LED with this method. It accepts three values, from 0 to 255, for setting the intensity of the red, green and blue components of the LED.

signage.ledOff()

For players that have a status LED around the screen, such as the Philips T-Line devices, it is possible to poweroff that LED with this method.

Text-To-Speech Engine

Text-To-Speech provides access to the underlying platform's ability to transform text into spoken word. Each text to be spoken is called an utterance and contains information about the language, pitch and rate of the text to be spoken.

All utterances are queued and spoken in First-In-First-Out order. To interrupt any utterance currently being spoken the signage.ttsStop() can be called. This will cause the TTS engine to start speaking the next queued utterance. If you want to make sure the engine is idle, call signage.ttsFlush() before calling signage.ttsStop().

signage.ttsSetLanguage("es-US-x-Voice1")

Sets the language, locale and voice that will be used for future signage.ttsSpeak("text to be spoken") calls that don't provide the language option.

The parameter is the IETF language tag followed by the voice name. Per the document, the two or three letter language code is to be picked from ISO 639-1 or ISO 639-2. The country code is picked from ISO 3166-1. The language tag and country subtag have to be separated using a hyphen.

The voice is platform dependent, goes from Voice1 to Voice9, with Voice1 being the default voice for the given locale. It is also used if the requested voice does not exist. To comply to the IETF format, the selected voice must be preceded by -x-, e.g. "en-GB-x-Voice2" or "pt-BR-x-Voice3".

signage.ttsSetPitch(value)

Sets the pitch that will be used for future signage.ttsSpeak("text to be spoken") calls that don't provide the pitch option.

Value ranges from 0.0 to 4.0. 1.0 is the normal pitch, lower values lower the tone of the synthesized voice, greater values increase it.

signage.ttsSetRate(value)

Sets the rate that will be used for future signage.ttsSpeak("text to be spoken") calls that don't provide the rate option.

Value ranges from 0.0 to 4.0. 1.0 is the normal speech rate, lower values slow down the speech (0.5 is half the normal speech rate), greater values accelerate it (2.0 is twice the normal speech rate).

signage.ttsSpeak(text, [options])

If the Text-To-Speech engine is idle, begins speaking text immediately. Otherwise, enqueues text the utterance queue.

When provided, options is an object that specifies the behavior for this utterance. The available options are:

  • language: overrides the language for the given text.
  • pitch: overrides the pitch for the given text.
  • rate: overrides the rate for the given text.
signage.ttsSpeak("the train will arrive in 5 minutes", {language: "en-US"});
signage.ttsSpeak("el tren llegará en 5 minutos", {language: "es", rate: 1.1});

This function also supports the signage.ttsSpeak(text, language) signature for simplicity.

signage.ttsSpeak("el tren llegará en 5 minutos", "es-ES");

Returns a Promise that will be fulfilled with a boolean parameter signifying whether the text was spoken until the end. The promise will be rejected when TTS engine is unable to speak the utterance due to an error.

signage.ttsSpeak("speaking might fail").then(function(spoken) {
  if (spoken) {
    console.log("the phrase was spoken");
  } else {
    console.log("the phrase was interrupted or cancelled");
  }
}).catch(function() {
  console.log("failed to speak the phrase");
});

signage.ttsSilence(duration)

Causes the engine to pause for the given duration instead of speaking the next utterance. Duration is given in milliseconds.

Returns a Promise that will be fulfilled with a boolean parameter signifying whether the silence was maintained until the end. The promise will be rejected when TTS engine is unable to pause due to an error.

signage.ttsFlush()

Remove all enqueued utterances. If there are no utterance enqueued, calling this function is a no-op. The utterance currently being spoken, if any, will not be stopped. For that you must call signage.ttsStop().

signage.ttsStop()

Stops any utterance currently being spoken. If there are enqueued utterances, the oldest one is immediately dequeued and started. To completely stop the engine, call signage.ttsFlush() before calling signage.ttsStop().

Signage Compatibility Matrix

Before using a method of the Javascript API please check to see whether they are available on your target platform.

Method Android Windows Linux Samsung SSP BrightSign LG WebOS ChromeOS Raspberry Pi
signage.getBrightness() 5.1.0 10.1.0 10.1.0 10.1.0 10.1.0 10.1.0 - 10.1.0
signage.getCurrentPosition() 5.3.5 10.0.6 10.0.6 10.1.0 10.1.0 10.1.0 - -
signage.getGeoLocation() 9.9.5 10.0.6 10.0.6 10.1.0 10.1.0 10.1.0 - 10.1.0
signage.getPlayerAttribute() 9.8.11 9.3.13 10.1.0 10.1.0 10.1.0 10.1.0 - 10.1.0
signage.getVolume() 8.3.0 10.1.0 - 10.1.0 10.1.0 10.1.0 - 10.1.0
signage.height() 4.3.0 5.9.0 5.9.0 2.4.0 2.4.0 2.4.0 2.4.0 10.0.0
signage.isVisible() 4.0.11 2.0.4 2.0.4 2.4.0 2.4.0 2.4.0 2.4.0 10.0.0
signage.ledOff() 8.1.0 - - - - - - -
signage.ledOn() 8.1.0 - - - - - - -
signage.log() 9.1.0 10.1.0 10.1.0 10.1.0 10.1.0 10.1.0 - 10.1.0
signage.playAudio() 4.0.9 2.0.4 2.0.4 10.1.0 10.1.0 10.1.0 - -
signage.playbackInfo() 5.3.5 5.9.0 5.9.0 1.0.8 1.1.1 1.0.8 1.1.1 10.0.0
signage.readContent() 10.2.0 10.2.0 10.2.0 10.2.0 10.2.0 10.2.0 - -
signage.playbackLoops() - - - - - - - -
signage.sendEvent() 10.1.0 10.0.20 10.0.20 10.1.0 10.1.0 10.1.0 - 10.1.0
signage.serialPortWrite() 10.2.0 10.2.2 10.2.2 - 10.1.1 - - -
signage.setBrightness() 5.1.0 10.1.0 10.1.0 10.1.0 10.1.0 10.1.0 - 10.1.0
signage.setPlayerAttribute() 9.8.11 9.3.13 9.3.13 10.1.0 10.1.0 10.1.0 - 10.1.0
signage.setPlayerAttributes() 10.1.1 10.1.6 10.1.6 10.1.0 10.1.0 10.1.0 - 10.1.0
signage.setVolume() 8.3.0 10.1.0 10.1.0 10.1.0 10.1.0 10.1.0 - 10.1.0
signage.stopCurrentCampaign() 8.3.0 9.3.13 9.3.13 10.1.0 10.1.0 10.1.0 - 10.1.0
signage.stopThisItem() 10.1.0 10.1.0 10.1.0 10.1.0 10.1.0 10.1.0 - 10.1.0
signage.triggerInteractivity() 9.8.11 9.3.13 9.3.13 10.1.0 10.1.0 10.1.0 - 10.1.0
signage.ttsFlush() 10.1.0 10.0.20 10.0.20 - - - - -
signage.ttsSetLanguage() 10.1.0 10.0.20 10.0.20 - - - - -
signage.ttsSetPitch() 10.1.0 10.0.20 10.0.20 - - - - -
signage.ttsSetRate() 10.1.0 10.0.20 10.0.20 - - - - -
signage.ttsSilence() 10.1.0 10.0.20 10.0.20 - - - - -
signage.ttsSpeak() 10.1.0 10.0.20 10.0.20 - - - - -
signage.ttsStop() 10.1.0 10.0.20 10.0.20 - - - - -
signage.width() 4.3.0 5.9.0 5.9.0 2.4.0 2.4.0 2.4.0 2.4.0 10.0.0
window.signageLoaded All All All All All All All All
window.signageVisible All All All All All All All All
document.addEventListener("signageloaded") All All All All All All All All
document.addEventListener("show") All All All All All All All All
document.addEventListener("restart") All All All All All All All All
document.addEventListener("sizechanged") All All All All All All All All
signage.addEventListener("attrchanged") 10.2.0 10.1.9 10.1.9 10.1.5 10.1.5 10.1.5 - -
signage.addEventListener("propchanged") 10.2.0 10.1.9 10.1.9 10.1.5 10.1.5 10.1.5 - -
signage.addEventListener("serialportdata") 10.2.0 10.2.2 10.2.1 - 10.1.5 - - -
signage.addEventListener("contentchanged") 10.2.0 10.2.0 10.2.0 10.2.0 10.2.0 10.2.0 - -
signage.addEventListener("playbackloopschanged") 10.3.0 10.3.0 10.3.0 10.3.0 10.3.0 10.3.0 - -